From 0ebf49bf3c2d40ef6a0c296c39ec5ff481f89646 Mon Sep 17 00:00:00 2001 From: Yuki Ueda Date: Tue, 5 Sep 2017 11:49:30 +0900 Subject: [PATCH 001/281] Fix word highlighting Solarized Dark theme #28343 --- .../themes/solarized-dark-color-theme.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json index 5309eb6fd1a..4144eeed162 100644 --- a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json +++ b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json @@ -364,9 +364,9 @@ // "editor.inactiveSelectionBackground": "", // "editor.lineHighlightBorder": "", // "editor.rangeHighlightBackground": "", - // "editor.selectionHighlightBackground": "", - // "editor.wordHighlightBackground": "", - // "editor.wordHighlightStrongBackground": "", + // "editor.selectionHighlightBackground": "#0FF0F0", + // "editor.wordHighlightBackground": "#ff0000", + // "editor.wordHighlightStrongBackground": "#00ff00", // Editor: Suggest // "editorSuggestWidget.background": "", @@ -476,4 +476,4 @@ "terminal.ansiBrightCyan": "#93a1a1", "terminal.ansiBrightWhite": "#fdf6e3" } -} \ No newline at end of file +} From 94d82edee01e2897ac8a1bc3cabd81ba5561b88d Mon Sep 17 00:00:00 2001 From: Nick Snyder Date: Thu, 7 Sep 2017 19:37:46 -0700 Subject: [PATCH 002/281] Use unused param --- src/vs/editor/common/commonCodeEditor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/common/commonCodeEditor.ts b/src/vs/editor/common/commonCodeEditor.ts index 29700d8baf2..346ced4fe41 100644 --- a/src/vs/editor/common/commonCodeEditor.ts +++ b/src/vs/editor/common/commonCodeEditor.ts @@ -450,7 +450,7 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo public revealRange(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth, revealVerticalInCenter: boolean = false, revealHorizontal: boolean = true): void { this._revealRange( range, - false ? VerticalRevealType.Center : VerticalRevealType.Simple, + revealVerticalInCenter ? VerticalRevealType.Center : VerticalRevealType.Simple, revealHorizontal, scrollType ); From 689dcf546f09e45720fdd33a079666147ef3fda3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Sep 2017 21:20:52 +0200 Subject: [PATCH 003/281] hacking my way around --- package.json | 3 +- .../electron-browser/mainThreadWorkspace.ts | 8 +- .../parts/files/browser/fileActions.ts | 3 +- .../parts/files/browser/views/explorerView.ts | 2 +- .../parts/files/common/explorerModel.ts | 10 +- .../services/editor/browser/editorService.ts | 4 +- .../electron-browser/ftpFileSystemProvider.ts | 94 ++++++++ .../files/electron-browser/jsftp.d.ts | 42 ++++ .../electron-browser/remoteFileService.ts | 208 +++++++++++++++--- .../textfile/common/textFileEditorModel.ts | 4 +- .../textfile/common/textFileService.ts | 11 +- .../common/textModelResolverService.ts | 5 +- 12 files changed, 343 insertions(+), 51 deletions(-) create mode 100644 src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts create mode 100644 src/vs/workbench/services/files/electron-browser/jsftp.d.ts diff --git a/package.json b/package.json index 3df93d97389..7b1684bb88b 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "https-proxy-agent": "0.3.6", "iconv-lite": "0.4.15", "jschardet": "^1.5.1", + "jsftp": "^2.0.0", "keytar": "^4.0.3", "minimist": "1.2.0", "native-keymap": "1.2.5", @@ -132,4 +133,4 @@ "windows-mutex": "^0.2.0", "fsevents": "0.3.8" } -} \ No newline at end of file +} diff --git a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts index ad58576214d..befe9744331 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts @@ -135,12 +135,14 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { const emitter = new Emitter(); const provider = { onDidChange: emitter.event, - resolve: (resource: URI) => { + read: (resource: URI) => { return this._proxy.$resolveFile(handle, resource); }, - update: (resource: URI, value: string) => { + write: (resource: URI, value: string) => { return this._proxy.$storeFile(handle, resource, value); - } + }, + stat: () => null, + readdir: () => null }; const searchProvider = { search: (query: ISearchQuery) => { diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index 3c609e62030..b5613afc437 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -1370,7 +1370,8 @@ export abstract class BaseSaveOneFileAction extends BaseSaveFileAction { if (this.resource) { source = this.resource; } else { - source = toResource(this.editorService.getActiveEditorInput(), { supportSideBySide: true, filter: ['file', 'untitled'] }); + // source = toResource(this.editorService.getActiveEditorInput(), { supportSideBySide: true, filter: ['file', 'untitled'] }); + source = toResource(this.editorService.getActiveEditorInput(), { supportSideBySide: true }); } if (source) { diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index e99e1d220a8..96db2a72d02 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -778,7 +778,7 @@ export class ExplorerView extends CollapsibleView { // Subsequent refresh: Merge stat into our local model and refresh tree modelStats.forEach((modelStat, index) => FileStat.mergeLocalWithDisk(modelStat, this.model.roots[index])); - const input = this.contextService.hasFolderWorkspace() ? this.model.roots[0] : this.model; + const input = /* this.contextService.hasFolderWorkspace() ? this.model.roots[0] : */ this.model; if (input === this.explorerViewer.getInput()) { return this.explorerViewer.refresh(); } diff --git a/src/vs/workbench/parts/files/common/explorerModel.ts b/src/vs/workbench/parts/files/common/explorerModel.ts index e3d97b1d97b..4f87e2acc53 100644 --- a/src/vs/workbench/parts/files/common/explorerModel.ts +++ b/src/vs/workbench/parts/files/common/explorerModel.ts @@ -25,7 +25,10 @@ export class Model { private _roots: FileStat[]; constructor( @IWorkspaceContextService private contextService: IWorkspaceContextService) { - const setRoots = () => this._roots = this.contextService.getWorkspace().roots.map(uri => new FileStat(uri, undefined)); + const setRoots = () => { + this._roots = this.contextService.getWorkspace().roots.map(uri => new FileStat(uri, undefined)); + this._roots.push(new FileStat(URI.parse('ftp://waws-prod-db3-029.ftp.azurewebsites.windows.net/'), undefined)); + }; this.contextService.onDidChangeWorkspaceRoots(() => setRoots()); setRoots(); } @@ -262,7 +265,8 @@ export class FileStat implements IFileStat { } private updateResource(recursive: boolean): void { - this.resource = URI.file(paths.join(this.parent.resource.fsPath, this.name)); + this.resource = this.parent.resource.with({ path: paths.join(this.parent.resource.path, this.name) }); + // this.resource = URI.file(paths.join(this.parent.resource.fsPath, this.name)); if (recursive) { if (this.isDirectory && this.hasChildren && this.children) { @@ -423,4 +427,4 @@ export class OpenEditor { public getResource(): URI { return toResource(this.editor, { supportSideBySide: true, filter: ['file', 'untitled'] }); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index f2ac5bbf146..4d9e1fdf586 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -273,7 +273,7 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { } let input: ICachedEditorInput; - if (resource.scheme === network.Schemas.file) { + if (resource.scheme === network.Schemas.file || resource.scheme === 'ftp') { input = this.fileInputFactory.createFileInput(resource, encoding, instantiationService); } else { input = instantiationService.createInstance(ResourceEditorInput, label, description, resource); @@ -359,4 +359,4 @@ export class DelegatingWorkbenchEditorService extends WorkbenchEditorService { return super.doCloseEditor(position, input); }); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts new file mode 100644 index 00000000000..26ac9949f53 --- /dev/null +++ b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts @@ -0,0 +1,94 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + + + +import URI from 'vs/base/common/uri'; +import Event from 'vs/base/common/event'; +import * as JSFtp from 'jsftp'; +import { ninvoke } from 'vs/base/common/async'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { Readable } from 'stream'; +import { join } from 'path'; +import { IStat } from 'vs/workbench/services/files/electron-browser/remoteFileService'; + +export class FtpFileSystemProvider { + + private _connection: JSFtp; + + onDidChange = Event.None; + + constructor() { + this._connection = new JSFtp({ + host: 'waws-prod-db3-029.ftp.azurewebsites.windows.net', + user: 'performanto-slack-updater\\riejo-test', + pass: 'Z0llikon' + }); + this._connection.keepAlive(1000 * 5); + } + + dispose(): void { + // + } + + stat(resource: URI): TPromise { + + return ninvoke(this._connection, this._connection.ls, resource.path).then(entries => { + + if (entries.length === 1) { + // stat one file + const [entry] = entries; + return { + resource, + mtime: entry.time, + size: entry.size, + isDirectory: false + }; + } + + // stat directory + return { + resource, + isDirectory: true, + mtime: 0, + size: 0 + }; + }); + } + + readdir(resource: URI): TPromise { + return ninvoke(this._connection, this._connection.ls, resource.path).then(ret => { + const promises: TPromise[] = []; + for (let entry of ret) { + promises.push(this.stat(resource.with({ path: join(resource.path, entry.name) }))); + } + return TPromise.join(promises); + }); + } + + write(resource: URI, content: string): TPromise { + return ninvoke(this._connection, this._connection.put, Buffer.from(content, 'utf8'), resource.path); + } + + read(resource: URI): TPromise { + return ninvoke(this._connection, this._connection.get, resource.path).then(stream => { + return new TPromise((resolve, reject) => { + let str = ''; + stream.on('data', function (d) { + str += d.toString(); + }); + stream.on('close', function (hadErr) { + if (hadErr) { + reject(hadErr); + } else { + resolve(str); + } + }); + stream.resume(); + }); + }); + } +} diff --git a/src/vs/workbench/services/files/electron-browser/jsftp.d.ts b/src/vs/workbench/services/files/electron-browser/jsftp.d.ts new file mode 100644 index 00000000000..767a28e7abd --- /dev/null +++ b/src/vs/workbench/services/files/electron-browser/jsftp.d.ts @@ -0,0 +1,42 @@ + + +import { Readable } from 'stream'; + +declare namespace JSFtp { + + + interface JSFtpOptions { + host: string; + port?: number | 21; + user?: string | 'anonymous'; + pass?: string | '@anonymous'; + } + + interface Callback { + (err: any, result: T): void; + } + + + interface Entry { + name: string; + size: number; + time: number; + type: 0 | 1; + } +} + +interface JSFtp { + keepAlive(wait?: number): void; + ls(path: string, callback: JSFtp.Callback): void; + put(buffer: Buffer, path: string, callback: JSFtp.Callback): void; + get(path: string, callback: JSFtp.Callback): void; + raw(command: string, args: any[], callback: JSFtp.Callback): void +} + +interface JSFtpConstructor { + new(options: JSFtp.JSFtpOptions): JSFtp; +} + +declare const JSFtp: JSFtpConstructor; + +export = JSFtp; diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 990dfba275b..2a658c72965 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -6,23 +6,128 @@ import URI from 'vs/base/common/uri'; import { FileService } from 'vs/workbench/services/files/electron-browser/fileService'; -import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, FileChangesEvent, FileChangeType } from 'vs/platform/files/common/files'; +import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, FileChangesEvent, FileChangeType, IResolveFileOptions, IResolveFileResult } from 'vs/platform/files/common/files'; import { TPromise } from 'vs/base/common/winjs.base'; import Event from 'vs/base/common/event'; import { EventEmitter } from 'events'; import { basename } from 'path'; import { IDisposable } from 'vs/base/common/lifecycle'; +import * as Ftp from './ftpFileSystemProvider'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; +import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { IMessageService } from 'vs/platform/message/common/message'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { groupBy, isFalsyOrEmpty } from 'vs/base/common/arrays'; +import { compare } from 'vs/base/common/strings'; + + +export interface IStat { + resource: URI; + mtime: number; + size: number; + isDirectory: boolean; +} + +function toIFileStat(provider: IRemoteFileSystemProvider, stat: IStat, recurse: boolean): TPromise { + const ret: IFileStat = { + isDirectory: false, + hasChildren: false, + resource: stat.resource, + name: basename(stat.resource.path), + mtime: stat.mtime, + size: stat.size, + etag: stat.mtime.toString(3) + stat.size.toString(7), + }; + + if (!stat.isDirectory) { + // done + return TPromise.as(ret); + + } else { + // dir -> resolve + return provider.readdir(stat.resource).then(items => { + ret.isDirectory = true; + ret.hasChildren = items.length > 0; + + if (recurse) { + // resolve children if requested + return TPromise.join(items.map(item => toIFileStat(provider, item, false))).then(children => { + ret.children = children; + return ret; + }); + } else { + return ret; + } + + }); + } +} export interface IRemoteFileSystemProvider { - onDidChange: Event; - resolve(resource: URI): TPromise; - update(resource: URI, content: string): TPromise; + onDidChange?: Event; + stat(resource: URI): TPromise; + readdir(resource: URI): TPromise; + write(resource: URI, content: string): TPromise; + read(resource: URI): TPromise; } export class RemoteFileService extends FileService { + // public existsFile(resource: URI): TPromise { + // throw new Error("Method not implemented."); + // } + // public moveFile(source: URI, target: URI, overwrite?: boolean): TPromise { + // throw new Error("Method not implemented."); + // } + // public copyFile(source: URI, target: URI, overwrite?: boolean): TPromise { + // throw new Error("Method not implemented."); + // } + // public createFile(resource: URI, content?: string): TPromise { + // throw new Error("Method not implemented."); + // } + // public createFolder(resource: URI): TPromise { + // throw new Error("Method not implemented."); + // } + // public touchFile(resource: URI): TPromise { + // throw new Error("Method not implemented."); + // } + // public rename(resource: URI, newName: string): TPromise { + // throw new Error("Method not implemented."); + // } + // public del(resource: URI, useTrash?: boolean): TPromise { + // throw new Error("Method not implemented."); + // } + + private readonly _provider = new Map(); + constructor( + @IConfigurationService configurationService: IConfigurationService, + @IWorkspaceContextService contextService: IWorkspaceContextService, + @IWorkbenchEditorService editorService: IWorkbenchEditorService, + @IEnvironmentService environmentService: IEnvironmentService, + @IEditorGroupService editorGroupService: IEditorGroupService, + @ILifecycleService lifecycleService: ILifecycleService, + @IMessageService messageService: IMessageService, + @IStorageService storageService: IStorageService + ) { + super( + configurationService, + contextService, + editorService, + environmentService, + editorGroupService, + lifecycleService, + messageService, + storageService, + ); + this.registerProvider('ftp', new Ftp.FtpFileSystemProvider()); + } + registerProvider(authority: string, provider: IRemoteFileSystemProvider): IDisposable { if (this._provider.has(authority)) { throw new Error(); @@ -41,59 +146,96 @@ export class RemoteFileService extends FileService { }; } + resolveFile(resource: URI, options?: IResolveFileOptions): TPromise { + const provider = this._provider.get(resource.scheme); + if (provider) { + return this._doResolveFiles(provider, [{ resource, options }]).then(data => { + if (isFalsyOrEmpty(data)) { + throw new Error('NotFound'); + } + return data[0].stat; + }); + } + return super.resolveFile(resource, options); + } + + resolveFiles(toResolve: { resource: URI; options?: IResolveFileOptions; }[]): TPromise { + const groups = groupBy(toResolve, (a, b) => compare(a.resource.scheme, b.resource.scheme)); + const promises: TPromise[] = []; + + for (const group of groups) { + const provider = this._provider.get(group[0].resource.scheme); + if (!provider) { + promises.push(super.resolveFiles(group)); + } else { + promises.push(this._doResolveFiles(provider, group)); + } + } + + return TPromise.join(promises).then(data => { + return [].concat(...data); + }); + } + + private _doResolveFiles(provider: IRemoteFileSystemProvider, toResolve: { resource: URI; options?: IResolveFileOptions; }[]): TPromise { + let result: IResolveFileResult[] = []; + let promises: TPromise[] = []; + for (const item of toResolve) { + promises.push(provider.stat(item.resource) + .then(stat => toIFileStat(provider, stat, true)) + .then(stat => result.push({ stat, success: true }))); + } + return TPromise.join(promises).then(() => result); + } + // --- resolve resolveContent(resource: URI, options?: IResolveContentOptions): TPromise { - if (this._provider.has(resource.authority)) { - return this._doResolveContent(resource); + const provider = this._provider.get(resource.scheme); + if (provider) { + return this._doResolveContent(provider, resource); } return super.resolveContent(resource, options); } resolveStreamContent(resource: URI, options?: IResolveContentOptions): TPromise { - if (this._provider.has(resource.authority)) { - return this._doResolveContent(resource).then(RemoteFileService._asStreamContent); + + const provider = this._provider.get(resource.scheme); + if (provider) { + return this._doResolveContent(provider, resource).then(RemoteFileService._asStreamContent); } return super.resolveStreamContent(resource, options); } - private async _doResolveContent(resource: URI): TPromise { + private _doResolveContent(provider: IRemoteFileSystemProvider, resource: URI): TPromise { - const stat = RemoteFileService._createFakeStat(resource); - const value = await this._provider.get(resource.authority).resolve(resource); - return { ...stat, value }; + return provider.stat(resource).then(stat => { + return provider.read(resource).then(value => { + return { + ...stat, + value, + }; + }); + }); } // --- saving updateContent(resource: URI, value: string, options?: IUpdateContentOptions): TPromise { - if (this._provider.has(resource.authority)) { - return this._doUpdateContent(resource, value).then(RemoteFileService._createFakeStat); + const provider = this._provider.get(resource.scheme); + if (provider) { + return this._doUpdateContent(provider, resource, value); } - return super.updateContent(resource, value, options); } - private async _doUpdateContent(resource: URI, content: string): TPromise { - await this._provider.get(resource.authority).update(resource, content); - return resource; - } - - // --- util - - private static _createFakeStat(resource: URI): IFileStat { - - return { - resource, - name: basename(resource.path), - encoding: 'utf8', - mtime: Date.now(), - etag: Date.now().toString(16), - isDirectory: false, - hasChildren: false - }; + private async _doUpdateContent(provider: IRemoteFileSystemProvider, resource: URI, content: string): TPromise { + await provider.write(resource, content); + const stat = await provider.stat(resource); + const fileStat = await toIFileStat(provider, stat, false); + return fileStat; } private static _asStreamContent(content: IContent): IStreamContent { diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index bdfaaa0b9ba..68cd75dc7b5 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -12,7 +12,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { guessMimeTypes } from 'vs/base/common/mime'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import URI from 'vs/base/common/uri'; -import * as assert from 'vs/base/common/assert'; +// import * as assert from 'vs/base/common/assert'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import paths = require('vs/base/common/paths'); import diagnostics = require('vs/base/common/diagnostics'); @@ -90,7 +90,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil ) { super(modelService, modeService); - assert.ok(resource.scheme === 'file', 'TextFileEditorModel can only handle file:// resources.'); + // assert.ok(resource.scheme === 'file', 'TextFileEditorModel can only handle file:// resources.'); this.resource = resource; this.toDispose = []; diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index 70e7a582514..746c09ba4b5 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -407,10 +407,13 @@ export abstract class TextFileService implements ITextFileService { const filesToSave: URI[] = []; const untitledToSave: URI[] = []; toSave.forEach(s => { - if (s.scheme === Schemas.file) { - filesToSave.push(s); - } else if ((Array.isArray(arg1) || arg1 === true /* includeUntitled */) && s.scheme === UNTITLED_SCHEMA) { + // if (s.scheme === Schemas.file) { + // filesToSave.push(s); + // } else + if ((Array.isArray(arg1) || arg1 === true /* includeUntitled */) && s.scheme === UNTITLED_SCHEMA) { untitledToSave.push(s); + } else { + filesToSave.push(s); } }); @@ -712,4 +715,4 @@ export abstract class TextFileService implements ITextFileService { // Clear all caches this._models.clear(); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts index c7b7668b869..9ed257d66b1 100644 --- a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts +++ b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts @@ -35,7 +35,10 @@ class ResourceModelCollection extends ReferenceCollection this.instantiationService.createInstance(ResourceEditorModel, resource)); } From e9ac57eeb7106bc5c27d668e00c54325b07ed7de Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Sep 2017 09:11:50 +0200 Subject: [PATCH 004/281] fix adoption issue --- .../services/files/electron-browser/remoteFileService.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 2a658c72965..aca431068fd 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -23,6 +23,7 @@ import { IMessageService } from 'vs/platform/message/common/message'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { groupBy, isFalsyOrEmpty } from 'vs/base/common/arrays'; import { compare } from 'vs/base/common/strings'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; export interface IStat { @@ -113,7 +114,8 @@ export class RemoteFileService extends FileService { @IEditorGroupService editorGroupService: IEditorGroupService, @ILifecycleService lifecycleService: ILifecycleService, @IMessageService messageService: IMessageService, - @IStorageService storageService: IStorageService + @IStorageService storageService: IStorageService, + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService ) { super( configurationService, @@ -124,6 +126,7 @@ export class RemoteFileService extends FileService { lifecycleService, messageService, storageService, + textResourceConfigurationService, ); this.registerProvider('ftp', new Ftp.FtpFileSystemProvider()); } From 022325bf05f03bb4097378d847b4992f1175b05a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Sep 2017 09:25:08 +0200 Subject: [PATCH 005/281] much more, del, streaming, etc --- .../electron-browser/mainThreadWorkspace.ts | 24 +++++------ .../electron-browser/ftpFileSystemProvider.ts | 34 +++++++-------- .../electron-browser/remoteFileService.ts | 42 ++++++++++++------- 3 files changed, 57 insertions(+), 43 deletions(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts index befe9744331..be55f7cf0fb 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts @@ -133,17 +133,17 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { throw new Error(); } const emitter = new Emitter(); - const provider = { - onDidChange: emitter.event, - read: (resource: URI) => { - return this._proxy.$resolveFile(handle, resource); - }, - write: (resource: URI, value: string) => { - return this._proxy.$storeFile(handle, resource, value); - }, - stat: () => null, - readdir: () => null - }; + // const provider = { + // onDidChange: emitter.event, + // read: (resource: URI) => { + // return this._proxy.$resolveFile(handle, resource); + // }, + // write: (resource: URI, value: string) => { + // return this._proxy.$storeFile(handle, resource, value); + // }, + // stat: () => null, + // readdir: () => null + // }; const searchProvider = { search: (query: ISearchQuery) => { if (query.type !== QueryType.File) { @@ -159,7 +159,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { } }; const registrations = combinedDisposable([ - this._fileService.registerProvider(authority, provider), + // this._fileService.registerProvider(authority, provider), this._searchService.registerSearchResultProvider(searchProvider), ]); this._provider.set(handle, [registrations, emitter]); diff --git a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts index 26ac9949f53..5ebf2f4bf07 100644 --- a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts +++ b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts @@ -13,9 +13,10 @@ import { ninvoke } from 'vs/base/common/async'; import { TPromise } from 'vs/base/common/winjs.base'; import { Readable } from 'stream'; import { join } from 'path'; -import { IStat } from 'vs/workbench/services/files/electron-browser/remoteFileService'; +import { IStat, IRemoteFileSystemProvider } from 'vs/workbench/services/files/electron-browser/remoteFileService'; +import { IProgress } from 'vs/platform/progress/common/progress'; -export class FtpFileSystemProvider { +export class FtpFileSystemProvider implements IRemoteFileSystemProvider { private _connection: JSFtp; @@ -23,9 +24,7 @@ export class FtpFileSystemProvider { constructor() { this._connection = new JSFtp({ - host: 'waws-prod-db3-029.ftp.azurewebsites.windows.net', - user: 'performanto-slack-updater\\riejo-test', - pass: 'Z0llikon' + host: 'waws-prod-db3-029.ftp.azurewebsites.windows.net' }); this._connection.keepAlive(1000 * 5); } @@ -69,26 +68,27 @@ export class FtpFileSystemProvider { }); } - write(resource: URI, content: string): TPromise { - return ninvoke(this._connection, this._connection.put, Buffer.from(content, 'utf8'), resource.path); - } - - read(resource: URI): TPromise { + read(resource: URI, progress: IProgress): TPromise { return ninvoke(this._connection, this._connection.get, resource.path).then(stream => { - return new TPromise((resolve, reject) => { - let str = ''; - stream.on('data', function (d) { - str += d.toString(); - }); - stream.on('close', function (hadErr) { + return new TPromise((resolve, reject) => { + stream.on('data', d => progress.report(d)); + stream.on('close', hadErr => { if (hadErr) { reject(hadErr); } else { - resolve(str); + resolve(undefined); } }); stream.resume(); }); }); } + + write(resource: URI, content: string): TPromise { + return ninvoke(this._connection, this._connection.put, Buffer.from(content, 'utf8'), resource.path); + } + + del(resource: URI): TPromise { + return ninvoke(this._connection, this._connection.raw, 'DELE', [resource.path]); + } } diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index aca431068fd..d04f796fda6 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -24,6 +24,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { groupBy, isFalsyOrEmpty } from 'vs/base/common/arrays'; import { compare } from 'vs/base/common/strings'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; +import { IProgress, Progress } from 'vs/platform/progress/common/progress'; export interface IStat { @@ -41,7 +42,7 @@ function toIFileStat(provider: IRemoteFileSystemProvider, stat: IStat, recurse: name: basename(stat.resource.path), mtime: stat.mtime, size: stat.size, - etag: stat.mtime.toString(3) + stat.size.toString(7), + etag: stat.mtime.toString(29) + stat.size.toString(31), }; if (!stat.isDirectory) { @@ -72,8 +73,9 @@ export interface IRemoteFileSystemProvider { onDidChange?: Event; stat(resource: URI): TPromise; readdir(resource: URI): TPromise; + read(resource: URI, progress: IProgress): TPromise; write(resource: URI, content: string): TPromise; - read(resource: URI): TPromise; + del(resource: URI): TPromise; } export class RemoteFileService extends FileService { @@ -99,9 +101,7 @@ export class RemoteFileService extends FileService { // public rename(resource: URI, newName: string): TPromise { // throw new Error("Method not implemented."); // } - // public del(resource: URI, useTrash?: boolean): TPromise { - // throw new Error("Method not implemented."); - // } + private readonly _provider = new Map(); @@ -212,16 +212,20 @@ export class RemoteFileService extends FileService { return super.resolveStreamContent(resource, options); } - private _doResolveContent(provider: IRemoteFileSystemProvider, resource: URI): TPromise { + private async _doResolveContent(provider: IRemoteFileSystemProvider, resource: URI): TPromise { - return provider.stat(resource).then(stat => { - return provider.read(resource).then(value => { - return { - ...stat, - value, - }; - }); - }); + const chunks: Uint8Array[] = []; + await provider.read(resource, new Progress(chunk => chunks.push(chunk))); + const stat = await toIFileStat(provider, await provider.stat(resource), false); + + return { + value: [].concat(...chunks).toString(), + resource: stat.resource, + name: stat.name, + etag: stat.etag, + mtime: stat.mtime, + encoding: this.getEncoding(resource) + }; } // --- saving @@ -252,4 +256,14 @@ export class RemoteFileService extends FileService { }, 0); return result; } + + // --- delete + + del(resource: URI, useTrash?: boolean): TPromise { + const provider = this._provider.get(resource.scheme); + if (provider) { + return provider.del(resource); + } + return super.del(resource, useTrash); + } } From d79003bccda3643a958d3f0bf7412dd5fa89b845 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Sep 2017 10:25:35 +0200 Subject: [PATCH 006/281] create file/folder, emit operation events --- .../parts/files/browser/fileActions.ts | 6 +- .../files/electron-browser/fileService.ts | 2 +- .../electron-browser/ftpFileSystemProvider.ts | 6 +- .../electron-browser/remoteFileService.ts | 79 +++++++++++++------ 4 files changed, 63 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index b5613afc437..850f696a4f2 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -589,7 +589,8 @@ export class CreateFileAction extends BaseCreateAction { } public runAction(fileName: string): TPromise { - return this.fileService.createFile(URI.file(paths.join(this.element.parent.resource.fsPath, fileName))).then(stat => { + const resource = this.element.parent.resource; + return this.fileService.createFile(resource.with({ path: paths.join(resource.path, fileName) })).then(stat => { return this.editorService.openEditor({ resource: stat.resource, options: { pinned: true } }); }, (error) => { this.onErrorWithRetry(error, () => this.runAction(fileName)); @@ -615,7 +616,8 @@ export class CreateFolderAction extends BaseCreateAction { } public runAction(fileName: string): TPromise { - return this.fileService.createFolder(URI.file(paths.join(this.element.parent.resource.fsPath, fileName))).then(null, (error) => { + const resource = this.element.parent.resource; + return this.fileService.createFolder(resource.with({ path: paths.join(resource.path, fileName) })).then(null, (error) => { this.onErrorWithRetry(error, () => this.runAction(fileName)); }); } diff --git a/src/vs/workbench/services/files/electron-browser/fileService.ts b/src/vs/workbench/services/files/electron-browser/fileService.ts index 402c628d38c..a60cb328e8a 100644 --- a/src/vs/workbench/services/files/electron-browser/fileService.ts +++ b/src/vs/workbench/services/files/electron-browser/fileService.ts @@ -43,7 +43,7 @@ export class FileService implements IFileService { private activeOutOfWorkspaceWatchers: ResourceMap; protected _onFileChanges: Emitter; - private _onAfterOperation: Emitter; + protected _onAfterOperation: Emitter; constructor( @IConfigurationService private configurationService: IConfigurationService, diff --git a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts index 5ebf2f4bf07..8a17b71a981 100644 --- a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts +++ b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts @@ -20,7 +20,7 @@ export class FtpFileSystemProvider implements IRemoteFileSystemProvider { private _connection: JSFtp; - onDidChange = Event.None; + readonly onDidChange = Event.None; constructor() { this._connection = new JSFtp({ @@ -91,4 +91,8 @@ export class FtpFileSystemProvider implements IRemoteFileSystemProvider { del(resource: URI): TPromise { return ninvoke(this._connection, this._connection.raw, 'DELE', [resource.path]); } + + mkdir(resource: URI): TPromise { + return ninvoke(this._connection, this._connection.raw, 'MKD', [resource.path]); + } } diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index d04f796fda6..8c06b849194 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -6,7 +6,7 @@ import URI from 'vs/base/common/uri'; import { FileService } from 'vs/workbench/services/files/electron-browser/fileService'; -import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, FileChangesEvent, FileChangeType, IResolveFileOptions, IResolveFileResult } from 'vs/platform/files/common/files'; +import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, FileChangesEvent, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation } from 'vs/platform/files/common/files'; import { TPromise } from 'vs/base/common/winjs.base'; import Event from 'vs/base/common/event'; import { EventEmitter } from 'events'; @@ -70,9 +70,10 @@ function toIFileStat(provider: IRemoteFileSystemProvider, stat: IStat, recurse: } export interface IRemoteFileSystemProvider { - onDidChange?: Event; + onDidChange?: Event; stat(resource: URI): TPromise; readdir(resource: URI): TPromise; + mkdir(resource: URI): TPromise; read(resource: URI, progress: IProgress): TPromise; write(resource: URI, content: string): TPromise; del(resource: URI): TPromise; @@ -80,21 +81,14 @@ export interface IRemoteFileSystemProvider { export class RemoteFileService extends FileService { - // public existsFile(resource: URI): TPromise { - // throw new Error("Method not implemented."); - // } + // public moveFile(source: URI, target: URI, overwrite?: boolean): TPromise { // throw new Error("Method not implemented."); // } // public copyFile(source: URI, target: URI, overwrite?: boolean): TPromise { // throw new Error("Method not implemented."); // } - // public createFile(resource: URI, content?: string): TPromise { - // throw new Error("Method not implemented."); - // } - // public createFolder(resource: URI): TPromise { - // throw new Error("Method not implemented."); - // } + // public touchFile(resource: URI): TPromise { // throw new Error("Method not implemented."); // } @@ -102,8 +96,6 @@ export class RemoteFileService extends FileService { // throw new Error("Method not implemented."); // } - - private readonly _provider = new Map(); constructor( @@ -139,7 +131,7 @@ export class RemoteFileService extends FileService { this._provider.set(authority, provider); const reg = provider.onDidChange(e => { // forward change events - this._onFileChanges.fire(new FileChangesEvent([{ resource: e, type: FileChangeType.UPDATED }])); + this._onFileChanges.fire(e); }); return { dispose: () => { @@ -149,6 +141,17 @@ export class RemoteFileService extends FileService { }; } + // --- stat + + existsFile(resource: URI): TPromise { + const provider = this._provider.get(resource.scheme); + if (provider) { + return this._doResolveFiles(provider, [{ resource }]).then(data => data.length > 0); + } else { + return super.existsFile(resource); + } + } + resolveFile(resource: URI, options?: IResolveFileOptions): TPromise { const provider = this._provider.get(resource.scheme); if (provider) { @@ -158,14 +161,14 @@ export class RemoteFileService extends FileService { } return data[0].stat; }); + } else { + return super.resolveFile(resource, options); } - return super.resolveFile(resource, options); } resolveFiles(toResolve: { resource: URI; options?: IResolveFileOptions; }[]): TPromise { const groups = groupBy(toResolve, (a, b) => compare(a.resource.scheme, b.resource.scheme)); const promises: TPromise[] = []; - for (const group of groups) { const provider = this._provider.get(group[0].resource.scheme); if (!provider) { @@ -174,7 +177,6 @@ export class RemoteFileService extends FileService { promises.push(this._doResolveFiles(provider, group)); } } - return TPromise.join(promises).then(data => { return [].concat(...data); }); @@ -197,19 +199,18 @@ export class RemoteFileService extends FileService { const provider = this._provider.get(resource.scheme); if (provider) { return this._doResolveContent(provider, resource); + } else { + return super.resolveContent(resource, options); } - - return super.resolveContent(resource, options); } resolveStreamContent(resource: URI, options?: IResolveContentOptions): TPromise { - const provider = this._provider.get(resource.scheme); if (provider) { return this._doResolveContent(provider, resource).then(RemoteFileService._asStreamContent); + } else { + return super.resolveStreamContent(resource, options); } - - return super.resolveStreamContent(resource, options); } private async _doResolveContent(provider: IRemoteFileSystemProvider, resource: URI): TPromise { @@ -230,12 +231,24 @@ export class RemoteFileService extends FileService { // --- saving + async createFile(resource: URI, content?: string): TPromise { + const provider = this._provider.get(resource.scheme); + if (provider) { + const stat = await this._doUpdateContent(provider, resource, content || ''); + this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, stat)); + return stat; + } else { + return super.createFile(resource, content); + } + } + updateContent(resource: URI, value: string, options?: IUpdateContentOptions): TPromise { const provider = this._provider.get(resource.scheme); if (provider) { return this._doUpdateContent(provider, resource, value); + } else { + return super.updateContent(resource, value, options); } - return super.updateContent(resource, value, options); } private async _doUpdateContent(provider: IRemoteFileSystemProvider, resource: URI, content: string): TPromise { @@ -259,11 +272,25 @@ export class RemoteFileService extends FileService { // --- delete - del(resource: URI, useTrash?: boolean): TPromise { + async del(resource: URI, useTrash?: boolean): TPromise { const provider = this._provider.get(resource.scheme); if (provider) { - return provider.del(resource); + await provider.del(resource); + this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.DELETE)); + } else { + return super.del(resource, useTrash); + } + } + + async createFolder(resource: URI): TPromise { + const provider = this._provider.get(resource.scheme); + if (provider) { + await provider.mkdir(resource); + const stat = await toIFileStat(provider, await provider.stat(resource), false); + this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, stat)); + return stat; + } else { + return super.createFolder(resource); } - return super.del(resource, useTrash); } } From e3aea3b9422aee2920ebadd098c6c1be42f32b60 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Sep 2017 10:32:22 +0200 Subject: [PATCH 007/281] better del (file or folder) --- .../files/electron-browser/ftpFileSystemProvider.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts index 8a17b71a981..14b3c184235 100644 --- a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts +++ b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts @@ -89,7 +89,16 @@ export class FtpFileSystemProvider implements IRemoteFileSystemProvider { } del(resource: URI): TPromise { + + return ninvoke(this._connection, this._connection.ls, resource.path).then(entries => { + if (entries.length === 1) { + // file; return ninvoke(this._connection, this._connection.raw, 'DELE', [resource.path]); + } else { + // dir + return ninvoke(this._connection, this._connection.raw, 'RMD', [resource.path]); + } + }); } mkdir(resource: URI): TPromise { From cdff1bcecf1fbd03134990b7c7b6261d5d152a5c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Sep 2017 12:50:55 +0200 Subject: [PATCH 008/281] proper streaming --- .../electron-browser/remoteFileService.ts | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 8c06b849194..e1050f00380 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -6,10 +6,9 @@ import URI from 'vs/base/common/uri'; import { FileService } from 'vs/workbench/services/files/electron-browser/fileService'; +import Event from 'vs/base/common/event'; import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, FileChangesEvent, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation } from 'vs/platform/files/common/files'; import { TPromise } from 'vs/base/common/winjs.base'; -import Event from 'vs/base/common/event'; -import { EventEmitter } from 'events'; import { basename } from 'path'; import { IDisposable } from 'vs/base/common/lifecycle'; import * as Ftp from './ftpFileSystemProvider'; @@ -25,6 +24,7 @@ import { groupBy, isFalsyOrEmpty } from 'vs/base/common/arrays'; import { compare } from 'vs/base/common/strings'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IProgress, Progress } from 'vs/platform/progress/common/progress'; +import { decodeStream } from 'vs/base/node/encoding'; export interface IStat { @@ -198,7 +198,7 @@ export class RemoteFileService extends FileService { resolveContent(resource: URI, options?: IResolveContentOptions): TPromise { const provider = this._provider.get(resource.scheme); if (provider) { - return this._doResolveContent(provider, resource); + return this._doResolveContent(provider, resource).then(RemoteFileService._asContent); } else { return super.resolveContent(resource, options); } @@ -207,25 +207,28 @@ export class RemoteFileService extends FileService { resolveStreamContent(resource: URI, options?: IResolveContentOptions): TPromise { const provider = this._provider.get(resource.scheme); if (provider) { - return this._doResolveContent(provider, resource).then(RemoteFileService._asStreamContent); + return this._doResolveContent(provider, resource); } else { return super.resolveStreamContent(resource, options); } } - private async _doResolveContent(provider: IRemoteFileSystemProvider, resource: URI): TPromise { + private async _doResolveContent(provider: IRemoteFileSystemProvider, resource: URI): TPromise { - const chunks: Uint8Array[] = []; - await provider.read(resource, new Progress(chunk => chunks.push(chunk))); const stat = await toIFileStat(provider, await provider.stat(resource), false); + const encoding = this.getEncoding(resource); + const stream = decodeStream(encoding); + await provider.read(resource, new Progress(chunk => stream.write(chunk))); + stream.end(); + return { - value: [].concat(...chunks).toString(), + encoding, + value: stream, resource: stat.resource, name: stat.name, etag: stat.etag, mtime: stat.mtime, - encoding: this.getEncoding(resource) }; } @@ -258,16 +261,20 @@ export class RemoteFileService extends FileService { return fileStat; } - private static _asStreamContent(content: IContent): IStreamContent { - const emitter = new EventEmitter(); - const { value } = content; - const result = content; - result.value = emitter; - setTimeout(() => { - emitter.emit('data', value); - emitter.emit('end'); - }, 0); - return result; + private static _asContent(content: IStreamContent): TPromise { + return new TPromise((resolve, reject) => { + let result: IContent = { + value: '', + encoding: content.encoding, + etag: content.etag, + mtime: content.mtime, + name: content.name, + resource: content.resource + }; + content.value.on('data', chunk => result.value += chunk); + content.value.on('error', reject); + content.value.on('end', () => resolve(result)); + }); } // --- delete From 03e0fa87ab73f193cf75c93b800380d2ebe44604 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Sep 2017 12:51:24 +0200 Subject: [PATCH 009/281] better hack to workaround textFileService.models --- .../textmodelResolver/common/textModelResolverService.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts index 9ed257d66b1..ae8b0ae383f 100644 --- a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts +++ b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts @@ -35,9 +35,8 @@ class ResourceModelCollection extends ReferenceCollection this.instantiationService.createInstance(ResourceEditorModel, resource)); } From 98c3ec57aaec1d5ccfd6a8586c9b7ccdc1386d8a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Sep 2017 13:03:24 +0200 Subject: [PATCH 010/281] refine readdir and write functions --- .../electron-browser/ftpFileSystemProvider.ts | 12 ++++++------ .../files/electron-browser/remoteFileService.ts | 17 +++++++++-------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts index 14b3c184235..ea73f4cde4c 100644 --- a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts +++ b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts @@ -58,13 +58,13 @@ export class FtpFileSystemProvider implements IRemoteFileSystemProvider { }); } - readdir(resource: URI): TPromise { + readdir(resource: URI): TPromise { return ninvoke(this._connection, this._connection.ls, resource.path).then(ret => { - const promises: TPromise[] = []; + const result: URI[] = []; for (let entry of ret) { - promises.push(this.stat(resource.with({ path: join(resource.path, entry.name) }))); + result.push(resource.with({ path: join(resource.path, entry.name) })); } - return TPromise.join(promises); + return result; }); } @@ -84,8 +84,8 @@ export class FtpFileSystemProvider implements IRemoteFileSystemProvider { }); } - write(resource: URI, content: string): TPromise { - return ninvoke(this._connection, this._connection.put, Buffer.from(content, 'utf8'), resource.path); + write(resource: URI, content: Uint8Array): TPromise { + return ninvoke(this._connection, this._connection.put, content, resource.path); } del(resource: URI): TPromise { diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index e1050f00380..edc922c029f 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -24,7 +24,7 @@ import { groupBy, isFalsyOrEmpty } from 'vs/base/common/arrays'; import { compare } from 'vs/base/common/strings'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IProgress, Progress } from 'vs/platform/progress/common/progress'; -import { decodeStream } from 'vs/base/node/encoding'; +import { decodeStream, encode } from 'vs/base/node/encoding'; export interface IStat { @@ -57,7 +57,7 @@ function toIFileStat(provider: IRemoteFileSystemProvider, stat: IStat, recurse: if (recurse) { // resolve children if requested - return TPromise.join(items.map(item => toIFileStat(provider, item, false))).then(children => { + return TPromise.join(items.map(resource => provider.stat(resource).then(stat => toIFileStat(provider, stat, false)))).then(children => { ret.children = children; return ret; }); @@ -72,10 +72,10 @@ function toIFileStat(provider: IRemoteFileSystemProvider, stat: IStat, recurse: export interface IRemoteFileSystemProvider { onDidChange?: Event; stat(resource: URI): TPromise; - readdir(resource: URI): TPromise; + readdir(resource: URI): TPromise; mkdir(resource: URI): TPromise; read(resource: URI, progress: IProgress): TPromise; - write(resource: URI, content: string): TPromise; + write(resource: URI, content: Uint8Array): TPromise; del(resource: URI): TPromise; } @@ -237,7 +237,7 @@ export class RemoteFileService extends FileService { async createFile(resource: URI, content?: string): TPromise { const provider = this._provider.get(resource.scheme); if (provider) { - const stat = await this._doUpdateContent(provider, resource, content || ''); + const stat = await this._doUpdateContent(provider, resource, content || '', {}); this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, stat)); return stat; } else { @@ -248,14 +248,15 @@ export class RemoteFileService extends FileService { updateContent(resource: URI, value: string, options?: IUpdateContentOptions): TPromise { const provider = this._provider.get(resource.scheme); if (provider) { - return this._doUpdateContent(provider, resource, value); + return this._doUpdateContent(provider, resource, value, options || {}); } else { return super.updateContent(resource, value, options); } } - private async _doUpdateContent(provider: IRemoteFileSystemProvider, resource: URI, content: string): TPromise { - await provider.write(resource, content); + private async _doUpdateContent(provider: IRemoteFileSystemProvider, resource: URI, content: string, options: IUpdateContentOptions): TPromise { + const encoding = this.getEncoding(resource, options.encoding); + await provider.write(resource, encode(content, encoding)); const stat = await provider.stat(resource); const fileStat = await toIFileStat(provider, stat, false); return fileStat; From fec3b0add134740095ccd95a813d10509fcdba7c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Sep 2017 15:12:39 +0200 Subject: [PATCH 011/281] move interfaces --- src/vs/platform/files/common/files.ts | 25 +++++++++++++ .../electron-browser/ftpFileSystemProvider.ts | 12 +++--- .../electron-browser/remoteFileService.ts | 37 +++++-------------- 3 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 455db1408ec..1e8606d14e0 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -13,6 +13,7 @@ import { isLinux } from 'vs/base/common/platform'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import Event from 'vs/base/common/event'; import { beginsWithIgnoreCase } from 'vs/base/common/strings'; +import { IProgress } from 'vs/platform/progress/common/progress'; export const IFileService = createDecorator('fileService'); @@ -150,6 +151,30 @@ export interface IFileService { dispose(): void; } + +export enum FileType { + File = 0, + Dir = 1, + Symlink = 2 +} +export interface IStat { + resource: URI; + mtime: number; + size: number; + type: FileType; +} + +export interface IFileSystemProvider { + onDidChange?: Event; + stat(resource: URI): TPromise; + readdir(resource: URI): TPromise; + mkdir(resource: URI): TPromise; + read(resource: URI, progress: IProgress): TPromise; + write(resource: URI, content: Uint8Array): TPromise; + del(resource: URI): TPromise; +} + + export enum FileOperation { CREATE, DELETE, diff --git a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts index ea73f4cde4c..3e064dd0f7b 100644 --- a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts +++ b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts @@ -13,10 +13,10 @@ import { ninvoke } from 'vs/base/common/async'; import { TPromise } from 'vs/base/common/winjs.base'; import { Readable } from 'stream'; import { join } from 'path'; -import { IStat, IRemoteFileSystemProvider } from 'vs/workbench/services/files/electron-browser/remoteFileService'; +import { IStat, FileType, IFileSystemProvider } from 'vs/platform/files/common/files'; import { IProgress } from 'vs/platform/progress/common/progress'; -export class FtpFileSystemProvider implements IRemoteFileSystemProvider { +export class FtpFileSystemProvider implements IFileSystemProvider { private _connection: JSFtp; @@ -30,7 +30,7 @@ export class FtpFileSystemProvider implements IRemoteFileSystemProvider { } dispose(): void { - // + ninvoke(this._connection, this._connection.raw, 'QUIT'); } stat(resource: URI): TPromise { @@ -44,16 +44,16 @@ export class FtpFileSystemProvider implements IRemoteFileSystemProvider { resource, mtime: entry.time, size: entry.size, - isDirectory: false + type: FileType.File }; } // stat directory return { resource, - isDirectory: true, mtime: 0, - size: 0 + size: 0, + type: FileType.Dir, }; }); } diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index edc922c029f..47b0aa5e864 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -6,8 +6,7 @@ import URI from 'vs/base/common/uri'; import { FileService } from 'vs/workbench/services/files/electron-browser/fileService'; -import Event from 'vs/base/common/event'; -import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, FileChangesEvent, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation } from 'vs/platform/files/common/files'; +import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation, IFileSystemProvider, IStat, FileType } from 'vs/platform/files/common/files'; import { TPromise } from 'vs/base/common/winjs.base'; import { basename } from 'path'; import { IDisposable } from 'vs/base/common/lifecycle'; @@ -23,18 +22,10 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { groupBy, isFalsyOrEmpty } from 'vs/base/common/arrays'; import { compare } from 'vs/base/common/strings'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; -import { IProgress, Progress } from 'vs/platform/progress/common/progress'; +import { Progress } from 'vs/platform/progress/common/progress'; import { decodeStream, encode } from 'vs/base/node/encoding'; - -export interface IStat { - resource: URI; - mtime: number; - size: number; - isDirectory: boolean; -} - -function toIFileStat(provider: IRemoteFileSystemProvider, stat: IStat, recurse: boolean): TPromise { +function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse: boolean): TPromise { const ret: IFileStat = { isDirectory: false, hasChildren: false, @@ -45,7 +36,7 @@ function toIFileStat(provider: IRemoteFileSystemProvider, stat: IStat, recurse: etag: stat.mtime.toString(29) + stat.size.toString(31), }; - if (!stat.isDirectory) { + if (stat.type === FileType.File) { // done return TPromise.as(ret); @@ -69,16 +60,6 @@ function toIFileStat(provider: IRemoteFileSystemProvider, stat: IStat, recurse: } } -export interface IRemoteFileSystemProvider { - onDidChange?: Event; - stat(resource: URI): TPromise; - readdir(resource: URI): TPromise; - mkdir(resource: URI): TPromise; - read(resource: URI, progress: IProgress): TPromise; - write(resource: URI, content: Uint8Array): TPromise; - del(resource: URI): TPromise; -} - export class RemoteFileService extends FileService { @@ -96,7 +77,7 @@ export class RemoteFileService extends FileService { // throw new Error("Method not implemented."); // } - private readonly _provider = new Map(); + private readonly _provider = new Map(); constructor( @IConfigurationService configurationService: IConfigurationService, @@ -123,7 +104,7 @@ export class RemoteFileService extends FileService { this.registerProvider('ftp', new Ftp.FtpFileSystemProvider()); } - registerProvider(authority: string, provider: IRemoteFileSystemProvider): IDisposable { + registerProvider(authority: string, provider: IFileSystemProvider): IDisposable { if (this._provider.has(authority)) { throw new Error(); } @@ -182,7 +163,7 @@ export class RemoteFileService extends FileService { }); } - private _doResolveFiles(provider: IRemoteFileSystemProvider, toResolve: { resource: URI; options?: IResolveFileOptions; }[]): TPromise { + private _doResolveFiles(provider: IFileSystemProvider, toResolve: { resource: URI; options?: IResolveFileOptions; }[]): TPromise { let result: IResolveFileResult[] = []; let promises: TPromise[] = []; for (const item of toResolve) { @@ -213,7 +194,7 @@ export class RemoteFileService extends FileService { } } - private async _doResolveContent(provider: IRemoteFileSystemProvider, resource: URI): TPromise { + private async _doResolveContent(provider: IFileSystemProvider, resource: URI): TPromise { const stat = await toIFileStat(provider, await provider.stat(resource), false); @@ -254,7 +235,7 @@ export class RemoteFileService extends FileService { } } - private async _doUpdateContent(provider: IRemoteFileSystemProvider, resource: URI, content: string, options: IUpdateContentOptions): TPromise { + private async _doUpdateContent(provider: IFileSystemProvider, resource: URI, content: string, options: IUpdateContentOptions): TPromise { const encoding = this.getEncoding(resource, options.encoding); await provider.write(resource, encode(content, encoding)); const stat = await provider.stat(resource); From a7e2b9827f0a32a344629237faa78cf063e406d7 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Sep 2017 16:13:51 +0200 Subject: [PATCH 012/281] rename and copy --- src/vs/platform/files/common/files.ts | 1 + .../parts/files/browser/fileActions.ts | 4 +- .../electron-browser/ftpFileSystemProvider.ts | 6 ++ .../electron-browser/remoteFileService.ts | 83 ++++++++++++++++--- 4 files changed, 80 insertions(+), 14 deletions(-) diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 1e8606d14e0..92a263e67d6 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -171,6 +171,7 @@ export interface IFileSystemProvider { mkdir(resource: URI): TPromise; read(resource: URI, progress: IProgress): TPromise; write(resource: URI, content: Uint8Array): TPromise; + rename(resource: URI, target: URI): TPromise; del(resource: URI): TPromise; } diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index 850f696a4f2..3c9a63d62b2 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -1049,14 +1049,14 @@ export class DuplicateFileAction extends BaseFileAction { private findTarget(): URI { let name = this.element.name; - let candidate = URI.file(paths.join(this.target.resource.fsPath, name)); + let candidate = this.target.resource.with({ path: paths.join(this.target.resource.fsPath, name) }); while (true) { if (!this.element.root.find(candidate)) { break; } name = this.toCopyName(name, this.element.isDirectory); - candidate = URI.file(paths.join(this.target.resource.fsPath, name)); + candidate = this.target.resource.with({ path: paths.join(this.target.resource.fsPath, name) }); } return candidate; diff --git a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts index 3e064dd0f7b..78c1581eb52 100644 --- a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts +++ b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts @@ -104,4 +104,10 @@ export class FtpFileSystemProvider implements IFileSystemProvider { mkdir(resource: URI): TPromise { return ninvoke(this._connection, this._connection.raw, 'MKD', [resource.path]); } + + rename(resource: URI, target: URI): TPromise { + return ninvoke(this._connection, this._connection.raw, 'RNFR', [resource.path]).then(() => { + return ninvoke(this._connection, this._connection.raw, 'RNTO', [target.path]); + }); + } } diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 47b0aa5e864..d2c1760963d 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -6,9 +6,9 @@ import URI from 'vs/base/common/uri'; import { FileService } from 'vs/workbench/services/files/electron-browser/fileService'; -import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation, IFileSystemProvider, IStat, FileType } from 'vs/platform/files/common/files'; +import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation, IFileSystemProvider, IStat, FileType, IImportResult } from 'vs/platform/files/common/files'; import { TPromise } from 'vs/base/common/winjs.base'; -import { basename } from 'path'; +import { basename, join } from 'path'; import { IDisposable } from 'vs/base/common/lifecycle'; import * as Ftp from './ftpFileSystemProvider'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -55,25 +55,19 @@ function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse: boolea } else { return ret; } - }); } } export class RemoteFileService extends FileService { - - // public moveFile(source: URI, target: URI, overwrite?: boolean): TPromise { - // throw new Error("Method not implemented."); - // } - // public copyFile(source: URI, target: URI, overwrite?: boolean): TPromise { - // throw new Error("Method not implemented."); - // } - // public touchFile(resource: URI): TPromise { // throw new Error("Method not implemented."); // } - // public rename(resource: URI, newName: string): TPromise { + // public watchFileChanges(resource: URI): void { + // throw new Error("Method not implemented."); + // } + // public unwatchFileChanges(resource: URI): void { // throw new Error("Method not implemented."); // } @@ -282,4 +276,69 @@ export class RemoteFileService extends FileService { return super.createFolder(resource); } } + + rename(resource: URI, newName: string): TPromise { + const provider = this._provider.get(resource.scheme); + if (provider) { + const target = resource.with({ path: join(resource.path, '..', newName) }); + return this._doMove(provider, resource, target, false); + } else { + return super.rename(resource, newName); + } + } + + moveFile(source: URI, target: URI, overwrite?: boolean): TPromise { + if (source.scheme !== target.scheme) { + return this._manualMove(source, target); + } + const provider = this._provider.get(source.scheme); + if (provider) { + return this._doMove(provider, source, target, overwrite); + } else { + return super.moveFile(source, target, overwrite); + } + } + + private async _doMove(provider: IFileSystemProvider, source: URI, target: URI, overwrite?: boolean): TPromise { + // TODO@joh overwrite? -> stat&delete? + await provider.rename(source, target); + const stat = await this.resolveFile(target); + this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.MOVE, stat)); + return stat; + } + + private async _manualMove(source: URI, target: URI, overwrite?: boolean): TPromise { + await this.copyFile(source, target, overwrite); + await this.del(source); + const stat = await this.resolveFile(target); + this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.MOVE, stat)); + return stat; + } + + importFile(source: URI, targetFolder: URI): TPromise { + if (source.scheme === targetFolder.scheme && !this._provider.has(source.scheme)) { + return super.importFile(source, targetFolder); + + } else { + const target = targetFolder.with({ path: join(targetFolder.path, basename(source.path)) }); + return this.copyFile(source, target, false).then(stat => ({ stat, isNew: false })); + } + } + + async copyFile(source: URI, target: URI, overwrite?: boolean): TPromise { + if (source.scheme === target.scheme && !this._provider.has(source.scheme)) { + return super.copyFile(source, target, overwrite); + + } else { + const content = await this.resolveContent(source); + const provider = this._provider.get(target.scheme); + if (provider) { + const stat = await this._doUpdateContent(provider, target, content.value, { encoding: content.encoding }); + this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.COPY, stat)); + return stat; + } else { + return super.updateContent(target, content.value, { encoding: content.encoding }); + } + } + } } From ca0e80a4a1e9c357245855113d163be77f5d76a3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 13 Sep 2017 12:29:49 +0200 Subject: [PATCH 013/281] don't 'normalize' authority --- src/vs/platform/opener/browser/openerService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/opener/browser/openerService.ts b/src/vs/platform/opener/browser/openerService.ts index f6d6e7a0287..d567a6f5779 100644 --- a/src/vs/platform/opener/browser/openerService.ts +++ b/src/vs/platform/opener/browser/openerService.ts @@ -73,7 +73,7 @@ export class OpenerService implements IOpenerService { return TPromise.as(undefined); } else if (resource.scheme === Schemas.file) { - resource = URI.file(normalize(resource.fsPath)); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) + resource = resource.with({ path: normalize(resource.path) }); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) } promise = this._editorService.openEditor({ resource, options: { selection, } }, options && options.openToSide); } From 6c9aa9ab8388828e5c969fd2088767d022d5fff1 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Sep 2017 10:24:35 +0200 Subject: [PATCH 014/281] ImportFileAction doesn't use URI (fixes #34235) --- .../parts/files/browser/fileActions.ts | 17 ++++++++--------- .../parts/files/browser/views/explorerViewer.ts | 5 ++--- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index 3c9a63d62b2..73e3395bb1c 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -800,10 +800,9 @@ export class ImportFileAction extends BaseFileAction { return this.tree; } - public run(context?: any): TPromise { + public run(resources: URI[]): TPromise { const importPromise = TPromise.as(null).then(() => { - const input = context.input as { paths: string[] }; - if (input.paths && input.paths.length > 0) { + if (resources && resources.length > 0) { // Find parent for import let targetElement: FileStat; @@ -828,8 +827,8 @@ export class ImportFileAction extends BaseFileAction { }); let overwrite = true; - if (input.paths.some(path => { - return !!targetNames[isLinux ? paths.basename(path) : paths.basename(path).toLowerCase()]; + if (resources.some(resource => { + return !!targetNames[isLinux ? paths.basename(resource.fsPath) : paths.basename(resource.fsPath).toLowerCase()]; })) { const confirm: IConfirmation = { message: nls.localize('confirmOverwrite', "A file or folder with the same name already exists in the destination folder. Do you want to replace it?"), @@ -847,10 +846,10 @@ export class ImportFileAction extends BaseFileAction { // Run import in sequence const importPromisesFactory: ITask>[] = []; - input.paths.forEach(path => { + resources.forEach(resource => { importPromisesFactory.push(() => { - const sourceFile = URI.file(path); - const targetFile = URI.file(paths.join(targetElement.resource.fsPath, paths.basename(path))); + const sourceFile = resource; + const targetFile = targetElement.resource.with({ path: paths.join(targetElement.resource.path, paths.basename(sourceFile.path)) }); // if the target exists and is dirty, make sure to revert it. otherwise the dirty contents // of the target file would replace the contents of the imported file. since we already @@ -864,7 +863,7 @@ export class ImportFileAction extends BaseFileAction { return this.fileService.importFile(sourceFile, targetElement.resource).then(res => { // if we only import one file, just open it directly - if (input.paths.length === 1) { + if (resources.length === 1) { this.editorService.openEditor({ resource: res.stat.resource, options: { pinned: true } }).done(null, errors.onUnexpectedError); } }, error => this.onError(error)); diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index 3622e0e1ba4..b1b520c78a4 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -910,9 +910,8 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { // Handle dropped files (only support FileStat as target) else if (target instanceof FileStat) { const importAction = this.instantiationService.createInstance(ImportFileAction, tree, target, null); - return importAction.run({ - input: { paths: droppedResources.map(res => res.resource.fsPath) } - }); + + return importAction.run(droppedResources.map(res => res.resource)); } return void 0; From 43bb163f55b6621c046b84adbcd4f86b0dfd9e21 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Sep 2017 10:27:46 +0200 Subject: [PATCH 015/281] fix some URI.file (for #34296) --- src/vs/workbench/parts/files/browser/fileActions.ts | 8 +++----- .../parts/files/common/editors/fileEditorTracker.ts | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index 73e3395bb1c..20bf26ed80a 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -296,22 +296,20 @@ class RenameFileAction extends BaseRenameAction { } public runAction(newName: string): TPromise { - const dirty = this.textFileService.getDirty().filter(d => paths.isEqualOrParent(d.fsPath, this.element.resource.fsPath, !isLinux /* ignorecase */)); const dirtyRenamed: URI[] = []; return TPromise.join(dirty.map(d => { - - const targetPath = paths.join(this.element.parent.resource.fsPath, newName); let renamed: URI; // If the dirty file itself got moved, just reparent it to the target folder + const targetPath = paths.join(this.element.parent.resource.path, newName); if (paths.isEqual(this.element.resource.fsPath, d.fsPath)) { - renamed = URI.file(targetPath); + renamed = this.element.parent.resource.with({ path: targetPath }); } // Otherwise, a parent of the dirty resource got moved, so we have to reparent more complicated. Example: else { - renamed = URI.file(paths.join(targetPath, d.fsPath.substr(this.element.resource.fsPath.length + 1))); + renamed = this.element.parent.resource.with({ path: paths.join(targetPath, d.path.substr(this.element.resource.path.length + 1)) }); } dirtyRenamed.push(renamed); diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts index 52124b9fb7e..1795f7b9bf0 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts @@ -205,8 +205,8 @@ export class FileEditorTracker implements IWorkbenchContribution { if (oldResource.toString() === resource.toString()) { reopenFileResource = newResource; // file got moved } else { - const index = indexOf(resource.fsPath, oldResource.fsPath, !isLinux /* ignorecase */); - reopenFileResource = URI.file(paths.join(newResource.fsPath, resource.fsPath.substr(index + oldResource.fsPath.length + 1))); // parent folder got moved + const index = indexOf(resource.path, oldResource.path, !isLinux /* ignorecase */); + reopenFileResource = newResource.with({ path: paths.join(newResource.path, resource.path.substr(index + oldResource.path.length + 1)) }); // parent folder got moved } // Reopen From cc2acee68d0e82615fba7e929dad348618711e72 Mon Sep 17 00:00:00 2001 From: isidor Date: Thu, 14 Sep 2017 15:04:58 +0200 Subject: [PATCH 016/281] fix root label --- src/vs/workbench/browser/labels.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 66922084d46..60cbefaea57 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -218,8 +218,8 @@ export class FileLabel extends ResourceLabel { this.setLabel({ resource, - name: (options && options.hideLabel) ? void 0 : paths.basename(resource.fsPath), - description: !hidePath ? getPathLabel(paths.dirname(resource.fsPath), rootProvider, this.environmentService) : void 0 + name: (options && options.hideLabel) ? void 0 : paths.basename(resource.toString()), + description: !hidePath ? getPathLabel(paths.dirname(resource.toString()), rootProvider, this.environmentService) : void 0 }, options); } } From 94deeec33fb2d0ddf5dfaea74b0bcb3b5d900257 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Sep 2017 16:01:25 +0200 Subject: [PATCH 017/281] properly stat files and folders --- .../electron-browser/ftpFileSystemProvider.ts | 35 +++++++++++-------- .../files/electron-browser/jsftp.d.ts | 6 +++- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts index 78c1581eb52..2867b30db59 100644 --- a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts +++ b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts @@ -12,7 +12,7 @@ import * as JSFtp from 'jsftp'; import { ninvoke } from 'vs/base/common/async'; import { TPromise } from 'vs/base/common/winjs.base'; import { Readable } from 'stream'; -import { join } from 'path'; +import { join, dirname, basename } from 'path'; import { IStat, FileType, IFileSystemProvider } from 'vs/platform/files/common/files'; import { IProgress } from 'vs/platform/progress/common/progress'; @@ -34,27 +34,32 @@ export class FtpFileSystemProvider implements IFileSystemProvider { } stat(resource: URI): TPromise { + const { path } = resource; + if (path === '/') { + // root directory + return TPromise.as({ + type: FileType.Dir, + resource, + mtime: 0, + size: 0 + }); + } - return ninvoke(this._connection, this._connection.ls, resource.path).then(entries => { - - if (entries.length === 1) { - // stat one file - const [entry] = entries; + const name = basename(path); + const dir = dirname(path); + return ninvoke(this._connection, this._connection.ls, dir).then(entries => { + for (const entry of entries) { + if (entry.name === name) { return { resource, mtime: entry.time, size: entry.size, - type: FileType.File + type: entry.type }; } - - // stat directory - return { - resource, - mtime: 0, - size: 0, - type: FileType.Dir, - }; + } + console.log(entries, name, resource); + throw new Error(`NotFound: ${resource.path}`); }); } diff --git a/src/vs/workbench/services/files/electron-browser/jsftp.d.ts b/src/vs/workbench/services/files/electron-browser/jsftp.d.ts index 767a28e7abd..59bfce7a3c5 100644 --- a/src/vs/workbench/services/files/electron-browser/jsftp.d.ts +++ b/src/vs/workbench/services/files/electron-browser/jsftp.d.ts @@ -1,6 +1,7 @@ import { Readable } from 'stream'; +import { EventEmitter } from 'events'; declare namespace JSFtp { @@ -10,6 +11,7 @@ declare namespace JSFtp { port?: number | 21; user?: string | 'anonymous'; pass?: string | '@anonymous'; + useList?: boolean } interface Callback { @@ -25,11 +27,13 @@ declare namespace JSFtp { } } -interface JSFtp { +interface JSFtp extends EventEmitter { keepAlive(wait?: number): void; ls(path: string, callback: JSFtp.Callback): void; + list(path: string, callback: JSFtp.Callback): void; put(buffer: Buffer, path: string, callback: JSFtp.Callback): void; get(path: string, callback: JSFtp.Callback): void; + setType(type: 'A' | 'AN' | 'AT' | 'AC' | 'E' | 'I' | 'L', callback: JSFtp.Callback): void; raw(command: string, args: any[], callback: JSFtp.Callback): void } From aa0439df1fd6e0f72ebe262a0d2cf37022d8ada6 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Sep 2017 16:27:48 +0200 Subject: [PATCH 018/281] have unlink and rmdir --- src/vs/platform/files/common/files.ts | 7 ++++--- .../electron-browser/ftpFileSystemProvider.ts | 17 ++++++----------- .../files/electron-browser/remoteFileService.ts | 3 ++- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 92a263e67d6..f4f448a3abd 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -167,12 +167,13 @@ export interface IStat { export interface IFileSystemProvider { onDidChange?: Event; stat(resource: URI): TPromise; - readdir(resource: URI): TPromise; - mkdir(resource: URI): TPromise; read(resource: URI, progress: IProgress): TPromise; write(resource: URI, content: Uint8Array): TPromise; + unlink(resource: URI): TPromise; rename(resource: URI, target: URI): TPromise; - del(resource: URI): TPromise; + mkdir(resource: URI): TPromise; + readdir(resource: URI): TPromise; + rmdir(resource: URI): TPromise; } diff --git a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts index 2867b30db59..c22fe332520 100644 --- a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts +++ b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts @@ -93,23 +93,18 @@ export class FtpFileSystemProvider implements IFileSystemProvider { return ninvoke(this._connection, this._connection.put, content, resource.path); } - del(resource: URI): TPromise { - - return ninvoke(this._connection, this._connection.ls, resource.path).then(entries => { - if (entries.length === 1) { - // file; - return ninvoke(this._connection, this._connection.raw, 'DELE', [resource.path]); - } else { - // dir - return ninvoke(this._connection, this._connection.raw, 'RMD', [resource.path]); - } - }); + rmdir(resource: URI): TPromise { + return ninvoke(this._connection, this._connection.raw, 'RMD', [resource.path]); } mkdir(resource: URI): TPromise { return ninvoke(this._connection, this._connection.raw, 'MKD', [resource.path]); } + unlink(resource: URI): TPromise { + return ninvoke(this._connection, this._connection.raw, 'DELE', [resource.path]); + } + rename(resource: URI, target: URI): TPromise { return ninvoke(this._connection, this._connection.raw, 'RNFR', [resource.path]).then(() => { return ninvoke(this._connection, this._connection.raw, 'RNTO', [target.path]); diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index d2c1760963d..00969284031 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -258,7 +258,8 @@ export class RemoteFileService extends FileService { async del(resource: URI, useTrash?: boolean): TPromise { const provider = this._provider.get(resource.scheme); if (provider) { - await provider.del(resource); + const stat = await provider.stat(resource); + await stat.type === FileType.Dir ? provider.rmdir(resource) : provider.unlink(resource); this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.DELETE)); } else { return super.del(resource, useTrash); From 46e98b15ecfb92e009942451d5cb7baf6c2fc1c7 Mon Sep 17 00:00:00 2001 From: isidor Date: Thu, 14 Sep 2017 16:48:58 +0200 Subject: [PATCH 019/281] use authority as label --- src/vs/workbench/browser/labels.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 60cbefaea57..ffbe2622a3b 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -216,10 +216,12 @@ export class FileLabel extends ResourceLabel { getWorkspace(): { folders: uri[]; } { return { folders: [options.root] }; }, } : this.contextService; + const name = resource.fsPath.length > 1 ? paths.basename(resource.fsPath) : resource.authority; + const description = resource.fsPath.length > 1 ? getPathLabel(paths.dirname(resource.fsPath), rootProvider, this.environmentService) : resource.authority; this.setLabel({ resource, - name: (options && options.hideLabel) ? void 0 : paths.basename(resource.toString()), - description: !hidePath ? getPathLabel(paths.dirname(resource.toString()), rootProvider, this.environmentService) : void 0 + name: (options && options.hideLabel) ? void 0 : name, + description: !hidePath ? description : void 0 }, options); } } From ad2918cda5edce9ea55e0582090da0672bef716e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Sep 2017 17:33:17 +0200 Subject: [PATCH 020/281] start with empty deepStat-function --- src/vs/platform/files/common/files.ts | 2 ++ .../services/files/electron-browser/remoteFileService.ts | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index f4f448a3abd..66ab40f91b6 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -165,6 +165,8 @@ export interface IStat { } export interface IFileSystemProvider { + // utime + // ... onDidChange?: Event; stat(resource: URI): TPromise; read(resource: URI, progress: IProgress): TPromise; diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 00969284031..049f53c424a 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -59,6 +59,14 @@ function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse: boolea } } +async function toDeepIFileStat(provider: IFileSystemProvider, stat: IFileStat, to: URI[]): TPromise { + if (isFalsyOrEmpty(to)) { + return TPromise.as(stat); + } + + return TPromise.as(stat); +} + export class RemoteFileService extends FileService { // public touchFile(resource: URI): TPromise { @@ -163,6 +171,7 @@ export class RemoteFileService extends FileService { for (const item of toResolve) { promises.push(provider.stat(item.resource) .then(stat => toIFileStat(provider, stat, true)) + .then(stat => toDeepIFileStat(provider, stat, item.options && item.options.resolveTo)) .then(stat => result.push({ stat, success: true }))); } return TPromise.join(promises).then(() => result); From 09a1d0e4f8319da2c5938f4c451481a7defa2fb3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 14 Sep 2017 18:29:09 +0200 Subject: [PATCH 021/281] del on overwrite, some comments for shortcommings --- .../electron-browser/remoteFileService.ts | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 049f53c424a..2c3cfd83122 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -310,7 +310,15 @@ export class RemoteFileService extends FileService { } private async _doMove(provider: IFileSystemProvider, source: URI, target: URI, overwrite?: boolean): TPromise { - // TODO@joh overwrite? -> stat&delete? + if (overwrite) { + try { + await this.del(target); + } catch (e) { + // TODO@Joh Better errors + // ignore not_exists error + // abort on other errors + } + } await provider.rename(source, target); const stat = await this.resolveFile(target); this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.MOVE, stat)); @@ -338,17 +346,28 @@ export class RemoteFileService extends FileService { async copyFile(source: URI, target: URI, overwrite?: boolean): TPromise { if (source.scheme === target.scheme && !this._provider.has(source.scheme)) { return super.copyFile(source, target, overwrite); + } - } else { - const content = await this.resolveContent(source); - const provider = this._provider.get(target.scheme); - if (provider) { - const stat = await this._doUpdateContent(provider, target, content.value, { encoding: content.encoding }); - this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.COPY, stat)); - return stat; - } else { - return super.updateContent(target, content.value, { encoding: content.encoding }); + if (overwrite) { + try { + await this.del(target); + } catch (e) { + // TODO@Joh Better errors + // ignore not_exists error + // abort on other errors } } + // TODO@Joh This does only work for textfiles + // because the content turns things into a string + // and all binary data will be broken + const content = await this.resolveContent(source); + const targetProvider = this._provider.get(target.scheme); + if (targetProvider) { + const stat = await this._doUpdateContent(targetProvider, target, content.value, { encoding: content.encoding }); + this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.COPY, stat)); + return stat; + } else { + return super.updateContent(target, content.value, { encoding: content.encoding }); + } } } From a21b9fee551506040e15100c0482e7db46ae73c5 Mon Sep 17 00:00:00 2001 From: Jonathan Widjaja Date: Thu, 14 Sep 2017 13:30:17 -0700 Subject: [PATCH 022/281] Maintain focus on stopped thread when stepping a multithreaded session --- src/vs/workbench/parts/debug/electron-browser/debugService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 953b094abc8..76bd349cb27 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -236,7 +236,7 @@ export class DebugService implements debug.IDebugService { private tryToAutoFocusStackFrame(thread: debug.IThread): TPromise { const callStack = thread.getCallStack(); - if (!callStack.length || this.viewModel.focusedStackFrame) { + if (!callStack.length || (this.viewModel.focusedStackFrame && this.viewModel.focusedStackFrame.thread.threadId === thread.threadId)) { return TPromise.as(null); } @@ -496,7 +496,7 @@ export class DebugService implements debug.IDebugService { } if (!stackFrame) { const threads = process ? process.getAllThreads() : null; - const callStack = threads && threads.length ? threads[0].getCallStack() : null; + const callStack = threads && threads.length === 1 ? threads[0].getCallStack() : null; stackFrame = callStack && callStack.length ? callStack[0] : null; } From 5c2037a8de3d53df5d2197fc87e485fd08198b92 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 15 Sep 2017 10:43:26 +0200 Subject: [PATCH 023/281] reveal in finder, open in terminal only for schema === 'file' --- .../electron-browser/execution.contribution.ts | 3 ++- .../files/browser/fileActions.contribution.ts | 15 +++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts b/src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts index 30ef13ec313..2d8142bf0e8 100644 --- a/src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts +++ b/src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts @@ -182,7 +182,8 @@ export class ExplorerViewerActionContributor extends ActionBarContributor { } public hasSecondaryActions(context: any): boolean { - return !!explorerItemToFileResource(context.element); + const fileResource = explorerItemToFileResource(context.element); + return fileResource && fileResource.resource.scheme === 'file'; } public getSecondaryActions(context: any): IAction[] { diff --git a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts index b72884929b5..150727ee766 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts @@ -165,18 +165,17 @@ class ExplorerViewersActionContributor extends ActionBarContributor { public getSecondaryActions(context: any): IAction[] { const actions: IAction[] = []; + const fileResource = explorerItemToFileResource(context.element); + const resource = fileResource.resource; - if (this.hasSecondaryActions(context)) { - const fileResource = explorerItemToFileResource(context.element); - const resource = fileResource.resource; - - // Reveal file in OS native explorer + // Reveal file in OS native explorer + if (resource.scheme === 'file') { actions.push(this.instantiationService.createInstance(RevealInOSAction, resource)); - - // Copy Path - actions.push(this.instantiationService.createInstance(CopyPathAction, resource)); } + // Copy Path + actions.push(this.instantiationService.createInstance(CopyPathAction, resource)); + return actions; } } From 1559b68d09b4b9541c74e16552c25726d2e8c29d Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 15 Sep 2017 10:49:31 +0200 Subject: [PATCH 024/281] git: open change enabled only for local files --- extensions/git/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index 995ac785f74..a207c29d6a5 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -693,7 +693,7 @@ { "command": "git.openChange", "group": "navigation", - "when": "config.git.enabled && gitOpenRepositoryCount != 0 && !isInDiffEditor && resourceScheme != extension" + "when": "config.git.enabled && gitOpenRepositoryCount != 0 && !isInDiffEditor && resourceScheme == file" }, { "command": "git.stageSelectedRanges", From 9844fcb96e9494eb9216704c00ba65dca2ba3441 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 15 Sep 2017 10:58:24 +0200 Subject: [PATCH 025/281] fix copy path command --- src/vs/workbench/parts/files/browser/fileCommands.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/fileCommands.ts b/src/vs/workbench/parts/files/browser/fileCommands.ts index f33e0388704..157239a2b27 100644 --- a/src/vs/workbench/parts/files/browser/fileCommands.ts +++ b/src/vs/workbench/parts/files/browser/fileCommands.ts @@ -22,7 +22,6 @@ import { FileStat, OpenEditor } from 'vs/workbench/parts/files/common/explorerMo import errors = require('vs/base/common/errors'); import { ITree } from 'vs/base/parts/tree/browser/tree'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -import labels = require('vs/base/common/labels'); import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IMessageService } from 'vs/platform/message/common/message'; @@ -44,7 +43,7 @@ export const copyPathCommand = (accessor: ServicesAccessor, resource?: URI) => { if (resource) { const clipboardService = accessor.get(IClipboardService); - clipboardService.writeText(labels.getPathLabel(resource)); + clipboardService.writeText(resource.scheme === 'file' ? resource.fsPath : resource.toString()); } else { const messageService = accessor.get(IMessageService); messageService.show(severity.Info, nls.localize('openFileToCopy', "Open a file first to copy its path")); From f4c844a3ed45173301f04737073c346636dec6cf Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 15 Sep 2017 10:35:23 +0200 Subject: [PATCH 026/281] support touch and utimes --- src/vs/platform/files/common/files.ts | 7 +++- .../electron-browser/ftpFileSystemProvider.ts | 5 +++ .../electron-browser/remoteFileService.ts | 39 ++++++++++++++----- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 66ab40f91b6..3113394611b 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -165,9 +165,12 @@ export interface IStat { } export interface IFileSystemProvider { - // utime - // ... + onDidChange?: Event; + + // more... + // + utimes(resource: URI, mtime: number): TPromise; stat(resource: URI): TPromise; read(resource: URI, progress: IProgress): TPromise; write(resource: URI, content: Uint8Array): TPromise; diff --git a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts index c22fe332520..0b375366ee5 100644 --- a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts +++ b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts @@ -33,6 +33,11 @@ export class FtpFileSystemProvider implements IFileSystemProvider { ninvoke(this._connection, this._connection.raw, 'QUIT'); } + utimes(resource: URI, mtime: number): TPromise { + return ninvoke(this._connection, this._connection.raw, 'NOOP') + .then(() => this.stat(resource)); + } + stat(resource: URI): TPromise { const { path } = resource; if (path === '/') { diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 2c3cfd83122..1c03f7d267f 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -69,16 +69,6 @@ async function toDeepIFileStat(provider: IFileSystemProvider, stat: IFileStat, t export class RemoteFileService extends FileService { - // public touchFile(resource: URI): TPromise { - // throw new Error("Method not implemented."); - // } - // public watchFileChanges(resource: URI): void { - // throw new Error("Method not implemented."); - // } - // public unwatchFileChanges(resource: URI): void { - // throw new Error("Method not implemented."); - // } - private readonly _provider = new Map(); constructor( @@ -370,4 +360,33 @@ export class RemoteFileService extends FileService { return super.updateContent(target, content.value, { encoding: content.encoding }); } } + + touchFile(resource: URI): TPromise { + const provider = this._provider.get(resource.scheme); + if (provider) { + return this._doTouchFile(provider, resource); + } else { + return super.touchFile(resource); + } + } + + private async _doTouchFile(provider: IFileSystemProvider, resource: URI): TPromise { + let stat: IStat; + try { + await provider.stat(resource); + stat = await provider.utimes(resource, Date.now()); + } catch (e) { + // TODO@Joh, if ENOENT + await provider.write(resource, new Uint8Array(0)); + stat = await provider.stat(resource); + } + return toIFileStat(provider, stat, false); + } + + // public watchFileChanges(resource: URI): void { + // throw new Error("Method not implemented."); + // } + // public unwatchFileChanges(resource: URI): void { + // throw new Error("Method not implemented."); + // } } From 6fbaf5480cbc2ab93f494df4d468d0f3c0109c3a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 15 Sep 2017 11:37:24 +0200 Subject: [PATCH 027/281] be ready for deep resolve --- .../electron-browser/remoteFileService.ts | 37 +++++++- .../remoteFileSystemProvider.test.ts | 88 +++++++++++++++++++ 2 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 src/vs/workbench/services/files/test/electron-browser/remoteFileSystemProvider.test.ts diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 1c03f7d267f..be70da6be78 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -8,7 +8,7 @@ import URI from 'vs/base/common/uri'; import { FileService } from 'vs/workbench/services/files/electron-browser/fileService'; import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation, IFileSystemProvider, IStat, FileType, IImportResult } from 'vs/platform/files/common/files'; import { TPromise } from 'vs/base/common/winjs.base'; -import { basename, join } from 'path'; +import { basename, join, dirname } from 'path'; import { IDisposable } from 'vs/base/common/lifecycle'; import * as Ftp from './ftpFileSystemProvider'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -24,6 +24,8 @@ import { compare } from 'vs/base/common/strings'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { Progress } from 'vs/platform/progress/common/progress'; import { decodeStream, encode } from 'vs/base/node/encoding'; +import { Graph } from 'vs/base/common/graph'; +import { values } from 'vs/base/common/collections'; function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse: boolean): TPromise { const ret: IFileStat = { @@ -59,11 +61,42 @@ function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse: boolea } } -async function toDeepIFileStat(provider: IFileSystemProvider, stat: IFileStat, to: URI[]): TPromise { +export async function toDeepIFileStat(provider: IFileSystemProvider, stat: IFileStat, to: URI[]): TPromise { if (isFalsyOrEmpty(to)) { return TPromise.as(stat); } + const graph = new Graph(uri => uri.path); + graph.lookupOrInsertNode(stat.resource); // root + + to.sort((a, b) => compare(a.path, b.path)).forEach(resource => { + let parent = resource.with({ path: dirname(resource.path) }); + let hitParent = false; + while (!hitParent) { + hitParent = !!graph.lookup(parent) || parent.path === '/'; + graph.insertEdge(parent, resource); + resource = parent; + parent = resource.with({ path: dirname(resource.path) }); + } + }); + + const stack: IFileStat[] = [stat]; + while (stack.length > 0) { + const parent = stack.shift(); + if (parent.isDirectory) { + parent.children = []; + const { outgoing } = graph.lookup(parent.resource); + + await values(outgoing).map(child => { + return provider.stat(child.data) + .then(stat => toIFileStat(provider, stat, false)) + .then(stat => parent.children.push(stat)); + }); + + stack.push(...parent.children); + } + } + return TPromise.as(stat); } diff --git a/src/vs/workbench/services/files/test/electron-browser/remoteFileSystemProvider.test.ts b/src/vs/workbench/services/files/test/electron-browser/remoteFileSystemProvider.test.ts new file mode 100644 index 00000000000..b45b2122b9a --- /dev/null +++ b/src/vs/workbench/services/files/test/electron-browser/remoteFileSystemProvider.test.ts @@ -0,0 +1,88 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { toDeepIFileStat } from 'vs/workbench/services/files/electron-browser/remoteFileService'; +import { IFileSystemProvider, IStat, IFileStat, FileType } from 'vs/platform/files/common/files'; +import URI from 'vs/base/common/uri'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { IProgress } from 'vs/platform/progress/common/progress'; +import { extname } from 'path'; + +suite('RemoteFileSystem', function () { + + class StatOnlyProvider implements IFileSystemProvider { + + stat(resource: URI): TPromise { + const ext = extname(resource.path); + return TPromise.as(!ext + ? StatOnlyProvider.createFolderStat(resource) + : StatOnlyProvider.createFileStat(resource) + ); + } + readdir(resource: URI): TPromise { + return TPromise.as([]); + } + // throw errors on the rest + utimes(resource: URI, mtime: number): TPromise { + throw new Error('Method not implemented.'); + } + read(resource: URI, progress: IProgress): TPromise { + throw new Error('Method not implemented.'); + } + write(resource: URI, content: Uint8Array): TPromise { + throw new Error('Method not implemented.'); + } + unlink(resource: URI): TPromise { + throw new Error('Method not implemented.'); + } + rename(resource: URI, target: URI): TPromise { + throw new Error('Method not implemented.'); + } + mkdir(resource: URI): TPromise { + throw new Error('Method not implemented.'); + } + rmdir(resource: URI): TPromise { + throw new Error('Method not implemented.'); + } + + static createFileStat(resource: URI): IStat { + return { + resource, + mtime: Date.now(), + size: 42, + type: FileType.File + }; + } + + static createFolderStat(resource: URI, hasChildren: boolean = true): IStat { + return { + resource, + mtime: Date.now(), + size: 42, + type: FileType.Dir + }; + } + }; + + test('toDeepIFileStat', function () { + + const provider = new StatOnlyProvider(); + const root: IFileStat = { + resource: URI.parse('foo:///test/root'), + name: 'root', + isDirectory: true, + hasChildren: true, + mtime: Date.now(), + etag: '' + }; + toDeepIFileStat(provider, root, [ + URI.parse('foo:///test/root/folder1'), + URI.parse('foo:///test/root/folder2/folder1/child2'), + URI.parse('foo:///test/root/folder2/child2'), + URI.parse('foo:///test/root/folder3/child2'), + ]); + }); +}); From b11100b3620ea26a2f5df0e468a85f34b64d2c6d Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 15 Sep 2017 12:05:57 +0200 Subject: [PATCH 028/281] move add remote root hack one level up --- src/vs/workbench/parts/files/common/explorerModel.ts | 1 - src/vs/workbench/services/configuration/node/configuration.ts | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/files/common/explorerModel.ts b/src/vs/workbench/parts/files/common/explorerModel.ts index 8f24cf208a4..c2d760614b2 100644 --- a/src/vs/workbench/parts/files/common/explorerModel.ts +++ b/src/vs/workbench/parts/files/common/explorerModel.ts @@ -27,7 +27,6 @@ export class Model { constructor( @IWorkspaceContextService private contextService: IWorkspaceContextService) { const setRoots = () => { this._roots = this.contextService.getWorkspace().folders.map(uri => new FileStat(uri, undefined)); - this._roots.push(new FileStat(URI.parse('ftp://waws-prod-db3-029.ftp.azurewebsites.windows.net/'), undefined)); }; this.contextService.onDidChangeWorkspaceFolders(() => setRoots()); setRoots(); diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configuration.ts index 102b1824712..00d8636d493 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configuration.ts @@ -471,6 +471,7 @@ export class WorkspaceServiceImpl extends WorkspaceService { .then(() => { const workspaceConfigurationModel = this.workspaceConfiguration.workspaceConfigurationModel; const workspaceFolders = this.parseWorkspaceFolders(workspaceConfigurationModel.folders); + workspaceFolders.push(URI.parse('ftp://waws-prod-db3-029.ftp.azurewebsites.windows.net/')); if (!workspaceFolders.length) { return TPromise.wrapError(new Error('Invalid workspace configuraton file ' + this.workspaceConfigPath)); } From 7b58f2fd6ec98faa0a62332428369b535f8eb850 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 15 Sep 2017 12:07:25 +0200 Subject: [PATCH 029/281] make workspace.ts ftp aware --- src/vs/platform/workspace/common/workspace.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index 38f755fc658..28a0c00b7e6 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -109,7 +109,7 @@ export class Workspace implements IWorkspace { } private ensureUnique(folders: URI[]): URI[] { - return distinct(folders, folder => isLinux ? folder.fsPath : folder.fsPath.toLowerCase()); + return distinct(folders, folder => isLinux ? folder.toString() : folder.toString().toLowerCase()); } public get folders(): URI[] { @@ -142,13 +142,13 @@ export class Workspace implements IWorkspace { return null; } - return this._foldersMap.findSubstr(resource.fsPath); + return this._foldersMap.findSubstr(resource.scheme === 'file' ? resource.fsPath : resource.authority); } private updateFoldersMap(): void { this._foldersMap = new TrieMap(); for (const folder of this.folders) { - this._foldersMap.insert(folder.fsPath, folder); + this._foldersMap.insert(folder.scheme === 'file' ? folder.fsPath : folder.authority, folder); } } From 5b8413124cf74234118e8ab0d36a6051ffd89d88 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 15 Sep 2017 12:58:14 +0200 Subject: [PATCH 030/281] readdir return IStat-array --- src/vs/platform/files/common/files.ts | 2 +- .../files/electron-browser/ftpFileSystemProvider.ts | 11 ++++++++--- .../files/electron-browser/remoteFileService.ts | 2 +- .../electron-browser/remoteFileSystemProvider.test.ts | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 3113394611b..4e8c9dab644 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -177,7 +177,7 @@ export interface IFileSystemProvider { unlink(resource: URI): TPromise; rename(resource: URI, target: URI): TPromise; mkdir(resource: URI): TPromise; - readdir(resource: URI): TPromise; + readdir(resource: URI): TPromise; rmdir(resource: URI): TPromise; } diff --git a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts index 0b375366ee5..830172bda7f 100644 --- a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts +++ b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts @@ -68,11 +68,16 @@ export class FtpFileSystemProvider implements IFileSystemProvider { }); } - readdir(resource: URI): TPromise { + readdir(resource: URI): TPromise { return ninvoke(this._connection, this._connection.ls, resource.path).then(ret => { - const result: URI[] = []; + const result: IStat[] = []; for (let entry of ret) { - result.push(resource.with({ path: join(resource.path, entry.name) })); + result.push({ + resource: resource.with({ path: join(resource.path, entry.name) }), + mtime: entry.time, + size: entry.size, + type: entry.type + }); } return result; }); diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index be70da6be78..9740498dc84 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -50,7 +50,7 @@ function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse: boolea if (recurse) { // resolve children if requested - return TPromise.join(items.map(resource => provider.stat(resource).then(stat => toIFileStat(provider, stat, false)))).then(children => { + return TPromise.join(items.map(stat => toIFileStat(provider, stat, false))).then(children => { ret.children = children; return ret; }); diff --git a/src/vs/workbench/services/files/test/electron-browser/remoteFileSystemProvider.test.ts b/src/vs/workbench/services/files/test/electron-browser/remoteFileSystemProvider.test.ts index b45b2122b9a..7dab064fca2 100644 --- a/src/vs/workbench/services/files/test/electron-browser/remoteFileSystemProvider.test.ts +++ b/src/vs/workbench/services/files/test/electron-browser/remoteFileSystemProvider.test.ts @@ -22,7 +22,7 @@ suite('RemoteFileSystem', function () { : StatOnlyProvider.createFileStat(resource) ); } - readdir(resource: URI): TPromise { + readdir(resource: URI): TPromise { return TPromise.as([]); } // throw errors on the rest From 2a6388e60e3dc218d0a9fa760cfc02f916464e88 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 15 Sep 2017 13:07:53 +0200 Subject: [PATCH 031/281] turn off deep stat, don't log when files don't exist --- .../services/files/electron-browser/ftpFileSystemProvider.ts | 4 ++-- .../services/files/electron-browser/remoteFileService.ts | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts index 830172bda7f..70efb4fcd2e 100644 --- a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts +++ b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts @@ -63,8 +63,8 @@ export class FtpFileSystemProvider implements IFileSystemProvider { }; } } - console.log(entries, name, resource); - throw new Error(`NotFound: ${resource.path}`); + // console.log(entries, name, resource); + throw new Error(`ENO: ${resource.path}`); }); } diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 9740498dc84..77053d3f48b 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -62,6 +62,9 @@ function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse: boolea } export async function toDeepIFileStat(provider: IFileSystemProvider, stat: IFileStat, to: URI[]): TPromise { + if (to) { + to.length = 0; + } if (isFalsyOrEmpty(to)) { return TPromise.as(stat); } From 1b6fd47b5005ad542e8d459510c6fd99155db2a0 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 15 Sep 2017 16:34:59 +0200 Subject: [PATCH 032/281] introduce resource.ts --- src/vs/base/common/resources.ts | 16 ++++++++++++++++ src/vs/workbench/browser/labels.ts | 17 +++++++---------- 2 files changed, 23 insertions(+), 10 deletions(-) create mode 100644 src/vs/base/common/resources.ts diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts new file mode 100644 index 00000000000..49840f9c960 --- /dev/null +++ b/src/vs/base/common/resources.ts @@ -0,0 +1,16 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import * as paths from 'vs/base/common/paths'; +import uri from 'vs/base/common/uri'; + +export function basename(resource: uri): string { + if (resource.scheme === 'file' || resource.scheme === 'untitled') { + return paths.basename(resource.fsPath); + } + + return paths.basename(resource.authority + resource.path); +} diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index ffbe2622a3b..6e571b517f7 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -7,6 +7,7 @@ import uri from 'vs/base/common/uri'; import paths = require('vs/base/common/paths'); +import resources = require('vs/base/common/resources'); import { IconLabel, IIconLabelOptions, IIconLabelCreationOptions } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -216,11 +217,11 @@ export class FileLabel extends ResourceLabel { getWorkspace(): { folders: uri[]; } { return { folders: [options.root] }; }, } : this.contextService; - const name = resource.fsPath.length > 1 ? paths.basename(resource.fsPath) : resource.authority; - const description = resource.fsPath.length > 1 ? getPathLabel(paths.dirname(resource.fsPath), rootProvider, this.environmentService) : resource.authority; + const description = resource.scheme === 'file' ? getPathLabel(paths.dirname(resource.fsPath), rootProvider, this.environmentService) : resource.authority; + this.setLabel({ resource, - name: (options && options.hideLabel) ? void 0 : name, + name: (options && options.hideLabel) ? void 0 : resources.basename(resource), description: !hidePath ? description : void 0 }, options); } @@ -231,13 +232,9 @@ export function getIconClasses(modelService: IModelService, modeService: IModeSe // we always set these base classes even if we do not have a path const classes = fileKind === FileKind.ROOT_FOLDER ? ['rootfolder-icon'] : fileKind === FileKind.FOLDER ? ['folder-icon'] : ['file-icon']; - let path: string; - if (resource) { - path = resource.fsPath; - } - if (path) { - const basename = cssEscape(paths.basename(path).toLowerCase()); + if (resource) { + const basename = cssEscape(resources.basename(resource).toLowerCase()); // Folders if (fileKind === FileKind.FOLDER) { @@ -258,7 +255,7 @@ export function getIconClasses(modelService: IModelService, modeService: IModeSe // Configured Language let configuredLangId = getConfiguredLangId(modelService, resource); - configuredLangId = configuredLangId || modeService.getModeIdByFilenameOrFirstLine(path); + configuredLangId = configuredLangId || modeService.getModeIdByFilenameOrFirstLine(basename); if (configuredLangId) { classes.push(`${cssEscape(configuredLangId)}-lang-file-icon`); } From 6faa350eba81cb8cdaecbde59816b9964749ee63 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 15 Sep 2017 17:10:52 +0200 Subject: [PATCH 033/281] basenameOrAuthority --- src/vs/base/common/resources.ts | 8 ++------ src/vs/workbench/browser/labels.ts | 14 +++++++------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts index 49840f9c960..2a2ddacc029 100644 --- a/src/vs/base/common/resources.ts +++ b/src/vs/base/common/resources.ts @@ -7,10 +7,6 @@ import * as paths from 'vs/base/common/paths'; import uri from 'vs/base/common/uri'; -export function basename(resource: uri): string { - if (resource.scheme === 'file' || resource.scheme === 'untitled') { - return paths.basename(resource.fsPath); - } - - return paths.basename(resource.authority + resource.path); +export function basenameOrAuthority(resource: uri): string { + return paths.basename(resource.fsPath) || resource.authority; } diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 6e571b517f7..c29b95aab08 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -217,11 +217,11 @@ export class FileLabel extends ResourceLabel { getWorkspace(): { folders: uri[]; } { return { folders: [options.root] }; }, } : this.contextService; - const description = resource.scheme === 'file' ? getPathLabel(paths.dirname(resource.fsPath), rootProvider, this.environmentService) : resource.authority; + const description = resource.scheme === 'file' || resource.scheme === 'untitled' ? getPathLabel(paths.dirname(resource.fsPath), rootProvider, this.environmentService) : resource.authority; this.setLabel({ resource, - name: (options && options.hideLabel) ? void 0 : resources.basename(resource), + name: (options && options.hideLabel) ? void 0 : resources.basenameOrAuthority(resource), description: !hidePath ? description : void 0 }, options); } @@ -234,28 +234,28 @@ export function getIconClasses(modelService: IModelService, modeService: IModeSe if (resource) { - const basename = cssEscape(resources.basename(resource).toLowerCase()); + const name = cssEscape(resources.basenameOrAuthority(resource).toLowerCase()); // Folders if (fileKind === FileKind.FOLDER) { - classes.push(`${basename}-name-folder-icon`); + classes.push(`${name}-name-folder-icon`); } // Files else { // Name - classes.push(`${basename}-name-file-icon`); + classes.push(`${name}-name-file-icon`); // Extension(s) - const dotSegments = basename.split('.'); + const dotSegments = name.split('.'); for (let i = 1; i < dotSegments.length; i++) { classes.push(`${dotSegments.slice(i).join('.')}-ext-file-icon`); // add each combination of all found extensions if more than one } // Configured Language let configuredLangId = getConfiguredLangId(modelService, resource); - configuredLangId = configuredLangId || modeService.getModeIdByFilenameOrFirstLine(basename); + configuredLangId = configuredLangId || modeService.getModeIdByFilenameOrFirstLine(name); if (configuredLangId) { classes.push(`${cssEscape(configuredLangId)}-lang-file-icon`); } From b47a91579585217f8a20cf976f12f9a7c68b188e Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 15 Sep 2017 17:26:46 +0200 Subject: [PATCH 034/281] resources.isEqualOrParent --- src/vs/base/common/resources.ts | 8 ++++++++ src/vs/workbench/parts/files/browser/fileActions.ts | 9 +++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts index 2a2ddacc029..5fd3fa80156 100644 --- a/src/vs/base/common/resources.ts +++ b/src/vs/base/common/resources.ts @@ -10,3 +10,11 @@ import uri from 'vs/base/common/uri'; export function basenameOrAuthority(resource: uri): string { return paths.basename(resource.fsPath) || resource.authority; } + +export function isEqualOrParent(first: uri, second: uri, ignoreCase?: boolean): boolean { + if (first.scheme === second.scheme && first.authority === second.authority) { + return paths.isEqualOrParent(first.fsPath, second.fsPath, ignoreCase); + } + + return false; +} diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index 20bf26ed80a..63bb24e78dd 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -11,6 +11,7 @@ import nls = require('vs/nls'); import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform'; import { sequence, ITask } from 'vs/base/common/async'; import paths = require('vs/base/common/paths'); +import resources = require('vs/base/common/resources'); import URI from 'vs/base/common/uri'; import errors = require('vs/base/common/errors'); import { toErrorMessage } from 'vs/base/common/errorMessage'; @@ -296,14 +297,14 @@ class RenameFileAction extends BaseRenameAction { } public runAction(newName: string): TPromise { - const dirty = this.textFileService.getDirty().filter(d => paths.isEqualOrParent(d.fsPath, this.element.resource.fsPath, !isLinux /* ignorecase */)); + const dirty = this.textFileService.getDirty().filter(d => resources.isEqualOrParent(d, this.element.resource, !isLinux /* ignorecase */)); const dirtyRenamed: URI[] = []; return TPromise.join(dirty.map(d => { let renamed: URI; // If the dirty file itself got moved, just reparent it to the target folder const targetPath = paths.join(this.element.parent.resource.path, newName); - if (paths.isEqual(this.element.resource.fsPath, d.fsPath)) { + if (this.element.resource.toString() === d.toString()) { renamed = this.element.parent.resource.with({ path: targetPath }); } @@ -673,7 +674,7 @@ export class BaseDeleteFileAction extends BaseFileAction { // Handle dirty let revertPromise: TPromise = TPromise.as(null); - const dirty = this.textFileService.getDirty().filter(d => paths.isEqualOrParent(d.fsPath, this.element.resource.fsPath, !isLinux /* ignorecase */)); + const dirty = this.textFileService.getDirty().filter(d => resources.isEqualOrParent(d, this.element.resource, !isLinux /* ignorecase */)); if (dirty.length) { let message: string; if (this.element.isDirectory) { @@ -963,7 +964,7 @@ export class PasteFileAction extends BaseFileAction { } // Check if target is ancestor of pasted folder - if (!paths.isEqual(this.element.resource.fsPath, fileToCopy.resource.fsPath) && paths.isEqualOrParent(this.element.resource.fsPath, fileToCopy.resource.fsPath, !isLinux /* ignorecase */)) { + if (this.element.resource.toString() !== fileToCopy.resource.toString() && resources.isEqualOrParent(this.element.resource, fileToCopy.resource, !isLinux /* ignorecase */)) { return false; } From 80aefe9aff01217d3aa361b148f7dad52662d48b Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 15 Sep 2017 17:51:10 +0200 Subject: [PATCH 035/281] ftp: fix hover in explorer --- src/vs/base/common/labels.ts | 3 +++ src/vs/workbench/browser/labels.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/base/common/labels.ts b/src/vs/base/common/labels.ts index 6192b7dcd01..904fc997bf7 100644 --- a/src/vs/base/common/labels.ts +++ b/src/vs/base/common/labels.ts @@ -36,6 +36,9 @@ export function getPathLabel(resource: URI | string, rootProvider?: IWorkspaceFo if (typeof resource === 'string') { resource = URI.file(resource); } + if (resource.scheme !== 'file' && resource.scheme !== 'untitled') { + return resource.authority + resource.path; + } // return early if we can resolve a relative path label from the root const baseResource = rootProvider ? rootProvider.getWorkspaceFolder(resource) : null; diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index c29b95aab08..350b94f71d9 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -148,7 +148,7 @@ export class ResourceLabel extends IconLabel { if (this.options && typeof this.options.title === 'string') { title = this.options.title; } else if (resource) { - title = getPathLabel(resource.fsPath, void 0, this.environmentService); + title = getPathLabel(resource, void 0, this.environmentService); } if (!this.computedIconClasses) { From abf77d9007f9852922f788015bf21a69d50b3981 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 15 Sep 2017 17:49:39 +0200 Subject: [PATCH 036/281] Properly implement toDeepIFileStat for explorer expansion --- .../electron-browser/remoteFileService.ts | 68 +++++--------- .../remoteFileSystemProvider.test.ts | 88 ------------------- 2 files changed, 20 insertions(+), 136 deletions(-) delete mode 100644 src/vs/workbench/services/files/test/electron-browser/remoteFileSystemProvider.test.ts diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 77053d3f48b..b5c9f9096d1 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -8,7 +8,7 @@ import URI from 'vs/base/common/uri'; import { FileService } from 'vs/workbench/services/files/electron-browser/fileService'; import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation, IFileSystemProvider, IStat, FileType, IImportResult } from 'vs/platform/files/common/files'; import { TPromise } from 'vs/base/common/winjs.base'; -import { basename, join, dirname } from 'path'; +import { basename, join } from 'path'; import { IDisposable } from 'vs/base/common/lifecycle'; import * as Ftp from './ftpFileSystemProvider'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -24,10 +24,9 @@ import { compare } from 'vs/base/common/strings'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { Progress } from 'vs/platform/progress/common/progress'; import { decodeStream, encode } from 'vs/base/node/encoding'; -import { Graph } from 'vs/base/common/graph'; -import { values } from 'vs/base/common/collections'; +import { TrieMap } from 'vs/base/common/map'; -function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse: boolean): TPromise { +function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse?: (stat: IStat) => boolean): TPromise { const ret: IFileStat = { isDirectory: false, hasChildren: false, @@ -48,9 +47,9 @@ function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse: boolea ret.isDirectory = true; ret.hasChildren = items.length > 0; - if (recurse) { + if (recurse && recurse(stat)) { // resolve children if requested - return TPromise.join(items.map(stat => toIFileStat(provider, stat, false))).then(children => { + return TPromise.join(items.map(stat => toIFileStat(provider, stat, recurse))).then(children => { ret.children = children; return ret; }); @@ -61,46 +60,20 @@ function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse: boolea } } -export async function toDeepIFileStat(provider: IFileSystemProvider, stat: IFileStat, to: URI[]): TPromise { - if (to) { - to.length = 0; - } - if (isFalsyOrEmpty(to)) { - return TPromise.as(stat); + +export function toDeepIFileStat(provider: IFileSystemProvider, stat: IStat, to: URI[]): TPromise { + + const trie = new TrieMap(); + trie.insert(stat.resource.toString(), true); + + if (!isFalsyOrEmpty(to)) { + to.forEach(uri => trie.insert(uri.toString(), true)); } - const graph = new Graph(uri => uri.path); - graph.lookupOrInsertNode(stat.resource); // root - - to.sort((a, b) => compare(a.path, b.path)).forEach(resource => { - let parent = resource.with({ path: dirname(resource.path) }); - let hitParent = false; - while (!hitParent) { - hitParent = !!graph.lookup(parent) || parent.path === '/'; - graph.insertEdge(parent, resource); - resource = parent; - parent = resource.with({ path: dirname(resource.path) }); - } + return toIFileStat(provider, stat, candidate => { + const sub = trie.findSuperstr(candidate.resource.toString()); + return !!sub; }); - - const stack: IFileStat[] = [stat]; - while (stack.length > 0) { - const parent = stack.shift(); - if (parent.isDirectory) { - parent.children = []; - const { outgoing } = graph.lookup(parent.resource); - - await values(outgoing).map(child => { - return provider.stat(child.data) - .then(stat => toIFileStat(provider, stat, false)) - .then(stat => parent.children.push(stat)); - }); - - stack.push(...parent.children); - } - } - - return TPromise.as(stat); } export class RemoteFileService extends FileService { @@ -196,7 +169,6 @@ export class RemoteFileService extends FileService { let promises: TPromise[] = []; for (const item of toResolve) { promises.push(provider.stat(item.resource) - .then(stat => toIFileStat(provider, stat, true)) .then(stat => toDeepIFileStat(provider, stat, item.options && item.options.resolveTo)) .then(stat => result.push({ stat, success: true }))); } @@ -225,7 +197,7 @@ export class RemoteFileService extends FileService { private async _doResolveContent(provider: IFileSystemProvider, resource: URI): TPromise { - const stat = await toIFileStat(provider, await provider.stat(resource), false); + const stat = await toIFileStat(provider, await provider.stat(resource)); const encoding = this.getEncoding(resource); const stream = decodeStream(encoding); @@ -268,7 +240,7 @@ export class RemoteFileService extends FileService { const encoding = this.getEncoding(resource, options.encoding); await provider.write(resource, encode(content, encoding)); const stat = await provider.stat(resource); - const fileStat = await toIFileStat(provider, stat, false); + const fileStat = await toIFileStat(provider, stat); return fileStat; } @@ -305,7 +277,7 @@ export class RemoteFileService extends FileService { const provider = this._provider.get(resource.scheme); if (provider) { await provider.mkdir(resource); - const stat = await toIFileStat(provider, await provider.stat(resource), false); + const stat = await toIFileStat(provider, await provider.stat(resource)); this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, stat)); return stat; } else { @@ -416,7 +388,7 @@ export class RemoteFileService extends FileService { await provider.write(resource, new Uint8Array(0)); stat = await provider.stat(resource); } - return toIFileStat(provider, stat, false); + return toIFileStat(provider, stat); } // public watchFileChanges(resource: URI): void { diff --git a/src/vs/workbench/services/files/test/electron-browser/remoteFileSystemProvider.test.ts b/src/vs/workbench/services/files/test/electron-browser/remoteFileSystemProvider.test.ts deleted file mode 100644 index 7dab064fca2..00000000000 --- a/src/vs/workbench/services/files/test/electron-browser/remoteFileSystemProvider.test.ts +++ /dev/null @@ -1,88 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import { toDeepIFileStat } from 'vs/workbench/services/files/electron-browser/remoteFileService'; -import { IFileSystemProvider, IStat, IFileStat, FileType } from 'vs/platform/files/common/files'; -import URI from 'vs/base/common/uri'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { IProgress } from 'vs/platform/progress/common/progress'; -import { extname } from 'path'; - -suite('RemoteFileSystem', function () { - - class StatOnlyProvider implements IFileSystemProvider { - - stat(resource: URI): TPromise { - const ext = extname(resource.path); - return TPromise.as(!ext - ? StatOnlyProvider.createFolderStat(resource) - : StatOnlyProvider.createFileStat(resource) - ); - } - readdir(resource: URI): TPromise { - return TPromise.as([]); - } - // throw errors on the rest - utimes(resource: URI, mtime: number): TPromise { - throw new Error('Method not implemented.'); - } - read(resource: URI, progress: IProgress): TPromise { - throw new Error('Method not implemented.'); - } - write(resource: URI, content: Uint8Array): TPromise { - throw new Error('Method not implemented.'); - } - unlink(resource: URI): TPromise { - throw new Error('Method not implemented.'); - } - rename(resource: URI, target: URI): TPromise { - throw new Error('Method not implemented.'); - } - mkdir(resource: URI): TPromise { - throw new Error('Method not implemented.'); - } - rmdir(resource: URI): TPromise { - throw new Error('Method not implemented.'); - } - - static createFileStat(resource: URI): IStat { - return { - resource, - mtime: Date.now(), - size: 42, - type: FileType.File - }; - } - - static createFolderStat(resource: URI, hasChildren: boolean = true): IStat { - return { - resource, - mtime: Date.now(), - size: 42, - type: FileType.Dir - }; - } - }; - - test('toDeepIFileStat', function () { - - const provider = new StatOnlyProvider(); - const root: IFileStat = { - resource: URI.parse('foo:///test/root'), - name: 'root', - isDirectory: true, - hasChildren: true, - mtime: Date.now(), - etag: '' - }; - toDeepIFileStat(provider, root, [ - URI.parse('foo:///test/root/folder1'), - URI.parse('foo:///test/root/folder2/folder1/child2'), - URI.parse('foo:///test/root/folder2/child2'), - URI.parse('foo:///test/root/folder3/child2'), - ]); - }); -}); From d421d4f53d0362c0d1d90768446704762f3c50ff Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 15 Sep 2017 18:55:22 +0200 Subject: [PATCH 037/281] fileEditorInput: getDescription, getTitle --- .../files/common/editors/fileEditorInput.ts | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts index 1393994840d..e3806ca1e36 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts @@ -6,6 +6,7 @@ import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; +import { memoize } from 'vs/base/common/decorators'; import paths = require('vs/base/common/paths'); import labels = require('vs/base/common/labels'); import URI from 'vs/base/common/uri'; @@ -33,14 +34,6 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { private name: string; - private shortDescription: string; - private mediumDescription: string; - private longDescription: string; - - private shortTitle: string; - private mediumTitle: string; - private longTitle: string; - private toUnbind: IDisposable[]; /** @@ -130,35 +123,65 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { return this.decorateOrphanedFiles(this.name); } + @memoize + private get shortDescription(): string { + return paths.basename(labels.getPathLabel(paths.dirname(this.resource.path), void 0, this.environmentService)); + } + + @memoize + private get mediumDescription(): string { + return labels.getPathLabel(paths.dirname(this.resource.path), this.contextService, this.environmentService); + } + + @memoize + private get longDescription(): string { + return labels.getPathLabel(paths.dirname(this.resource.path), void 0, this.environmentService); + } + public getDescription(verbosity: Verbosity = Verbosity.MEDIUM): string { let description: string; switch (verbosity) { case Verbosity.SHORT: - description = this.shortDescription ? this.shortDescription : (this.shortDescription = paths.basename(labels.getPathLabel(paths.dirname(this.resource.fsPath), void 0, this.environmentService))); + description = this.shortDescription; break; case Verbosity.LONG: - description = this.longDescription ? this.longDescription : (this.longDescription = labels.getPathLabel(paths.dirname(this.resource.fsPath), void 0, this.environmentService)); + description = this.longDescription; break; case Verbosity.MEDIUM: default: - description = this.mediumDescription ? this.mediumDescription : (this.mediumDescription = labels.getPathLabel(paths.dirname(this.resource.fsPath), this.contextService, this.environmentService)); + description = this.mediumDescription; break; } return description; } + @memoize + private get shortTitle(): string { + return this.getName(); + } + + @memoize + private get mediumTitle(): string { + return labels.getPathLabel(this.resource, this.contextService, this.environmentService); + } + + @memoize + private get longTitle(): string { + return labels.getPathLabel(this.resource, void 0, this.environmentService); + } + public getTitle(verbosity: Verbosity): string { let title: string; switch (verbosity) { case Verbosity.SHORT: - title = this.shortTitle ? this.shortTitle : (this.shortTitle = this.getName()); + title = this.shortTitle; break; case Verbosity.MEDIUM: - title = this.mediumTitle ? this.mediumTitle : (this.mediumTitle = labels.getPathLabel(this.resource, this.contextService, this.environmentService)); + title = this.mediumTitle; break; case Verbosity.LONG: - title = this.longTitle ? this.longTitle : (this.longTitle = labels.getPathLabel(this.resource, void 0, this.environmentService)); + title = this.longTitle; break; } From a6af9d66711917e8c18100a1e1b029bd656fbffb Mon Sep 17 00:00:00 2001 From: Alex Cao Date: Fri, 15 Sep 2017 11:40:16 -0700 Subject: [PATCH 038/281] Improve search aria label generation performance --- src/vs/workbench/parts/search/browser/searchResultsView.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/parts/search/browser/searchResultsView.ts b/src/vs/workbench/parts/search/browser/searchResultsView.ts index 752b44681bc..20a3086d064 100644 --- a/src/vs/workbench/parts/search/browser/searchResultsView.ts +++ b/src/vs/workbench/parts/search/browser/searchResultsView.ts @@ -310,12 +310,12 @@ export class SearchAccessibilityProvider implements IAccessibilityProvider { const match = element; const searchModel: SearchModel = (tree.getInput()).searchModel; const replace = searchModel.isReplaceActive() && !!searchModel.replaceString; - const preview = match.preview(); + const matchString = match.getMatchString(); const range = match.range(); if (replace) { - return nls.localize('replacePreviewResultAria', "Replace term {0} with {1} at column position {2} in line with text {3}", preview.inside, match.replaceString, range.startColumn + 1, match.text()); + return nls.localize('replacePreviewResultAria', "Replace term {0} with {1} at column position {2} in line with text {3}", matchString, match.replaceString, range.startColumn + 1, match.text()); } - return nls.localize('searchResultAria', "Found term {0} at column position {1} in line with text {2}", preview.inside, range.startColumn + 1, match.text()); + return nls.localize('searchResultAria', "Found term {0} at column position {1} in line with text {2}", matchString, range.startColumn + 1, match.text()); } return undefined; } From 86dace91a2ddc6cb61f06b047b00c04b44f237c4 Mon Sep 17 00:00:00 2001 From: Putta Khunchalee Date: Sun, 17 Sep 2017 21:18:54 +0700 Subject: [PATCH 039/281] replace bash shebang with '#!/usr/bin/env bash" for portability --- build/tfs/common/common.sh | 2 +- build/tfs/common/node.sh | 2 +- build/tfs/linux/build-ia32.sh | 2 +- build/tfs/linux/build-x64.sh | 2 +- build/tfs/linux/build.sh | 2 +- build/tfs/linux/ia32/run-agent.sh | 2 +- build/tfs/linux/ia32/xvfb.init | 2 +- build/tfs/linux/release.sh | 2 +- build/tfs/linux/repoapi_client.sh | 2 +- build/tfs/linux/smoketest.sh | 2 +- build/tfs/linux/x64/run-agent.sh | 2 +- build/tfs/linux/x64/xvfb.init | 2 +- resources/linux/debian/postrm.template | 2 +- scripts/env.sh | 2 +- scripts/npm.sh | 2 +- scripts/test-integration.sh | 2 +- scripts/test-mocha.sh | 2 +- scripts/test.sh | 2 +- src/vs/base/node/terminateProcess.sh | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/build/tfs/common/common.sh b/build/tfs/common/common.sh index 52f53537943..cdd656676a3 100755 --- a/build/tfs/common/common.sh +++ b/build/tfs/common/common.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e # set agent specific npm cache diff --git a/build/tfs/common/node.sh b/build/tfs/common/node.sh index 87f95a5e1d7..67f3f59552f 100755 --- a/build/tfs/common/node.sh +++ b/build/tfs/common/node.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e # setup nvm diff --git a/build/tfs/linux/build-ia32.sh b/build/tfs/linux/build-ia32.sh index 0b0f1c2a458..0d9f98c692d 100755 --- a/build/tfs/linux/build-ia32.sh +++ b/build/tfs/linux/build-ia32.sh @@ -1,3 +1,3 @@ -#!/bin/bash +#!/usr/bin/env bash set -e ./build/tfs/linux/build.sh ia32 "$@" \ No newline at end of file diff --git a/build/tfs/linux/build-x64.sh b/build/tfs/linux/build-x64.sh index fb5b38e02b3..e193a01a5b7 100755 --- a/build/tfs/linux/build-x64.sh +++ b/build/tfs/linux/build-x64.sh @@ -1,3 +1,3 @@ -#!/bin/bash +#!/usr/bin/env bash set -e ./build/tfs/linux/build.sh x64 "$@" \ No newline at end of file diff --git a/build/tfs/linux/build.sh b/build/tfs/linux/build.sh index b3d1825c2d9..4af53947033 100755 --- a/build/tfs/linux/build.sh +++ b/build/tfs/linux/build.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash . ./build/tfs/common/node.sh . ./scripts/env.sh diff --git a/build/tfs/linux/ia32/run-agent.sh b/build/tfs/linux/ia32/run-agent.sh index bcf9017f3cf..efcc96632a3 100755 --- a/build/tfs/linux/ia32/run-agent.sh +++ b/build/tfs/linux/ia32/run-agent.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash if [ ! -f pat ]; then echo "Error: file pat not found" diff --git a/build/tfs/linux/ia32/xvfb.init b/build/tfs/linux/ia32/xvfb.init index 4d77d253a26..74f6e3b2522 100644 --- a/build/tfs/linux/ia32/xvfb.init +++ b/build/tfs/linux/ia32/xvfb.init @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # /etc/rc.d/init.d/xvfbd # diff --git a/build/tfs/linux/release.sh b/build/tfs/linux/release.sh index 41f6d35e675..e4d2009a172 100755 --- a/build/tfs/linux/release.sh +++ b/build/tfs/linux/release.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash . ./scripts/env.sh . ./build/tfs/common/common.sh diff --git a/build/tfs/linux/repoapi_client.sh b/build/tfs/linux/repoapi_client.sh index b214ef10726..80de4db4a2a 100755 --- a/build/tfs/linux/repoapi_client.sh +++ b/build/tfs/linux/repoapi_client.sh @@ -1,4 +1,4 @@ -#!/bin/bash -e +#!/usr/bin/env bash -e # This is a VERY basic script for Create/Delete operations on repos and packages # cmd=$1 diff --git a/build/tfs/linux/smoketest.sh b/build/tfs/linux/smoketest.sh index 308fb047590..9866874a208 100644 --- a/build/tfs/linux/smoketest.sh +++ b/build/tfs/linux/smoketest.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e . ./build/tfs/common/node.sh diff --git a/build/tfs/linux/x64/run-agent.sh b/build/tfs/linux/x64/run-agent.sh index 76978ce2b02..1f122aa40dd 100755 --- a/build/tfs/linux/x64/run-agent.sh +++ b/build/tfs/linux/x64/run-agent.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash if [ ! -f pat ]; then echo "Error: file pat not found" diff --git a/build/tfs/linux/x64/xvfb.init b/build/tfs/linux/x64/xvfb.init index 4d77d253a26..74f6e3b2522 100644 --- a/build/tfs/linux/x64/xvfb.init +++ b/build/tfs/linux/x64/xvfb.init @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # /etc/rc.d/init.d/xvfbd # diff --git a/resources/linux/debian/postrm.template b/resources/linux/debian/postrm.template index c43a2b16ae3..1dfa892a0ea 100755 --- a/resources/linux/debian/postrm.template +++ b/resources/linux/debian/postrm.template @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for license information. diff --git a/scripts/env.sh b/scripts/env.sh index 35d09f66bb2..f530bf28369 100755 --- a/scripts/env.sh +++ b/scripts/env.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash export npm_config_disturl=https://atom.io/download/electron export npm_config_target=$(node -p "require('./package.json').electronVersion") export npm_config_runtime=electron diff --git a/scripts/npm.sh b/scripts/npm.sh index 69c6d0c48ae..02268eafd6e 100755 --- a/scripts/npm.sh +++ b/scripts/npm.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash if [[ "$OSTYPE" == "darwin"* ]]; then realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; } diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index d0154a4101d..2bfd21a20c7 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e if [[ "$OSTYPE" == "darwin"* ]]; then diff --git a/scripts/test-mocha.sh b/scripts/test-mocha.sh index 9aa16fa3241..5d1d71a2da2 100755 --- a/scripts/test-mocha.sh +++ b/scripts/test-mocha.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash if [[ "$OSTYPE" == "darwin"* ]]; then realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; } diff --git a/scripts/test.sh b/scripts/test.sh index ce1e5e11856..157c6da2cc7 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash if [[ "$OSTYPE" == "darwin"* ]]; then diff --git a/src/vs/base/node/terminateProcess.sh b/src/vs/base/node/terminateProcess.sh index acdcbf8ed42..dceeae9745f 100755 --- a/src/vs/base/node/terminateProcess.sh +++ b/src/vs/base/node/terminateProcess.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash terminateTree() { for cpid in $(/usr/bin/pgrep -P $1); do From 853c9a14951493a15e9603d1ef66d8196668b3ba Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 18 Sep 2017 10:14:28 +0200 Subject: [PATCH 040/281] prevent double login attempt --- .../electron-browser/ftpFileSystemProvider.ts | 53 +++++++++++++------ .../files/electron-browser/jsftp.d.ts | 1 + 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts index 70efb4fcd2e..df081ff4b54 100644 --- a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts +++ b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts @@ -9,7 +9,6 @@ import URI from 'vs/base/common/uri'; import Event from 'vs/base/common/event'; import * as JSFtp from 'jsftp'; -import { ninvoke } from 'vs/base/common/async'; import { TPromise } from 'vs/base/common/winjs.base'; import { Readable } from 'stream'; import { join, dirname, basename } from 'path'; @@ -18,23 +17,47 @@ import { IProgress } from 'vs/platform/progress/common/progress'; export class FtpFileSystemProvider implements IFileSystemProvider { - private _connection: JSFtp; + private _connection: TPromise; readonly onDidChange = Event.None; constructor() { - this._connection = new JSFtp({ + this._connection = new TPromise((resolve, reject) => { + const connection = new JSFtp({ host: 'waws-prod-db3-029.ftp.azurewebsites.windows.net' }); - this._connection.keepAlive(1000 * 5); + connection.keepAlive(1000 * 5); + connection.auth('USER', 'PASS', (err) => { + if (err) { + reject(err); + } else { + resolve(connection); + } + }); + }); + } + + private _withConnection(func: keyof JSFtp, ...args: any[]): TPromise { + return this._connection.then(connection => { + return new TPromise((resolve, reject) => { + (connection[func]).apply(connection, args.concat([function (err, result) { + if (err) { + reject(err); + } else { + resolve(result); + } + }])); + }); + }); } dispose(): void { - ninvoke(this._connection, this._connection.raw, 'QUIT'); + this._withConnection('raw', 'QUIT'); + } utimes(resource: URI, mtime: number): TPromise { - return ninvoke(this._connection, this._connection.raw, 'NOOP') + return this._withConnection('raw', 'NOOP') .then(() => this.stat(resource)); } @@ -52,7 +75,7 @@ export class FtpFileSystemProvider implements IFileSystemProvider { const name = basename(path); const dir = dirname(path); - return ninvoke(this._connection, this._connection.ls, dir).then(entries => { + return this._withConnection('ls', dir).then(entries => { for (const entry of entries) { if (entry.name === name) { return { @@ -69,7 +92,7 @@ export class FtpFileSystemProvider implements IFileSystemProvider { } readdir(resource: URI): TPromise { - return ninvoke(this._connection, this._connection.ls, resource.path).then(ret => { + return this._withConnection('ls', resource.path).then(ret => { const result: IStat[] = []; for (let entry of ret) { result.push({ @@ -84,7 +107,7 @@ export class FtpFileSystemProvider implements IFileSystemProvider { } read(resource: URI, progress: IProgress): TPromise { - return ninvoke(this._connection, this._connection.get, resource.path).then(stream => { + return this._withConnection('get', resource.path).then(stream => { return new TPromise((resolve, reject) => { stream.on('data', d => progress.report(d)); stream.on('close', hadErr => { @@ -100,24 +123,24 @@ export class FtpFileSystemProvider implements IFileSystemProvider { } write(resource: URI, content: Uint8Array): TPromise { - return ninvoke(this._connection, this._connection.put, content, resource.path); + return this._withConnection('put', content, resource.path); } rmdir(resource: URI): TPromise { - return ninvoke(this._connection, this._connection.raw, 'RMD', [resource.path]); + return this._withConnection('raw', 'RMD', [resource.path]); } mkdir(resource: URI): TPromise { - return ninvoke(this._connection, this._connection.raw, 'MKD', [resource.path]); + return this._withConnection('raw', 'MKD', [resource.path]); } unlink(resource: URI): TPromise { - return ninvoke(this._connection, this._connection.raw, 'DELE', [resource.path]); + return this._withConnection('raw', 'DELE', [resource.path]); } rename(resource: URI, target: URI): TPromise { - return ninvoke(this._connection, this._connection.raw, 'RNFR', [resource.path]).then(() => { - return ninvoke(this._connection, this._connection.raw, 'RNTO', [target.path]); + return this._withConnection('raw', 'RNFR', [resource.path]).then(() => { + return this._withConnection('raw', 'RNTO', [target.path]); }); } } diff --git a/src/vs/workbench/services/files/electron-browser/jsftp.d.ts b/src/vs/workbench/services/files/electron-browser/jsftp.d.ts index 59bfce7a3c5..4d728c4d05c 100644 --- a/src/vs/workbench/services/files/electron-browser/jsftp.d.ts +++ b/src/vs/workbench/services/files/electron-browser/jsftp.d.ts @@ -28,6 +28,7 @@ declare namespace JSFtp { } interface JSFtp extends EventEmitter { + auth(user: string, password: string, callback: JSFtp.Callback): void keepAlive(wait?: number): void; ls(path: string, callback: JSFtp.Callback): void; list(path: string, callback: JSFtp.Callback): void; From 19c992bae8283a61589b07fd59424ebba0d9b5ef Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 18 Sep 2017 16:15:38 +0200 Subject: [PATCH 041/281] move ftp provider into an extensions, expose things as proposed api --- package.json | 1 - src/vs/platform/files/common/files.ts | 8 +- src/vs/vscode.proposed.d.ts | 45 +++++- .../extensionHost.contribution.ts | 1 + .../electron-browser/mainThreadFileSystem.ts | 127 +++++++++++++++ .../electron-browser/mainThreadWorkspace.ts | 90 +---------- src/vs/workbench/api/node/extHost.api.impl.ts | 11 +- src/vs/workbench/api/node/extHost.protocol.ts | 29 +++- .../workbench/api/node/extHostFileSystem.ts | 75 +++++++++ src/vs/workbench/api/node/extHostWorkspace.ts | 51 ------ .../configuration/node/configuration.ts | 6 - .../electron-browser/ftpFileSystemProvider.ts | 146 ------------------ .../files/electron-browser/jsftp.d.ts | 47 ------ .../electron-browser/remoteFileService.ts | 28 ++-- 14 files changed, 298 insertions(+), 367 deletions(-) create mode 100644 src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts create mode 100644 src/vs/workbench/api/node/extHostFileSystem.ts delete mode 100644 src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts delete mode 100644 src/vs/workbench/services/files/electron-browser/jsftp.d.ts diff --git a/package.json b/package.json index 8107b39bc42..dba3a582d9e 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,6 @@ "https-proxy-agent": "0.3.6", "iconv-lite": "0.4.15", "jschardet": "^1.5.1", - "jsftp": "^2.0.0", "keytar": "^4.0.3", "minimist": "1.2.0", "native-keymap": "1.2.5", diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 0c78c12054c..6059ab7e0de 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -14,6 +14,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import Event from 'vs/base/common/event'; import { beginsWithIgnoreCase } from 'vs/base/common/strings'; import { IProgress } from 'vs/platform/progress/common/progress'; +import { IDisposable } from 'vs/base/common/lifecycle'; export const IFileService = createDecorator('fileService'); @@ -31,6 +32,11 @@ export interface IFileService { */ onAfterOperation: Event; + /** + * + */ + registerProvider?(authority: string, provider: IFileSystemProvider): IDisposable; + /** * Resolve the properties of a file identified by the resource. * @@ -166,7 +172,7 @@ export interface IStat { export interface IFileSystemProvider { - onDidChange?: Event; + onDidChange?: Event; // more... // diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 575bde2236b..d11c7f4f541 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -25,17 +25,48 @@ declare module 'vscode' { export function showSaveDialog(options: SaveDialogOptions): Thenable; } + export enum FileChangeType { + Updated = 0, + Added = 1, + Deleted = 2 + } + + export interface FileChange { + type: FileChangeType; + resource: Uri; + } + + export enum FileType { + File = 0, + Dir = 1, + Symlink = 2 + } + + export interface FileStat { + resource: Uri; + mtime: number; + size: number; + type: FileType; + } + // todo@joh discover files etc export interface FileSystemProvider { - // todo@joh -> added, deleted, renamed, changed - onDidChange: Event; - resolveContents(resource: Uri): string | Thenable; - writeContents(resource: Uri, contents: string): void | Thenable; + onDidChange?: Event; - // -- search - // todo@joh - extract into its own provider? - findFiles(query: string, progress: Progress, token?: CancellationToken): Thenable; + root: Uri; + + // more... + // + utimes(resource: Uri, mtime: number): Thenable; + stat(resource: Uri): Thenable; + read(resource: Uri, progress: Progress): Thenable; + write(resource: Uri, content: Uint8Array): Thenable; + unlink(resource: Uri): Thenable; + rename(resource: Uri, target: Uri): Thenable; + mkdir(resource: Uri): Thenable; + readdir(resource: Uri): Thenable; + rmdir(resource: Uri): Thenable; } export namespace workspace { diff --git a/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts b/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts index 746d242419b..be065d33308 100644 --- a/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts +++ b/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts @@ -28,6 +28,7 @@ import './mainThreadEditor'; import './mainThreadEditors'; import './mainThreadErrors'; import './mainThreadExtensionService'; +import './mainThreadFileSystem'; import './mainThreadFileSystemEventService'; import './mainThreadHeapService'; import './mainThreadLanguageFeatures'; diff --git a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts new file mode 100644 index 00000000000..2699aee0f75 --- /dev/null +++ b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts @@ -0,0 +1,127 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import URI from 'vs/base/common/uri'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { ExtHostContext, MainContext, IExtHostContext, MainThreadFileSystemShape, ExtHostFileSystemShape } from '../node/extHost.protocol'; +import { IFileService, IFileSystemProvider, IStat, IFileChange } from 'vs/platform/files/common/files'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import Event, { Emitter } from 'vs/base/common/event'; +import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; +import { IProgress } from 'vs/platform/progress/common/progress'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; + +@extHostNamedCustomer(MainContext.MainThreadFileSystem) +export class MainThreadFileSystem implements MainThreadFileSystemShape { + + private readonly _toDispose: IDisposable[] = []; + private readonly _proxy: ExtHostFileSystemShape; + private readonly _provider = new Map(); + + constructor( + extHostContext: IExtHostContext, + @IFileService private readonly _fileService: IFileService, + @IWorkspaceContextService private readonly _workspaceEditService: IWorkspaceContextService + ) { + this._proxy = extHostContext.get(ExtHostContext.ExtHostFileSystem); + } + + dispose(): void { + dispose(this._toDispose); + } + + $registerFileSystemProvider(handle: number, scheme: string): void { + this._provider.set(handle, new RemoteFileSystemProvider(this._fileService, scheme, handle, this._proxy)); + } + + $unregisterFileSystemProvider(handle: number): void { + dispose(this._provider.get(handle)); + this._provider.delete(handle); + } + + $onDidAddFileSystemRoot(uri: URI): void { + const folders = this._workspaceEditService.getWorkspace().folders.slice(0); + folders.push({ + uri, + name: uri.authority, + index: folders.length, + raw: null + }); + (this._workspaceEditService.getWorkspace()).folders = folders; + (this._workspaceEditService).onFoldersChanged(); + (this._workspaceEditService)._onDidChangeWorkspaceFolders.fire(null); + } + + $onFileSystemChange(handle: number, changes: IFileChange[]): void { + this._provider.get(handle).$onFileSystemChange(changes); + } + + $reportFileChunk(handle: number, resource: URI, chunk: number[]): void { + this._provider.get(handle).reportFileChunk(resource, chunk); + } +} + +class RemoteFileSystemProvider implements IFileSystemProvider { + + private readonly _onDidChange = new Emitter(); + private readonly _registration: IDisposable; + private readonly _reads = new Map>(); + + readonly onDidChange: Event = this._onDidChange.event; + + + constructor( + service: IFileService, + scheme: string, + private readonly _handle: number, + private readonly _proxy: ExtHostFileSystemShape + ) { + this._registration = service.registerProvider(scheme, this); + } + + dispose(): void { + this._registration.dispose(); + this._onDidChange.dispose(); + } + + $onFileSystemChange(changes: IFileChange[]): void { + this._onDidChange.fire(changes); + } + + // --- forwarding calls + + utimes(resource: URI, mtime: number): TPromise { + return this._proxy.$utimes(this._handle, resource, mtime); + } + stat(resource: URI): TPromise { + return this._proxy.$stat(this._handle, resource); + } + read(resource: URI, progress: IProgress): TPromise { + this._reads.set(resource.toString(), progress); + return this._proxy.$read(this._handle, resource); + } + reportFileChunk(resource: URI, chunk: number[]): void { + this._reads.get(resource.toString()).report(Buffer.from(chunk)); + } + write(resource: URI, content: Uint8Array): TPromise { + return this._proxy.$write(this._handle, resource, [].slice.call(content)); + } + unlink(resource: URI): TPromise { + return this._proxy.$unlink(this._handle, resource); + } + rename(resource: URI, target: URI): TPromise { + return this._proxy.$rename(this._handle, resource, target); + } + mkdir(resource: URI): TPromise { + return this._proxy.$mkdir(this._handle, resource); + } + readdir(resource: URI): TPromise { + return this._proxy.$readdir(this._handle, resource); + } + rmdir(resource: URI): TPromise { + return this._proxy.$rmdir(this._handle, resource); + } +} diff --git a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts index 950cb025900..3b249dbc200 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts @@ -6,19 +6,17 @@ import { isPromiseCanceledError } from 'vs/base/common/errors'; import URI from 'vs/base/common/uri'; -import { ISearchService, QueryType, ISearchQuery, ISearchProgressItem, ISearchComplete } from 'vs/platform/search/common/search'; +import { ISearchService, QueryType, ISearchQuery } from 'vs/platform/search/common/search'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { ICommonCodeEditor, isCommonCodeEditor } from 'vs/editor/common/editorCommon'; import { bulkEdit, IResourceEdit } from 'vs/editor/common/services/bulkEdit'; -import { TPromise, PPromise } from 'vs/base/common/winjs.base'; +import { TPromise } from 'vs/base/common/winjs.base'; import { MainThreadWorkspaceShape, ExtHostWorkspaceShape, ExtHostContext, MainContext, IExtHostContext } from '../node/extHost.protocol'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { IFileService } from 'vs/platform/files/common/files'; -import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; -import { RemoteFileService } from 'vs/workbench/services/files/electron-browser/remoteFileService'; -import { Emitter } from 'vs/base/common/event'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import { IExperimentService } from 'vs/platform/telemetry/common/experiments'; @@ -36,7 +34,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { @ITextFileService private readonly _textFileService: ITextFileService, @IWorkbenchEditorService private readonly _editorService: IWorkbenchEditorService, @ITextModelService private readonly _textModelResolverService: ITextModelService, - @IExperimentService private experimentService: IExperimentService, + @IExperimentService private _experimentService: IExperimentService, @IFileService private readonly _fileService: IFileService ) { this._proxy = extHostContext.get(ExtHostContext.ExtHostWorkspace); @@ -71,7 +69,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { maxResults, includePattern: { [include]: true }, excludePattern: { [exclude]: true }, - useRipgrep: this.experimentService.getExperiments().ripgrepQuickSearch + useRipgrep: this._experimentService.getExperiments().ripgrepQuickSearch }; this._searchService.extendQuery(query); @@ -123,83 +121,5 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { return bulkEdit(this._textModelResolverService, codeEditor, edits, this._fileService) .then(() => true); } - - // --- EXPERIMENT: workspace provider - - private _idPool: number = 0; - private readonly _provider = new Map]>(); - private readonly _searchSessions = new Map void, reject: Function, progress: (item: ISearchProgressItem) => void, matches: URI[] }>(); - - $registerFileSystemProvider(handle: number, authority: string): void { - if (!(this._fileService instanceof RemoteFileService)) { - throw new Error(); - } - const emitter = new Emitter(); - // const provider = { - // onDidChange: emitter.event, - // read: (resource: URI) => { - // return this._proxy.$resolveFile(handle, resource); - // }, - // write: (resource: URI, value: string) => { - // return this._proxy.$storeFile(handle, resource, value); - // }, - // stat: () => null, - // readdir: () => null - // }; - const searchProvider = { - search: (query: ISearchQuery) => { - if (query.type !== QueryType.File) { - return undefined; - } - const session = ++this._idPool; - return new PPromise((resolve, reject, progress) => { - this._searchSessions.set(session, { resolve, reject, progress, matches: [] }); - this._proxy.$startSearch(handle, session, query.filePattern); - }, () => { - this._proxy.$cancelSearch(handle, session); - }); - } - }; - const registrations = combinedDisposable([ - // this._fileService.registerProvider(authority, provider), - this._searchService.registerSearchResultProvider(searchProvider), - ]); - this._provider.set(handle, [registrations, emitter]); - } - - $unregisterFileSystemProvider(handle: number): void { - if (this._provider.has(handle)) { - dispose(this._provider.get(handle)[0]); - this._provider.delete(handle); - } - } - - $onFileSystemChange(handle: number, resource: URI) { - const [, emitter] = this._provider.get(handle); - emitter.fire(resource); - }; - - $updateSearchSession(session: number, data: URI): void { - if (this._searchSessions.has(session)) { - this._searchSessions.get(session).progress({ resource: data }); - this._searchSessions.get(session).matches.push(data); - } - } - - $finishSearchSession(session: number, err?: any): void { - if (this._searchSessions.has(session)) { - const { matches, resolve, reject } = this._searchSessions.get(session); - this._searchSessions.delete(session); - if (err) { - reject(err); - } else { - resolve({ - limitHit: false, - stats: undefined, - results: matches.map(resource => ({ resource })) - }); - } - } - } } diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 4c9ed5a511f..8ca08b322f6 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -53,6 +53,8 @@ import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions'; import { ExtHostThreadService } from 'vs/workbench/services/thread/node/extHostThreadService'; import { ProxyIdentifier } from 'vs/workbench/services/thread/common/threadService'; import { ExtHostDialogs } from 'vs/workbench/api/node/extHostDialogs'; +import { ExtHostFileSystem } from 'vs/workbench/api/node/extHostFileSystem'; +import { FileChangeType, FileType } from 'vs/platform/files/common/files'; export interface IExtensionApiFactory { (extension: IExtensionDescription): typeof vscode; @@ -93,6 +95,7 @@ export function createApiFactory( const extHostConfiguration = threadService.set(ExtHostContext.ExtHostConfiguration, new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration), extHostWorkspace, initData.configuration)); const extHostDiagnostics = threadService.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(threadService)); const languageFeatures = threadService.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(threadService, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics)); + const extHostFileSystem = threadService.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(threadService)); const extHostFileSystemEvent = threadService.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService()); const extHostQuickOpen = threadService.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(threadService)); const extHostTerminalService = threadService.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(threadService)); @@ -477,7 +480,7 @@ export function createApiFactory( return extHostTask.registerTaskProvider(extension, provider); }, registerFileSystemProvider: proposedApiFunction(extension, (authority, provider) => { - return extHostWorkspace.registerFileSystemProvider(authority, provider); + return extHostFileSystem.registerFileSystemProvider(authority, provider); }) }; @@ -601,7 +604,11 @@ export function createApiFactory( ShellExecution: extHostTypes.ShellExecution, TaskScope: extHostTypes.TaskScope, Task: extHostTypes.Task, - ConfigurationTarget: extHostTypes.ConfigurationTarget + ConfigurationTarget: extHostTypes.ConfigurationTarget, + + // TODO@JOH + FileChangeType: FileChangeType, + FileType: FileType }; if (extension.enableProposedApi && extension.isBuiltin) { api['credentials'] = credentials; diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 2a77558ba23..80e6c34dc05 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -49,6 +49,7 @@ import { ThemeColor } from 'vs/platform/theme/common/themeService'; import { IDisposable } from 'vs/base/common/lifecycle'; import { SerializedError } from 'vs/base/common/errors'; import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IStat, IFileChange } from 'vs/platform/files/common/files'; export interface IEnvironment { isExtensionDevelopmentDebug: boolean; @@ -302,12 +303,15 @@ export interface MainThreadWorkspaceShape extends IDisposable { $cancelSearch(requestId: number): Thenable; $saveAll(includeUntitled?: boolean): Thenable; $applyWorkspaceEdit(edits: IResourceEdit[]): TPromise; +} - $registerFileSystemProvider(handle: number, authority: string): void; +export interface MainThreadFileSystemShape extends IDisposable { + $registerFileSystemProvider(handle: number, scheme: string): void; $unregisterFileSystemProvider(handle: number): void; - $onFileSystemChange(handle: number, resource: URI): void; - $updateSearchSession(session: number, data): void; - $finishSearchSession(session: number, err?: any): void; + + $onDidAddFileSystemRoot(root: URI): void; + $onFileSystemChange(handle: number, resource: IFileChange[]): void; + $reportFileChunk(handle: number, resource: URI, chunk: number[] | null): void; } export interface MainThreadTaskShape extends IDisposable { @@ -461,11 +465,18 @@ export interface ExtHostTreeViewsShape { export interface ExtHostWorkspaceShape { $acceptWorkspaceData(workspace: IWorkspaceData): void; +} - $resolveFile(handle: number, resource: URI): TPromise; - $storeFile(handle: number, resource: URI, content: string): TPromise; - $startSearch(handle: number, session: number, query: string): void; - $cancelSearch(handle: number, session: number): void; +export interface ExtHostFileSystemShape { + $utimes(handle: number, resource: URI, mtime: number): TPromise; + $stat(handle: number, resource: URI): TPromise; + $read(handle: number, resource: URI): TPromise; + $write(handle: number, resource: URI, content: number[]): TPromise; + $unlink(handle: number, resource: URI): TPromise; + $rename(handle: number, resource: URI, target: URI): TPromise; + $mkdir(handle: number, resource: URI): TPromise; + $readdir(handle: number, resource: URI): TPromise; + $rmdir(handle: number, resource: URI): TPromise; } export interface ExtHostExtensionServiceShape { @@ -602,6 +613,7 @@ export const MainContext = { MainThreadTelemetry: createMainId('MainThreadTelemetry'), MainThreadTerminalService: createMainId('MainThreadTerminalService'), MainThreadWorkspace: createMainId('MainThreadWorkspace'), + MainThreadFileSystem: createMainId('MainThreadFileSystem'), MainThreadExtensionService: createMainId('MainThreadExtensionService'), MainThreadSCM: createMainId('MainThreadSCM'), MainThreadTask: createMainId('MainThreadTask'), @@ -620,6 +632,7 @@ export const ExtHostContext = { ExtHostDocumentSaveParticipant: createExtId('ExtHostDocumentSaveParticipant'), ExtHostEditors: createExtId('ExtHostEditors'), ExtHostTreeViews: createExtId('ExtHostTreeViews'), + ExtHostFileSystem: createExtId('ExtHostFileSystem'), ExtHostFileSystemEventService: createExtId('ExtHostFileSystemEventService'), ExtHostHeapService: createExtId('ExtHostHeapMonitor'), ExtHostLanguageFeatures: createExtId('ExtHostLanguageFeatures'), diff --git a/src/vs/workbench/api/node/extHostFileSystem.ts b/src/vs/workbench/api/node/extHostFileSystem.ts new file mode 100644 index 00000000000..d46e8ac3f3a --- /dev/null +++ b/src/vs/workbench/api/node/extHostFileSystem.ts @@ -0,0 +1,75 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import URI from 'vs/base/common/uri'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { MainContext, IMainContext, ExtHostFileSystemShape, MainThreadFileSystemShape } from './extHost.protocol'; +import * as vscode from 'vscode'; +import { IStat } from 'vs/platform/files/common/files'; +import { IDisposable } from 'vs/base/common/lifecycle'; + +export class ExtHostFileSystem implements ExtHostFileSystemShape { + + private readonly _proxy: MainThreadFileSystemShape; + private readonly _provider = new Map(); + private _handlePool: number = 0; + + constructor(mainContext: IMainContext) { + this._proxy = mainContext.get(MainContext.MainThreadFileSystem); + } + + registerFileSystemProvider(scheme: string, provider: vscode.FileSystemProvider) { + const handle = this._handlePool++; + this._provider.set(handle, provider); + this._proxy.$registerFileSystemProvider(handle, scheme); + this._proxy.$onDidAddFileSystemRoot(provider.root); + let reg: IDisposable; + if (provider.onDidChange) { + reg = provider.onDidChange(event => this._proxy.$onFileSystemChange(handle, event)); + } + return { + dispose: () => { + if (reg) { + reg.dispose(); + } + this._provider.delete(handle); + this._proxy.$unregisterFileSystemProvider(handle); + } + }; + } + + $utimes(handle: number, resource: URI, mtime: number): TPromise { + return TPromise.as(this._provider.get(handle).utimes(resource, mtime)); + } + $stat(handle: number, resource: URI): TPromise { + return TPromise.as(this._provider.get(handle).stat(resource)); + } + $read(handle: number, resource: URI): TPromise { + return TPromise.as(this._provider.get(handle).read(resource, { + report: (chunk) => { + this._proxy.$reportFileChunk(handle, resource, [].slice.call(chunk)); + } + })); + } + $write(handle: number, resource: URI, content: number[]): TPromise { + return TPromise.as(this._provider.get(handle).write(resource, Buffer.from(content))); + } + $unlink(handle: number, resource: URI): TPromise { + return TPromise.as(this._provider.get(handle).unlink(resource)); + } + $rename(handle: number, resource: URI, target: URI): TPromise { + return TPromise.as(this._provider.get(handle).rename(resource, target)); + } + $mkdir(handle: number, resource: URI): TPromise { + return TPromise.as(this._provider.get(handle).mkdir(resource)); + } + $readdir(handle: number, resource: URI): TPromise { + return TPromise.as(this._provider.get(handle).readdir(resource)); + } + $rmdir(handle: number, resource: URI): TPromise { + return TPromise.as(this._provider.get(handle).rmdir(resource)); + } +} diff --git a/src/vs/workbench/api/node/extHostWorkspace.ts b/src/vs/workbench/api/node/extHostWorkspace.ts index 43323d5c00c..c66128780f6 100644 --- a/src/vs/workbench/api/node/extHostWorkspace.ts +++ b/src/vs/workbench/api/node/extHostWorkspace.ts @@ -16,11 +16,7 @@ import { fromRange, EndOfLine } from 'vs/workbench/api/node/extHostTypeConverter import { IWorkspaceData, ExtHostWorkspaceShape, MainContext, MainThreadWorkspaceShape, IMainContext } from './extHost.protocol'; import * as vscode from 'vscode'; import { compare } from 'vs/base/common/strings'; -import { asWinJsPromise } from 'vs/base/common/async'; -import { Disposable } from 'vs/workbench/api/node/extHostTypes'; import { TrieMap } from 'vs/base/common/map'; -import { CancellationTokenSource } from 'vs/base/common/cancellation'; -import { Progress } from 'vs/platform/progress/common/progress'; class Workspace2 extends Workspace { @@ -203,51 +199,4 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { return this._proxy.$applyWorkspaceEdit(resourceEdits); } - // --- EXPERIMENT: workspace resolver - - - private _handlePool = 0; - private readonly _fsProvider = new Map(); - private readonly _searchSession = new Map(); - - registerFileSystemProvider(authority: string, provider: vscode.FileSystemProvider): vscode.Disposable { - const handle = ++this._handlePool; - this._fsProvider.set(handle, provider); - const reg = provider.onDidChange(e => this._proxy.$onFileSystemChange(handle, e)); - this._proxy.$registerFileSystemProvider(handle, authority); - return new Disposable(() => { - this._fsProvider.delete(handle); - reg.dispose(); - }); - } - - $resolveFile(handle: number, resource: URI): TPromise { - const provider = this._fsProvider.get(handle); - return asWinJsPromise(token => provider.resolveContents(resource)); - } - - $storeFile(handle: number, resource: URI, content: string): TPromise { - const provider = this._fsProvider.get(handle); - return asWinJsPromise(token => provider.writeContents(resource, content)); - } - - $startSearch(handle: number, session: number, query: string): void { - const provider = this._fsProvider.get(handle); - const source = new CancellationTokenSource(); - const progress = new Progress(chunk => this._proxy.$updateSearchSession(session, chunk)); - - this._searchSession.set(session, source); - TPromise.wrap(provider.findFiles(query, progress, source.token)).then(() => { - this._proxy.$finishSearchSession(session); - }, err => { - this._proxy.$finishSearchSession(session, err); - }); - } - - $cancelSearch(handle: number, session: number): void { - if (this._searchSession.has(session)) { - this._searchSession.get(session).cancel(); - this._searchSession.delete(session); - } - } } diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configuration.ts index ded7484b703..13a8dfa35a5 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configuration.ts @@ -472,12 +472,6 @@ export class WorkspaceServiceImpl extends WorkspaceService { const workspaceConfigurationModel = this.workspaceConfiguration.workspaceConfigurationModel; const workspaceFolders = toWorkspaceFolders(workspaceConfigurationModel.folders, URI.file(paths.dirname(this.workspaceConfigPath.fsPath))); - workspaceFolders.push({ - uri: URI.parse('ftp://waws-prod-db3-029.ftp.azurewebsites.windows.net/'), - name: 'FTP Sample', - index: workspaceFolders.length, - raw: null - }); if (!workspaceFolders.length) { return TPromise.wrapError(new Error('Invalid workspace configuraton file ' + this.workspaceConfigPath)); } diff --git a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts b/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts deleted file mode 100644 index df081ff4b54..00000000000 --- a/src/vs/workbench/services/files/electron-browser/ftpFileSystemProvider.ts +++ /dev/null @@ -1,146 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - - - -import URI from 'vs/base/common/uri'; -import Event from 'vs/base/common/event'; -import * as JSFtp from 'jsftp'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { Readable } from 'stream'; -import { join, dirname, basename } from 'path'; -import { IStat, FileType, IFileSystemProvider } from 'vs/platform/files/common/files'; -import { IProgress } from 'vs/platform/progress/common/progress'; - -export class FtpFileSystemProvider implements IFileSystemProvider { - - private _connection: TPromise; - - readonly onDidChange = Event.None; - - constructor() { - this._connection = new TPromise((resolve, reject) => { - const connection = new JSFtp({ - host: 'waws-prod-db3-029.ftp.azurewebsites.windows.net' - }); - connection.keepAlive(1000 * 5); - connection.auth('USER', 'PASS', (err) => { - if (err) { - reject(err); - } else { - resolve(connection); - } - }); - }); - } - - private _withConnection(func: keyof JSFtp, ...args: any[]): TPromise { - return this._connection.then(connection => { - return new TPromise((resolve, reject) => { - (connection[func]).apply(connection, args.concat([function (err, result) { - if (err) { - reject(err); - } else { - resolve(result); - } - }])); - }); - }); - } - - dispose(): void { - this._withConnection('raw', 'QUIT'); - - } - - utimes(resource: URI, mtime: number): TPromise { - return this._withConnection('raw', 'NOOP') - .then(() => this.stat(resource)); - } - - stat(resource: URI): TPromise { - const { path } = resource; - if (path === '/') { - // root directory - return TPromise.as({ - type: FileType.Dir, - resource, - mtime: 0, - size: 0 - }); - } - - const name = basename(path); - const dir = dirname(path); - return this._withConnection('ls', dir).then(entries => { - for (const entry of entries) { - if (entry.name === name) { - return { - resource, - mtime: entry.time, - size: entry.size, - type: entry.type - }; - } - } - // console.log(entries, name, resource); - throw new Error(`ENO: ${resource.path}`); - }); - } - - readdir(resource: URI): TPromise { - return this._withConnection('ls', resource.path).then(ret => { - const result: IStat[] = []; - for (let entry of ret) { - result.push({ - resource: resource.with({ path: join(resource.path, entry.name) }), - mtime: entry.time, - size: entry.size, - type: entry.type - }); - } - return result; - }); - } - - read(resource: URI, progress: IProgress): TPromise { - return this._withConnection('get', resource.path).then(stream => { - return new TPromise((resolve, reject) => { - stream.on('data', d => progress.report(d)); - stream.on('close', hadErr => { - if (hadErr) { - reject(hadErr); - } else { - resolve(undefined); - } - }); - stream.resume(); - }); - }); - } - - write(resource: URI, content: Uint8Array): TPromise { - return this._withConnection('put', content, resource.path); - } - - rmdir(resource: URI): TPromise { - return this._withConnection('raw', 'RMD', [resource.path]); - } - - mkdir(resource: URI): TPromise { - return this._withConnection('raw', 'MKD', [resource.path]); - } - - unlink(resource: URI): TPromise { - return this._withConnection('raw', 'DELE', [resource.path]); - } - - rename(resource: URI, target: URI): TPromise { - return this._withConnection('raw', 'RNFR', [resource.path]).then(() => { - return this._withConnection('raw', 'RNTO', [target.path]); - }); - } -} diff --git a/src/vs/workbench/services/files/electron-browser/jsftp.d.ts b/src/vs/workbench/services/files/electron-browser/jsftp.d.ts deleted file mode 100644 index 4d728c4d05c..00000000000 --- a/src/vs/workbench/services/files/electron-browser/jsftp.d.ts +++ /dev/null @@ -1,47 +0,0 @@ - - -import { Readable } from 'stream'; -import { EventEmitter } from 'events'; - -declare namespace JSFtp { - - - interface JSFtpOptions { - host: string; - port?: number | 21; - user?: string | 'anonymous'; - pass?: string | '@anonymous'; - useList?: boolean - } - - interface Callback { - (err: any, result: T): void; - } - - - interface Entry { - name: string; - size: number; - time: number; - type: 0 | 1; - } -} - -interface JSFtp extends EventEmitter { - auth(user: string, password: string, callback: JSFtp.Callback): void - keepAlive(wait?: number): void; - ls(path: string, callback: JSFtp.Callback): void; - list(path: string, callback: JSFtp.Callback): void; - put(buffer: Buffer, path: string, callback: JSFtp.Callback): void; - get(path: string, callback: JSFtp.Callback): void; - setType(type: 'A' | 'AN' | 'AT' | 'AC' | 'E' | 'I' | 'L', callback: JSFtp.Callback): void; - raw(command: string, args: any[], callback: JSFtp.Callback): void -} - -interface JSFtpConstructor { - new(options: JSFtp.JSFtpOptions): JSFtp; -} - -declare const JSFtp: JSFtpConstructor; - -export = JSFtp; diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index b5c9f9096d1..f5dd9610f56 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -6,11 +6,10 @@ import URI from 'vs/base/common/uri'; import { FileService } from 'vs/workbench/services/files/electron-browser/fileService'; -import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation, IFileSystemProvider, IStat, FileType, IImportResult } from 'vs/platform/files/common/files'; +import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation, IFileSystemProvider, IStat, FileType, IImportResult, FileChangesEvent } from 'vs/platform/files/common/files'; import { TPromise } from 'vs/base/common/winjs.base'; import { basename, join } from 'path'; import { IDisposable } from 'vs/base/common/lifecycle'; -import * as Ftp from './ftpFileSystemProvider'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -60,7 +59,6 @@ function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse?: (stat } } - export function toDeepIFileStat(provider: IFileSystemProvider, stat: IStat, to: URI[]): TPromise { const trie = new TrieMap(); @@ -102,7 +100,6 @@ export class RemoteFileService extends FileService { storageService, textResourceConfigurationService, ); - this.registerProvider('ftp', new Ftp.FtpFileSystemProvider()); } registerProvider(authority: string, provider: IFileSystemProvider): IDisposable { @@ -111,9 +108,9 @@ export class RemoteFileService extends FileService { } this._provider.set(authority, provider); - const reg = provider.onDidChange(e => { + const reg = provider.onDidChange(changes => { // forward change events - this._onFileChanges.fire(e); + this._onFileChanges.fire(new FileChangesEvent(changes)); }); return { dispose: () => { @@ -201,7 +198,7 @@ export class RemoteFileService extends FileService { const encoding = this.getEncoding(resource); const stream = decodeStream(encoding); - await provider.read(resource, new Progress(chunk => stream.write(chunk))); + await provider.read(resource, new Progress(chunk => stream.write(chunk))); stream.end(); return { @@ -391,10 +388,15 @@ export class RemoteFileService extends FileService { return toIFileStat(provider, stat); } - // public watchFileChanges(resource: URI): void { - // throw new Error("Method not implemented."); - // } - // public unwatchFileChanges(resource: URI): void { - // throw new Error("Method not implemented."); - // } + // TODO@Joh - file watching on demand! + public watchFileChanges(resource: URI): void { + if (!this._provider.has(resource.scheme)) { + super.watchFileChanges(resource); + } + } + public unwatchFileChanges(resource: URI): void { + if (!this._provider.has(resource.scheme)) { + super.unwatchFileChanges(resource); + } + } } From a8eb4b710d7dfdee5abf1b12693257bbf901c504 Mon Sep 17 00:00:00 2001 From: Nguyen Long Nhat Date: Tue, 19 Sep 2017 20:33:16 +0700 Subject: [PATCH 042/281] Using node 7.9.0 --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b552f3ee567..15af121f5c8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,8 +27,8 @@ before_install: - git submodule update --init --recursive - git clone --depth 1 https://github.com/creationix/nvm.git ./.nvm - source ./.nvm/nvm.sh - - nvm install 7.4.0 - - nvm use 7.4.0 + - nvm install 7.9.0 + - nvm use 7.9.0 - npm config set python `which python` - npm install -g gulp - if [ $TRAVIS_OS_NAME == "linux" ]; then From 5a5050de6880db0ee905874dbb958769eff273fc Mon Sep 17 00:00:00 2001 From: Nguyen Long Nhat Date: Tue, 19 Sep 2017 20:34:06 +0700 Subject: [PATCH 043/281] Using node 7.9.0 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 49e80fed313..eaf86cb5b20 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,7 +3,7 @@ environment: VSCODE_BUILD_VERBOSE: true install: - - ps: Install-Product node 7.4.0 x64 + - ps: Install-Product node 7.9.0 x64 - npm install -g npm@4 --silent - npm install -g gulp mocha --silent From 02e9e6223fb79d1ce68f5d16144b2bbfd60b8468 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 19 Sep 2017 15:49:24 +0200 Subject: [PATCH 044/281] untitledEditorInput: title and description --- .../common/editor/untitledEditorInput.ts | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/common/editor/untitledEditorInput.ts b/src/vs/workbench/common/editor/untitledEditorInput.ts index 8ce430fb0f5..b465661bd0a 100644 --- a/src/vs/workbench/common/editor/untitledEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledEditorInput.ts @@ -7,6 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; import { suggestFilename } from 'vs/base/common/mime'; +import { memoize } from 'vs/base/common/decorators'; import labels = require('vs/base/common/labels'); import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; import paths = require('vs/base/common/paths'); @@ -37,14 +38,6 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport private toUnbind: IDisposable[]; - private shortDescription: string; - private mediumDescription: string; - private longDescription: string; - - private shortTitle: string; - private mediumTitle: string; - private longTitle: string; - constructor( private resource: URI, hasAssociatedFilePath: boolean, @@ -97,6 +90,21 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport return this.hasAssociatedFilePath ? paths.basename(this.resource.fsPath) : this.resource.fsPath; } + @memoize + private get shortDescription(): string { + return paths.basename(labels.getPathLabel(paths.dirname(this.resource.path), void 0, this.environmentService)); + } + + @memoize + private get mediumDescription(): string { + return labels.getPathLabel(paths.dirname(this.resource.path), this.contextService, this.environmentService); + } + + @memoize + private get longDescription(): string { + return labels.getPathLabel(paths.dirname(this.resource.path), void 0, this.environmentService); + } + public getDescription(verbosity: Verbosity = Verbosity.MEDIUM): string { if (!this.hasAssociatedFilePath) { return null; @@ -105,20 +113,35 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport let description: string; switch (verbosity) { case Verbosity.SHORT: - description = this.shortDescription ? this.shortDescription : (this.shortDescription = paths.basename(labels.getPathLabel(paths.dirname(this.resource.fsPath), void 0, this.environmentService))); + description = this.shortDescription; break; case Verbosity.LONG: - description = this.longDescription ? this.longDescription : (this.longDescription = labels.getPathLabel(paths.dirname(this.resource.fsPath), void 0, this.environmentService)); + description = this.longDescription; break; case Verbosity.MEDIUM: default: - description = this.mediumDescription ? this.mediumDescription : (this.mediumDescription = labels.getPathLabel(paths.dirname(this.resource.fsPath), this.contextService, this.environmentService)); + description = this.mediumDescription; break; } return description; } + @memoize + private get shortTitle(): string { + return this.getName(); + } + + @memoize + private get mediumTitle(): string { + return labels.getPathLabel(this.resource, this.contextService, this.environmentService); + } + + @memoize + private get longTitle(): string { + return labels.getPathLabel(this.resource, void 0, this.environmentService); + } + public getTitle(verbosity: Verbosity): string { if (!this.hasAssociatedFilePath) { return this.getName(); @@ -127,13 +150,13 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport let title: string; switch (verbosity) { case Verbosity.SHORT: - title = this.shortTitle ? this.shortTitle : (this.shortTitle = this.getName()); + title = this.shortTitle; break; case Verbosity.MEDIUM: - title = this.mediumTitle ? this.mediumTitle : (this.mediumTitle = labels.getPathLabel(this.resource, this.contextService, this.environmentService)); + title = this.mediumTitle; break; case Verbosity.LONG: - title = this.longTitle ? this.longTitle : (this.longTitle = labels.getPathLabel(this.resource, void 0, this.environmentService)); + title = this.longTitle; break; } From 0d612087dec52e71d9e43ffb751a6efff3d53791 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 19 Sep 2017 15:47:21 +0200 Subject: [PATCH 045/281] undo explorerView-change --- src/vs/workbench/parts/files/browser/views/explorerView.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index 102d34a7ada..835b87bc02d 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -784,7 +784,6 @@ export class ExplorerView extends CollapsibleView { modelStats.forEach((modelStat, index) => FileStat.mergeLocalWithDisk(modelStat, this.model.roots[index])); let input = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER ? this.model.roots[0] : this.model; - input = this.model; if (input === this.explorerViewer.getInput()) { return this.explorerViewer.refresh(); } From 1fdb6afb1328d47609b8a145aab664b668cb2906 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 19 Sep 2017 15:54:14 +0200 Subject: [PATCH 046/281] fix merge breakage --- src/vs/workbench/browser/labels.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 87c3471be47..b3ec715b473 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -223,8 +223,8 @@ export class FileLabel extends ResourceLabel { const hidePath = (options && options.hidePath) || (resource.scheme === Schemas.untitled && !this.untitledEditorService.hasAssociatedFilePath(resource)); + let rootProvider: IWorkspaceFolderProvider; if (!hidePath) { - let rootProvider: IWorkspaceFolderProvider; if (options && options.root) { rootProvider = { getWorkspaceFolder(): { uri } { return { uri: options.root }; }, @@ -233,15 +233,15 @@ export class FileLabel extends ResourceLabel { } else { rootProvider = this.contextService; } - - const description = resource.scheme === 'file' || resource.scheme === 'untitled' ? getPathLabel(paths.dirname(resource.fsPath), rootProvider, this.environmentService) : resource.authority; - - this.setLabel({ - resource, - name: (options && options.hideLabel) ? void 0 : resources.basenameOrAuthority(resource), - description: !hidePath ? description : void 0 - }, options); } + + const description = resource.scheme === 'file' || resource.scheme === 'untitled' ? getPathLabel(paths.dirname(resource.fsPath), rootProvider, this.environmentService) : resource.authority; + + this.setLabel({ + resource, + name: (options && options.hideLabel) ? void 0 : resources.basenameOrAuthority(resource), + description: !hidePath ? description : void 0 + }, options); } } From ceb34634b110f02296f3036d9837d41767919671 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 19 Sep 2017 15:59:23 +0200 Subject: [PATCH 047/281] always use uri.toString() when comparing uris for equality --- extensions/git/src/commands.ts | 4 ++-- extensions/git/src/contentProvider.ts | 2 +- extensions/markdown/src/extension.ts | 4 ++-- .../markdown/src/previewContentProvider.ts | 2 +- .../src/features/codeActionProvider.ts | 2 +- .../features/implementationsCodeLensProvider.ts | 2 +- .../src/features/referencesCodeLensProvider.ts | 2 +- .../parts/html/browser/html.contribution.ts | 2 +- .../preferences/browser/preferencesEditor.ts | 2 +- .../preferences/browser/preferencesService.ts | 16 ++++++++-------- .../preferences/browser/preferencesWidgets.ts | 8 ++++---- .../services/configuration/node/configuration.ts | 6 +++--- 12 files changed, 26 insertions(+), 26 deletions(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 80fad68410e..df47f973a01 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -174,7 +174,7 @@ export class CommandCenter { const activeTextEditor = window.activeTextEditor; - if (preserveSelection && activeTextEditor && activeTextEditor.document.uri.fsPath === right.fsPath) { + if (preserveSelection && activeTextEditor && activeTextEditor.document.uri.toString() === right.toString()) { opts.selection = activeTextEditor.selection; } @@ -368,7 +368,7 @@ export class CommandCenter { viewColumn: activeTextEditor && activeTextEditor.viewColumn || ViewColumn.One }; - if (activeTextEditor && activeTextEditor.document.uri.fsPath === uri.fsPath) { + if (activeTextEditor && activeTextEditor.document.uri.toString() === uri.toString()) { opts.selection = activeTextEditor.selection; } diff --git a/extensions/git/src/contentProvider.ts b/extensions/git/src/contentProvider.ts index f47765c484e..ff8529d1612 100644 --- a/extensions/git/src/contentProvider.ts +++ b/extensions/git/src/contentProvider.ts @@ -101,7 +101,7 @@ export class GitContentProvider { Object.keys(this.cache).forEach(key => { const row = this.cache[key]; - const isOpen = window.visibleTextEditors.some(e => e.document.uri.fsPath === row.uri.fsPath); + const isOpen = window.visibleTextEditors.some(e => e.document.toString() === row.uri.toString()); if (isOpen || now - row.timestamp < THREE_MINUTES) { cache[row.uri.toString()] = row; diff --git a/extensions/markdown/src/extension.ts b/extensions/markdown/src/extension.ts index 2dd53b296d7..2d6bf4d1877 100644 --- a/extensions/markdown/src/extension.ts +++ b/extensions/markdown/src/extension.ts @@ -117,7 +117,7 @@ export function activate(context: vscode.ExtensionContext) { logger.log('revealLine', { uri, sourceUri: sourceUri.toString(), line }); vscode.window.visibleTextEditors - .filter(editor => isMarkdownFile(editor.document) && editor.document.uri.fsPath === sourceUri.fsPath) + .filter(editor => isMarkdownFile(editor.document) && editor.document.uri.toString() === sourceUri.toString()) .forEach(editor => { const sourceLine = Math.floor(line); const fraction = line - sourceLine; @@ -296,7 +296,7 @@ function showSource(mdUri: vscode.Uri) { const docUri = vscode.Uri.parse(mdUri.query); for (const editor of vscode.window.visibleTextEditors) { - if (editor.document.uri.scheme === docUri.scheme && editor.document.uri.fsPath === docUri.fsPath) { + if (editor.document.uri.scheme === docUri.scheme && editor.document.uri.toString() === docUri.toString()) { return vscode.window.showTextDocument(editor.document, editor.viewColumn); } } diff --git a/extensions/markdown/src/previewContentProvider.ts b/extensions/markdown/src/previewContentProvider.ts index a7eef2330a3..870816c1eeb 100644 --- a/extensions/markdown/src/previewContentProvider.ts +++ b/extensions/markdown/src/previewContentProvider.ts @@ -205,7 +205,7 @@ export class MDDocumentContentProvider implements vscode.TextDocumentContentProv let initialLine: number | undefined = undefined; const editor = vscode.window.activeTextEditor; - if (editor && editor.document.uri.fsPath === sourceUri.fsPath) { + if (editor && editor.document.uri.toString() === sourceUri.toString()) { initialLine = editor.selection.active.line; } diff --git a/extensions/typescript/src/features/codeActionProvider.ts b/extensions/typescript/src/features/codeActionProvider.ts index c48caaf79e4..bf04c0b069a 100644 --- a/extensions/typescript/src/features/codeActionProvider.ts +++ b/extensions/typescript/src/features/codeActionProvider.ts @@ -126,7 +126,7 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider let firstEdit: TextEdit | undefined = undefined; for (const [uri, edits] of workspaceEdit.entries()) { - if (uri.fsPath === source.uri.fsPath) { + if (uri.toString() === source.uri.toString()) { firstEdit = edits[0]; break; } diff --git a/extensions/typescript/src/features/implementationsCodeLensProvider.ts b/extensions/typescript/src/features/implementationsCodeLensProvider.ts index 30daa644a4e..f2901a29f47 100644 --- a/extensions/typescript/src/features/implementationsCodeLensProvider.ts +++ b/extensions/typescript/src/features/implementationsCodeLensProvider.ts @@ -58,7 +58,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip reference.start.line, 0))) // Exclude original from implementations .filter(location => - !(location.uri.fsPath === codeLens.document.fsPath && + !(location.uri.toString() === codeLens.document.toString() && location.range.start.line === codeLens.range.start.line && location.range.start.character === codeLens.range.start.character)); diff --git a/extensions/typescript/src/features/referencesCodeLensProvider.ts b/extensions/typescript/src/features/referencesCodeLensProvider.ts index 5576bfc4825..6ce55aa371f 100644 --- a/extensions/typescript/src/features/referencesCodeLensProvider.ts +++ b/extensions/typescript/src/features/referencesCodeLensProvider.ts @@ -53,7 +53,7 @@ export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBase reference.end.line - 1, reference.end.offset - 1))) .filter(location => // Exclude original definition from references - !(location.uri.fsPath === codeLens.document.fsPath && + !(location.uri.toString() === codeLens.document.toString() && location.range.start.isEqual(codeLens.range.start))); codeLens.command = { diff --git a/src/vs/workbench/parts/html/browser/html.contribution.ts b/src/vs/workbench/parts/html/browser/html.contribution.ts index 0362b085b92..0e1fa1374bb 100644 --- a/src/vs/workbench/parts/html/browser/html.contribution.ts +++ b/src/vs/workbench/parts/html/browser/html.contribution.ts @@ -27,7 +27,7 @@ function getActivePreviewsForResource(accessor: ServicesAccessor, resource: URI return accessor.get(IWorkbenchEditorService).getVisibleEditors() .filter(c => c instanceof HtmlPreviewPart && c.model) .map(e => e as HtmlPreviewPart) - .filter(e => e.model.uri.scheme === uri.scheme && e.model.uri.fsPath === uri.fsPath); + .filter(e => e.model.uri.scheme === uri.scheme && e.model.uri.toString() === uri.toString()); } // --- Register Editor diff --git a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts index c80df1ab899..4df30ec8542 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts @@ -791,7 +791,7 @@ abstract class AbstractSettingsEditorContribution extends Disposable { private _hasAssociatedPreferencesModelChanged(associatedPreferencesModelUri: URI): TPromise { return this.preferencesRendererCreationPromise.then(preferencesRenderer => { - return !(preferencesRenderer && preferencesRenderer.associatedPreferencesModel && preferencesRenderer.associatedPreferencesModel.uri.fsPath === associatedPreferencesModelUri.fsPath); + return !(preferencesRenderer && preferencesRenderer.associatedPreferencesModel && preferencesRenderer.associatedPreferencesModel.uri.toString() === associatedPreferencesModelUri.toString()); }); } diff --git a/src/vs/workbench/parts/preferences/browser/preferencesService.ts b/src/vs/workbench/parts/preferences/browser/preferencesService.ts index 49c69f7201f..05fe0487f3e 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesService.ts @@ -122,7 +122,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic resolveContent(uri: URI): TPromise { const workspaceSettingsUri = this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE); - if (workspaceSettingsUri && workspaceSettingsUri.fsPath === uri.fsPath) { + if (workspaceSettingsUri && workspaceSettingsUri.toString() === uri.toString()) { return this.resolveSettingsContentFromWorkspaceConfiguration(); } return this.createPreferencesEditorModel(uri) @@ -135,7 +135,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic return promise; } - if (this.defaultSettingsResource.fsPath === uri.fsPath) { + if (this.defaultSettingsResource.toString() === uri.toString()) { promise = TPromise.join([this.extensionService.onReady(), this.fetchMostCommonlyUsedSettings()]) .then(result => { const mostCommonSettings = result[1]; @@ -146,7 +146,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic return promise; } - if (this.defaultResourceSettingsResource.fsPath === uri.fsPath) { + if (this.defaultResourceSettingsResource.toString() === uri.toString()) { promise = TPromise.join([this.extensionService.onReady(), this.fetchMostCommonlyUsedSettings()]) .then(result => { const mostCommonSettings = result[1]; @@ -157,25 +157,25 @@ export class PreferencesService extends Disposable implements IPreferencesServic return promise; } - if (this.defaultKeybindingsResource.fsPath === uri.fsPath) { + if (this.defaultKeybindingsResource.toString() === uri.toString()) { const model = this.instantiationService.createInstance(DefaultKeybindingsEditorModel, uri); promise = TPromise.wrap(model); this.defaultPreferencesEditorModels.set(uri, promise); return promise; } - if (this.workspaceConfigSettingsResource.fsPath === uri.fsPath) { + if (this.workspaceConfigSettingsResource.toString() === uri.toString()) { promise = this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE, uri); this.defaultPreferencesEditorModels.set(uri, promise); return promise; } - if (this.getEditableSettingsURI(ConfigurationTarget.USER).fsPath === uri.fsPath) { + if (this.getEditableSettingsURI(ConfigurationTarget.USER).toString() === uri.toString()) { return this.createEditableSettingsEditorModel(ConfigurationTarget.USER, uri); } const workspaceSettingsUri = this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE); - if (workspaceSettingsUri && workspaceSettingsUri.fsPath === uri.fsPath) { + if (workspaceSettingsUri && workspaceSettingsUri.toString() === uri.toString()) { return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE, workspaceSettingsUri); } @@ -288,7 +288,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic private createEditableSettingsEditorModel(configurationTarget: ConfigurationTarget, resource: URI): TPromise { const settingsUri = this.getEditableSettingsURI(configurationTarget, resource); if (settingsUri) { - if (settingsUri.fsPath === this.workspaceConfigSettingsResource.fsPath) { + if (settingsUri.toString() === this.workspaceConfigSettingsResource.toString()) { return TPromise.join([this.textModelResolverService.createModelReference(settingsUri), this.textModelResolverService.createModelReference(this.contextService.getWorkspace().configuration)]) .then(([reference, workspaceConfigReference]) => this.instantiationService.createInstance(WorkspaceConfigModel, reference, workspaceConfigReference, configurationTarget, this._onDispose.event)); } diff --git a/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts index 2e69c1dfc87..6decbcc4dd9 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts @@ -332,7 +332,7 @@ export class SettingsTargetsWidget extends Widget { actions.push({ id: 'userSettingsTarget', label: getSettingsTargetName(ConfigurationTarget.USER, userSettingsResource, this.workspaceContextService), - checked: this.uri.fsPath === userSettingsResource.fsPath, + checked: this.uri.toString() === userSettingsResource.toString(), enabled: true, run: () => this.onTargetClicked(userSettingsResource) }); @@ -342,7 +342,7 @@ export class SettingsTargetsWidget extends Widget { actions.push({ id: 'workspaceSettingsTarget', label: getSettingsTargetName(ConfigurationTarget.WORKSPACE, workspaceSettingsResource, this.workspaceContextService), - checked: this.uri.fsPath === workspaceSettingsResource.fsPath, + checked: this.uri.toString() === workspaceSettingsResource.toString(), enabled: true, run: () => this.onTargetClicked(workspaceSettingsResource) }); @@ -355,7 +355,7 @@ export class SettingsTargetsWidget extends Widget { return { id: 'folderSettingsTarget' + index, label: getSettingsTargetName(ConfigurationTarget.FOLDER, folder.uri, this.workspaceContextService), - checked: this.uri.fsPath === folder.uri.fsPath, + checked: this.uri.toString() === folder.uri.toString(), enabled: true, run: () => this.onTargetClicked(folder.uri) }; @@ -366,7 +366,7 @@ export class SettingsTargetsWidget extends Widget { } private onTargetClicked(target: URI): void { - if (this.uri.fsPath === target.fsPath) { + if (this.uri.toString() === target.toString()) { return; } this._onDidTargetChange.fire(target); diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configuration.ts index fd6f77db55d..056c367bf57 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configuration.ts @@ -438,7 +438,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat this._onDidChangeWorkspaceName.fire(); } - if (!equals(this.workspace.folders, currentFolders, (folder1, folder2) => folder1.uri.fsPath === folder2.uri.fsPath)) { + if (!equals(this.workspace.folders, currentFolders, (folder1, folder2) => folder1.uri.toString() === folder2.uri.toString())) { this._onDidChangeWorkspaceFolders.fire(); } } @@ -487,7 +487,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat private onWorkspaceConfigurationChanged(): void { if (this.workspace && this.workspace.configuration) { let configuredFolders = toWorkspaceFolders(this.workspaceConfiguration.workspaceConfigurationModel.folders, URI.file(paths.dirname(this.workspace.configuration.fsPath))); - const foldersChanged = !equals(this.workspace.folders, configuredFolders, (folder1, folder2) => folder1.uri.fsPath === folder2.uri.fsPath); + const foldersChanged = !equals(this.workspace.folders, configuredFolders, (folder1, folder2) => folder1.uri.toString() === folder2.uri.toString()); if (foldersChanged) { // TODO@Sandeep be smarter here about detecting changes this.workspace.folders = configuredFolders; this.onFoldersChanged() @@ -841,7 +841,7 @@ export class Configuration extends BaseConfiguration { } deleteFolderConfiguration(folder: URI): boolean { - if (this._workspace && this._workspace.folders.length > 0 && this._workspace.folders[0].uri.fsPath === folder.fsPath) { + if (this._workspace && this._workspace.folders.length > 0 && this._workspace.folders[0].uri.toString() === folder.toString()) { // Do not remove workspace configuration return false; } From 0359e0596fd8c084a612ad985f3339271432f40a Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 19 Sep 2017 16:23:32 +0200 Subject: [PATCH 048/281] introduce resources.dirname, fixes label in no-tab view --- src/vs/base/common/resources.ts | 6 ++++++ src/vs/workbench/common/editor/untitledEditorInput.ts | 9 +++++---- .../parts/files/common/editors/fileEditorInput.ts | 10 ++++++---- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts index 5fd3fa80156..50ebdc2069f 100644 --- a/src/vs/base/common/resources.ts +++ b/src/vs/base/common/resources.ts @@ -18,3 +18,9 @@ export function isEqualOrParent(first: uri, second: uri, ignoreCase?: boolean): return false; } + +export function dirname(resource: uri): uri { + return resource.with({ + path: paths.dirname(resource.path) + }); +} diff --git a/src/vs/workbench/common/editor/untitledEditorInput.ts b/src/vs/workbench/common/editor/untitledEditorInput.ts index b465661bd0a..dac7180d617 100644 --- a/src/vs/workbench/common/editor/untitledEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledEditorInput.ts @@ -11,6 +11,7 @@ import { memoize } from 'vs/base/common/decorators'; import labels = require('vs/base/common/labels'); import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; import paths = require('vs/base/common/paths'); +import resources = require('vs/base/common/resources'); import { EditorInput, IEncodingSupport, EncodingMode, ConfirmResult } from 'vs/workbench/common/editor'; import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -87,22 +88,22 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport } public getName(): string { - return this.hasAssociatedFilePath ? paths.basename(this.resource.fsPath) : this.resource.fsPath; + return this.hasAssociatedFilePath ? resources.basenameOrAuthority(this.resource) : this.resource.path; } @memoize private get shortDescription(): string { - return paths.basename(labels.getPathLabel(paths.dirname(this.resource.path), void 0, this.environmentService)); + return paths.basename(labels.getPathLabel(resources.dirname(this.resource), void 0, this.environmentService)); } @memoize private get mediumDescription(): string { - return labels.getPathLabel(paths.dirname(this.resource.path), this.contextService, this.environmentService); + return labels.getPathLabel(resources.dirname(this.resource), this.contextService, this.environmentService); } @memoize private get longDescription(): string { - return labels.getPathLabel(paths.dirname(this.resource.path), void 0, this.environmentService); + return labels.getPathLabel(resources.dirname(this.resource), void 0, this.environmentService); } public getDescription(verbosity: Verbosity = Verbosity.MEDIUM): string { diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts index e3806ca1e36..d3930c9fcff 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts @@ -8,6 +8,7 @@ import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { memoize } from 'vs/base/common/decorators'; import paths = require('vs/base/common/paths'); +import resources = require('vs/base/common/resources'); import labels = require('vs/base/common/labels'); import URI from 'vs/base/common/uri'; import { EncodingMode, ConfirmResult, EditorInput, IFileEditorInput, ITextEditorModel } from 'vs/workbench/common/editor'; @@ -117,7 +118,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { public getName(): string { if (!this.name) { - this.name = paths.basename(this.resource.fsPath); + this.name = resources.basenameOrAuthority(this.resource); } return this.decorateOrphanedFiles(this.name); @@ -125,17 +126,18 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { @memoize private get shortDescription(): string { - return paths.basename(labels.getPathLabel(paths.dirname(this.resource.path), void 0, this.environmentService)); + + return paths.basename(labels.getPathLabel(resources.dirname(this.resource), void 0, this.environmentService)); } @memoize private get mediumDescription(): string { - return labels.getPathLabel(paths.dirname(this.resource.path), this.contextService, this.environmentService); + return labels.getPathLabel(resources.dirname(this.resource), this.contextService, this.environmentService); } @memoize private get longDescription(): string { - return labels.getPathLabel(paths.dirname(this.resource.path), void 0, this.environmentService); + return labels.getPathLabel(resources.dirname(this.resource), void 0, this.environmentService); } public getDescription(verbosity: Verbosity = Verbosity.MEDIUM): string { From d4e9abd920715da8ac11fa326683639580bf9aca Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 19 Sep 2017 16:12:21 +0200 Subject: [PATCH 049/281] add todo@remote tags --- src/vs/workbench/services/textfile/common/textFileEditorModel.ts | 1 + src/vs/workbench/services/textfile/common/textFileService.ts | 1 + .../textmodelResolver/common/textModelResolverService.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 67b8ff2d6e3..80db2087ae8 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -90,6 +90,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil ) { super(modelService, modeService); + // TODO@remote // assert.ok(resource.scheme === 'file', 'TextFileEditorModel can only handle file:// resources.'); this.resource = resource; diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index 6950f4bb23c..e754ef1bf38 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -407,6 +407,7 @@ export abstract class TextFileService implements ITextFileService { const filesToSave: URI[] = []; const untitledToSave: URI[] = []; toSave.forEach(s => { + // TODO@remote // if (s.scheme === Schemas.file) { // filesToSave.push(s); // } else diff --git a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts index ae8b0ae383f..125ef301221 100644 --- a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts +++ b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts @@ -36,6 +36,7 @@ class ResourceModelCollection extends ReferenceCollection this.instantiationService.createInstance(ResourceEditorModel, resource)); From 81d3bb87c27bdc7245a8b6411be5fd3eacc7a5d9 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 19 Sep 2017 16:30:10 +0200 Subject: [PATCH 050/281] don't let the file service track editors, let the file tracker do it --- .../files/common/editors/fileEditorTracker.ts | 47 ++++++++++++++++++- .../files/electron-browser/fileService.ts | 46 ------------------ .../electron-browser/remoteFileService.ts | 33 ------------- 3 files changed, 45 insertions(+), 81 deletions(-) diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts index 1795f7b9bf0..419a6b49c96 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts @@ -24,6 +24,8 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { isLinux } from 'vs/base/common/platform'; import { ResourceQueue } from 'vs/base/common/async'; +import { ResourceMap } from 'vs/base/common/map'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; export class FileEditorTracker implements IWorkbenchContribution { @@ -32,6 +34,7 @@ export class FileEditorTracker implements IWorkbenchContribution { private stacks: IEditorStacksModel; private toUnbind: IDisposable[]; private modelLoadQueue: ResourceQueue; + private activeOutOfWorkspaceWatchers: ResourceMap; constructor( @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @@ -40,11 +43,13 @@ export class FileEditorTracker implements IWorkbenchContribution { @IEditorGroupService private editorGroupService: IEditorGroupService, @IFileService private fileService: IFileService, @IEnvironmentService private environmentService: IEnvironmentService, - @IConfigurationService private configurationService: IConfigurationService + @IConfigurationService private configurationService: IConfigurationService, + @IWorkspaceContextService private contextService: IWorkspaceContextService, ) { this.toUnbind = []; this.stacks = editorGroupService.getStacksModel(); this.modelLoadQueue = new ResourceQueue(); + this.activeOutOfWorkspaceWatchers = new ResourceMap(); this.onConfigurationUpdated(configurationService.getConfiguration()); @@ -63,6 +68,9 @@ export class FileEditorTracker implements IWorkbenchContribution { // Update editors from disk changes this.toUnbind.push(this.fileService.onFileChanges(e => this.onFileChanges(e))); + // Editor changing + this.toUnbind.push(this.editorGroupService.onEditorsChanged(() => this.onEditorsChanged())); + // Lifecycle this.lifecycleService.onShutdown(this.dispose, this); @@ -290,7 +298,42 @@ export class FileEditorTracker implements IWorkbenchContribution { } } + private onEditorsChanged(): void { + this.handleOutOfWorkspaceWatchers(); + } + + private handleOutOfWorkspaceWatchers(): void { + const visibleOutOfWorkspacePaths = new ResourceMap(); + this.editorService.getVisibleEditors().map(editor => { + return toResource(editor.input, { supportSideBySide: true, filter: 'file' }); + }).filter(fileResource => { + return !!fileResource && !this.contextService.isInsideWorkspace(fileResource); + }).forEach(resource => { + visibleOutOfWorkspacePaths.set(resource, resource); + }); + + // Handle no longer visible out of workspace resources + this.activeOutOfWorkspaceWatchers.forEach(resource => { + if (!visibleOutOfWorkspacePaths.get(resource)) { + this.fileService.unwatchFileChanges(resource); + this.activeOutOfWorkspaceWatchers.delete(resource); + } + }); + + // Handle newly visible out of workspace resources + visibleOutOfWorkspacePaths.forEach(resource => { + if (!this.activeOutOfWorkspaceWatchers.get(resource)) { + this.fileService.watchFileChanges(resource); + this.activeOutOfWorkspaceWatchers.set(resource, resource); + } + }); + } + public dispose(): void { this.toUnbind = dispose(this.toUnbind); + + // Dispose watchers if any + this.activeOutOfWorkspaceWatchers.forEach(resource => this.fileService.unwatchFileChanges(resource)); + this.activeOutOfWorkspaceWatchers.clear(); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/files/electron-browser/fileService.ts b/src/vs/workbench/services/files/electron-browser/fileService.ts index b61c993312b..d2c61424a26 100644 --- a/src/vs/workbench/services/files/electron-browser/fileService.ts +++ b/src/vs/workbench/services/files/electron-browser/fileService.ts @@ -11,17 +11,13 @@ import paths = require('vs/base/common/paths'); import encoding = require('vs/base/node/encoding'); import errors = require('vs/base/common/errors'); import uri from 'vs/base/common/uri'; -import { toResource } from 'vs/workbench/common/editor'; import { FileOperation, FileOperationEvent, IFileService, IFilesConfiguration, IResolveFileOptions, IFileStat, IResolveFileResult, IContent, IStreamContent, IImportResult, IResolveContentOptions, IUpdateContentOptions, FileChangesEvent, ICreateFileOptions } from 'vs/platform/files/common/files'; import { FileService as NodeFileService, IFileServiceOptions, IEncodingOverride } from 'vs/workbench/services/files/node/fileService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { Action } from 'vs/base/common/actions'; -import { ResourceMap } from 'vs/base/common/map'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IMessageService, IMessageWithAction, Severity, CloseAction } from 'vs/platform/message/common/message'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import Event, { Emitter } from 'vs/base/common/event'; @@ -40,7 +36,6 @@ export class FileService implements IFileService { private raw: IFileService; private toUnbind: IDisposable[]; - private activeOutOfWorkspaceWatchers: ResourceMap; protected _onFileChanges: Emitter; protected _onAfterOperation: Emitter; @@ -48,16 +43,13 @@ export class FileService implements IFileService { constructor( @IConfigurationService private configurationService: IConfigurationService, @IWorkspaceContextService private contextService: IWorkspaceContextService, - @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IEnvironmentService private environmentService: IEnvironmentService, - @IEditorGroupService private editorGroupService: IEditorGroupService, @ILifecycleService private lifecycleService: ILifecycleService, @IMessageService private messageService: IMessageService, @IStorageService private storageService: IStorageService, @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService ) { this.toUnbind = []; - this.activeOutOfWorkspaceWatchers = new ResourceMap(); this._onFileChanges = new Emitter(); this.toUnbind.push(this._onFileChanges); @@ -129,9 +121,6 @@ export class FileService implements IFileService { // Config changes this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration()))); - // Editor changing - this.toUnbind.push(this.editorGroupService.onEditorsChanged(() => this.onEditorsChanged())); - // Root changes this.toUnbind.push(this.contextService.onDidChangeWorkspaceFolders(() => this.onDidChangeWorkspaceFolders())); @@ -153,37 +142,6 @@ export class FileService implements IFileService { return encodingOverride; } - private onEditorsChanged(): void { - this.handleOutOfWorkspaceWatchers(); - } - - private handleOutOfWorkspaceWatchers(): void { - const visibleOutOfWorkspacePaths = new ResourceMap(); - this.editorService.getVisibleEditors().map(editor => { - return toResource(editor.input, { supportSideBySide: true, filter: 'file' }); - }).filter(fileResource => { - return !!fileResource && !this.contextService.isInsideWorkspace(fileResource); - }).forEach(resource => { - visibleOutOfWorkspacePaths.set(resource, resource); - }); - - // Handle no longer visible out of workspace resources - this.activeOutOfWorkspaceWatchers.forEach(resource => { - if (!visibleOutOfWorkspacePaths.get(resource)) { - this.unwatchFileChanges(resource); - this.activeOutOfWorkspaceWatchers.delete(resource); - } - }); - - // Handle newly visible out of workspace resources - visibleOutOfWorkspacePaths.forEach(resource => { - if (!this.activeOutOfWorkspaceWatchers.get(resource)) { - this.watchFileChanges(resource); - this.activeOutOfWorkspaceWatchers.set(resource, resource); - } - }); - } - private onConfigurationChange(configuration: IFilesConfiguration): void { this.updateOptions(configuration.files); } @@ -297,10 +255,6 @@ export class FileService implements IFileService { public dispose(): void { this.toUnbind = dispose(this.toUnbind); - // Dispose watchers if any - this.activeOutOfWorkspaceWatchers.forEach(resource => this.unwatchFileChanges(resource)); - this.activeOutOfWorkspaceWatchers.clear(); - // Dispose service this.raw.dispose(); } diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index f5dd9610f56..f694e1e891b 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -10,17 +10,8 @@ import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateCon import { TPromise } from 'vs/base/common/winjs.base'; import { basename, join } from 'path'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { IMessageService } from 'vs/platform/message/common/message'; -import { IStorageService } from 'vs/platform/storage/common/storage'; import { groupBy, isFalsyOrEmpty } from 'vs/base/common/arrays'; import { compare } from 'vs/base/common/strings'; -import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { Progress } from 'vs/platform/progress/common/progress'; import { decodeStream, encode } from 'vs/base/node/encoding'; import { TrieMap } from 'vs/base/common/map'; @@ -78,30 +69,6 @@ export class RemoteFileService extends FileService { private readonly _provider = new Map(); - constructor( - @IConfigurationService configurationService: IConfigurationService, - @IWorkspaceContextService contextService: IWorkspaceContextService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, - @IEnvironmentService environmentService: IEnvironmentService, - @IEditorGroupService editorGroupService: IEditorGroupService, - @ILifecycleService lifecycleService: ILifecycleService, - @IMessageService messageService: IMessageService, - @IStorageService storageService: IStorageService, - @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService - ) { - super( - configurationService, - contextService, - editorService, - environmentService, - editorGroupService, - lifecycleService, - messageService, - storageService, - textResourceConfigurationService, - ); - } - registerProvider(authority: string, provider: IFileSystemProvider): IDisposable { if (this._provider.has(authority)) { throw new Error(); From 6676cd02ac18684884a7d7500fe751db15fb135e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 19 Sep 2017 17:11:47 +0200 Subject: [PATCH 051/281] first check for file-schema and then call super, send activation event for others --- .../electron-browser/remoteFileService.ts | 173 +++++++++++------- 1 file changed, 110 insertions(+), 63 deletions(-) diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index f694e1e891b..cccd85fb9c6 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -12,9 +12,18 @@ import { basename, join } from 'path'; import { IDisposable } from 'vs/base/common/lifecycle'; import { groupBy, isFalsyOrEmpty } from 'vs/base/common/arrays'; import { compare } from 'vs/base/common/strings'; +import { Schemas } from 'vs/base/common/network'; import { Progress } from 'vs/platform/progress/common/progress'; import { decodeStream, encode } from 'vs/base/node/encoding'; import { TrieMap } from 'vs/base/common/map'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { IMessageService } from 'vs/platform/message/common/message'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse?: (stat: IStat) => boolean): TPromise { const ret: IFileStat = { @@ -69,6 +78,27 @@ export class RemoteFileService extends FileService { private readonly _provider = new Map(); + constructor( + @IExtensionService private readonly _extensionService: IExtensionService, + @IConfigurationService configurationService: IConfigurationService, + @IWorkspaceContextService contextService: IWorkspaceContextService, + @IEnvironmentService environmentService: IEnvironmentService, + @ILifecycleService lifecycleService: ILifecycleService, + @IMessageService messageService: IMessageService, + @IStorageService storageService: IStorageService, + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, + ) { + super( + configurationService, + contextService, + environmentService, + lifecycleService, + messageService, + storageService, + textResourceConfigurationService, + ); + } + registerProvider(authority: string, provider: IFileSystemProvider): IDisposable { if (this._provider.has(authority)) { throw new Error(); @@ -89,38 +119,56 @@ export class RemoteFileService extends FileService { // --- stat - existsFile(resource: URI): TPromise { - const provider = this._provider.get(resource.scheme); - if (provider) { - return this._doResolveFiles(provider, [{ resource }]).then(data => data.length > 0); - } else { + private _withProvider(resource: URI): TPromise { + return this._extensionService.activateByEvent('onFileSystemAccess:' + resource.scheme).then(() => { + const provider = this._provider.get(resource.scheme); + if (!provider) { + throw new Error('ENOPRO - no provider known for ' + resource); + } + return provider; + }); + } + + async existsFile(resource: URI): TPromise { + if (resource.scheme === Schemas.file) { return super.existsFile(resource); + } else { + const provider = await this._withProvider(resource); + return provider + ? this._doResolveFiles(provider, [{ resource }]).then(data => data.length > 0) + : true; } } - resolveFile(resource: URI, options?: IResolveFileOptions): TPromise { - const provider = this._provider.get(resource.scheme); - if (provider) { + async resolveFile(resource: URI, options?: IResolveFileOptions): TPromise { + if (resource.scheme === Schemas.file) { + return super.resolveFile(resource, options); + } else { + const provider = await this._withProvider(resource); + if (!provider) { + throw new Error('ENOENT'); + } return this._doResolveFiles(provider, [{ resource, options }]).then(data => { if (isFalsyOrEmpty(data)) { throw new Error('NotFound'); } return data[0].stat; }); - } else { - return super.resolveFile(resource, options); } } - resolveFiles(toResolve: { resource: URI; options?: IResolveFileOptions; }[]): TPromise { + async resolveFiles(toResolve: { resource: URI; options?: IResolveFileOptions; }[]): TPromise { const groups = groupBy(toResolve, (a, b) => compare(a.resource.scheme, b.resource.scheme)); const promises: TPromise[] = []; for (const group of groups) { - const provider = this._provider.get(group[0].resource.scheme); - if (!provider) { + if (group[0].resource.scheme === Schemas.file) { promises.push(super.resolveFiles(group)); } else { - promises.push(this._doResolveFiles(provider, group)); + await this._extensionService.onReady(); + const provider = this._provider.get(group[0].resource.scheme); + if (provider) { + promises.push(this._doResolveFiles(provider, group)); + } } } return TPromise.join(promises).then(data => { @@ -141,21 +189,21 @@ export class RemoteFileService extends FileService { // --- resolve - resolveContent(resource: URI, options?: IResolveContentOptions): TPromise { - const provider = this._provider.get(resource.scheme); - if (provider) { - return this._doResolveContent(provider, resource).then(RemoteFileService._asContent); - } else { + async resolveContent(resource: URI, options?: IResolveContentOptions): TPromise { + if (resource.scheme === Schemas.file) { return super.resolveContent(resource, options); + } else { + const provider = await this._withProvider(resource); + return this._doResolveContent(provider, resource).then(RemoteFileService._asContent); } } - resolveStreamContent(resource: URI, options?: IResolveContentOptions): TPromise { - const provider = this._provider.get(resource.scheme); - if (provider) { - return this._doResolveContent(provider, resource); - } else { + async resolveStreamContent(resource: URI, options?: IResolveContentOptions): TPromise { + if (resource.scheme === Schemas.file) { return super.resolveStreamContent(resource, options); + } else { + const provider = await this._withProvider(resource); + return this._doResolveContent(provider, resource); } } @@ -181,22 +229,22 @@ export class RemoteFileService extends FileService { // --- saving async createFile(resource: URI, content?: string): TPromise { - const provider = this._provider.get(resource.scheme); - if (provider) { + if (resource.scheme === Schemas.file) { + return super.createFile(resource, content); + } else { + const provider = await this._withProvider(resource); const stat = await this._doUpdateContent(provider, resource, content || '', {}); this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, stat)); return stat; - } else { - return super.createFile(resource, content); } } - updateContent(resource: URI, value: string, options?: IUpdateContentOptions): TPromise { - const provider = this._provider.get(resource.scheme); - if (provider) { - return this._doUpdateContent(provider, resource, value, options || {}); - } else { + async updateContent(resource: URI, value: string, options?: IUpdateContentOptions): TPromise { + if (resource.scheme === Schemas.file) { return super.updateContent(resource, value, options); + } else { + const provider = await this._withProvider(resource); + return this._doUpdateContent(provider, resource, value, options || {}); } } @@ -227,47 +275,46 @@ export class RemoteFileService extends FileService { // --- delete async del(resource: URI, useTrash?: boolean): TPromise { - const provider = this._provider.get(resource.scheme); - if (provider) { + if (resource.scheme === Schemas.file) { + return super.del(resource, useTrash); + } else { + const provider = await this._withProvider(resource); const stat = await provider.stat(resource); await stat.type === FileType.Dir ? provider.rmdir(resource) : provider.unlink(resource); this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.DELETE)); - } else { - return super.del(resource, useTrash); } } async createFolder(resource: URI): TPromise { - const provider = this._provider.get(resource.scheme); - if (provider) { + if (resource.scheme === Schemas.file) { + return super.createFolder(resource); + } else { + const provider = await this._withProvider(resource); await provider.mkdir(resource); const stat = await toIFileStat(provider, await provider.stat(resource)); this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, stat)); return stat; - } else { - return super.createFolder(resource); } } - rename(resource: URI, newName: string): TPromise { - const provider = this._provider.get(resource.scheme); - if (provider) { + async rename(resource: URI, newName: string): TPromise { + if (resource.scheme === Schemas.file) { + return super.rename(resource, newName); + } else { + const provider = await this._withProvider(resource); const target = resource.with({ path: join(resource.path, '..', newName) }); return this._doMove(provider, resource, target, false); - } else { - return super.rename(resource, newName); } } - moveFile(source: URI, target: URI, overwrite?: boolean): TPromise { + async moveFile(source: URI, target: URI, overwrite?: boolean): TPromise { if (source.scheme !== target.scheme) { return this._manualMove(source, target); - } - const provider = this._provider.get(source.scheme); - if (provider) { - return this._doMove(provider, source, target, overwrite); - } else { + } else if (source.scheme === Schemas.file) { return super.moveFile(source, target, overwrite); + } else { + const provider = await this._withProvider(source); + return this._doMove(provider, source, target, overwrite); } } @@ -296,9 +343,8 @@ export class RemoteFileService extends FileService { } importFile(source: URI, targetFolder: URI): TPromise { - if (source.scheme === targetFolder.scheme && !this._provider.has(source.scheme)) { + if (source.scheme === targetFolder.scheme && source.scheme === Schemas.file) { return super.importFile(source, targetFolder); - } else { const target = targetFolder.with({ path: join(targetFolder.path, basename(source.path)) }); return this.copyFile(source, target, false).then(stat => ({ stat, isNew: false })); @@ -306,7 +352,7 @@ export class RemoteFileService extends FileService { } async copyFile(source: URI, target: URI, overwrite?: boolean): TPromise { - if (source.scheme === target.scheme && !this._provider.has(source.scheme)) { + if (source.scheme === target.scheme && source.scheme === Schemas.file) { return super.copyFile(source, target, overwrite); } @@ -323,7 +369,8 @@ export class RemoteFileService extends FileService { // because the content turns things into a string // and all binary data will be broken const content = await this.resolveContent(source); - const targetProvider = this._provider.get(target.scheme); + const targetProvider = await this._withProvider(target); + if (targetProvider) { const stat = await this._doUpdateContent(targetProvider, target, content.value, { encoding: content.encoding }); this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.COPY, stat)); @@ -333,12 +380,12 @@ export class RemoteFileService extends FileService { } } - touchFile(resource: URI): TPromise { - const provider = this._provider.get(resource.scheme); - if (provider) { - return this._doTouchFile(provider, resource); - } else { + async touchFile(resource: URI): TPromise { + if (resource.scheme === Schemas.file) { return super.touchFile(resource); + } else { + const provider = await this._withProvider(resource); + return this._doTouchFile(provider, resource); } } @@ -357,12 +404,12 @@ export class RemoteFileService extends FileService { // TODO@Joh - file watching on demand! public watchFileChanges(resource: URI): void { - if (!this._provider.has(resource.scheme)) { + if (resource.scheme === Schemas.file) { super.watchFileChanges(resource); } } public unwatchFileChanges(resource: URI): void { - if (!this._provider.has(resource.scheme)) { + if (resource.scheme === Schemas.file) { super.unwatchFileChanges(resource); } } From 8631b22498653dc1079cbfff2be482181857a5cc Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 19 Sep 2017 11:30:14 -0400 Subject: [PATCH 052/281] Closes #27408 - Adds ViewColumn.Active --- .../vscode-api-tests/src/window.test.ts | 20 +++++++++++++++++++ src/vs/vscode.d.ts | 1 + .../api/node/extHostTypeConverters.ts | 2 ++ src/vs/workbench/api/node/extHostTypes.ts | 1 + 4 files changed, 24 insertions(+) diff --git a/extensions/vscode-api-tests/src/window.test.ts b/extensions/vscode-api-tests/src/window.test.ts index a9d78e8cad3..275ac5ee5ca 100644 --- a/extensions/vscode-api-tests/src/window.test.ts +++ b/extensions/vscode-api-tests/src/window.test.ts @@ -138,6 +138,26 @@ suite('window namespace tests', () => { assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.One); }); + test('issue #27408 - showTextDocument & vscode.diff always default to ViewColumn.One', async () => { + const [docA, docB, docC] = await Promise.all([ + workspace.openTextDocument(await createRandomFile()), + workspace.openTextDocument(await createRandomFile()), + workspace.openTextDocument(await createRandomFile()) + ]); + + await window.showTextDocument(docA, ViewColumn.One); + await window.showTextDocument(docB, ViewColumn.Two); + + assert.ok(window.activeTextEditor); + assert.ok(window.activeTextEditor!.document === docB); + assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.Two); + + await window.showTextDocument(docC, ViewColumn.Active); + + assert.ok(window.activeTextEditor!.document === docC); + assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.Two); + }); + test('issue #5362 - Incorrect TextEditor passed by onDidChangeTextEditorSelection', (done) => { const file10Path = join(workspace.rootPath || '', './10linefile.ts'); const file30Path = join(workspace.rootPath || '', './30linefile.ts'); diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 92310b76a73..f955fbbc245 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -3311,6 +3311,7 @@ declare module 'vscode' { * used to show editors side by side. */ export enum ViewColumn { + Active = -1, One = 1, Two = 2, Three = 3 diff --git a/src/vs/workbench/api/node/extHostTypeConverters.ts b/src/vs/workbench/api/node/extHostTypeConverters.ts index 0a8c0bcb019..fa732f92951 100644 --- a/src/vs/workbench/api/node/extHostTypeConverters.ts +++ b/src/vs/workbench/api/node/extHostTypeConverters.ts @@ -115,6 +115,8 @@ export function fromViewColumn(column?: vscode.ViewColumn): EditorPosition { editorColumn = EditorPosition.TWO; } else if (column === types.ViewColumn.Three) { editorColumn = EditorPosition.THREE; + } else if (column === types.ViewColumn.Active) { + editorColumn = undefined; } return editorColumn; } diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index a9b213648b8..b6d063810b6 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -953,6 +953,7 @@ export class CompletionList { } export enum ViewColumn { + Active = -1, One = 1, Two = 2, Three = 3 From b0ff3b0e012f144d0b55490cd7a9e7c8514af258 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 19 Sep 2017 17:36:39 +0200 Subject: [PATCH 053/281] find in folder only for local folders --- src/vs/workbench/parts/search/browser/search.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/search/browser/search.contribution.ts b/src/vs/workbench/parts/search/browser/search.contribution.ts index 76b10d2b040..ba0b901980a 100644 --- a/src/vs/workbench/parts/search/browser/search.contribution.ts +++ b/src/vs/workbench/parts/search/browser/search.contribution.ts @@ -190,7 +190,7 @@ class ExplorerViewerActionContributor extends ActionBarContributor { return false; } - return fileResource.isDirectory; + return fileResource.isDirectory && fileResource.resource.scheme === 'file'; } public getSecondaryActions(context: any): IAction[] { From a23633b5d42dc486a668e49a232957696750c254 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 19 Sep 2017 17:51:46 +0200 Subject: [PATCH 054/281] a somewhat sane way to know how to open a file --- src/vs/platform/files/common/files.ts | 2 ++ .../workbench/electron-browser/workbench.ts | 10 +++++----- .../services/editor/browser/editorService.ts | 12 ++++++++---- .../electron-browser/remoteFileService.ts | 19 ++++++++++++++++--- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 6059ab7e0de..469fe9552c6 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -37,6 +37,8 @@ export interface IFileService { */ registerProvider?(authority: string, provider: IFileSystemProvider): IDisposable; + supportResource?(resource: URI): boolean; + /** * Resolve the properties of a file identified by the resource. * diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 8133a94c1b8..1917de3e094 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -554,6 +554,11 @@ export class Workbench implements IPartService { this.toShutdown.push(this.activitybarPart); serviceCollection.set(IActivityBarService, this.activitybarPart); + // File Service + this.fileService = this.instantiationService.createInstance(RemoteFileService); + serviceCollection.set(IFileService, this.fileService); + this.toDispose.push(this.fileService.onFileChanges(e => this.configurationService.handleWorkspaceFileEvents(e))); + // Editor service (editor part) this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, !this.hasFilesToCreateOpenOrDiff); this.toDispose.push(this.editorPart); @@ -568,11 +573,6 @@ export class Workbench implements IPartService { this.toShutdown.push(this.titlebarPart); serviceCollection.set(ITitleService, this.titlebarPart); - // File Service - this.fileService = this.instantiationService.createInstance(RemoteFileService); - serviceCollection.set(IFileService, this.fileService); - this.toDispose.push(this.fileService.onFileChanges(e => this.configurationService.handleWorkspaceFileEvents(e))); - // History serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService)); diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index 4d9e1fdf586..52fa698bfd4 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -23,6 +23,7 @@ import { getPathLabel } from 'vs/base/common/labels'; import { ResourceMap } from 'vs/base/common/map'; import { once } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IFileService } from 'vs/platform/files/common/files'; export interface IEditorPart { openEditor(input?: IEditorInput, options?: IEditorOptions | ITextEditorOptions, sideBySide?: boolean): TPromise; @@ -53,7 +54,8 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { @IUntitledEditorService private untitledEditorService: IUntitledEditorService, @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, @IInstantiationService private instantiationService: IInstantiationService, - @IEnvironmentService private environmentService: IEnvironmentService + @IEnvironmentService private environmentService: IEnvironmentService, + @IFileService private fileService: IFileService ) { this.editorPart = editorPart; this.fileInputFactory = Registry.as(Extensions.Editors).getFileInputFactory(); @@ -273,7 +275,7 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { } let input: ICachedEditorInput; - if (resource.scheme === network.Schemas.file || resource.scheme === 'ftp') { + if (resource.scheme === network.Schemas.file || this.fileService.supportResource && this.fileService.supportResource(resource)) { input = this.fileInputFactory.createFileInput(resource, encoding, instantiationService); } else { input = instantiationService.createInstance(ResourceEditorInput, label, description, resource); @@ -319,14 +321,16 @@ export class DelegatingWorkbenchEditorService extends WorkbenchEditorService { @IInstantiationService instantiationService: IInstantiationService, @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, @IWorkbenchEditorService editorService: IWorkbenchEditorService, - @IEnvironmentService environmentService: IEnvironmentService + @IEnvironmentService environmentService: IEnvironmentService, + @IFileService fileService: IFileService ) { super( editorService, untitledEditorService, workspaceContextService, instantiationService, - environmentService + environmentService, + fileService ); } diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index cccd85fb9c6..134751d2f76 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -10,7 +10,7 @@ import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateCon import { TPromise } from 'vs/base/common/winjs.base'; import { basename, join } from 'path'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { groupBy, isFalsyOrEmpty } from 'vs/base/common/arrays'; +import { groupBy, isFalsyOrEmpty, distinct } from 'vs/base/common/arrays'; import { compare } from 'vs/base/common/strings'; import { Schemas } from 'vs/base/common/network'; import { Progress } from 'vs/platform/progress/common/progress'; @@ -77,15 +77,16 @@ export function toDeepIFileStat(provider: IFileSystemProvider, stat: IStat, to: export class RemoteFileService extends FileService { private readonly _provider = new Map(); + private _supportedSchemes: string[]; constructor( @IExtensionService private readonly _extensionService: IExtensionService, + @IStorageService private readonly _storageService: IStorageService, @IConfigurationService configurationService: IConfigurationService, @IWorkspaceContextService contextService: IWorkspaceContextService, @IEnvironmentService environmentService: IEnvironmentService, @ILifecycleService lifecycleService: ILifecycleService, @IMessageService messageService: IMessageService, - @IStorageService storageService: IStorageService, @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, ) { super( @@ -94,9 +95,11 @@ export class RemoteFileService extends FileService { environmentService, lifecycleService, messageService, - storageService, + _storageService, textResourceConfigurationService, ); + + this._supportedSchemes = JSON.parse(this._storageService.get('remote_schemes', undefined, '[]')); } registerProvider(authority: string, provider: IFileSystemProvider): IDisposable { @@ -104,6 +107,9 @@ export class RemoteFileService extends FileService { throw new Error(); } + this._supportedSchemes.push(authority); + this._storageService.store('remote_schemes', JSON.stringify(distinct(this._supportedSchemes))); + this._provider.set(authority, provider); const reg = provider.onDidChange(changes => { // forward change events @@ -117,6 +123,13 @@ export class RemoteFileService extends FileService { }; } + supportResource(resource: URI): boolean { + return resource.scheme === Schemas.file + || this._provider.has(resource.scheme) + // TODO@remote + || this._supportedSchemes.indexOf(resource.scheme) >= 0; + } + // --- stat private _withProvider(resource: URI): TPromise { From f86638df5f1d2f7c7872e411b6f5cf2c877e7653 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 19 Sep 2017 17:53:07 +0200 Subject: [PATCH 055/281] ftp: fix drag and drop --- .../files/browser/views/explorerViewer.ts | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index 34a5a76546e..a98fe094684 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -13,6 +13,7 @@ import URI from 'vs/base/common/uri'; import { MIME_BINARY } from 'vs/base/common/mime'; import { once } from 'vs/base/common/functional'; import paths = require('vs/base/common/paths'); +import resources = require('vs/base/common/resources'); import errors = require('vs/base/common/errors'); import { isString } from 'vs/base/common/types'; import { IAction, ActionRunner as BaseActionRunner, IActionRunner } from 'vs/base/common/actions'; @@ -350,9 +351,9 @@ export class FileRenderer implements IRenderer { }); const styler = attachInputBoxStyler(inputBox, this.themeService); - const parent = paths.dirname(stat.resource.fsPath); + const parent = resources.dirname(stat.resource); inputBox.onDidChange(value => { - label.setFile(URI.file(paths.join(parent, value)), labelOptions); // update label icon while typing! + label.setFile(parent.with({ path: paths.join(parent.path, value) }), labelOptions); // update label icon while typing! }); const value = stat.name || ''; @@ -752,7 +753,7 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { } if (stat.isDirectory) { - return URI.from({ scheme: 'folder', path: stat.resource.fsPath }); // indicates that we are dragging a folder + return URI.from({ scheme: 'folder', path: stat.resource.path }); // indicates that we are dragging a folder } return stat.resource; @@ -836,11 +837,11 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { return true; // Can not move anything onto itself } - if (!isCopy && paths.isEqual(paths.dirname(source.resource.fsPath), target.resource.fsPath)) { + if (!isCopy && resources.dirname(source.resource).toString() === target.resource.toString()) { return true; // Can not move a file to the same parent unless we copy } - if (paths.isEqualOrParent(target.resource.fsPath, source.resource.fsPath, !isLinux /* ignorecase */)) { + if (resources.isEqualOrParent(target.resource, source.resource, !isLinux /* ignorecase */)) { return true; // Can not move a parent folder into one of its children } @@ -961,18 +962,18 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { }; // 1. check for dirty files that are being moved and backup to new target - const dirty = this.textFileService.getDirty().filter(d => paths.isEqualOrParent(d.fsPath, source.resource.fsPath, !isLinux /* ignorecase */)); + const dirty = this.textFileService.getDirty().filter(d => resources.isEqualOrParent(d, source.resource, !isLinux /* ignorecase */)); return TPromise.join(dirty.map(d => { let moved: URI; // If the dirty file itself got moved, just reparent it to the target folder - if (paths.isEqual(source.resource.fsPath, d.fsPath)) { - moved = URI.file(paths.join(target.resource.fsPath, source.name)); + if (source.resource.toString() === d.toString()) { + moved = target.resource.with({ path: paths.join(target.resource.path, source.name) }); } // Otherwise, a parent of the dirty resource got moved, so we have to reparent more complicated. Example: else { - moved = URI.file(paths.join(target.resource.fsPath, d.fsPath.substr(source.parent.resource.fsPath.length + 1))); + moved = target.resource.with({ path: paths.join(target.resource.path, d.path.substr(source.parent.resource.path.length + 1)) }); } dirtyMoved.push(moved); @@ -987,7 +988,7 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { // 3.) run the move operation .then(() => { - const targetResource = URI.file(paths.join(target.resource.fsPath, source.name)); + const targetResource = target.resource.with({ path: paths.join(target.resource.path, source.name) }); let didHandleConflict = false; return this.fileService.moveFile(source.resource, targetResource).then(null, error => { @@ -1005,7 +1006,7 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { // Move with overwrite if the user confirms if (this.messageService.confirm(confirm)) { - const targetDirty = this.textFileService.getDirty().filter(d => paths.isEqualOrParent(d.fsPath, targetResource.fsPath, !isLinux /* ignorecase */)); + const targetDirty = this.textFileService.getDirty().filter(d => resources.isEqualOrParent(d, targetResource, !isLinux /* ignorecase */)); // Make sure to revert all dirty in target first to be able to overwrite properly return this.textFileService.revertAll(targetDirty, { soft: true /* do not attempt to load content from disk */ }).then(() => { From bef99125c71912803aaff7658eba0d8be597bd86 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 19 Sep 2017 18:05:51 +0200 Subject: [PATCH 056/281] :lipstick: --- .../services/workspace/node/workspaceEditingService.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts index 173f8e1d103..e1789dfa8af 100644 --- a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts @@ -99,15 +99,9 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { } private doSetFolders(folders: IStoredWorkspaceFolder[]): TPromise { - if (folders.length) { - const workspace = this.contextService.getWorkspace(); + const workspace = this.contextService.getWorkspace(); - return this.jsonEditingService.write(workspace.configuration, { key: 'folders', value: folders }, true); - } else { - // TODO: Sandeep - Removing all folders? - } - - return TPromise.as(void 0); + return this.jsonEditingService.write(workspace.configuration, { key: 'folders', value: folders }, true); } private isSupported(): boolean { From c19f1d76e00c4ee87618e67db224bbd037681362 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 19 Sep 2017 18:25:34 +0200 Subject: [PATCH 057/281] pickWorkspace => pickWorkspaceFolder --- src/vs/workbench/browser/actions/workspaceActions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index 3ab372f4166..58f09abc65b 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -287,9 +287,9 @@ export class OpenWorkspaceConfigFileAction extends Action { } } -export const PICK_WORKSPACE_COMMAND = '_workbench.pickWorkspace'; +export const PICK_WORKSPACE_FOLDER_COMMAND = '_workbench.pickWorkspaceFolder'; -CommandsRegistry.registerCommand(PICK_WORKSPACE_COMMAND, function (accessor: ServicesAccessor, args?: [IPickOptions, CancellationToken]) { +CommandsRegistry.registerCommand(PICK_WORKSPACE_FOLDER_COMMAND, function (accessor: ServicesAccessor, args?: [IPickOptions, CancellationToken]) { const contextService = accessor.get(IWorkspaceContextService); const quickOpenService = accessor.get(IQuickOpenService); const environmentService = accessor.get(IEnvironmentService); From 933e0a8127f508ceec2cd446a85d6e7454ae22b5 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 19 Sep 2017 11:03:02 -0700 Subject: [PATCH 058/281] Fix markdown table of contents name for strings like # ff Fixes #34644 --- extensions/markdown/src/tableOfContentsProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/markdown/src/tableOfContentsProvider.ts b/extensions/markdown/src/tableOfContentsProvider.ts index 26e64e4d837..c93dd25f6e7 100644 --- a/extensions/markdown/src/tableOfContentsProvider.ts +++ b/extensions/markdown/src/tableOfContentsProvider.ts @@ -79,7 +79,7 @@ export class TableOfContentsProvider { } private static getHeaderText(header: string): string { - return header.replace(/^\s*#+\s*(.*?)\s*\1*$/, (_, word) => `${word.trim()}`); + return header.replace(/^\s*#+\s*(.*?)\s*#*$/, (_, word) => word.trim()); } public static slugify(header: string): string { From 4f599ae71d21a58c6457e031e077e2057686f5be Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Tue, 19 Sep 2017 20:41:19 +0100 Subject: [PATCH 059/281] Update .tsx import statement snippet to be consistent with .ts (#34653) Fixes https://github.com/Microsoft/vscode/issues/34646 --- extensions/typescript/snippets/typescriptreact.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/typescript/snippets/typescriptreact.json b/extensions/typescript/snippets/typescriptreact.json index c0d38f23c18..894d6177276 100644 --- a/extensions/typescript/snippets/typescriptreact.json +++ b/extensions/typescript/snippets/typescriptreact.json @@ -50,7 +50,7 @@ "Import external module.": { "prefix": "import statement", "body": [ - "import ${1:name} = require('$0');" + "import { $0 } from \"${1:module}\";" ], "description": "Import external module." }, From e090c114142785d054810fa197ac57a5b18b7b24 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 19 Sep 2017 22:57:05 +0200 Subject: [PATCH 060/281] Implement #34659 --- .../common/extensionManagement.ts | 8 +- .../node/extensionManagementService.ts | 176 ++++++++---------- .../node/extensionsWorkbenchService.ts | 10 +- 3 files changed, 93 insertions(+), 101 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 24d82c47bb5..b68462db6f9 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -228,12 +228,18 @@ export interface InstallExtensionEvent { gallery?: IGalleryExtension; } +export enum ErrorCode { + OBSOLETE = 1, + GALLERY, + LOCAL +} + export interface DidInstallExtensionEvent { id: string; zipPath?: string; gallery?: IGalleryExtension; local?: ILocalExtension; - error?: Error; + error?: ErrorCode; } export interface DidUninstallExtensionEvent { diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 24f88da7d2a..ce0bae03b33 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -18,7 +18,8 @@ import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IExtensionManifest, IGalleryMetadata, InstallExtensionEvent, DidInstallExtensionEvent, DidUninstallExtensionEvent, LocalExtensionType, - StatisticType + StatisticType, + ErrorCode } from 'vs/platform/extensionManagement/common/extensionManagement'; import { getLocalExtensionIdFromGallery, getLocalExtensionIdFromManifest, getGalleryExtensionIdFromLocal, getIdAndVersionFromLocalExtensionId, adoptToGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { localizeManifest } from '../common/extensionNls'; @@ -68,6 +69,12 @@ function readManifest(extensionPath: string): TPromise<{ manifest: IExtensionMan }); } +interface InstallableExtension { + zipPath: string; + id: string; + metadata: IGalleryMetadata; +} + export class ExtensionManagementService implements IExtensionManagementService { _serviceBrand: any; @@ -107,12 +114,12 @@ export class ExtensionManagementService implements IExtensionManagementService { return this.isObsolete(id).then(isObsolete => { if (isObsolete) { - return TPromise.wrapError(new Error(nls.localize('restartCode', "Please restart Code before reinstalling {0}.", manifest.displayName || manifest.name))); + return TPromise.wrapError(new Error(nls.localize('restartCodeLocal', "Please restart Code before reinstalling {0}.", manifest.displayName || manifest.name))); } this._onInstallExtension.fire({ id, zipPath }); - return this.installExtension(zipPath, id) + return this.installExtension({ zipPath, id, metadata: null }) .then( local => this._onDidInstallExtension.fire({ id, zipPath, local }), error => { this._onDidInstallExtension.fire({ id, zipPath, error }); return TPromise.wrapError(error); } @@ -122,91 +129,83 @@ export class ExtensionManagementService implements IExtensionManagementService { } installFromGallery(extension: IGalleryExtension): TPromise { - const id = getLocalExtensionIdFromGallery(extension, extension.version); + return this.prepareAndCollectExtensionsToInstall(extension) + .then(extensionsToInstall => this.downloadAndInstallExtensions(extensionsToInstall) + .then(local => this.onDidInstallExtensions(extensionsToInstall, local))); + } - return this.isObsolete(id).then(isObsolete => { - if (isObsolete) { - return TPromise.wrapError(new Error(nls.localize('restartCode', "Please restart Code before reinstalling {0}.", extension.displayName || extension.name))); - } - this._onInstallExtension.fire({ id, gallery: extension }); - return this.installCompatibleVersion(extension, true) + private prepareAndCollectExtensionsToInstall(extension: IGalleryExtension): TPromise { + this.onInstallExtensions([extension]); + return this.collectExtensionsToInstall(extension) + .then( + extensionsToInstall => this.checkForObsolete(extensionsToInstall) .then( - local => this._onDidInstallExtension.fire({ id, local, gallery: extension }), - error => { - this._onDidInstallExtension.fire({ id, gallery: extension, error }); - return TPromise.wrapError(error); - } - ); - }); - } - - private installCompatibleVersion(extension: IGalleryExtension, installDependencies: boolean): TPromise { - return this.galleryService.loadCompatibleVersion(extension) - .then(compatibleVersion => this.getDependenciesToInstall(extension, installDependencies) - .then(dependencies => dependencies.length ? this.installWithDependencies(compatibleVersion) : this.downloadAndInstall(compatibleVersion))); - } - - private getDependenciesToInstall(extension: IGalleryExtension, checkDependecies: boolean): TPromise { - if (!checkDependecies) { - return TPromise.wrap([]); - } - // Filter out self - const dependencies = extension.properties.dependencies ? extension.properties.dependencies.filter(id => id !== extension.id) : []; - if (!dependencies.length) { - return TPromise.wrap([]); - } - // Filter out installed dependencies - return this.getInstalled().then(installed => { - return dependencies.filter(dep => installed.every(i => `${i.manifest.publisher}.${i.manifest.name}` !== dep)); - }); - } - - private installWithDependencies(extension: IGalleryExtension): TPromise { - return this.galleryService.getAllDependencies(extension) - .then(allDependencies => this.filterDependenciesToInstall(extension, allDependencies)) - .then(toInstall => this.filterObsolete(...toInstall.map(i => getLocalExtensionIdFromGallery(i, i.version))) - .then((obsolete) => { - if (obsolete.length) { - return TPromise.wrapError(new Error(nls.localize('restartCode', "Please restart Code before reinstalling {0}.", extension.displayName || extension.name))); + extensionsToInstall => { + if (extensionsToInstall.length > 1) { + this.onInstallExtensions(extensionsToInstall.slice(1)); } - return this.bulkInstallWithDependencies(extension, toInstall); - }) + return extensionsToInstall; + }, + error => this.onDidInstallExtensions([extension], null, ErrorCode.OBSOLETE, error) + ), + error => this.onDidInstallExtensions([extension], null, ErrorCode.GALLERY, error) ); } - private bulkInstallWithDependencies(extension: IGalleryExtension, dependecies: IGalleryExtension[]): TPromise { - for (const dependency of dependecies) { - const id = getLocalExtensionIdFromGallery(dependency, dependency.version); - this._onInstallExtension.fire({ id, gallery: dependency }); - } - return this.downloadAndInstall(extension) - .then(localExtension => { - return TPromise.join(dependecies.map((dep) => this.installCompatibleVersion(dep, false))) - .then(installedLocalExtensions => { - for (const installedLocalExtension of installedLocalExtensions) { - const gallery = this.getGalleryExtensionForLocalExtension(dependecies, installedLocalExtension); - this._onDidInstallExtension.fire({ id: installedLocalExtension.id, local: installedLocalExtension, gallery }); - } - return localExtension; - }, error => { - return this.rollback(localExtension, dependecies).then(() => { - return TPromise.wrapError(Array.isArray(error) ? error[error.length - 1] : error); - }); - }); - }) - .then(localExtension => localExtension, error => { - for (const dependency of dependecies) { - this._onDidInstallExtension.fire({ id: getLocalExtensionIdFromGallery(dependency, dependency.version), gallery: dependency, error }); - } - return TPromise.wrapError(error); - }); + private downloadAndInstallExtensions(extensions: IGalleryExtension[]): TPromise { + return TPromise.join(extensions.map(extensionToInstall => this.downloadInstallableExtension(extensionToInstall))) + .then( + installableExtensions => TPromise.join(installableExtensions.map(installableExtension => this.installExtension(installableExtension))) + .then(null, error => this.rollback(extensions).then(() => this.onDidInstallExtensions(extensions, null, ErrorCode.LOCAL, error))), + error => this.onDidInstallExtensions(extensions, null, ErrorCode.GALLERY, error)); } - private rollback(localExtension: ILocalExtension, dependecies: IGalleryExtension[]): TPromise { - return this.doUninstall(localExtension) - .then(() => this.filterOutUninstalled(dependecies)) - .then(installed => TPromise.join(installed.map((i) => this.doUninstall(i)))) - .then(() => null); + private collectExtensionsToInstall(extension: IGalleryExtension): TPromise { + return this.galleryService.loadCompatibleVersion(extension) + .then(extensionToInstall => this.galleryService.getAllDependencies(extension) + .then(allDependencies => this.filterDependenciesToInstall(extension, allDependencies)) + .then(dependenciesToInstall => [extensionToInstall, ...dependenciesToInstall])); + } + + private checkForObsolete(extensionsToInstall: IGalleryExtension[]): TPromise { + return this.filterObsolete(...extensionsToInstall.map(i => getLocalExtensionIdFromGallery(i, i.version))) + .then(obsolete => obsolete.length ? TPromise.wrapError(new Error(nls.localize('restartCodeGallery', "Please restart Code before reinstalling."))) : extensionsToInstall); + } + + private downloadInstallableExtension(extension: IGalleryExtension): TPromise { + const id = getLocalExtensionIdFromGallery(extension, extension.version); + const metadata = { + id: extension.uuid, + publisherId: extension.publisherId, + publisherDisplayName: extension.publisherDisplayName, + }; + return this.galleryService.download(extension) + .then(zipPath => validate(zipPath).then(() => ({ zipPath, id, metadata }))); + } + + private rollback(extensions: IGalleryExtension[]): TPromise { + return this.filterOutUninstalled(extensions) + .then(installed => TPromise.join(installed.map(local => this.uninstallExtension(local.id)))) + .then(() => null, () => null); + } + + private onInstallExtensions(extensions: IGalleryExtension[]): void { + for (const extension of extensions) { + const id = getLocalExtensionIdFromGallery(extension, extension.version); + this._onInstallExtension.fire({ id, gallery: extension }); + } + } + + private onDidInstallExtensions(extensions: IGalleryExtension[], local: ILocalExtension[], errorCode?: ErrorCode, error?: any): TPromise { + extensions.forEach((gallery, index) => { + const id = getLocalExtensionIdFromGallery(gallery, gallery.version); + if (errorCode) { + this._onDidInstallExtension.fire({ id, gallery, error: errorCode }); + } else { + this._onDidInstallExtension.fire({ id, gallery, local: local[index] }); + } + }); + return error ? TPromise.wrapError(Array.isArray(error) ? this.joinErrors(error) : error) : TPromise.as(null); } private filterDependenciesToInstall(extension: IGalleryExtension, dependencies: IGalleryExtension[]): TPromise { @@ -232,20 +231,7 @@ export class ExtensionManagementService implements IExtensionManagementService { return filtered.length ? filtered[0] : null; } - private downloadAndInstall(extension: IGalleryExtension): TPromise { - const id = getLocalExtensionIdFromGallery(extension, extension.version); - const metadata = { - id: extension.uuid, - publisherId: extension.publisherId, - publisherDisplayName: extension.publisherDisplayName, - }; - - return this.galleryService.download(extension) - .then(zipPath => validate(zipPath).then(() => zipPath)) - .then(zipPath => this.installExtension(zipPath, id, metadata)); - } - - private installExtension(zipPath: string, id: string, metadata: IGalleryMetadata = null): TPromise { + private installExtension({ zipPath, id, metadata }: InstallableExtension): TPromise { const extensionPath = path.join(this.extensionsPath, id); return pfs.rimraf(extensionPath).then(() => { @@ -291,7 +277,7 @@ export class ExtensionManagementService implements IExtensionManagementService { } return errors.reduce((previousValue: Error, currentValue: Error | string) => { - return new Error(`${previousValue.message}\n${currentValue instanceof Error ? currentValue.message : currentValue}`); + return new Error(`${previousValue.message}${previousValue.message ? ',' : ''}${currentValue instanceof Error ? currentValue.message : currentValue}`); }, new Error('')); } diff --git a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts index 9cebb13bc64..d05db9e48fe 100644 --- a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts @@ -20,7 +20,7 @@ import { IPager, mapPager, singlePagePager } from 'vs/base/common/paging'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions, IExtensionManifest, - InstallExtensionEvent, DidInstallExtensionEvent, LocalExtensionType, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionTipsService + InstallExtensionEvent, DidInstallExtensionEvent, LocalExtensionType, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionTipsService, ErrorCode } from 'vs/platform/extensionManagement/common/extensionManagement'; import { getGalleryExtensionIdFromLocal, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -725,7 +725,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { } if (extension.gallery) { // Report telemetry only for gallery extensions - this.reportTelemetry(installing, !error); + this.reportTelemetry(installing, error); } } this._onChange.fire(); @@ -759,7 +759,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { } if (!error) { - this.reportTelemetry(uninstalling, true); + this.reportTelemetry(uninstalling); } this._onChange.fire(); @@ -789,12 +789,12 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return local ? ExtensionState.Installed : ExtensionState.Uninstalled; } - private reportTelemetry(active: IActiveExtension, success: boolean): void { + private reportTelemetry(active: IActiveExtension, errorcode?: ErrorCode): void { const data = active.extension.telemetryData; const duration = new Date().getTime() - active.start.getTime(); const eventName = toTelemetryEventName(active.operation); - this.telemetryService.publicLog(eventName, assign(data, { success, duration })); + this.telemetryService.publicLog(eventName, assign(data, { success: !errorcode, duration, errorcode })); } private onError(err: any): void { From a79a99078626299b81e29f695fdf9cca562749ec Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 19 Sep 2017 23:06:13 +0200 Subject: [PATCH 061/281] #34659 Use error code in uninstall event --- .../extensionManagement/common/extensionManagement.ts | 2 +- .../extensionManagement/node/extensionManagementService.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index b68462db6f9..df42ecd966c 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -244,7 +244,7 @@ export interface DidInstallExtensionEvent { export interface DidUninstallExtensionEvent { id: string; - error?: Error; + error?: ErrorCode; } export interface IExtensionManagementService { diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index ce0bae03b33..ae321626480 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -286,7 +286,7 @@ export class ExtensionManagementService implements IExtensionManagementService { .then(() => this.hasDependencies(extension, installed) ? this.promptForDependenciesAndUninstall(extension, installed, force) : this.promptAndUninstall(extension, installed, force)) .then(() => this.postUninstallExtension(extension), error => { - this.postUninstallExtension(extension, error); + this.postUninstallExtension(extension, ErrorCode.LOCAL); return TPromise.wrapError(error); }); } @@ -402,7 +402,7 @@ export class ExtensionManagementService implements IExtensionManagementService { .then(() => this.uninstallExtension(extension.id)) .then(() => this.postUninstallExtension(extension), error => { - this.postUninstallExtension(extension, error); + this.postUninstallExtension(extension, ErrorCode.LOCAL); return TPromise.wrapError(error); }); } @@ -421,7 +421,7 @@ export class ExtensionManagementService implements IExtensionManagementService { .then(() => this.unsetObsolete(id)); } - private async postUninstallExtension(extension: ILocalExtension, error?: any): TPromise { + private async postUninstallExtension(extension: ILocalExtension, error?: ErrorCode): TPromise { if (!error) { await this.galleryService.reportStatistic(extension.manifest.publisher, extension.manifest.name, extension.manifest.version, StatisticType.Uninstall); } From 358641a473476ab237fb460572d87921fb699932 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 19 Sep 2017 15:12:51 -0700 Subject: [PATCH 062/281] Run --export-default-configuration with fresh user-data-dir and extensions-dir --- build/gulpfile.vscode.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 3c351d454ad..81dd6d2a7a8 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -479,8 +479,10 @@ gulp.task('generate-vscode-configuration', () => { return reject(new Error('$AGENT_BUILDDIRECTORY not set')); } + const userDataDir = path.join(os.tmpdir(), 'tmpuserdata'); + const extensionsDir = path.join(os.tmpdir(), 'tmpextdir'); const appPath = path.join(buildDir, 'VSCode-darwin/Visual\\ Studio\\ Code\\ -\\ Insiders.app/Contents/Resources/app/bin/code'); - const codeProc = cp.exec(`${appPath} --export-default-configuration='${allConfigDetailsPath}' --wait`); + const codeProc = cp.exec(`${appPath} --export-default-configuration='${allConfigDetailsPath}' --wait --user-data-dir='${userDataDir}' --extensions-dir='${extensionsDir}'`); const timer = setTimeout(() => { codeProc.kill(); From 6d6d83b2f542c4618aa6ff535a67864c54177a7c Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 19 Sep 2017 16:35:52 -0700 Subject: [PATCH 063/281] Pick up latest TS 2.5.3 insiders Fixes #33972 --- extensions/npm-shrinkwrap.json | 6 +++--- extensions/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/npm-shrinkwrap.json b/extensions/npm-shrinkwrap.json index 2cdcc763dd5..cf47f857cf2 100644 --- a/extensions/npm-shrinkwrap.json +++ b/extensions/npm-shrinkwrap.json @@ -3,9 +3,9 @@ "version": "0.0.1", "dependencies": { "typescript": { - "version": "2.5.3-insiders.20170909", - "from": "typescript@2.5.3-insiders.20170909", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3-insiders.20170909.tgz" + "version": "2.5.3-insiders.20170919", + "from": "typescript@2.5.3-insiders.20170919", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3-insiders.20170919.tgz" } } } diff --git a/extensions/package.json b/extensions/package.json index 3ad8d484a3d..9e0ef9f6fd2 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "2.5.3-insiders.20170909" + "typescript": "2.5.3-insiders.20170919" }, "scripts": { "postinstall": "node ./postinstall" From ce3c4b3ca0b8ce7ca97bae058a243ca8dc8f5f4f Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 20 Sep 2017 09:08:02 +0900 Subject: [PATCH 064/281] Uplevel xterm.js Fixes #34493 Fixes #34563 --- npm-shrinkwrap.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index ad603585240..35551d36615 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -574,7 +574,7 @@ "xterm": { "version": "3.0.0", "from": "Tyriar/xterm.js#vscode-release/1.17", - "resolved": "git+https://github.com/Tyriar/xterm.js.git#35088059e61ba654ac78df453633c7a9272ed8bd" + "resolved": "git+https://github.com/Tyriar/xterm.js.git#851dff7253fc9718bb90f691fc79a7c3c542bcfa" }, "yauzl": { "version": "2.8.0", From 474a29ee48f39b31288268c933a03825ed62213e Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 19 Sep 2017 17:59:08 -0700 Subject: [PATCH 065/281] Replace duplicated textSpan conversion logic --- .../src/features/baseCodeLensProvider.ts | 6 ++---- .../typescript/src/features/codeActionProvider.ts | 5 ++--- .../src/features/completionItemProvider.ts | 3 ++- .../src/features/definitionProviderBase.ts | 5 +++-- .../src/features/documentHighlightProvider.ts | 9 +++++---- .../src/features/documentSymbolProvider.ts | 10 ++++------ .../typescript/src/features/formattingProvider.ts | 4 ++-- .../typescript/src/features/hoverProvider.ts | 5 +++-- .../features/implementationsCodeLensProvider.ts | 5 ++--- .../typescript/src/features/refactorProvider.ts | 5 ++--- .../typescript/src/features/referenceProvider.ts | 7 +++---- .../src/features/referencesCodeLensProvider.ts | 6 ++---- .../typescript/src/features/renameProvider.ts | 7 +++---- .../src/features/workspaceSymbolProvider.ts | 5 +++-- extensions/typescript/src/utils/convert.ts | 14 ++++++++++++++ 15 files changed, 52 insertions(+), 44 deletions(-) create mode 100644 extensions/typescript/src/utils/convert.ts diff --git a/extensions/typescript/src/features/baseCodeLensProvider.ts b/extensions/typescript/src/features/baseCodeLensProvider.ts index 84ba69a0a96..cb8e675db4d 100644 --- a/extensions/typescript/src/features/baseCodeLensProvider.ts +++ b/extensions/typescript/src/features/baseCodeLensProvider.ts @@ -7,6 +7,7 @@ import { CodeLensProvider, CodeLens, CancellationToken, TextDocument, Range, Uri import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; +import { textSpanToRange } from '../utils/convert'; export class ReferencesCodeLens extends CodeLens { constructor( @@ -99,10 +100,7 @@ export abstract class TypeScriptBaseCodeLensProvider implements CodeLensProvider return null; } - const range = new Range( - span.start.line - 1, span.start.offset - 1, - span.end.line - 1, span.end.offset - 1); - + const range = textSpanToRange(span); const text = document.getText(range); const identifierMatch = new RegExp(`^(.*?(\\b|\\W))${(item.text || '').replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')}(\\b|\\W)`, 'gm'); diff --git a/extensions/typescript/src/features/codeActionProvider.ts b/extensions/typescript/src/features/codeActionProvider.ts index c48caaf79e4..925eac1fff4 100644 --- a/extensions/typescript/src/features/codeActionProvider.ts +++ b/extensions/typescript/src/features/codeActionProvider.ts @@ -7,6 +7,7 @@ import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionC import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; +import { textSpanToRange } from '../utils/convert'; interface NumberSet { [key: number]: boolean; @@ -112,9 +113,7 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider for (const change of action.changes) { for (const textChange of change.textChanges) { workspaceEdit.replace(this.client.asUrl(change.fileName), - new Range( - textChange.start.line - 1, textChange.start.offset - 1, - textChange.end.line - 1, textChange.end.offset - 1), + textSpanToRange(textChange), textChange.newText); } } diff --git a/extensions/typescript/src/features/completionItemProvider.ts b/extensions/typescript/src/features/completionItemProvider.ts index 1fbcb707863..759642b929d 100644 --- a/extensions/typescript/src/features/completionItemProvider.ts +++ b/extensions/typescript/src/features/completionItemProvider.ts @@ -11,6 +11,7 @@ import TypingsStatus from '../utils/typingsStatus'; import * as PConst from '../protocol.const'; import { CompletionEntry, CompletionsRequestArgs, CompletionDetailsRequestArgs, CompletionEntryDetails, FileLocationRequestArgs } from '../protocol'; import * as Previewer from './previewer'; +import { textSpanToRange } from '../utils/convert'; import * as nls from 'vscode-nls'; let localize = nls.loadMessageBundle(); @@ -32,7 +33,7 @@ class MyCompletionItem extends CompletionItem { let span: protocol.TextSpan = entry.replacementSpan; // The indexing for the range returned by the server uses 1-based indexing. // We convert to 0-based indexing. - this.textEdit = TextEdit.replace(new Range(span.start.line - 1, span.start.offset - 1, span.end.line - 1, span.end.offset - 1), entry.name); + this.textEdit = TextEdit.replace(textSpanToRange(span), entry.name); } else { // Try getting longer, prefix based range for completions that span words const wordRange = document.getWordRangeAtPosition(position); diff --git a/extensions/typescript/src/features/definitionProviderBase.ts b/extensions/typescript/src/features/definitionProviderBase.ts index 78768df2fee..e137a1e3de7 100644 --- a/extensions/typescript/src/features/definitionProviderBase.ts +++ b/extensions/typescript/src/features/definitionProviderBase.ts @@ -3,10 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { TextDocument, Position, Range, CancellationToken, Location } from 'vscode'; +import { TextDocument, Position, CancellationToken, Location } from 'vscode'; import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; +import { textSpanToRange } from '../utils/convert'; export default class TypeScriptDefinitionProviderBase { constructor( @@ -37,7 +38,7 @@ export default class TypeScriptDefinitionProviderBase { if (resource === null) { return null; } else { - return new Location(resource, new Range(location.start.line - 1, location.start.offset - 1, location.end.line - 1, location.end.offset - 1)); + return new Location(resource, textSpanToRange(location)); } }).filter(x => x !== null) as Location[]; }, () => { diff --git a/extensions/typescript/src/features/documentHighlightProvider.ts b/extensions/typescript/src/features/documentHighlightProvider.ts index 15224ca2c2e..97733afb1ce 100644 --- a/extensions/typescript/src/features/documentHighlightProvider.ts +++ b/extensions/typescript/src/features/documentHighlightProvider.ts @@ -7,6 +7,7 @@ import { DocumentHighlightProvider, DocumentHighlight, DocumentHighlightKind, Te import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; +import { textSpanToRange } from '../utils/convert'; export default class TypeScriptDocumentHighlightProvider implements DocumentHighlightProvider { @@ -37,10 +38,10 @@ export default class TypeScriptDocumentHighlightProvider implements DocumentHigh return []; } } - return data.map((item) => { - return new DocumentHighlight(new Range(item.start.line - 1, item.start.offset - 1, item.end.line - 1, item.end.offset - 1), - item.isWriteAccess ? DocumentHighlightKind.Write : DocumentHighlightKind.Read); - }); + return data.map(item => + new DocumentHighlight( + textSpanToRange(item), + item.isWriteAccess ? DocumentHighlightKind.Write : DocumentHighlightKind.Read)); } return []; }, () => { diff --git a/extensions/typescript/src/features/documentSymbolProvider.ts b/extensions/typescript/src/features/documentSymbolProvider.ts index 456776cf3a6..57f507840d8 100644 --- a/extensions/typescript/src/features/documentSymbolProvider.ts +++ b/extensions/typescript/src/features/documentSymbolProvider.ts @@ -3,11 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { DocumentSymbolProvider, SymbolInformation, SymbolKind, TextDocument, Range, Location, CancellationToken, Uri } from 'vscode'; +import { DocumentSymbolProvider, SymbolInformation, SymbolKind, TextDocument, Location, CancellationToken, Uri } from 'vscode'; import * as Proto from '../protocol'; import * as PConst from '../protocol.const'; import { ITypescriptServiceClient } from '../typescriptService'; +import { textSpanToRange } from '../utils/convert'; const outlineTypeTable: { [kind: string]: SymbolKind } = Object.create(null); outlineTypeTable[PConst.Kind.module] = SymbolKind.Module; @@ -25,9 +26,6 @@ outlineTypeTable[PConst.Kind.variable] = SymbolKind.Variable; outlineTypeTable[PConst.Kind.function] = SymbolKind.Function; outlineTypeTable[PConst.Kind.localFunction] = SymbolKind.Function; -function textSpan2Range(value: Proto.TextSpan): Range { - return new Range(value.start.line - 1, value.start.offset - 1, value.end.line - 1, value.end.offset - 1); -} export default class TypeScriptDocumentSymbolProvider implements DocumentSymbolProvider { public constructor( @@ -73,7 +71,7 @@ export default class TypeScriptDocumentSymbolProvider implements DocumentSymbolP let result = new SymbolInformation(item.text, outlineTypeTable[item.kind as string] || SymbolKind.Variable, containerLabel ? containerLabel : '', - new Location(resource, textSpan2Range(item.spans[0]))); + new Location(resource, textSpanToRange(item.spans[0]))); foldingMap[key] = result; bucket.push(result); } @@ -88,7 +86,7 @@ export default class TypeScriptDocumentSymbolProvider implements DocumentSymbolP const result = new SymbolInformation(item.text, outlineTypeTable[item.kind as string] || SymbolKind.Variable, containerLabel ? containerLabel : '', - new Location(resource, textSpan2Range(item.spans[0])) + new Location(resource, textSpanToRange(item.spans[0])) ); if (item.childItems && item.childItems.length > 0) { for (const child of item.childItems) { diff --git a/extensions/typescript/src/features/formattingProvider.ts b/extensions/typescript/src/features/formattingProvider.ts index 1c5e7866b8f..10e20dd9b39 100644 --- a/extensions/typescript/src/features/formattingProvider.ts +++ b/extensions/typescript/src/features/formattingProvider.ts @@ -7,6 +7,7 @@ import { workspace as Workspace, DocumentRangeFormattingEditProvider, OnTypeForm import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; +import { textSpanToRange } from '../utils/convert'; interface Configuration { enable: boolean; @@ -205,8 +206,7 @@ export class TypeScriptFormattingProvider implements DocumentRangeFormattingEdit } private codeEdit2SingleEditOperation(edit: Proto.CodeEdit): TextEdit { - return new TextEdit(new Range(edit.start.line - 1, edit.start.offset - 1, edit.end.line - 1, edit.end.offset - 1), - edit.newText); + return new TextEdit(textSpanToRange(edit), edit.newText); } private getFormatOptions(options: FormattingOptions): Proto.FormatCodeSettings { diff --git a/extensions/typescript/src/features/hoverProvider.ts b/extensions/typescript/src/features/hoverProvider.ts index 9fd1483b625..89971ba5b61 100644 --- a/extensions/typescript/src/features/hoverProvider.ts +++ b/extensions/typescript/src/features/hoverProvider.ts @@ -3,11 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { HoverProvider, Hover, TextDocument, Position, Range, CancellationToken } from 'vscode'; +import { HoverProvider, Hover, TextDocument, Position, CancellationToken } from 'vscode'; import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; import { tagsMarkdownPreview } from './previewer'; +import { textSpanToRange } from '../utils/convert'; export default class TypeScriptHoverProvider implements HoverProvider { @@ -31,7 +32,7 @@ export default class TypeScriptHoverProvider implements HoverProvider { const data = response.body; return new Hover( TypeScriptHoverProvider.getContents(data), - new Range(data.start.line - 1, data.start.offset - 1, data.end.line - 1, data.end.offset - 1)); + textSpanToRange(data)); } } catch (e) { // noop diff --git a/extensions/typescript/src/features/implementationsCodeLensProvider.ts b/extensions/typescript/src/features/implementationsCodeLensProvider.ts index 30daa644a4e..9a6d1a79b42 100644 --- a/extensions/typescript/src/features/implementationsCodeLensProvider.ts +++ b/extensions/typescript/src/features/implementationsCodeLensProvider.ts @@ -9,6 +9,7 @@ import * as PConst from '../protocol.const'; import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens } from './baseCodeLensProvider'; import { ITypescriptServiceClient } from '../typescriptService'; +import { textSpanToRange } from '../utils/convert'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); @@ -50,9 +51,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip // Only take first line on implementation: https://github.com/Microsoft/vscode/issues/23924 new Location(this.client.asUrl(reference.file), reference.start.line === reference.end.line - ? new Range( - reference.start.line - 1, reference.start.offset - 1, - reference.end.line - 1, reference.end.offset - 1) + ? textSpanToRange(reference) : new Range( reference.start.line - 1, reference.start.offset - 1, reference.start.line, 0))) diff --git a/extensions/typescript/src/features/refactorProvider.ts b/extensions/typescript/src/features/refactorProvider.ts index 1b9062998b5..563160640c9 100644 --- a/extensions/typescript/src/features/refactorProvider.ts +++ b/extensions/typescript/src/features/refactorProvider.ts @@ -9,6 +9,7 @@ import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionC import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; +import { textSpanToRange } from '../utils/convert'; export default class TypeScriptRefactorProvider implements CodeActionProvider { @@ -85,9 +86,7 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { for (const edit of edits) { for (const textChange of edit.textChanges) { workspaceEdit.replace(this.client.asUrl(edit.fileName), - new Range( - textChange.start.line - 1, textChange.start.offset - 1, - textChange.end.line - 1, textChange.end.offset - 1), + textSpanToRange(textChange), textChange.newText); } } diff --git a/extensions/typescript/src/features/referenceProvider.ts b/extensions/typescript/src/features/referenceProvider.ts index 9f7ccf9f49a..b6af1f23033 100644 --- a/extensions/typescript/src/features/referenceProvider.ts +++ b/extensions/typescript/src/features/referenceProvider.ts @@ -3,10 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ReferenceProvider, Location, TextDocument, Position, Range, CancellationToken } from 'vscode'; +import { ReferenceProvider, Location, TextDocument, Position, CancellationToken } from 'vscode'; import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; +import { textSpanToRange } from '../utils/convert'; export default class TypeScriptReferenceSupport implements ReferenceProvider { public constructor( @@ -35,9 +36,7 @@ export default class TypeScriptReferenceSupport implements ReferenceProvider { continue; } const url = this.client.asUrl(ref.file); - const location = new Location( - url, - new Range(ref.start.line - 1, ref.start.offset - 1, ref.end.line - 1, ref.end.offset - 1)); + const location = new Location(url, textSpanToRange(ref)); result.push(location); } return result; diff --git a/extensions/typescript/src/features/referencesCodeLensProvider.ts b/extensions/typescript/src/features/referencesCodeLensProvider.ts index 5576bfc4825..40c56f48df9 100644 --- a/extensions/typescript/src/features/referencesCodeLensProvider.ts +++ b/extensions/typescript/src/features/referencesCodeLensProvider.ts @@ -9,6 +9,7 @@ import * as PConst from '../protocol.const'; import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens } from './baseCodeLensProvider'; import { ITypescriptServiceClient } from '../typescriptService'; +import { textSpanToRange } from '../utils/convert'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); @@ -47,10 +48,7 @@ export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBase const locations = response.body.refs .map(reference => - new Location(this.client.asUrl(reference.file), - new Range( - reference.start.line - 1, reference.start.offset - 1, - reference.end.line - 1, reference.end.offset - 1))) + new Location(this.client.asUrl(reference.file), textSpanToRange(reference))) .filter(location => // Exclude original definition from references !(location.uri.fsPath === codeLens.document.fsPath && diff --git a/extensions/typescript/src/features/renameProvider.ts b/extensions/typescript/src/features/renameProvider.ts index 291be640ca7..e7adfc1cea7 100644 --- a/extensions/typescript/src/features/renameProvider.ts +++ b/extensions/typescript/src/features/renameProvider.ts @@ -3,10 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { RenameProvider, WorkspaceEdit, TextDocument, Position, Range, CancellationToken } from 'vscode'; +import { RenameProvider, WorkspaceEdit, TextDocument, Position, CancellationToken } from 'vscode'; import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; +import { textSpanToRange } from '../utils/convert'; export default class TypeScriptRenameProvider implements RenameProvider { public constructor( @@ -49,9 +50,7 @@ export default class TypeScriptRenameProvider implements RenameProvider { continue; } for (const textSpan of spanGroup.locs) { - result.replace(resource, - new Range(textSpan.start.line - 1, textSpan.start.offset - 1, textSpan.end.line - 1, textSpan.end.offset - 1), - newName); + result.replace(resource, textSpanToRange(textSpan), newName); } } return result; diff --git a/extensions/typescript/src/features/workspaceSymbolProvider.ts b/extensions/typescript/src/features/workspaceSymbolProvider.ts index ab2329501a3..6ebc45b36bb 100644 --- a/extensions/typescript/src/features/workspaceSymbolProvider.ts +++ b/extensions/typescript/src/features/workspaceSymbolProvider.ts @@ -3,10 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { workspace, window, Uri, WorkspaceSymbolProvider, SymbolInformation, SymbolKind, Range, Location, CancellationToken } from 'vscode'; +import { workspace, window, Uri, WorkspaceSymbolProvider, SymbolInformation, SymbolKind, Location, CancellationToken } from 'vscode'; import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; +import { textSpanToRange } from '../utils/convert'; function getSymbolKind(item: Proto.NavtoItem): SymbolKind { switch (item.kind) { @@ -67,7 +68,7 @@ export default class TypeScriptWorkspaceSymbolProvider implements WorkspaceSymbo if (!item.containerName && item.kind === 'alias') { continue; } - const range = new Range(item.start.line - 1, item.start.offset - 1, item.end.line - 1, item.end.offset - 1); + const range = textSpanToRange(item); let label = item.name; if (item.kind === 'method' || item.kind === 'function') { label += '()'; diff --git a/extensions/typescript/src/utils/convert.ts b/extensions/typescript/src/utils/convert.ts new file mode 100644 index 00000000000..92511d1fb1a --- /dev/null +++ b/extensions/typescript/src/utils/convert.ts @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Range } from 'vscode'; + +import * as Proto from '../protocol'; + + +export const textSpanToRange = (span: Proto.TextSpan) => + new Range( + span.start.line - 1, span.start.offset - 1, + span.end.line - 1, span.end.offset - 1); \ No newline at end of file From 703e7408d63e2bc1e65ce999fd078e33461717e0 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 19 Sep 2017 18:14:41 -0700 Subject: [PATCH 066/281] Continue moving range/position conversion to single location --- .../src/features/codeActionProvider.ts | 8 ++----- .../src/features/completionItemProvider.ts | 17 ++++----------- .../src/features/definitionProviderBase.ts | 8 ++----- .../src/features/documentHighlightProvider.ts | 9 ++------ .../typescript/src/features/hoverProvider.ts | 9 ++------ .../implementationsCodeLensProvider.ts | 8 ++----- .../src/features/jsDocCompletionProvider.ts | 9 +++----- .../src/features/refactorProvider.ts | 19 ++++------------- .../src/features/referenceProvider.ts | 9 ++------ .../features/referencesCodeLensProvider.ts | 8 ++----- extensions/typescript/src/utils/convert.ts | 21 +++++++++++++++---- 11 files changed, 42 insertions(+), 83 deletions(-) diff --git a/extensions/typescript/src/features/codeActionProvider.ts b/extensions/typescript/src/features/codeActionProvider.ts index 925eac1fff4..76051c6e505 100644 --- a/extensions/typescript/src/features/codeActionProvider.ts +++ b/extensions/typescript/src/features/codeActionProvider.ts @@ -7,7 +7,7 @@ import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionC import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange } from '../utils/convert'; +import { textSpanToRange, rangeToFileRange } from '../utils/convert'; interface NumberSet { [key: number]: boolean; @@ -68,11 +68,7 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider formattingOptions: formattingOptions }; const args: Proto.CodeFixRequestArgs = { - file: file, - startLine: range.start.line + 1, - endLine: range.end.line + 1, - startOffset: range.start.character + 1, - endOffset: range.end.character + 1, + ...rangeToFileRange(file, range), errorCodes: Array.from(supportedActions) }; const response = await this.client.execute('getCodeFixes', args, token); diff --git a/extensions/typescript/src/features/completionItemProvider.ts b/extensions/typescript/src/features/completionItemProvider.ts index 759642b929d..b225fa375c0 100644 --- a/extensions/typescript/src/features/completionItemProvider.ts +++ b/extensions/typescript/src/features/completionItemProvider.ts @@ -9,9 +9,9 @@ import { ITypescriptServiceClient } from '../typescriptService'; import TypingsStatus from '../utils/typingsStatus'; import * as PConst from '../protocol.const'; -import { CompletionEntry, CompletionsRequestArgs, CompletionDetailsRequestArgs, CompletionEntryDetails, FileLocationRequestArgs } from '../protocol'; +import { CompletionEntry, CompletionsRequestArgs, CompletionDetailsRequestArgs, CompletionEntryDetails } from '../protocol'; import * as Previewer from './previewer'; -import { textSpanToRange } from '../utils/convert'; +import { textSpanToRange, positionToFileLocation } from '../utils/convert'; import * as nls from 'vscode-nls'; let localize = nls.loadMessageBundle(); @@ -175,12 +175,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP if (!file) { return Promise.resolve([]); } - const args: CompletionsRequestArgs = { - file: file, - line: position.line + 1, - offset: position.character + 1 - }; - + const args: CompletionsRequestArgs = positionToFileLocation(file, position); return this.client.execute('completions', args, token).then((msg) => { // This info has to come from the tsserver. See https://github.com/Microsoft/TypeScript/issues/2831 // let isMemberCompletion = false; @@ -270,11 +265,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP } private isValidFunctionCompletionContext(filepath: string, position: Position): Promise { - const args: FileLocationRequestArgs = { - file: filepath, - line: position.line + 1, - offset: position.character + 1 - }; + const args = positionToFileLocation(filepath, position); // Workaround for https://github.com/Microsoft/TypeScript/issues/12677 // Don't complete function calls inside of destructive assigments or imports return this.client.execute('quickinfo', args).then(infoResponse => { diff --git a/extensions/typescript/src/features/definitionProviderBase.ts b/extensions/typescript/src/features/definitionProviderBase.ts index e137a1e3de7..7f241eadc6a 100644 --- a/extensions/typescript/src/features/definitionProviderBase.ts +++ b/extensions/typescript/src/features/definitionProviderBase.ts @@ -7,7 +7,7 @@ import { TextDocument, Position, CancellationToken, Location } from 'vscode'; import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange } from '../utils/convert'; +import { textSpanToRange, positionToFileLocation } from '../utils/convert'; export default class TypeScriptDefinitionProviderBase { constructor( @@ -23,11 +23,7 @@ export default class TypeScriptDefinitionProviderBase { if (!filepath) { return Promise.resolve(null); } - const args: Proto.FileLocationRequestArgs = { - file: filepath, - line: position.line + 1, - offset: position.character + 1 - }; + const args = positionToFileLocation(filepath, position); return this.client.execute(definitionType, args, token).then(response => { const locations: Proto.FileSpan[] = (response && response.body) || []; if (!locations || locations.length === 0) { diff --git a/extensions/typescript/src/features/documentHighlightProvider.ts b/extensions/typescript/src/features/documentHighlightProvider.ts index 97733afb1ce..283a88ef880 100644 --- a/extensions/typescript/src/features/documentHighlightProvider.ts +++ b/extensions/typescript/src/features/documentHighlightProvider.ts @@ -5,9 +5,8 @@ import { DocumentHighlightProvider, DocumentHighlight, DocumentHighlightKind, TextDocument, Position, Range, CancellationToken } from 'vscode'; -import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange } from '../utils/convert'; +import { textSpanToRange, positionToFileLocation } from '../utils/convert'; export default class TypeScriptDocumentHighlightProvider implements DocumentHighlightProvider { @@ -19,11 +18,7 @@ export default class TypeScriptDocumentHighlightProvider implements DocumentHigh if (!filepath) { return Promise.resolve([]); } - const args: Proto.FileLocationRequestArgs = { - file: filepath, - line: position.line + 1, - offset: position.character + 1 - }; + const args = positionToFileLocation(filepath, position); return this.client.execute('occurrences', args, token).then((response): DocumentHighlight[] => { let data = response.body; if (data && data.length) { diff --git a/extensions/typescript/src/features/hoverProvider.ts b/extensions/typescript/src/features/hoverProvider.ts index 89971ba5b61..693e990fe25 100644 --- a/extensions/typescript/src/features/hoverProvider.ts +++ b/extensions/typescript/src/features/hoverProvider.ts @@ -8,7 +8,7 @@ import { HoverProvider, Hover, TextDocument, Position, CancellationToken } from import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; import { tagsMarkdownPreview } from './previewer'; -import { textSpanToRange } from '../utils/convert'; +import { textSpanToRange, positionToFileLocation } from '../utils/convert'; export default class TypeScriptHoverProvider implements HoverProvider { @@ -20,12 +20,7 @@ export default class TypeScriptHoverProvider implements HoverProvider { if (!filepath) { return undefined; } - const args: Proto.FileLocationRequestArgs = { - file: filepath, - line: position.line + 1, - offset: position.character + 1 - }; - + const args = positionToFileLocation(filepath, position); try { const response = await this.client.execute('quickinfo', args, token); if (response && response.body) { diff --git a/extensions/typescript/src/features/implementationsCodeLensProvider.ts b/extensions/typescript/src/features/implementationsCodeLensProvider.ts index 9a6d1a79b42..7890d665084 100644 --- a/extensions/typescript/src/features/implementationsCodeLensProvider.ts +++ b/extensions/typescript/src/features/implementationsCodeLensProvider.ts @@ -9,7 +9,7 @@ import * as PConst from '../protocol.const'; import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens } from './baseCodeLensProvider'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange } from '../utils/convert'; +import { textSpanToRange, positionToFileLocation } from '../utils/convert'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); @@ -36,11 +36,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip resolveCodeLens(inputCodeLens: CodeLens, token: CancellationToken): Promise { const codeLens = inputCodeLens as ReferencesCodeLens; - const args: Proto.FileLocationRequestArgs = { - file: codeLens.file, - line: codeLens.range.start.line + 1, - offset: codeLens.range.start.character + 1 - }; + const args = positionToFileLocation(codeLens.file, codeLens.range.start); return this.client.execute('implementation', args, token).then(response => { if (!response || !response.body) { throw codeLens; diff --git a/extensions/typescript/src/features/jsDocCompletionProvider.ts b/extensions/typescript/src/features/jsDocCompletionProvider.ts index 50f0147cbc0..c78116fb09e 100644 --- a/extensions/typescript/src/features/jsDocCompletionProvider.ts +++ b/extensions/typescript/src/features/jsDocCompletionProvider.ts @@ -6,9 +6,10 @@ import { Position, Range, CompletionItemProvider, CompletionItemKind, TextDocument, CancellationToken, CompletionItem, window, Uri, ProviderResult, TextEditor, SnippetString, workspace } from 'vscode'; import { ITypescriptServiceClient } from '../typescriptService'; -import { FileLocationRequestArgs, DocCommandTemplateResponse } from '../protocol'; +import { DocCommandTemplateResponse } from '../protocol'; import * as nls from 'vscode-nls'; +import { positionToFileLocation } from '../utils/convert'; const localize = nls.loadMessageBundle(); const configurationNamespace = 'jsDocCompletion'; @@ -118,11 +119,7 @@ export class TryCompleteJsDocCommand { } private tryInsertJsDocFromTemplate(editor: TextEditor, file: string, position: Position): Promise { - const args: FileLocationRequestArgs = { - file: file, - line: position.line + 1, - offset: position.character + 1 - }; + const args = positionToFileLocation(file, position); return Promise.race([ this.lazyClient().execute('docCommentTemplate', args), new Promise((_, reject) => setTimeout(reject, 250)) diff --git a/extensions/typescript/src/features/refactorProvider.ts b/extensions/typescript/src/features/refactorProvider.ts index 563160640c9..a67ce08f2c7 100644 --- a/extensions/typescript/src/features/refactorProvider.ts +++ b/extensions/typescript/src/features/refactorProvider.ts @@ -9,7 +9,7 @@ import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionC import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange } from '../utils/convert'; +import { textSpanToRange, rangeToFileRange } from '../utils/convert'; export default class TypeScriptRefactorProvider implements CodeActionProvider { @@ -43,14 +43,7 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { return []; } - const args: Proto.GetApplicableRefactorsRequestArgs = { - file: file, - startLine: range.start.line + 1, - startOffset: range.start.character + 1, - endLine: range.end.line + 1, - endOffset: range.end.character + 1 - }; - + const args: Proto.GetApplicableRefactorsRequestArgs = rangeToFileRange(file, range); try { const response = await this.client.execute('getApplicableRefactors', args, token); if (!response || !response.body) { @@ -107,13 +100,9 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { private async doRefactoring(file: string, refactor: string, action: string, range: Range): Promise { const args: Proto.GetEditsForRefactorRequestArgs = { - file, + ...rangeToFileRange(file, range), refactor, - action, - startLine: range.start.line + 1, - startOffset: range.start.character + 1, - endLine: range.end.line + 1, - endOffset: range.end.character + 1 + action }; const response = await this.client.execute('getEditsForRefactor', args); diff --git a/extensions/typescript/src/features/referenceProvider.ts b/extensions/typescript/src/features/referenceProvider.ts index b6af1f23033..4e4847b1106 100644 --- a/extensions/typescript/src/features/referenceProvider.ts +++ b/extensions/typescript/src/features/referenceProvider.ts @@ -5,9 +5,8 @@ import { ReferenceProvider, Location, TextDocument, Position, CancellationToken } from 'vscode'; -import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange } from '../utils/convert'; +import { textSpanToRange, positionToFileLocation } from '../utils/convert'; export default class TypeScriptReferenceSupport implements ReferenceProvider { public constructor( @@ -18,11 +17,7 @@ export default class TypeScriptReferenceSupport implements ReferenceProvider { if (!filepath) { return Promise.resolve([]); } - const args: Proto.FileLocationRequestArgs = { - file: filepath, - line: position.line + 1, - offset: position.character + 1 - }; + const args = positionToFileLocation(filepath, position); const apiVersion = this.client.apiVersion; return this.client.execute('references', args, token).then((msg) => { const result: Location[] = []; diff --git a/extensions/typescript/src/features/referencesCodeLensProvider.ts b/extensions/typescript/src/features/referencesCodeLensProvider.ts index 40c56f48df9..11cd28b7ef7 100644 --- a/extensions/typescript/src/features/referencesCodeLensProvider.ts +++ b/extensions/typescript/src/features/referencesCodeLensProvider.ts @@ -9,7 +9,7 @@ import * as PConst from '../protocol.const'; import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens } from './baseCodeLensProvider'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange } from '../utils/convert'; +import { textSpanToRange, positionToFileLocation } from '../utils/convert'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); @@ -36,11 +36,7 @@ export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBase resolveCodeLens(inputCodeLens: CodeLens, token: CancellationToken): Promise { const codeLens = inputCodeLens as ReferencesCodeLens; - const args: Proto.FileLocationRequestArgs = { - file: codeLens.file, - line: codeLens.range.start.line + 1, - offset: codeLens.range.start.character + 1 - }; + const args = positionToFileLocation(codeLens.file, codeLens.range.start); return this.client.execute('references', args, token).then(response => { if (!response || !response.body) { throw codeLens; diff --git a/extensions/typescript/src/utils/convert.ts b/extensions/typescript/src/utils/convert.ts index 92511d1fb1a..40e2dbef7b1 100644 --- a/extensions/typescript/src/utils/convert.ts +++ b/extensions/typescript/src/utils/convert.ts @@ -3,12 +3,25 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Range } from 'vscode'; - +import * as vscode from 'vscode'; import * as Proto from '../protocol'; export const textSpanToRange = (span: Proto.TextSpan) => - new Range( + new vscode.Range( span.start.line - 1, span.start.offset - 1, - span.end.line - 1, span.end.offset - 1); \ No newline at end of file + span.end.line - 1, span.end.offset - 1); + +export const positionToFileLocation = (file: string, position: vscode.Position): Proto.FileLocationRequestArgs => ({ + file, + line: position.line + 1, + offset: position.character + 1 +}); + +export const rangeToFileRange = (file: string, range: vscode.Range): Proto.FileRangeRequestArgs => ({ + file, + startLine: range.start.line + 1, + startOffset: range.start.character + 1, + endLine: range.end.line + 1, + endOffset: range.end.character + 1 +}); \ No newline at end of file From f1043f2b9d786a6ae4579f7d564c8ee384c0f360 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 19 Sep 2017 18:25:20 -0700 Subject: [PATCH 067/281] Continue moving vs loc to ts loc location into single set of functions --- .../typescript/src/features/baseCodeLensProvider.ts | 4 ++-- .../typescript/src/features/codeActionProvider.ts | 6 +++--- .../src/features/completionItemProvider.ts | 12 +++++------- .../src/features/definitionProviderBase.ts | 6 +++--- .../src/features/documentHighlightProvider.ts | 6 +++--- .../src/features/documentSymbolProvider.ts | 6 +++--- .../typescript/src/features/formattingProvider.ts | 4 ++-- extensions/typescript/src/features/hoverProvider.ts | 6 +++--- .../src/features/implementationsCodeLensProvider.ts | 6 +++--- .../src/features/jsDocCompletionProvider.ts | 4 ++-- .../typescript/src/features/refactorProvider.ts | 13 ++++++------- .../typescript/src/features/referenceProvider.ts | 6 +++--- .../src/features/referencesCodeLensProvider.ts | 6 +++--- .../typescript/src/features/renameProvider.ts | 8 +++----- .../src/features/signatureHelpProvider.ts | 7 ++----- .../src/features/workspaceSymbolProvider.ts | 4 ++-- extensions/typescript/src/typescriptMain.ts | 3 ++- extensions/typescript/src/utils/convert.ts | 9 ++++++--- 18 files changed, 56 insertions(+), 60 deletions(-) diff --git a/extensions/typescript/src/features/baseCodeLensProvider.ts b/extensions/typescript/src/features/baseCodeLensProvider.ts index cb8e675db4d..9f5d6012d80 100644 --- a/extensions/typescript/src/features/baseCodeLensProvider.ts +++ b/extensions/typescript/src/features/baseCodeLensProvider.ts @@ -7,7 +7,7 @@ import { CodeLensProvider, CodeLens, CancellationToken, TextDocument, Range, Uri import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange } from '../utils/convert'; +import { tsTextSpanToVsRange } from '../utils/convert'; export class ReferencesCodeLens extends CodeLens { constructor( @@ -100,7 +100,7 @@ export abstract class TypeScriptBaseCodeLensProvider implements CodeLensProvider return null; } - const range = textSpanToRange(span); + const range = tsTextSpanToVsRange(span); const text = document.getText(range); const identifierMatch = new RegExp(`^(.*?(\\b|\\W))${(item.text || '').replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')}(\\b|\\W)`, 'gm'); diff --git a/extensions/typescript/src/features/codeActionProvider.ts b/extensions/typescript/src/features/codeActionProvider.ts index 76051c6e505..fefe85a3835 100644 --- a/extensions/typescript/src/features/codeActionProvider.ts +++ b/extensions/typescript/src/features/codeActionProvider.ts @@ -7,7 +7,7 @@ import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionC import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange, rangeToFileRange } from '../utils/convert'; +import { tsTextSpanToVsRange, vsRangeToTsFileRange } from '../utils/convert'; interface NumberSet { [key: number]: boolean; @@ -68,7 +68,7 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider formattingOptions: formattingOptions }; const args: Proto.CodeFixRequestArgs = { - ...rangeToFileRange(file, range), + ...vsRangeToTsFileRange(file, range), errorCodes: Array.from(supportedActions) }; const response = await this.client.execute('getCodeFixes', args, token); @@ -109,7 +109,7 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider for (const change of action.changes) { for (const textChange of change.textChanges) { workspaceEdit.replace(this.client.asUrl(change.fileName), - textSpanToRange(textChange), + tsTextSpanToVsRange(textChange), textChange.newText); } } diff --git a/extensions/typescript/src/features/completionItemProvider.ts b/extensions/typescript/src/features/completionItemProvider.ts index b225fa375c0..e91e71ac9fd 100644 --- a/extensions/typescript/src/features/completionItemProvider.ts +++ b/extensions/typescript/src/features/completionItemProvider.ts @@ -11,7 +11,7 @@ import TypingsStatus from '../utils/typingsStatus'; import * as PConst from '../protocol.const'; import { CompletionEntry, CompletionsRequestArgs, CompletionDetailsRequestArgs, CompletionEntryDetails } from '../protocol'; import * as Previewer from './previewer'; -import { textSpanToRange, positionToFileLocation } from '../utils/convert'; +import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; import * as nls from 'vscode-nls'; let localize = nls.loadMessageBundle(); @@ -33,7 +33,7 @@ class MyCompletionItem extends CompletionItem { let span: protocol.TextSpan = entry.replacementSpan; // The indexing for the range returned by the server uses 1-based indexing. // We convert to 0-based indexing. - this.textEdit = TextEdit.replace(textSpanToRange(span), entry.name); + this.textEdit = TextEdit.replace(tsTextSpanToVsRange(span), entry.name); } else { // Try getting longer, prefix based range for completions that span words const wordRange = document.getWordRangeAtPosition(position); @@ -175,7 +175,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP if (!file) { return Promise.resolve([]); } - const args: CompletionsRequestArgs = positionToFileLocation(file, position); + const args: CompletionsRequestArgs = vsPositionToTsFileLocation(file, position); return this.client.execute('completions', args, token).then((msg) => { // This info has to come from the tsserver. See https://github.com/Microsoft/TypeScript/issues/2831 // let isMemberCompletion = false; @@ -234,9 +234,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP return null; } const args: CompletionDetailsRequestArgs = { - file: filepath, - line: item.position.line + 1, - offset: item.position.character + 1, + ...vsPositionToTsFileLocation(filepath, item.position), entryNames: [item.label] }; return this.client.execute('completionEntryDetails', args, token).then((response) => { @@ -265,7 +263,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP } private isValidFunctionCompletionContext(filepath: string, position: Position): Promise { - const args = positionToFileLocation(filepath, position); + const args = vsPositionToTsFileLocation(filepath, position); // Workaround for https://github.com/Microsoft/TypeScript/issues/12677 // Don't complete function calls inside of destructive assigments or imports return this.client.execute('quickinfo', args).then(infoResponse => { diff --git a/extensions/typescript/src/features/definitionProviderBase.ts b/extensions/typescript/src/features/definitionProviderBase.ts index 7f241eadc6a..bf5ffabd704 100644 --- a/extensions/typescript/src/features/definitionProviderBase.ts +++ b/extensions/typescript/src/features/definitionProviderBase.ts @@ -7,7 +7,7 @@ import { TextDocument, Position, CancellationToken, Location } from 'vscode'; import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange, positionToFileLocation } from '../utils/convert'; +import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; export default class TypeScriptDefinitionProviderBase { constructor( @@ -23,7 +23,7 @@ export default class TypeScriptDefinitionProviderBase { if (!filepath) { return Promise.resolve(null); } - const args = positionToFileLocation(filepath, position); + const args = vsPositionToTsFileLocation(filepath, position); return this.client.execute(definitionType, args, token).then(response => { const locations: Proto.FileSpan[] = (response && response.body) || []; if (!locations || locations.length === 0) { @@ -34,7 +34,7 @@ export default class TypeScriptDefinitionProviderBase { if (resource === null) { return null; } else { - return new Location(resource, textSpanToRange(location)); + return new Location(resource, tsTextSpanToVsRange(location)); } }).filter(x => x !== null) as Location[]; }, () => { diff --git a/extensions/typescript/src/features/documentHighlightProvider.ts b/extensions/typescript/src/features/documentHighlightProvider.ts index 283a88ef880..d91cb8fd90b 100644 --- a/extensions/typescript/src/features/documentHighlightProvider.ts +++ b/extensions/typescript/src/features/documentHighlightProvider.ts @@ -6,7 +6,7 @@ import { DocumentHighlightProvider, DocumentHighlight, DocumentHighlightKind, TextDocument, Position, Range, CancellationToken } from 'vscode'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange, positionToFileLocation } from '../utils/convert'; +import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; export default class TypeScriptDocumentHighlightProvider implements DocumentHighlightProvider { @@ -18,7 +18,7 @@ export default class TypeScriptDocumentHighlightProvider implements DocumentHigh if (!filepath) { return Promise.resolve([]); } - const args = positionToFileLocation(filepath, position); + const args = vsPositionToTsFileLocation(filepath, position); return this.client.execute('occurrences', args, token).then((response): DocumentHighlight[] => { let data = response.body; if (data && data.length) { @@ -35,7 +35,7 @@ export default class TypeScriptDocumentHighlightProvider implements DocumentHigh } return data.map(item => new DocumentHighlight( - textSpanToRange(item), + tsTextSpanToVsRange(item), item.isWriteAccess ? DocumentHighlightKind.Write : DocumentHighlightKind.Read)); } return []; diff --git a/extensions/typescript/src/features/documentSymbolProvider.ts b/extensions/typescript/src/features/documentSymbolProvider.ts index 57f507840d8..bf289d24ee2 100644 --- a/extensions/typescript/src/features/documentSymbolProvider.ts +++ b/extensions/typescript/src/features/documentSymbolProvider.ts @@ -8,7 +8,7 @@ import { DocumentSymbolProvider, SymbolInformation, SymbolKind, TextDocument, Lo import * as Proto from '../protocol'; import * as PConst from '../protocol.const'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange } from '../utils/convert'; +import { tsTextSpanToVsRange } from '../utils/convert'; const outlineTypeTable: { [kind: string]: SymbolKind } = Object.create(null); outlineTypeTable[PConst.Kind.module] = SymbolKind.Module; @@ -71,7 +71,7 @@ export default class TypeScriptDocumentSymbolProvider implements DocumentSymbolP let result = new SymbolInformation(item.text, outlineTypeTable[item.kind as string] || SymbolKind.Variable, containerLabel ? containerLabel : '', - new Location(resource, textSpanToRange(item.spans[0]))); + new Location(resource, tsTextSpanToVsRange(item.spans[0]))); foldingMap[key] = result; bucket.push(result); } @@ -86,7 +86,7 @@ export default class TypeScriptDocumentSymbolProvider implements DocumentSymbolP const result = new SymbolInformation(item.text, outlineTypeTable[item.kind as string] || SymbolKind.Variable, containerLabel ? containerLabel : '', - new Location(resource, textSpanToRange(item.spans[0])) + new Location(resource, tsTextSpanToVsRange(item.spans[0])) ); if (item.childItems && item.childItems.length > 0) { for (const child of item.childItems) { diff --git a/extensions/typescript/src/features/formattingProvider.ts b/extensions/typescript/src/features/formattingProvider.ts index 10e20dd9b39..b4f26fdcd0a 100644 --- a/extensions/typescript/src/features/formattingProvider.ts +++ b/extensions/typescript/src/features/formattingProvider.ts @@ -7,7 +7,7 @@ import { workspace as Workspace, DocumentRangeFormattingEditProvider, OnTypeForm import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange } from '../utils/convert'; +import { tsTextSpanToVsRange } from '../utils/convert'; interface Configuration { enable: boolean; @@ -206,7 +206,7 @@ export class TypeScriptFormattingProvider implements DocumentRangeFormattingEdit } private codeEdit2SingleEditOperation(edit: Proto.CodeEdit): TextEdit { - return new TextEdit(textSpanToRange(edit), edit.newText); + return new TextEdit(tsTextSpanToVsRange(edit), edit.newText); } private getFormatOptions(options: FormattingOptions): Proto.FormatCodeSettings { diff --git a/extensions/typescript/src/features/hoverProvider.ts b/extensions/typescript/src/features/hoverProvider.ts index 693e990fe25..9ee37c5954b 100644 --- a/extensions/typescript/src/features/hoverProvider.ts +++ b/extensions/typescript/src/features/hoverProvider.ts @@ -8,7 +8,7 @@ import { HoverProvider, Hover, TextDocument, Position, CancellationToken } from import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; import { tagsMarkdownPreview } from './previewer'; -import { textSpanToRange, positionToFileLocation } from '../utils/convert'; +import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; export default class TypeScriptHoverProvider implements HoverProvider { @@ -20,14 +20,14 @@ export default class TypeScriptHoverProvider implements HoverProvider { if (!filepath) { return undefined; } - const args = positionToFileLocation(filepath, position); + const args = vsPositionToTsFileLocation(filepath, position); try { const response = await this.client.execute('quickinfo', args, token); if (response && response.body) { const data = response.body; return new Hover( TypeScriptHoverProvider.getContents(data), - textSpanToRange(data)); + tsTextSpanToVsRange(data)); } } catch (e) { // noop diff --git a/extensions/typescript/src/features/implementationsCodeLensProvider.ts b/extensions/typescript/src/features/implementationsCodeLensProvider.ts index 7890d665084..a36ab6b2527 100644 --- a/extensions/typescript/src/features/implementationsCodeLensProvider.ts +++ b/extensions/typescript/src/features/implementationsCodeLensProvider.ts @@ -9,7 +9,7 @@ import * as PConst from '../protocol.const'; import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens } from './baseCodeLensProvider'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange, positionToFileLocation } from '../utils/convert'; +import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); @@ -36,7 +36,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip resolveCodeLens(inputCodeLens: CodeLens, token: CancellationToken): Promise { const codeLens = inputCodeLens as ReferencesCodeLens; - const args = positionToFileLocation(codeLens.file, codeLens.range.start); + const args = vsPositionToTsFileLocation(codeLens.file, codeLens.range.start); return this.client.execute('implementation', args, token).then(response => { if (!response || !response.body) { throw codeLens; @@ -47,7 +47,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip // Only take first line on implementation: https://github.com/Microsoft/vscode/issues/23924 new Location(this.client.asUrl(reference.file), reference.start.line === reference.end.line - ? textSpanToRange(reference) + ? tsTextSpanToVsRange(reference) : new Range( reference.start.line - 1, reference.start.offset - 1, reference.start.line, 0))) diff --git a/extensions/typescript/src/features/jsDocCompletionProvider.ts b/extensions/typescript/src/features/jsDocCompletionProvider.ts index c78116fb09e..d9c87da1cc0 100644 --- a/extensions/typescript/src/features/jsDocCompletionProvider.ts +++ b/extensions/typescript/src/features/jsDocCompletionProvider.ts @@ -9,7 +9,7 @@ import { ITypescriptServiceClient } from '../typescriptService'; import { DocCommandTemplateResponse } from '../protocol'; import * as nls from 'vscode-nls'; -import { positionToFileLocation } from '../utils/convert'; +import { vsPositionToTsFileLocation } from '../utils/convert'; const localize = nls.loadMessageBundle(); const configurationNamespace = 'jsDocCompletion'; @@ -119,7 +119,7 @@ export class TryCompleteJsDocCommand { } private tryInsertJsDocFromTemplate(editor: TextEditor, file: string, position: Position): Promise { - const args = positionToFileLocation(file, position); + const args = vsPositionToTsFileLocation(file, position); return Promise.race([ this.lazyClient().execute('docCommentTemplate', args), new Promise((_, reject) => setTimeout(reject, 250)) diff --git a/extensions/typescript/src/features/refactorProvider.ts b/extensions/typescript/src/features/refactorProvider.ts index a67ce08f2c7..d87d6c01076 100644 --- a/extensions/typescript/src/features/refactorProvider.ts +++ b/extensions/typescript/src/features/refactorProvider.ts @@ -5,11 +5,11 @@ 'use strict'; -import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands, workspace, WorkspaceEdit, window, QuickPickItem, Selection, Position } from 'vscode'; +import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands, workspace, WorkspaceEdit, window, QuickPickItem, Selection } from 'vscode'; import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange, rangeToFileRange } from '../utils/convert'; +import { tsTextSpanToVsRange, vsRangeToTsFileRange, tsLocationToVsPosition } from '../utils/convert'; export default class TypeScriptRefactorProvider implements CodeActionProvider { @@ -25,7 +25,6 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { commands.registerCommand(this.doRefactorCommandId, this.doRefactoring, this); commands.registerCommand(this.selectRefactorCommandId, this.selectRefactoring, this); - } public async provideCodeActions( @@ -43,7 +42,7 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { return []; } - const args: Proto.GetApplicableRefactorsRequestArgs = rangeToFileRange(file, range); + const args: Proto.GetApplicableRefactorsRequestArgs = vsRangeToTsFileRange(file, range); try { const response = await this.client.execute('getApplicableRefactors', args, token); if (!response || !response.body) { @@ -79,7 +78,7 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { for (const edit of edits) { for (const textChange of edit.textChanges) { workspaceEdit.replace(this.client.asUrl(edit.fileName), - textSpanToRange(textChange), + tsTextSpanToVsRange(textChange), textChange.newText); } } @@ -100,7 +99,7 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { private async doRefactoring(file: string, refactor: string, action: string, range: Range): Promise { const args: Proto.GetEditsForRefactorRequestArgs = { - ...rangeToFileRange(file, range), + ...vsRangeToTsFileRange(file, range), refactor, action }; @@ -118,7 +117,7 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { const renameLocation = response.body.renameLocation; if (renameLocation) { if (window.activeTextEditor && window.activeTextEditor.document.uri.fsPath === file) { - const pos = new Position(renameLocation.line - 1, renameLocation.offset - 1); + const pos = tsLocationToVsPosition(renameLocation); window.activeTextEditor.selection = new Selection(pos, pos); await commands.executeCommand('editor.action.rename'); } diff --git a/extensions/typescript/src/features/referenceProvider.ts b/extensions/typescript/src/features/referenceProvider.ts index 4e4847b1106..1bce17a5b65 100644 --- a/extensions/typescript/src/features/referenceProvider.ts +++ b/extensions/typescript/src/features/referenceProvider.ts @@ -6,7 +6,7 @@ import { ReferenceProvider, Location, TextDocument, Position, CancellationToken } from 'vscode'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange, positionToFileLocation } from '../utils/convert'; +import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; export default class TypeScriptReferenceSupport implements ReferenceProvider { public constructor( @@ -17,7 +17,7 @@ export default class TypeScriptReferenceSupport implements ReferenceProvider { if (!filepath) { return Promise.resolve([]); } - const args = positionToFileLocation(filepath, position); + const args = vsPositionToTsFileLocation(filepath, position); const apiVersion = this.client.apiVersion; return this.client.execute('references', args, token).then((msg) => { const result: Location[] = []; @@ -31,7 +31,7 @@ export default class TypeScriptReferenceSupport implements ReferenceProvider { continue; } const url = this.client.asUrl(ref.file); - const location = new Location(url, textSpanToRange(ref)); + const location = new Location(url, tsTextSpanToVsRange(ref)); result.push(location); } return result; diff --git a/extensions/typescript/src/features/referencesCodeLensProvider.ts b/extensions/typescript/src/features/referencesCodeLensProvider.ts index 11cd28b7ef7..251337ab59c 100644 --- a/extensions/typescript/src/features/referencesCodeLensProvider.ts +++ b/extensions/typescript/src/features/referencesCodeLensProvider.ts @@ -9,7 +9,7 @@ import * as PConst from '../protocol.const'; import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens } from './baseCodeLensProvider'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange, positionToFileLocation } from '../utils/convert'; +import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); @@ -36,7 +36,7 @@ export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBase resolveCodeLens(inputCodeLens: CodeLens, token: CancellationToken): Promise { const codeLens = inputCodeLens as ReferencesCodeLens; - const args = positionToFileLocation(codeLens.file, codeLens.range.start); + const args = vsPositionToTsFileLocation(codeLens.file, codeLens.range.start); return this.client.execute('references', args, token).then(response => { if (!response || !response.body) { throw codeLens; @@ -44,7 +44,7 @@ export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBase const locations = response.body.refs .map(reference => - new Location(this.client.asUrl(reference.file), textSpanToRange(reference))) + new Location(this.client.asUrl(reference.file), tsTextSpanToVsRange(reference))) .filter(location => // Exclude original definition from references !(location.uri.fsPath === codeLens.document.fsPath && diff --git a/extensions/typescript/src/features/renameProvider.ts b/extensions/typescript/src/features/renameProvider.ts index e7adfc1cea7..26bbb6a29ea 100644 --- a/extensions/typescript/src/features/renameProvider.ts +++ b/extensions/typescript/src/features/renameProvider.ts @@ -7,7 +7,7 @@ import { RenameProvider, WorkspaceEdit, TextDocument, Position, CancellationToke import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange } from '../utils/convert'; +import { tsTextSpanToVsRange, vsPositionToTsFileLocation } from '../utils/convert'; export default class TypeScriptRenameProvider implements RenameProvider { public constructor( @@ -25,9 +25,7 @@ export default class TypeScriptRenameProvider implements RenameProvider { } const args: Proto.RenameRequestArgs = { - file: filepath, - line: position.line + 1, - offset: position.character + 1, + ...vsPositionToTsFileLocation(filepath, position), findInStrings: false, findInComments: false }; @@ -50,7 +48,7 @@ export default class TypeScriptRenameProvider implements RenameProvider { continue; } for (const textSpan of spanGroup.locs) { - result.replace(resource, textSpanToRange(textSpan), newName); + result.replace(resource, tsTextSpanToVsRange(textSpan), newName); } } return result; diff --git a/extensions/typescript/src/features/signatureHelpProvider.ts b/extensions/typescript/src/features/signatureHelpProvider.ts index d4fb33e2bfb..ea0de1f04d5 100644 --- a/extensions/typescript/src/features/signatureHelpProvider.ts +++ b/extensions/typescript/src/features/signatureHelpProvider.ts @@ -8,6 +8,7 @@ import { SignatureHelpProvider, SignatureHelp, SignatureInformation, ParameterIn import * as Previewer from './previewer'; import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; +import { vsPositionToTsFileLocation } from '../utils/convert'; export default class TypeScriptSignatureHelpProvider implements SignatureHelpProvider { @@ -19,11 +20,7 @@ export default class TypeScriptSignatureHelpProvider implements SignatureHelpPro if (!filepath) { return Promise.resolve(null); } - const args: Proto.SignatureHelpRequestArgs = { - file: filepath, - line: position.line + 1, - offset: position.character + 1 - }; + const args: Proto.SignatureHelpRequestArgs = vsPositionToTsFileLocation(filepath, position); return this.client.execute('signatureHelp', args, token).then((response) => { const info = response.body; if (!info) { diff --git a/extensions/typescript/src/features/workspaceSymbolProvider.ts b/extensions/typescript/src/features/workspaceSymbolProvider.ts index 6ebc45b36bb..8885eb877ac 100644 --- a/extensions/typescript/src/features/workspaceSymbolProvider.ts +++ b/extensions/typescript/src/features/workspaceSymbolProvider.ts @@ -7,7 +7,7 @@ import { workspace, window, Uri, WorkspaceSymbolProvider, SymbolInformation, Sym import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; -import { textSpanToRange } from '../utils/convert'; +import { tsTextSpanToVsRange } from '../utils/convert'; function getSymbolKind(item: Proto.NavtoItem): SymbolKind { switch (item.kind) { @@ -68,7 +68,7 @@ export default class TypeScriptWorkspaceSymbolProvider implements WorkspaceSymbo if (!item.containerName && item.kind === 'alias') { continue; } - const range = textSpanToRange(item); + const range = tsTextSpanToVsRange(item); let label = item.name; if (item.kind === 'method' || item.kind === 'function') { label += '()'; diff --git a/extensions/typescript/src/typescriptMain.ts b/extensions/typescript/src/typescriptMain.ts index 9c472f187f0..87c312eb268 100644 --- a/extensions/typescript/src/typescriptMain.ts +++ b/extensions/typescript/src/typescriptMain.ts @@ -33,6 +33,7 @@ import TypingsStatus, { AtaProgressReporter } from './utils/typingsStatus'; import VersionStatus from './utils/versionStatus'; import { getContributedTypeScriptServerPlugins, TypeScriptServerPlugin } from './utils/plugins'; import { openOrCreateConfigFile, isImplicitProjectConfigFile } from './utils/tsconfig'; +import { tsLocationToVsPosition } from './utils/convert'; interface LanguageDescription { id: string; @@ -681,7 +682,7 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost { const result: Diagnostic[] = []; for (let diagnostic of diagnostics) { const { start, end, text } = diagnostic; - const range = new Range(start.line - 1, start.offset - 1, end.line - 1, end.offset - 1); + const range = new Range(tsLocationToVsPosition(start), tsLocationToVsPosition(end)); const converted = new Diagnostic(range, text); converted.severity = this.getDiagnosticSeverity(diagnostic); converted.source = diagnostic.source || source; diff --git a/extensions/typescript/src/utils/convert.ts b/extensions/typescript/src/utils/convert.ts index 40e2dbef7b1..299597f34d5 100644 --- a/extensions/typescript/src/utils/convert.ts +++ b/extensions/typescript/src/utils/convert.ts @@ -7,18 +7,21 @@ import * as vscode from 'vscode'; import * as Proto from '../protocol'; -export const textSpanToRange = (span: Proto.TextSpan) => +export const tsTextSpanToVsRange = (span: Proto.TextSpan) => new vscode.Range( span.start.line - 1, span.start.offset - 1, span.end.line - 1, span.end.offset - 1); -export const positionToFileLocation = (file: string, position: vscode.Position): Proto.FileLocationRequestArgs => ({ +export const tsLocationToVsPosition = (tslocation: Proto.Location) => + new vscode.Position(tslocation.line - 1, tslocation.offset - 1); + +export const vsPositionToTsFileLocation = (file: string, position: vscode.Position): Proto.FileLocationRequestArgs => ({ file, line: position.line + 1, offset: position.character + 1 }); -export const rangeToFileRange = (file: string, range: vscode.Range): Proto.FileRangeRequestArgs => ({ +export const vsRangeToTsFileRange = (file: string, range: vscode.Range): Proto.FileRangeRequestArgs => ({ file, startLine: range.start.line + 1, startOffset: range.start.character + 1, From 54f23869cca42861e7ee7f3f454e6bd6d2a7d4c2 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 20 Sep 2017 12:01:20 +0900 Subject: [PATCH 068/281] Fix terminal mouse coordinate issues Fixes #34184 --- npm-shrinkwrap.json | 2 +- .../parts/terminal/electron-browser/media/terminal.css | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 35551d36615..065aeccefa0 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -574,7 +574,7 @@ "xterm": { "version": "3.0.0", "from": "Tyriar/xterm.js#vscode-release/1.17", - "resolved": "git+https://github.com/Tyriar/xterm.js.git#851dff7253fc9718bb90f691fc79a7c3c542bcfa" + "resolved": "git+https://github.com/Tyriar/xterm.js.git#2d89a723a61c3b2aabb15bd278dc7792466b8ec5" }, "yauzl": { "version": "2.8.0", diff --git a/src/vs/workbench/parts/terminal/electron-browser/media/terminal.css b/src/vs/workbench/parts/terminal/electron-browser/media/terminal.css index 1d9961ab042..e032054ea47 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/media/terminal.css +++ b/src/vs/workbench/parts/terminal/electron-browser/media/terminal.css @@ -41,7 +41,10 @@ height: 100%; } -.monaco-workbench .panel.integrated-terminal .xterm-viewport, +.monaco-workbench .panel.integrated-terminal .xterm-viewport { + margin-right: -20px; +} + .monaco-workbench .panel.integrated-terminal canvas { /* Align the viewport and canvases to the bottom of the panel */ position: absolute; @@ -71,8 +74,9 @@ } .monaco-workbench .panel.integrated-terminal .xterm { - position: relative; - height: 100%; + position: absolute; + bottom: 0; + left: 0; user-select: none; } From f7962f0682a76516df51de4856f8ccc5d8ad578a Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 20 Sep 2017 12:58:40 +0900 Subject: [PATCH 069/281] Uplevel xterm.js See sourcelair/xterm.js#990 --- npm-shrinkwrap.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 065aeccefa0..e5f51982d1d 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -574,7 +574,7 @@ "xterm": { "version": "3.0.0", "from": "Tyriar/xterm.js#vscode-release/1.17", - "resolved": "git+https://github.com/Tyriar/xterm.js.git#2d89a723a61c3b2aabb15bd278dc7792466b8ec5" + "resolved": "git+https://github.com/Tyriar/xterm.js.git#875b219802d116106d3e05a1731bf895bc95851b" }, "yauzl": { "version": "2.8.0", From d0668fb1671dcc754fc5b1168934a2e64c3e274a Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 20 Sep 2017 09:29:14 +0200 Subject: [PATCH 070/281] git: leverage new ViewColumn.Active --- extensions/git/src/commands.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 80fad68410e..d49e59d2eeb 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -169,7 +169,7 @@ export class CommandCenter { const opts: TextDocumentShowOptions = { preserveFocus, preview, - viewColumn: window.activeTextEditor && window.activeTextEditor.viewColumn || ViewColumn.One + viewColumn: ViewColumn.Active }; const activeTextEditor = window.activeTextEditor; @@ -365,7 +365,7 @@ export class CommandCenter { const opts: TextDocumentShowOptions = { preserveFocus, preview: preview, - viewColumn: activeTextEditor && activeTextEditor.viewColumn || ViewColumn.One + viewColumn: ViewColumn.Active }; if (activeTextEditor && activeTextEditor.document.uri.fsPath === uri.fsPath) { From f56d080258b3c5c32ad0a1e30b21d3fdf78a95c7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 20 Sep 2017 09:43:50 +0200 Subject: [PATCH 071/281] fix npe --- src/vs/workbench/browser/labels.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index ac2e3bc2d34..20399881630 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -210,14 +210,19 @@ export class FileLabel extends ResourceLabel { } public setFile(resource: uri, options?: IFileLabelOptions): void { + const hideLabel = options && options.hideLabel; let name: string; - if (options && options.hideLabel) { - name = void 0; - } else if (options && options.fileKind === FileKind.ROOT_FOLDER) { - const workspaceFolder = this.contextService.getWorkspaceFolder(resource); - name = workspaceFolder.name; - } else { - name = paths.basename(resource.fsPath); + if (!hideLabel) { + if (options && options.fileKind === FileKind.ROOT_FOLDER) { + const workspaceFolder = this.contextService.getWorkspaceFolder(resource); + if (workspaceFolder) { + name = workspaceFolder.name; + } + } + + if (!name) { + name = paths.basename(resource.fsPath); + } } let description: string; From ed20bae44ae9c6aa7084457551211fb8ce19de5b Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 20 Sep 2017 09:45:50 +0200 Subject: [PATCH 072/281] introduce IWorkspaceFoldersChangeEvent for onDidChangeWorkspaceFolders (for #31195) --- .../standalone/browser/simpleServices.ts | 6 ++-- src/vs/platform/workspace/common/workspace.ts | 8 ++++- .../configuration/node/configuration.ts | 31 +++++++++++++------ .../workbench/test/workbenchTestServices.ts | 8 ++--- 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 3eea14eb51a..23ed80e4d83 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -18,7 +18,7 @@ import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingReso import { IKeybindingEvent, KeybindingSource, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IConfirmation, IMessageService } from 'vs/platform/message/common/message'; -import { IWorkspaceContextService, IWorkspace, WorkbenchState, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, IWorkspace, WorkbenchState, WorkspaceFolder, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { Selection } from 'vs/editor/common/core/selection'; @@ -525,8 +525,8 @@ export class SimpleWorkspaceContextService implements IWorkspaceContextService { private readonly _onDidChangeWorkspaceName: Emitter = new Emitter(); public readonly onDidChangeWorkspaceName: Event = this._onDidChangeWorkspaceName.event; - private readonly _onDidChangeWorkspaceFolders: Emitter = new Emitter(); - public readonly onDidChangeWorkspaceFolders: Event = this._onDidChangeWorkspaceFolders.event; + private readonly _onDidChangeWorkspaceFolders: Emitter = new Emitter(); + public readonly onDidChangeWorkspaceFolders: Event = this._onDidChangeWorkspaceFolders.event; private readonly _onDidChangeWorkbenchState: Emitter = new Emitter(); public readonly onDidChangeWorkbenchState: Event = this._onDidChangeWorkbenchState.event; diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index 0e307a99689..e923eb66709 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -21,6 +21,12 @@ export enum WorkbenchState { WORKSPACE } +export interface IWorkspaceFoldersChangeEvent { + added: WorkspaceFolder[]; + removed: WorkspaceFolder[]; + changed: WorkspaceFolder[]; +} + export interface IWorkspaceContextService { _serviceBrand: any; @@ -52,7 +58,7 @@ export interface IWorkspaceContextService { /** * An event which fires on workspace folders change. */ - onDidChangeWorkspaceFolders: Event; + onDidChangeWorkspaceFolders: Event; /** * Returns the folder for the given resource from the workspace. diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configuration.ts index fd6f77db55d..fe168920f34 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configuration.ts @@ -9,7 +9,6 @@ import * as paths from 'vs/base/common/paths'; import { TPromise } from 'vs/base/common/winjs.base'; import Event, { Emitter } from 'vs/base/common/event'; import { StrictResourceMap } from 'vs/base/common/map'; -import { equals } from 'vs/base/common/arrays'; import * as objects from 'vs/base/common/objects'; import * as errors from 'vs/base/common/errors'; import * as collections from 'vs/base/common/collections'; @@ -18,7 +17,7 @@ import { RunOnceScheduler } from 'vs/base/common/async'; import { readFile, stat, writeFile } from 'vs/base/node/pfs'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import * as extfs from 'vs/base/node/extfs'; -import { IWorkspaceContextService, IWorkspace, Workspace, WorkbenchState, WorkspaceFolder, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, IWorkspace, Workspace, WorkbenchState, WorkspaceFolder, toWorkspaceFolders, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files'; import { isLinux } from 'vs/base/common/platform'; import { ConfigWatcher } from 'vs/base/node/config'; @@ -253,8 +252,8 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat protected readonly _onDidUpdateConfiguration: Emitter = this._register(new Emitter()); public readonly onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; - protected readonly _onDidChangeWorkspaceFolders: Emitter = this._register(new Emitter()); - public readonly onDidChangeWorkspaceFolders: Event = this._onDidChangeWorkspaceFolders.event; + protected readonly _onDidChangeWorkspaceFolders: Emitter = this._register(new Emitter()); + public readonly onDidChangeWorkspaceFolders: Event = this._onDidChangeWorkspaceFolders.event; protected readonly _onDidChangeWorkspaceName: Emitter = this._register(new Emitter()); public readonly onDidChangeWorkspaceName: Event = this._onDidChangeWorkspaceName.event; @@ -438,11 +437,25 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat this._onDidChangeWorkspaceName.fire(); } - if (!equals(this.workspace.folders, currentFolders, (folder1, folder2) => folder1.uri.fsPath === folder2.uri.fsPath)) { - this._onDidChangeWorkspaceFolders.fire(); + const changes = this.compareFolders(currentFolders, this.workspace.folders); + if (changes.added.length || changes.removed.length || changes.changed.length) { + this._onDidChangeWorkspaceFolders.fire(changes); } } + private compareFolders(currentFolders: WorkspaceFolder[], newFolders: WorkspaceFolder[]): IWorkspaceFoldersChangeEvent { + const result = { added: [], removed: [], changed: [] }; + + result.added = newFolders.filter(newFolder => !currentFolders.some(currentFolder => newFolder.uri.toString() === currentFolder.uri.toString())); + result.removed = currentFolders.filter(currentFolder => !newFolders.some(newFolder => currentFolder.uri.toString() === newFolder.uri.toString())); + + if (result.added.length === 0 && result.removed.length === 0) { + result.changed = currentFolders.filter((currentFolder, index) => newFolders[index].uri.toString() !== currentFolder.uri.toString()); + } + + return result; + } + private initializeConfiguration(trigger: boolean = true): TPromise { this.resetCaches(); return this.updateConfiguration() @@ -487,12 +500,12 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat private onWorkspaceConfigurationChanged(): void { if (this.workspace && this.workspace.configuration) { let configuredFolders = toWorkspaceFolders(this.workspaceConfiguration.workspaceConfigurationModel.folders, URI.file(paths.dirname(this.workspace.configuration.fsPath))); - const foldersChanged = !equals(this.workspace.folders, configuredFolders, (folder1, folder2) => folder1.uri.fsPath === folder2.uri.fsPath); - if (foldersChanged) { // TODO@Sandeep be smarter here about detecting changes + const changes = this.compareFolders(this.workspace.folders, configuredFolders); + if (changes.added.length || changes.removed.length || changes.changed.length) { // TODO@Sandeep be smarter here about detecting changes this.workspace.folders = configuredFolders; this.onFoldersChanged() .then(configurationChanged => { - this._onDidChangeWorkspaceFolders.fire(); + this._onDidChangeWorkspaceFolders.fire(changes); if (configurationChanged) { this.triggerConfigurationChange(); } diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 1502ef8fe6e..7f89866c96d 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -27,7 +27,7 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { IEditorInput, IEditorOptions, Position, Direction, IEditor, IResourceInput, ITextEditorSelection } from 'vs/platform/editor/common/editor'; import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { IMessageService, IConfirmation } from 'vs/platform/message/common/message'; -import { IWorkspaceContextService, IWorkspace as IWorkbenchWorkspace, WorkbenchState, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, IWorkspace as IWorkbenchWorkspace, WorkbenchState, WorkspaceFolder, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; import { ILifecycleService, ShutdownEvent, ShutdownReason, StartupKind, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { EditorStacksModel } from 'vs/workbench/common/editor/editorStacksModel'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; @@ -74,14 +74,14 @@ export class TestContextService implements IWorkspaceContextService { private options: any; private _onDidChangeWorkspaceName: Emitter; - private _onDidChangeWorkspaceFolders: Emitter; + private _onDidChangeWorkspaceFolders: Emitter; private _onDidChangeWorkbenchState: Emitter; constructor(workspace: any = TestWorkspace, options: any = null) { this.workspace = workspace; this.id = generateUuid(); this.options = options || Object.create(null); - this._onDidChangeWorkspaceFolders = new Emitter(); + this._onDidChangeWorkspaceFolders = new Emitter(); this._onDidChangeWorkbenchState = new Emitter(); } @@ -89,7 +89,7 @@ export class TestContextService implements IWorkspaceContextService { return this._onDidChangeWorkspaceName.event; } - public get onDidChangeWorkspaceFolders(): Event { + public get onDidChangeWorkspaceFolders(): Event { return this._onDidChangeWorkspaceFolders.event; } From 54dfbf8c66e457a9ca79e63f9412158a3f7bb895 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 20 Sep 2017 09:54:24 +0200 Subject: [PATCH 073/281] fix #34520 --- src/vs/base/common/htmlContent.ts | 2 +- src/vs/workbench/api/node/extHostTypeConverters.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/base/common/htmlContent.ts b/src/vs/base/common/htmlContent.ts index ab7ae6065f1..ce013b916cc 100644 --- a/src/vs/base/common/htmlContent.ts +++ b/src/vs/base/common/htmlContent.ts @@ -56,7 +56,7 @@ export function isEmptyMarkdownString(oneOrMany: IMarkdownString | IMarkdownStri export function isMarkdownString(thing: any): thing is IMarkdownString { if (thing instanceof MarkdownString) { return true; - } else if (typeof thing === 'object') { + } else if (thing && typeof thing === 'object') { return typeof (thing).value === 'string' && (typeof (thing).isTrusted === 'boolean' || (thing).isTrusted === void 0); } diff --git a/src/vs/workbench/api/node/extHostTypeConverters.ts b/src/vs/workbench/api/node/extHostTypeConverters.ts index aa6a0d2b7d5..d8aef198fd8 100644 --- a/src/vs/workbench/api/node/extHostTypeConverters.ts +++ b/src/vs/workbench/api/node/extHostTypeConverters.ts @@ -158,7 +158,7 @@ export namespace MarkdownString { } function isCodeblock(thing: any): thing is Codeblock { - return typeof thing === 'object' + return thing && typeof thing === 'object' && typeof (thing).language === 'string' && typeof (thing).value === 'string'; } From 94eaf80a25cd292db2b1230e928b5304eefce0df Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 20 Sep 2017 10:01:56 +0200 Subject: [PATCH 074/281] Use workbench state instead of checking on workspace config --- .../parts/extensions/browser/extensionsActions.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts index 7640073567b..311b186a859 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts @@ -1368,11 +1368,13 @@ export class ConfigureWorkspaceRecommendedExtensionsAction extends AbstractConfi } public run(event: any): TPromise { - const workspace = this.contextService.getWorkspace(); - if (workspace.configuration) { - return this.openWorkspaceConfigurationFile(workspace.configuration); + switch (this.contextService.getWorkbenchState()) { + case WorkbenchState.FOLDER: + return this.openExtensionsFile(this.contextService.toResource(paths.join('.vscode', 'extensions.json'), this.contextService.getWorkspace().folders[0])); + case WorkbenchState.WORKSPACE: + return this.openWorkspaceConfigurationFile(this.contextService.getWorkspace().configuration); } - return this.openExtensionsFile(this.contextService.toResource(paths.join('.vscode', 'extensions.json'), workspace.folders[0])); + return TPromise.as(null); } dispose(): void { From d37fc99376f600077734dec4a4cdbab101a76a95 Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 20 Sep 2017 10:04:45 +0200 Subject: [PATCH 075/281] polish label --- src/vs/workbench/browser/labels.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index b3ec715b473..75c85fdb9f7 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -235,12 +235,10 @@ export class FileLabel extends ResourceLabel { } } - const description = resource.scheme === 'file' || resource.scheme === 'untitled' ? getPathLabel(paths.dirname(resource.fsPath), rootProvider, this.environmentService) : resource.authority; - this.setLabel({ resource, name: (options && options.hideLabel) ? void 0 : resources.basenameOrAuthority(resource), - description: !hidePath ? description : void 0 + description: !hidePath ? getPathLabel(resources.dirname(resource), rootProvider, this.environmentService) : void 0 }, options); } } From e7293b93fb73e2b30084f99613dd81d42122d459 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 20 Sep 2017 10:17:34 +0200 Subject: [PATCH 076/281] Use workspace folder picker --- .../extensions/browser/extensionsActions.ts | 27 +++++++------------ .../preferences/browser/preferencesActions.ts | 27 +++++++------------ 2 files changed, 20 insertions(+), 34 deletions(-) diff --git a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts index 311b186a859..d631f79db21 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts @@ -26,19 +26,19 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Query } from 'vs/workbench/parts/extensions/common/extensionQuery'; import { IFileService, IContent } from 'vs/platform/files/common/files'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { IExtensionService, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import URI from 'vs/base/common/uri'; -import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { buttonBackground, buttonForeground, buttonHoverBackground, contrastBorder, registerColor, foreground } from 'vs/platform/theme/common/colorRegistry'; import { Color } from 'vs/base/common/color'; -import { IPickOpenEntry, IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; import { ITextEditorSelection } from 'vs/platform/editor/common/editor'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { PICK_WORKSPACE_FOLDER_COMMAND } from 'vs/workbench/browser/actions/workspaceActions'; export class InstallAction extends Action { @@ -1393,12 +1393,12 @@ export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends Abstrac constructor( id: string, label: string, - @IQuickOpenService private quickOpenService: IQuickOpenService, @IFileService fileService: IFileService, @IWorkspaceContextService contextService: IWorkspaceContextService, @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IJSONEditingService jsonEditingService: IJSONEditingService, - @ITextModelService textModelResolverService: ITextModelService + @ITextModelService textModelResolverService: ITextModelService, + @ICommandService private commandService: ICommandService ) { super(id, label, contextService, fileService, editorService, jsonEditingService, textModelResolverService); this.contextService.onDidChangeWorkspaceFolders(() => this.update(), this, this.disposables); @@ -1410,19 +1410,12 @@ export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends Abstrac } public run(): TPromise { - const picks: IPickOpenEntry[] = this.contextService.getWorkspace().folders.map((folder, index) => { - return { - label: folder.name, - id: `${index}` - }; - }); - - return this.quickOpenService.pick(picks, { placeHolder: localize('pickFolder', "Select Workspace Folder") }) - .then(pick => { - if (pick) { - return this.openExtensionsFile(this.contextService.toResource(paths.join('.vscode', 'extensions.json'), this.contextService.getWorkspace().folders[parseInt(pick.id)])); + return this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND) + .then(workspaceFolder => { + if (workspaceFolder) { + return this.openExtensionsFile(this.contextService.toResource(paths.join('.vscode', 'extensions.json'), workspaceFolder)); } - return undefined; + return null; }); } diff --git a/src/vs/workbench/parts/preferences/browser/preferencesActions.ts b/src/vs/workbench/parts/preferences/browser/preferencesActions.ts index 0417094813d..c1e222a04dd 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesActions.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesActions.ts @@ -11,9 +11,10 @@ import { Action } from 'vs/base/common/actions'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IQuickOpenService, IPickOpenEntry, IFilePickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen'; -import { IPreferencesService, getSettingsTargetName } from 'vs/workbench/parts/preferences/common/preferences'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { IPreferencesService } from 'vs/workbench/parts/preferences/common/preferences'; +import { IWorkspaceContextService, WorkbenchState, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { PICK_WORKSPACE_FOLDER_COMMAND } from 'vs/workbench/browser/actions/workspaceActions'; export class OpenGlobalSettingsAction extends Action { @@ -114,7 +115,7 @@ export class OpenFolderSettingsAction extends Action { label: string, @IPreferencesService private preferencesService: IPreferencesService, @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, - @IQuickOpenService private quickOpenService: IQuickOpenService + @ICommandService private commandService: ICommandService ) { super(id, label); this.update(); @@ -127,21 +128,13 @@ export class OpenFolderSettingsAction extends Action { } public run(): TPromise { - const picks: IPickOpenEntry[] = this.workspaceContextService.getWorkspace().folders.map((folder, index) => { - return { - label: getSettingsTargetName(ConfigurationTarget.FOLDER, folder.uri, this.workspaceContextService), - id: `${index}` - }; - }); - - return this.quickOpenService.pick(picks, { placeHolder: nls.localize('pickFolder', "Select Folder") }) - .then(pick => { - if (pick) { - return this.preferencesService.openFolderSettings(this.workspaceContextService.getWorkspace().folders[parseInt(pick.id)].uri); + return this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND) + .then(workspaceFolder => { + if (workspaceFolder) { + return this.preferencesService.openFolderSettings(workspaceFolder.uri); } - return undefined; + return null; }); - } public dispose(): void { From 10eb2b73c6b5cb845fbe52d8280278cb965d5eb5 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 20 Sep 2017 10:42:39 +0200 Subject: [PATCH 077/281] more fixes for #34490 --- src/vs/workbench/services/history/browser/history.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index 2b8dedeb038..8e8e0c3efee 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -720,7 +720,10 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic if (input instanceof EditorInput) { const factory = registry.getEditorInputFactory(input.getTypeId()); if (factory) { - return { editorInputJSON: { typeId: input.getTypeId(), deserialized: factory.serialize(input) } } as ISerializedEditorHistoryEntry; + const deserialized = factory.serialize(input); + if (deserialized) { + return { editorInputJSON: { typeId: input.getTypeId(), deserialized } } as ISerializedEditorHistoryEntry; + } } } @@ -754,10 +757,11 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic } // Editor input: via factory - if (serializedEditorHistoryEntry.editorInputJSON) { - const factory = registry.getEditorInputFactory(serializedEditorHistoryEntry.editorInputJSON.typeId); + const { editorInputJSON } = serializedEditorHistoryEntry; + if (editorInputJSON && editorInputJSON.deserialized) { + const factory = registry.getEditorInputFactory(editorInputJSON.typeId); if (factory) { - return factory.deserialize(this.instantiationService, serializedEditorHistoryEntry.editorInputJSON.deserialized); + return factory.deserialize(this.instantiationService, editorInputJSON.deserialized); } } From 250d71b2b95a4acacec6f828227f67fb585bea25 Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 20 Sep 2017 11:04:58 +0200 Subject: [PATCH 078/281] alex: first remove decoration types and only then fire a model change event --- src/vs/editor/common/commonCodeEditor.ts | 26 ++++++++++++++---------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/vs/editor/common/commonCodeEditor.ts b/src/vs/editor/common/commonCodeEditor.ts index 29700d8baf2..bc5bde47a62 100644 --- a/src/vs/editor/common/commonCodeEditor.ts +++ b/src/vs/editor/common/commonCodeEditor.ts @@ -170,7 +170,7 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo // editor actions don't need to be disposed this._actions = {}; - + this._removeDecorationTypes(); this._postDetachModelCleanup(this._detachModel()); this._onDidDispose.fire(); @@ -232,10 +232,24 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo newModelUrl: model ? model.uri : null }; + this._removeDecorationTypes(); this._onDidChangeModel.fire(e); this._postDetachModelCleanup(detachedModel); } + private _removeDecorationTypes(): void { + this._decorationTypeKeysToIds = {}; + if (this._decorationTypeSubtypes) { + for (let decorationType in this._decorationTypeSubtypes) { + let subTypes = this._decorationTypeSubtypes[decorationType]; + for (let subType in subTypes) { + this._removeDecorationType(decorationType + '-' + subType); + } + } + this._decorationTypeSubtypes = {}; + } + } + public getCenteredRangeInViewport(): Range { if (!this.hasView) { return null; @@ -948,16 +962,6 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo protected _postDetachModelCleanup(detachedModel: editorCommon.IModel): void { if (detachedModel) { - this._decorationTypeKeysToIds = {}; - if (this._decorationTypeSubtypes) { - for (let decorationType in this._decorationTypeSubtypes) { - let subTypes = this._decorationTypeSubtypes[decorationType]; - for (let subType in subTypes) { - this._removeDecorationType(decorationType + '-' + subType); - } - } - this._decorationTypeSubtypes = {}; - } detachedModel.removeAllDecorationsWithOwnerId(this.id); } } From 58b39d719a9aeb9c895755042ddf2dcbbdb72bb1 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 20 Sep 2017 09:00:03 +0200 Subject: [PATCH 079/281] Move indent ranges to ITokenizedModel --- src/vs/editor/common/editorCommon.ts | 29 +-- src/vs/editor/common/model/indentRanges.ts | 4 +- src/vs/editor/common/model/textModel.ts | 62 ------ .../common/model/textModelWithTokens.ts | 65 +++++++ .../test/common/model/textModel.test.ts | 176 +----------------- .../common/model/textModelWithTokens.test.ts | 174 +++++++++++++++++ 6 files changed, 257 insertions(+), 253 deletions(-) diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index a8faeb62a75..d2c5e4b1a71 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -585,20 +585,6 @@ export interface ITextModel { */ getLineContent(lineNumber: number): string; - /** - * @internal - */ - getIndentLevel(lineNumber: number): number; - - /** - * @internal - */ - getIndentRanges(): IndentRange[]; - - /** - * @internal - */ - getLineIndentGuide(lineNumber: number): number; /** * Get the text for all lines. @@ -912,6 +898,21 @@ export interface ITokenizedModel extends ITextModel { * @internal */ matchBracket(position: IPosition): [Range, Range]; + + /** + * @internal + */ + getIndentLevel(lineNumber: number): number; + + /** + * @internal + */ + getIndentRanges(): IndentRange[]; + + /** + * @internal + */ + getLineIndentGuide(lineNumber: number): number; } /** diff --git a/src/vs/editor/common/model/indentRanges.ts b/src/vs/editor/common/model/indentRanges.ts index f220df0cfba..c96840a624d 100644 --- a/src/vs/editor/common/model/indentRanges.ts +++ b/src/vs/editor/common/model/indentRanges.ts @@ -5,7 +5,7 @@ 'use strict'; -import { ITextModel } from 'vs/editor/common/editorCommon'; +import { ITokenizedModel } from 'vs/editor/common/editorCommon'; export class IndentRange { _indentRangeBrand: void; @@ -29,7 +29,7 @@ export class IndentRange { } } -export function computeRanges(model: ITextModel, minimumRangeSize: number = 1): IndentRange[] { +export function computeRanges(model: ITokenizedModel, minimumRangeSize: number = 1): IndentRange[] { let result: IndentRange[] = []; diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index ce088944f8d..3e55882ed96 100644 --- a/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -13,7 +13,6 @@ import { ModelLine, IModelLine, MinimalModelLine } from 'vs/editor/common/model/ import { guessIndentation } from 'vs/editor/common/model/indentationGuesser'; import { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/config/editorOptions'; import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; -import { IndentRange, computeRanges } from 'vs/editor/common/model/indentRanges'; import { TextModelSearch, SearchParams } from 'vs/editor/common/model/textModelSearch'; import { TextSource, ITextSource, IRawTextSource, RawTextSource } from 'vs/editor/common/model/textSource'; import { IDisposable } from 'vs/base/common/lifecycle'; @@ -85,7 +84,6 @@ export class TextModel implements editorCommon.ITextModel { protected _isDisposing: boolean; protected _options: editorCommon.TextModelResolvedOptions; protected _lineStarts: PrefixSumComputer; - private _indentRanges: IndentRange[]; private _versionId: number; /** @@ -513,65 +511,6 @@ export class TextModel implements editorCommon.ITextModel { return this._lines[lineNumber - 1].getIndentLevel(); } - protected _resetIndentRanges(): void { - this._indentRanges = null; - } - - private _getIndentRanges(): IndentRange[] { - if (!this._indentRanges) { - this._indentRanges = computeRanges(this); - } - return this._indentRanges; - } - - public getIndentRanges(): IndentRange[] { - this._assertNotDisposed(); - let indentRanges = this._getIndentRanges(); - return IndentRange.deepCloneArr(indentRanges); - } - - private _toValidLineIndentGuide(lineNumber: number, indentGuide: number): number { - let lineIndentLevel = this._lines[lineNumber - 1].getIndentLevel(); - if (lineIndentLevel === -1) { - return indentGuide; - } - let maxIndentGuide = Math.ceil(lineIndentLevel / this._options.tabSize); - return Math.min(maxIndentGuide, indentGuide); - } - - public getLineIndentGuide(lineNumber: number): number { - this._assertNotDisposed(); - if (lineNumber < 1 || lineNumber > this.getLineCount()) { - throw new Error('Illegal value ' + lineNumber + ' for `lineNumber`'); - } - - let indentRanges = this._getIndentRanges(); - - for (let i = indentRanges.length - 1; i >= 0; i--) { - let rng = indentRanges[i]; - - if (rng.startLineNumber === lineNumber) { - return this._toValidLineIndentGuide(lineNumber, Math.ceil(rng.indent / this._options.tabSize)); - } - if (rng.startLineNumber < lineNumber && lineNumber <= rng.endLineNumber) { - return this._toValidLineIndentGuide(lineNumber, 1 + Math.floor(rng.indent / this._options.tabSize)); - } - if (rng.endLineNumber + 1 === lineNumber) { - let bestIndent = rng.indent; - while (i > 0) { - i--; - rng = indentRanges[i]; - if (rng.endLineNumber + 1 === lineNumber) { - bestIndent = rng.indent; - } - } - return this._toValidLineIndentGuide(lineNumber, Math.ceil(bestIndent / this._options.tabSize)); - } - } - - return 0; - } - public getLinesContent(): string[] { this._assertNotDisposed(); var r: string[] = []; @@ -785,7 +724,6 @@ export class TextModel implements editorCommon.ITextModel { this._EOL = textSource.EOL; this._lines = modelLines; this._lineStarts = null; - this._resetIndentRanges(); } private _getEndOfLine(eol: editorCommon.EndOfLinePreference): string { diff --git a/src/vs/editor/common/model/textModelWithTokens.ts b/src/vs/editor/common/model/textModelWithTokens.ts index d4f31ffcc58..648685cb9a4 100644 --- a/src/vs/editor/common/model/textModelWithTokens.ts +++ b/src/vs/editor/common/model/textModelWithTokens.ts @@ -22,6 +22,7 @@ import { getWordAtText } from 'vs/editor/common/model/wordHelper'; import { TokenizationResult2 } from 'vs/editor/common/core/token'; import { ITextSource, IRawTextSource } from 'vs/editor/common/model/textSource'; import * as textModelEvents from 'vs/editor/common/model/textModelEvents'; +import { IndentRange, computeRanges } from 'vs/editor/common/model/indentRanges'; class ModelTokensChangedEventBuilder { @@ -69,6 +70,8 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke private _invalidLineStartIndex: number; private _lastState: IState; + private _indentRanges: IndentRange[]; + private _revalidateTokensTimeout: number; constructor(rawTextSource: IRawTextSource, creationOptions: editorCommon.ITextModelCreationOptions, languageIdentifier: LanguageIdentifier) { @@ -96,6 +99,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke this._revalidateTokensTimeout = -1; this._resetTokenizationState(); + this._resetIndentRanges(); } public dispose(): void { @@ -114,6 +118,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke super._resetValue(newValue); // Cancel tokenization, clear all tokens and begin tokenizing this._resetTokenizationState(); + this._resetIndentRanges(); } protected _resetTokenizationState(): void { @@ -225,6 +230,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke // Cancel tokenization, clear all tokens and begin tokenizing this._resetTokenizationState(); + this._resetIndentRanges(); this.emitModelTokensChangedEvent({ ranges: [{ @@ -814,4 +820,63 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke isOpen: modeBrackets.textIsOpenBracket[text] }; } + + protected _resetIndentRanges(): void { + this._indentRanges = null; + } + + private _getIndentRanges(): IndentRange[] { + if (!this._indentRanges) { + this._indentRanges = computeRanges(this); + } + return this._indentRanges; + } + + public getIndentRanges(): IndentRange[] { + this._assertNotDisposed(); + let indentRanges = this._getIndentRanges(); + return IndentRange.deepCloneArr(indentRanges); + } + + public getLineIndentGuide(lineNumber: number): number { + this._assertNotDisposed(); + if (lineNumber < 1 || lineNumber > this.getLineCount()) { + throw new Error('Illegal value ' + lineNumber + ' for `lineNumber`'); + } + + let indentRanges = this._getIndentRanges(); + + for (let i = indentRanges.length - 1; i >= 0; i--) { + let rng = indentRanges[i]; + + if (rng.startLineNumber === lineNumber) { + return this._toValidLineIndentGuide(lineNumber, Math.ceil(rng.indent / this._options.tabSize)); + } + if (rng.startLineNumber < lineNumber && lineNumber <= rng.endLineNumber) { + return this._toValidLineIndentGuide(lineNumber, 1 + Math.floor(rng.indent / this._options.tabSize)); + } + if (rng.endLineNumber + 1 === lineNumber) { + let bestIndent = rng.indent; + while (i > 0) { + i--; + rng = indentRanges[i]; + if (rng.endLineNumber + 1 === lineNumber) { + bestIndent = rng.indent; + } + } + return this._toValidLineIndentGuide(lineNumber, Math.ceil(bestIndent / this._options.tabSize)); + } + } + + return 0; + } + + private _toValidLineIndentGuide(lineNumber: number, indentGuide: number): number { + let lineIndentLevel = this._lines[lineNumber - 1].getIndentLevel(); + if (lineIndentLevel === -1) { + return indentGuide; + } + let maxIndentGuide = Math.ceil(lineIndentLevel / this._options.tabSize); + return Math.min(maxIndentGuide, indentGuide); + } } diff --git a/src/vs/editor/test/common/model/textModel.test.ts b/src/vs/editor/test/common/model/textModel.test.ts index cba2a056eba..e36e11308e5 100644 --- a/src/vs/editor/test/common/model/textModel.test.ts +++ b/src/vs/editor/test/common/model/textModel.test.ts @@ -820,178 +820,4 @@ suite('TextModel.mightContainRTL', () => { assert.equal(model.mightContainRTL(), false); }); -}); - -suite('TextModel.getLineIndentGuide', () => { - function assertIndentGuides(lines: [number, string][]): void { - let text = lines.map(l => l[1]).join('\n'); - let model = TextModel.createFromString(text); - - let actual: [number, string][] = []; - for (let line = 1; line <= model.getLineCount(); line++) { - actual[line - 1] = [model.getLineIndentGuide(line), model.getLineContent(line)]; - } - - // let expected = lines.map(l => l[0]); - - assert.deepEqual(actual, lines); - - model.dispose(); - } - - test('getLineIndentGuide one level', () => { - assertIndentGuides([ - [0, 'A'], - [1, ' A'], - [1, ' A'], - [1, ' A'], - ]); - }); - - test('getLineIndentGuide two levels', () => { - assertIndentGuides([ - [0, 'A'], - [1, ' A'], - [1, ' A'], - [1, ' A'], - [1, ' A'], - ]); - }); - - test('getLineIndentGuide three levels', () => { - assertIndentGuides([ - [0, 'A'], - [1, ' A'], - [1, ' A'], - [2, ' A'], - [0, 'A'], - ]); - }); - - test('getLineIndentGuide decreasing indent', () => { - assertIndentGuides([ - [0, ' A'], - [0, ' A'], - [0, 'A'], - ]); - }); - - test('getLineIndentGuide Java', () => { - assertIndentGuides([ - /* 1*/[0, 'class A {'], - /* 2*/[1, ' void foo() {'], - /* 3*/[1, ' console.log(1);'], - /* 4*/[1, ' console.log(2);'], - /* 5*/[1, ' }'], - /* 6*/[1, ''], - /* 7*/[1, ' void bar() {'], - /* 8*/[1, ' console.log(3);'], - /* 9*/[1, ' }'], - /*10*/[0, '}'], - /*11*/[0, 'interface B {'], - /*12*/[1, ' void bar();'], - /*13*/[0, '}'], - ]); - }); - - test('getLineIndentGuide Javadoc', () => { - assertIndentGuides([ - [0, '/**'], - [1, ' * Comment'], - [1, ' */'], - [0, 'class A {'], - [1, ' void foo() {'], - [1, ' }'], - [0, '}'], - ]); - }); - - test('getLineIndentGuide Whitespace', () => { - assertIndentGuides([ - [0, 'class A {'], - [1, ''], - [1, ' void foo() {'], - [1, ' '], - [1, ' return 1;'], - [1, ' }'], - [1, ' '], - [0, '}'], - ]); - }); - - test('getLineIndentGuide Tabs', () => { - assertIndentGuides([ - [0, 'class A {'], - [1, '\t\t'], - [1, '\tvoid foo() {'], - [2, '\t \t//hello'], - [2, '\t return 2;'], - [1, ' \t}'], - [1, ' '], - [0, '}'], - ]); - }); - - test('getLineIndentGuide checker.ts', () => { - assertIndentGuides([ - /* 1*/[0, '/// '], - /* 2*/[0, ''], - /* 3*/[0, '/* @internal */'], - /* 4*/[0, 'namespace ts {'], - /* 5*/[1, ' let nextSymbolId = 1;'], - /* 6*/[1, ' let nextNodeId = 1;'], - /* 7*/[1, ' let nextMergeId = 1;'], - /* 8*/[1, ' let nextFlowId = 1;'], - /* 9*/[1, ''], - /*10*/[1, ' export function getNodeId(node: Node): number {'], - /*11*/[2, ' if (!node.id) {'], - /*12*/[3, ' node.id = nextNodeId;'], - /*13*/[3, ' nextNodeId++;'], - /*14*/[2, ' }'], - /*15*/[2, ' return node.id;'], - /*16*/[1, ' }'], - /*17*/[0, '}'], - ]); - }); - - test('issue #8425 - Missing indentation lines for first level indentation', () => { - assertIndentGuides([ - [1, '\tindent1'], - [2, '\t\tindent2'], - [2, '\t\tindent2'], - [1, '\tindent1'], - ]); - }); - - test('issue #8952 - Indentation guide lines going through text on .yml file', () => { - assertIndentGuides([ - [0, 'properties:'], - [1, ' emailAddress:'], - [2, ' - bla'], - [2, ' - length:'], - [3, ' max: 255'], - [0, 'getters:'], - ]); - }); - - test('issue #11892 - Indent guides look funny', () => { - assertIndentGuides([ - [0, 'function test(base) {'], - [1, '\tswitch (base) {'], - [2, '\t\tcase 1:'], - [3, '\t\t\treturn 1;'], - [2, '\t\tcase 2:'], - [3, '\t\t\treturn 2;'], - [1, '\t}'], - [0, '}'], - ]); - }); - - test('issue #12398 - Problem in indent guidelines', () => { - assertIndentGuides([ - [2, '\t\t.bla'], - [3, '\t\t\tlabel(for)'], - [0, 'include script'], - ]); - }); -}); +}); \ No newline at end of file diff --git a/src/vs/editor/test/common/model/textModelWithTokens.test.ts b/src/vs/editor/test/common/model/textModelWithTokens.test.ts index 6ac512096dd..24c66e08947 100644 --- a/src/vs/editor/test/common/model/textModelWithTokens.test.ts +++ b/src/vs/editor/test/common/model/textModelWithTokens.test.ts @@ -359,3 +359,177 @@ suite('TextModelWithTokens regression tests', () => { registration.dispose(); }); }); + +suite('TextModel.getLineIndentGuide', () => { + function assertIndentGuides(lines: [number, string][]): void { + let text = lines.map(l => l[1]).join('\n'); + let model = Model.createFromString(text); + + let actual: [number, string][] = []; + for (let line = 1; line <= model.getLineCount(); line++) { + actual[line - 1] = [model.getLineIndentGuide(line), model.getLineContent(line)]; + } + + // let expected = lines.map(l => l[0]); + + assert.deepEqual(actual, lines); + + model.dispose(); + } + + test('getLineIndentGuide one level', () => { + assertIndentGuides([ + [0, 'A'], + [1, ' A'], + [1, ' A'], + [1, ' A'], + ]); + }); + + test('getLineIndentGuide two levels', () => { + assertIndentGuides([ + [0, 'A'], + [1, ' A'], + [1, ' A'], + [1, ' A'], + [1, ' A'], + ]); + }); + + test('getLineIndentGuide three levels', () => { + assertIndentGuides([ + [0, 'A'], + [1, ' A'], + [1, ' A'], + [2, ' A'], + [0, 'A'], + ]); + }); + + test('getLineIndentGuide decreasing indent', () => { + assertIndentGuides([ + [0, ' A'], + [0, ' A'], + [0, 'A'], + ]); + }); + + test('getLineIndentGuide Java', () => { + assertIndentGuides([ + /* 1*/[0, 'class A {'], + /* 2*/[1, ' void foo() {'], + /* 3*/[1, ' console.log(1);'], + /* 4*/[1, ' console.log(2);'], + /* 5*/[1, ' }'], + /* 6*/[1, ''], + /* 7*/[1, ' void bar() {'], + /* 8*/[1, ' console.log(3);'], + /* 9*/[1, ' }'], + /*10*/[0, '}'], + /*11*/[0, 'interface B {'], + /*12*/[1, ' void bar();'], + /*13*/[0, '}'], + ]); + }); + + test('getLineIndentGuide Javadoc', () => { + assertIndentGuides([ + [0, '/**'], + [1, ' * Comment'], + [1, ' */'], + [0, 'class A {'], + [1, ' void foo() {'], + [1, ' }'], + [0, '}'], + ]); + }); + + test('getLineIndentGuide Whitespace', () => { + assertIndentGuides([ + [0, 'class A {'], + [1, ''], + [1, ' void foo() {'], + [1, ' '], + [1, ' return 1;'], + [1, ' }'], + [1, ' '], + [0, '}'], + ]); + }); + + test('getLineIndentGuide Tabs', () => { + assertIndentGuides([ + [0, 'class A {'], + [1, '\t\t'], + [1, '\tvoid foo() {'], + [2, '\t \t//hello'], + [2, '\t return 2;'], + [1, ' \t}'], + [1, ' '], + [0, '}'], + ]); + }); + + test('getLineIndentGuide checker.ts', () => { + assertIndentGuides([ + /* 1*/[0, '/// '], + /* 2*/[0, ''], + /* 3*/[0, '/* @internal */'], + /* 4*/[0, 'namespace ts {'], + /* 5*/[1, ' let nextSymbolId = 1;'], + /* 6*/[1, ' let nextNodeId = 1;'], + /* 7*/[1, ' let nextMergeId = 1;'], + /* 8*/[1, ' let nextFlowId = 1;'], + /* 9*/[1, ''], + /*10*/[1, ' export function getNodeId(node: Node): number {'], + /*11*/[2, ' if (!node.id) {'], + /*12*/[3, ' node.id = nextNodeId;'], + /*13*/[3, ' nextNodeId++;'], + /*14*/[2, ' }'], + /*15*/[2, ' return node.id;'], + /*16*/[1, ' }'], + /*17*/[0, '}'], + ]); + }); + + test('issue #8425 - Missing indentation lines for first level indentation', () => { + assertIndentGuides([ + [1, '\tindent1'], + [2, '\t\tindent2'], + [2, '\t\tindent2'], + [1, '\tindent1'], + ]); + }); + + test('issue #8952 - Indentation guide lines going through text on .yml file', () => { + assertIndentGuides([ + [0, 'properties:'], + [1, ' emailAddress:'], + [2, ' - bla'], + [2, ' - length:'], + [3, ' max: 255'], + [0, 'getters:'], + ]); + }); + + test('issue #11892 - Indent guides look funny', () => { + assertIndentGuides([ + [0, 'function test(base) {'], + [1, '\tswitch (base) {'], + [2, '\t\tcase 1:'], + [3, '\t\t\treturn 1;'], + [2, '\t\tcase 2:'], + [3, '\t\t\treturn 2;'], + [1, '\t}'], + [0, '}'], + ]); + }); + + test('issue #12398 - Problem in indent guidelines', () => { + assertIndentGuides([ + [2, '\t\t.bla'], + [3, '\t\t\tlabel(for)'], + [0, 'include script'], + ]); + }); +}); From c2a6d7ae1fbe2b0800b0f6c577867f021b710dbe Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 20 Sep 2017 09:13:26 +0200 Subject: [PATCH 080/281] add IModelLanguageConfigurationChangedEvent and ViewLanguageConfigurationEvent --- src/vs/editor/common/commonCodeEditor.ts | 9 ++++++++- src/vs/editor/common/controller/cursor.ts | 6 ++---- src/vs/editor/common/editorCommon.ts | 12 +++++++++++- src/vs/editor/common/model/model.ts | 4 +++- src/vs/editor/common/model/textModelEvents.ts | 7 +++++++ .../editor/common/model/textModelWithTokens.ts | 16 ++++++++++++++++ .../modes/languageConfigurationRegistry.ts | 12 ++++++++---- src/vs/editor/common/view/viewEvents.ts | 12 +++++++++++- .../editor/common/viewModel/viewEventHandler.ts | 10 +++++++++- src/vs/editor/common/viewModel/viewModelImpl.ts | 4 ++++ src/vs/monaco.d.ts | 16 ++++++++++++++++ 11 files changed, 95 insertions(+), 13 deletions(-) diff --git a/src/vs/editor/common/commonCodeEditor.ts b/src/vs/editor/common/commonCodeEditor.ts index bc5bde47a62..e3f5394ff42 100644 --- a/src/vs/editor/common/commonCodeEditor.ts +++ b/src/vs/editor/common/commonCodeEditor.ts @@ -23,7 +23,7 @@ import { hash } from 'vs/base/common/hash'; import { EditorModeContext } from 'vs/editor/common/modes/editorModeContext'; import { IModelContentChangedEvent, IModelDecorationsChangedEvent, - IModelLanguageChangedEvent, IModelOptionsChangedEvent, TextModelEventType + IModelLanguageChangedEvent, IModelOptionsChangedEvent, TextModelEventType, IModelLanguageConfigurationChangedEvent } from 'vs/editor/common/model/textModelEvents'; import * as editorOptions from 'vs/editor/common/config/editorOptions'; import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; @@ -44,6 +44,9 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo private readonly _onDidChangeModelLanguage: Emitter = this._register(new Emitter()); public readonly onDidChangeModelLanguage: Event = this._onDidChangeModelLanguage.event; + private readonly _onDidChangeModelLanguageConfiguration: Emitter = this._register(new Emitter()); + public readonly onDidChangeModelLanguageConfiguration: Event = this._onDidChangeModelLanguage.event; + private readonly _onDidChangeModelOptions: Emitter = this._register(new Emitter()); public readonly onDidChangeModelOptions: Event = this._onDidChangeModelOptions.event; @@ -901,6 +904,10 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo this._onDidChangeModelLanguage.fire(e); break; + case TextModelEventType.ModelLanguageConfigurationChanged: + this._onDidChangeModelLanguageConfiguration.fire(e); + break; + case TextModelEventType.ModelContentChanged: this._onDidChangeModelContent.fire(e); break; diff --git a/src/vs/editor/common/controller/cursor.ts b/src/vs/editor/common/controller/cursor.ts index 89edd8d344c..65bc4059e5c 100644 --- a/src/vs/editor/common/controller/cursor.ts +++ b/src/vs/editor/common/controller/cursor.ts @@ -13,7 +13,6 @@ import { Range } from 'vs/editor/common/core/range'; import { Selection, SelectionDirection, ISelection } from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { CursorColumns, CursorConfiguration, EditOperationResult, CursorContext, CursorState, RevealTarget, IColumnSelectData, ICursors } from 'vs/editor/common/controller/cursorCommon'; -import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations'; import { TypeOperations } from 'vs/editor/common/controller/cursorTypeOperations'; import { TextModelEventType, ModelRawContentChangedEvent, RawContentChangedType } from 'vs/editor/common/model/textModelEvents'; @@ -150,11 +149,10 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this.context = new CursorContext(this._configuration, this._model, this._viewModel); this._cursors.updateContext(this.context); }; - this._register(this._model.onDidChangeLanguage((e) => { + this._register(model.onDidChangeLanguage((e) => { updateCursorContext(); })); - this._register(LanguageConfigurationRegistry.onDidChange(() => { - // TODO@Alex: react only if certain supports changed? (and if my model's mode changed) + this._register(model.onDidChangeLanguageConfiguration(() => { updateCursorContext(); })); this._register(model.onDidChangeOptions(() => { diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index d2c5e4b1a71..4cebd942285 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -19,7 +19,7 @@ import { IndentRange } from 'vs/editor/common/model/indentRanges'; import { ITextSource } from 'vs/editor/common/model/textSource'; import { ModelRawContentChangedEvent, IModelContentChangedEvent, IModelDecorationsChangedEvent, - IModelLanguageChangedEvent, IModelOptionsChangedEvent + IModelLanguageChangedEvent, IModelOptionsChangedEvent, IModelLanguageConfigurationChangedEvent } from 'vs/editor/common/model/textModelEvents'; import * as editorOptions from 'vs/editor/common/config/editorOptions'; import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; @@ -1150,6 +1150,11 @@ export interface IModel extends IReadOnlyModel, IEditableTextModel, ITextModelWi * @event */ onDidChangeLanguage(listener: (e: IModelLanguageChangedEvent) => void): IDisposable; + /** + * An event emitted when the language configuration associated with the model has changed. + * @event + */ + onDidChangeLanguageConfiguration(listener: (e: IModelLanguageConfigurationChangedEvent) => void): IDisposable; /** * An event emitted right before disposing the model. * @event @@ -1749,6 +1754,11 @@ export interface ICommonCodeEditor extends IEditor { * @event */ onDidChangeModelLanguage(listener: (e: IModelLanguageChangedEvent) => void): IDisposable; + /** + * An event emitted when the language configuration of the current model has changed. + * @event + */ + onDidChangeModelLanguageConfiguration(listener: (e: IModelLanguageConfigurationChangedEvent) => void): IDisposable; /** * An event emitted when the options of the current model has changed. * @event diff --git a/src/vs/editor/common/model/model.ts b/src/vs/editor/common/model/model.ts index aef76d48016..1228592fe0f 100644 --- a/src/vs/editor/common/model/model.ts +++ b/src/vs/editor/common/model/model.ts @@ -34,7 +34,9 @@ export class Model extends EditableTextModel implements IModel { public onDidChangeLanguage(listener: (e: textModelEvents.IModelLanguageChangedEvent) => void): IDisposable { return this._eventEmitter.addListener(textModelEvents.TextModelEventType.ModelLanguageChanged, listener); } - + public onDidChangeLanguageConfiguration(listener: (e: textModelEvents.IModelLanguageConfigurationChangedEvent) => void): IDisposable { + return this._eventEmitter.addListener(textModelEvents.TextModelEventType.ModelLanguageConfigurationChanged, listener); + } public static createFromString(text: string, options: ITextModelCreationOptions = TextModel.DEFAULT_CREATION_OPTIONS, languageIdentifier: LanguageIdentifier = null, uri: URI = null): Model { return new Model(RawTextSource.fromString(text), options, languageIdentifier, uri); } diff --git a/src/vs/editor/common/model/textModelEvents.ts b/src/vs/editor/common/model/textModelEvents.ts index 890dd25df46..2acaf260be2 100644 --- a/src/vs/editor/common/model/textModelEvents.ts +++ b/src/vs/editor/common/model/textModelEvents.ts @@ -18,6 +18,7 @@ export const TextModelEventType = { ModelContentChanged: 'contentChanged', ModelRawContentChanged2: 'rawContentChanged2', ModelDecorationsChanged: 'decorationsChanged', + ModelLanguageConfigurationChanged: 'modelLanguageConfigurationChanged' }; /** @@ -34,6 +35,12 @@ export interface IModelLanguageChangedEvent { readonly newLanguage: string; } +/** + * An event describing that the language configuration associated with a model has changed. + */ +export interface IModelLanguageConfigurationChangedEvent { +} + export interface IModelContentChange { /** * The range that got replaced. diff --git a/src/vs/editor/common/model/textModelWithTokens.ts b/src/vs/editor/common/model/textModelWithTokens.ts index 648685cb9a4..cf6853eea35 100644 --- a/src/vs/editor/common/model/textModelWithTokens.ts +++ b/src/vs/editor/common/model/textModelWithTokens.ts @@ -71,6 +71,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke private _lastState: IState; private _indentRanges: IndentRange[]; + private _languageRegistryListener: IDisposable; private _revalidateTokensTimeout: number; @@ -98,12 +99,20 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke this._revalidateTokensTimeout = -1; + this._languageRegistryListener = LanguageConfigurationRegistry.onDidChange((e) => { + if (e.languageIdentifier.id === this._languageIdentifier.id) { + this._resetIndentRanges(); + this._emitModelLanguageConfigurationEvent({}); + } + }); + this._resetTokenizationState(); this._resetIndentRanges(); } public dispose(): void { this._tokenizationListener.dispose(); + this._languageRegistryListener.dispose(); this._clearTimers(); this._lastState = null; @@ -239,6 +248,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke }] }); this._emitModelModeChangedEvent(e); + this._emitModelLanguageConfigurationEvent({}); } public getLanguageIdAtPosition(_lineNumber: number, _column: number): LanguageId { @@ -404,6 +414,12 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke } } + private _emitModelLanguageConfigurationEvent(e: textModelEvents.IModelLanguageConfigurationChangedEvent): void { + if (!this._isDisposing) { + this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelLanguageConfigurationChanged, e); + } + } + private _emitModelModeChangedEvent(e: textModelEvents.IModelLanguageChangedEvent): void { if (!this._isDisposing) { this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelLanguageChanged, e); diff --git a/src/vs/editor/common/modes/languageConfigurationRegistry.ts b/src/vs/editor/common/modes/languageConfigurationRegistry.ts index dd3e1ec8acc..56a384e5822 100644 --- a/src/vs/editor/common/modes/languageConfigurationRegistry.ts +++ b/src/vs/editor/common/modes/languageConfigurationRegistry.ts @@ -143,12 +143,16 @@ export class RichEditSupport { } } +export class LanguageConfigurationChangeEvent { + languageIdentifier: LanguageIdentifier; +} + export class LanguageConfigurationRegistryImpl { private _entries: RichEditSupport[]; - private _onDidChange: Emitter = new Emitter(); - public onDidChange: Event = this._onDidChange.event; + private _onDidChange: Emitter = new Emitter(); + public onDidChange: Event = this._onDidChange.event; constructor() { this._entries = []; @@ -158,12 +162,12 @@ export class LanguageConfigurationRegistryImpl { let previous = this._getRichEditSupport(languageIdentifier.id); let current = new RichEditSupport(languageIdentifier, previous, configuration); this._entries[languageIdentifier.id] = current; - this._onDidChange.fire(void 0); + this._onDidChange.fire({ languageIdentifier }); return { dispose: () => { if (this._entries[languageIdentifier.id] === current) { this._entries[languageIdentifier.id] = previous; - this._onDidChange.fire(void 0); + this._onDidChange.fire({ languageIdentifier }); } } }; diff --git a/src/vs/editor/common/view/viewEvents.ts b/src/vs/editor/common/view/viewEvents.ts index 4034473fa40..46244956a30 100644 --- a/src/vs/editor/common/view/viewEvents.ts +++ b/src/vs/editor/common/view/viewEvents.ts @@ -27,7 +27,8 @@ export const enum ViewEventType { ViewTokensChanged = 12, ViewTokensColorsChanged = 13, ViewZonesChanged = 14, - ViewThemeChanged = 15 + ViewThemeChanged = 15, + ViewLanguageConfigurationChanged = 16 } export class ViewConfigurationChangedEvent { @@ -282,6 +283,14 @@ export class ViewZonesChangedEvent { } } +export class ViewLanguageConfigurationEvent { + + public readonly type = ViewEventType.ViewLanguageConfigurationChanged; + + constructor() { + } +} + export type ViewEvent = ( ViewConfigurationChangedEvent | ViewCursorStateChangedEvent @@ -298,6 +307,7 @@ export type ViewEvent = ( | ViewTokensColorsChangedEvent | ViewZonesChangedEvent | ViewThemeChangedEvent + | ViewLanguageConfigurationEvent ); export interface IViewEventListener { diff --git a/src/vs/editor/common/viewModel/viewEventHandler.ts b/src/vs/editor/common/viewModel/viewEventHandler.ts index a3e03e9005d..874b206787e 100644 --- a/src/vs/editor/common/viewModel/viewEventHandler.ts +++ b/src/vs/editor/common/viewModel/viewEventHandler.ts @@ -49,6 +49,9 @@ export class ViewEventHandler extends Disposable { public onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean { return false; } + public onLanguageConfigurationChanged(e: viewEvents.ViewLanguageConfigurationEvent): boolean { + return false; + } public onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): boolean { return false; } @@ -121,6 +124,12 @@ export class ViewEventHandler extends Disposable { } break; + case viewEvents.ViewEventType.ViewLanguageConfigurationChanged: + if (this.onLanguageConfigurationChanged(e)) { + shouldRender = true; + } + break; + case viewEvents.ViewEventType.ViewLineMappingChanged: if (this.onLineMappingChanged(e)) { shouldRender = true; @@ -175,7 +184,6 @@ export class ViewEventHandler extends Disposable { } break; - case viewEvents.ViewEventType.ViewThemeChanged: if (this.onThemeChanged(e)) { shouldRender = true; diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index 20b51a429b4..13331cdc5ba 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -261,6 +261,10 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel // That's ok, a model tokens changed event will follow shortly break; } + case textModelEvents.TextModelEventType.ModelLanguageConfigurationChanged: { + eventsCollector.emit(new viewEvents.ViewLanguageConfigurationEvent()); + break; + } case textModelEvents.TextModelEventType.ModelContentChanged: { // Ignore break; diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index e1b0f728c19..2a28b96e6fa 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -1787,6 +1787,11 @@ declare module monaco.editor { * @event */ onDidChangeLanguage(listener: (e: IModelLanguageChangedEvent) => void): IDisposable; + /** + * An event emitted when the language configuration associated with the model has changed. + * @event + */ + onDidChangeLanguageConfiguration(listener: (e: IModelLanguageConfigurationChangedEvent) => void): IDisposable; /** * An event emitted right before disposing the model. * @event @@ -2185,6 +2190,11 @@ declare module monaco.editor { * @event */ onDidChangeModelLanguage(listener: (e: IModelLanguageChangedEvent) => void): IDisposable; + /** + * An event emitted when the language configuration of the current model has changed. + * @event + */ + onDidChangeModelLanguageConfiguration(listener: (e: IModelLanguageConfigurationChangedEvent) => void): IDisposable; /** * An event emitted when the options of the current model has changed. * @event @@ -2419,6 +2429,12 @@ declare module monaco.editor { readonly newLanguage: string; } + /** + * An event describing that the language configuration associated with a model has changed. + */ + export interface IModelLanguageConfigurationChangedEvent { + } + export interface IModelContentChange { /** * The range that got replaced. From de68414a9a6372840c93bc2cfbdab37a306dad71 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 20 Sep 2017 09:34:33 +0200 Subject: [PATCH 081/281] [folding] should not fold whitespace after function. Fixes #3353 --- .../clojure/language-configuration.json | 7 +++++- .../coffeescript/language-configuration.json | 7 +++++- extensions/fsharp/language-configuration.json | 7 +++++- .../markdown/language-configuration.json | 7 +++++- extensions/pug/language-configuration.json | 7 +++++- extensions/python/language-configuration.json | 8 +++++-- extensions/yaml/language-configuration.json | 7 +++++- .../viewParts/indentGuides/indentGuides.ts | 3 +++ src/vs/editor/common/model/indentRanges.ts | 9 ++++++- .../common/modes/languageConfiguration.ts | 23 ++++++++++++++++++ .../modes/languageConfigurationRegistry.ts | 16 ++++++++++--- .../editor/contrib/folding/browser/folding.ts | 3 +++ src/vs/monaco.d.ts | 19 +++++++++++++++ .../languageConfigurationExtensionPoint.ts | 24 ++++++++++++++++++- 14 files changed, 134 insertions(+), 13 deletions(-) diff --git a/extensions/clojure/language-configuration.json b/extensions/clojure/language-configuration.json index 004e1dbd95b..b68c24d92e3 100644 --- a/extensions/clojure/language-configuration.json +++ b/extensions/clojure/language-configuration.json @@ -18,5 +18,10 @@ ["[", "]"], ["(", ")"], ["\"", "\""] - ] + ], + "folding": { + "indendationBasedFolding": { + "offSide": true + } + } } \ No newline at end of file diff --git a/extensions/coffeescript/language-configuration.json b/extensions/coffeescript/language-configuration.json index 745427eacfb..be41b444061 100644 --- a/extensions/coffeescript/language-configuration.json +++ b/extensions/coffeescript/language-configuration.json @@ -21,5 +21,10 @@ ["(", ")"], ["\"", "\""], ["'", "'"] - ] + ], + "folding": { + "indendationBasedFolding": { + "offSide": true + } + } } \ No newline at end of file diff --git a/extensions/fsharp/language-configuration.json b/extensions/fsharp/language-configuration.json index 89dc2adb5a8..8a88df12433 100644 --- a/extensions/fsharp/language-configuration.json +++ b/extensions/fsharp/language-configuration.json @@ -20,5 +20,10 @@ ["(", ")"], ["\"", "\""], ["'", "'"] - ] + ], + "folding": { + "indendationBasedFolding": { + "offSide": true + } + } } diff --git a/extensions/markdown/language-configuration.json b/extensions/markdown/language-configuration.json index 6c811c66aa6..c328f05d0e0 100644 --- a/extensions/markdown/language-configuration.json +++ b/extensions/markdown/language-configuration.json @@ -37,5 +37,10 @@ ["(", ")"], ["[", "]"], ["`", "`"] - ] + ], + "folding": { + "indendationBasedFolding": { + "offSide": true + } + } } \ No newline at end of file diff --git a/extensions/pug/language-configuration.json b/extensions/pug/language-configuration.json index e22b6120252..96f950546e6 100644 --- a/extensions/pug/language-configuration.json +++ b/extensions/pug/language-configuration.json @@ -20,5 +20,10 @@ ["(", ")"], ["'", "'"], ["\"", "\""] - ] + ], + "folding": { + "indendationBasedFolding": { + "offSide": true + } + } } \ No newline at end of file diff --git a/extensions/python/language-configuration.json b/extensions/python/language-configuration.json index c995ea91f3d..7d9f13e6ce5 100644 --- a/extensions/python/language-configuration.json +++ b/extensions/python/language-configuration.json @@ -21,6 +21,10 @@ ["(", ")"], ["\"", "\""], ["'", "'"] - ] - // enhancedBrackets: [ { open: /.*:\s*$/, closeComplete: 'else:' } ], + ], + "folding": { + "indendationBasedFolding": { + "offSide": true + } + } } \ No newline at end of file diff --git a/extensions/yaml/language-configuration.json b/extensions/yaml/language-configuration.json index cab4f6602ff..3d122eed6e0 100644 --- a/extensions/yaml/language-configuration.json +++ b/extensions/yaml/language-configuration.json @@ -20,5 +20,10 @@ ["(", ")"], ["\"", "\""], ["'", "'"] - ] + ], + "folding": { + "indendationBasedFolding": { + "offSide": true + } + } } \ No newline at end of file diff --git a/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts b/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts index dfd4f11d014..b50adb24b77 100644 --- a/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts +++ b/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts @@ -77,6 +77,9 @@ export class IndentGuidesOverlay extends DynamicViewOverlay { public onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean { return true; } + public onLanguageConfigurationChanged(e: viewEvents.ViewLanguageConfigurationEvent): boolean { + return true; + } // --- end event handlers diff --git a/src/vs/editor/common/model/indentRanges.ts b/src/vs/editor/common/model/indentRanges.ts index c96840a624d..76a57dd540b 100644 --- a/src/vs/editor/common/model/indentRanges.ts +++ b/src/vs/editor/common/model/indentRanges.ts @@ -6,6 +6,7 @@ 'use strict'; import { ITokenizedModel } from 'vs/editor/common/editorCommon'; +import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; export class IndentRange { _indentRangeBrand: void; @@ -32,17 +33,23 @@ export class IndentRange { export function computeRanges(model: ITokenizedModel, minimumRangeSize: number = 1): IndentRange[] { let result: IndentRange[] = []; + let foldingRules = LanguageConfigurationRegistry.getFoldingRules(model.getLanguageIdentifier().id); + let offSide = foldingRules && foldingRules.indendationBasedFolding && foldingRules.indendationBasedFolding.offSide; let previousRegions: { indent: number, line: number }[] = []; previousRegions.push({ indent: -1, line: model.getLineCount() + 1 }); // sentinel, to make sure there's at least one entry for (let line = model.getLineCount(); line > 0; line--) { let indent = model.getIndentLevel(line); + let previous = previousRegions[previousRegions.length - 1]; if (indent === -1) { + if (offSide) { + // for offSide languages, empty lines are associated to the next block + previous.line = line; + } continue; // only whitespace } - let previous = previousRegions[previousRegions.length - 1]; if (previous.indent > indent) { // discard all regions with larger indent diff --git a/src/vs/editor/common/modes/languageConfiguration.ts b/src/vs/editor/common/modes/languageConfiguration.ts index 1fec47f4806..ad764283935 100644 --- a/src/vs/editor/common/modes/languageConfiguration.ts +++ b/src/vs/editor/common/modes/languageConfiguration.ts @@ -61,6 +61,12 @@ export interface LanguageConfiguration { * settings will be used. */ surroundingPairs?: IAutoClosingPair[]; + + /** + * The language's folding rules. + */ + folding?: FoldingRules; + /** * **Deprecated** Do not use. * @@ -89,8 +95,25 @@ export interface IndentationRule { * If a line matches this pattern, then its indentation should not be changed and it should not be evaluated against the other rules. */ unIndentedLinePattern?: RegExp; + } +/** + * Describes folding rules for a language. + */ +export interface FoldingRules { + indendationBasedFolding?: { + /** + * Used by the indentation based strategy to decide wheter empty lines belong to the previous or the next block. + * A language adheres to the off-side rule if blocks in that language are expressed by their indentation. + * See [wikipedia](https://en.wikipedia.org/wiki/Off-side_rule) for more information. + * If not set, `false` is used and empty lines belong to the previous block. + */ + offSide: boolean; + }; +} + + /** * Describes a rule to be evaluated when pressing Enter. */ diff --git a/src/vs/editor/common/modes/languageConfigurationRegistry.ts b/src/vs/editor/common/modes/languageConfigurationRegistry.ts index 56a384e5822..f069921add2 100644 --- a/src/vs/editor/common/modes/languageConfigurationRegistry.ts +++ b/src/vs/editor/common/modes/languageConfigurationRegistry.ts @@ -18,7 +18,7 @@ import { DEFAULT_WORD_REGEXP, ensureValidWordDefinition } from 'vs/editor/common import { createScopedLineTokens } from 'vs/editor/common/modes/supports'; import { LineTokens } from 'vs/editor/common/core/lineTokens'; import { Range } from 'vs/editor/common/core/range'; -import { IndentAction, EnterAction, IAutoClosingPair, LanguageConfiguration, IndentationRule } from 'vs/editor/common/modes/languageConfiguration'; +import { IndentAction, EnterAction, IAutoClosingPair, LanguageConfiguration, IndentationRule, FoldingRules } from 'vs/editor/common/modes/languageConfiguration'; import { LanguageIdentifier, LanguageId } from 'vs/editor/common/modes'; /** @@ -55,6 +55,7 @@ export class RichEditSupport { public readonly indentRulesSupport: IndentRulesSupport; public readonly brackets: RichEditBrackets; public readonly indentationRules: IndentationRule; + public readonly foldingRules: FoldingRules; constructor(languageIdentifier: LanguageIdentifier, previous: RichEditSupport, rawConf: LanguageConfiguration) { @@ -82,6 +83,8 @@ export class RichEditSupport { if (this._conf.indentationRules) { this.indentRulesSupport = new IndentRulesSupport(this._conf.indentationRules); } + + this.foldingRules = this._conf.folding || {}; } private static _mergeConf(prev: LanguageConfiguration, current: LanguageConfiguration): LanguageConfiguration { @@ -93,6 +96,7 @@ export class RichEditSupport { onEnterRules: (prev ? current.onEnterRules || prev.onEnterRules : current.onEnterRules), autoClosingPairs: (prev ? current.autoClosingPairs || prev.autoClosingPairs : current.autoClosingPairs), surroundingPairs: (prev ? current.surroundingPairs || prev.surroundingPairs : current.surroundingPairs), + folding: (prev ? current.folding || prev.folding : current.folding), __electricCharacterSupport: (prev ? current.__electricCharacterSupport || prev.__electricCharacterSupport : current.__electricCharacterSupport), }; } @@ -272,9 +276,15 @@ export class LanguageConfigurationRegistryImpl { return ensureValidWordDefinition(value.wordDefinition || null); } + public getFoldingRules(languageId: LanguageId): FoldingRules { + let value = this._getRichEditSupport(languageId); + if (!value) { + return {}; + } + return value.foldingRules; + } - - // beigin Indent Rules + // begin Indent Rules public getIndentRulesSupport(languageId: LanguageId): IndentRulesSupport { let value = this._getRichEditSupport(languageId); diff --git a/src/vs/editor/contrib/folding/browser/folding.ts b/src/vs/editor/contrib/folding/browser/folding.ts index bbe359dd428..d6eba543ba4 100644 --- a/src/vs/editor/contrib/folding/browser/folding.ts +++ b/src/vs/editor/contrib/folding/browser/folding.ts @@ -237,6 +237,9 @@ export class FoldingController implements IFoldingController { this.localToDispose.push(this.contentChangedScheduler); this.localToDispose.push(this.cursorChangedScheduler); + this.localToDispose.push(model.onDidChangeLanguageConfiguration(e => { + this.contentChangedScheduler.schedule(); + })); this.localToDispose.push(this.editor.onDidChangeModelContent(e => this.contentChangedScheduler.schedule())); this.localToDispose.push(this.editor.onDidChangeCursorPosition((e) => { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 2a28b96e6fa..8be006d7a8c 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4310,6 +4310,10 @@ declare module monaco.languages { * settings will be used. */ surroundingPairs?: IAutoClosingPair[]; + /** + * The language's folding rules. + */ + folding?: FoldingRules; /** * **Deprecated** Do not use. * @@ -4340,6 +4344,21 @@ declare module monaco.languages { unIndentedLinePattern?: RegExp; } + /** + * Describes folding rules for a language. + */ + export interface FoldingRules { + indendationBasedFolding?: { + /** + * Used by the indentation based strategy to decide wheter empty lines belong to the previous or the next block. + * A language adheres to the off-side rule if blocks in that language are expressed by their indentation. + * See [wikipedia](https://en.wikipedia.org/wiki/Off-side_rule) for more information. + * If not set, `false` is used and empty lines belong to the previous block. + */ + offSide: boolean; + }; + } + /** * Describes a rule to be evaluated when pressing Enter. */ diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts b/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts index c5ba3a10a1b..b97d7b652e3 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { parse, ParseError } from 'vs/base/common/json'; import { readFile } from 'vs/base/node/pfs'; -import { CharacterPair, LanguageConfiguration, IAutoClosingPair, IAutoClosingPairConditional, IndentationRule, CommentRule } from 'vs/editor/common/modes/languageConfiguration'; +import { CharacterPair, LanguageConfiguration, IAutoClosingPair, IAutoClosingPairConditional, IndentationRule, CommentRule, FoldingRules } from 'vs/editor/common/modes/languageConfiguration'; import { IModeService } from 'vs/editor/common/services/modeService'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; @@ -35,6 +35,7 @@ interface ILanguageConfiguration { surroundingPairs?: (CharacterPair | IAutoClosingPair)[]; wordPattern?: string | IRegExp; indentationRules?: IIndentationRules; + folding?: FoldingRules; } export class LanguageConfigurationFileHandler { @@ -117,6 +118,10 @@ export class LanguageConfigurationFileHandler { } } + if (configuration.folding) { + richEditConfig.folding = configuration.folding; + } + LanguageConfigurationRegistry.register(languageIdentifier, richEditConfig); } @@ -377,7 +382,24 @@ const schema: IJSONSchema = { } } } + }, + folding: { + type: 'object', + description: nls.localize('schema.folding', 'The language\'s folding settings.'), + properties: { + indendationBasedFolding: { + type: 'object', + description: nls.localize('schema.folding.indendationBasedFolding', 'Settings for indentation based folding.'), + properties: { + offSide: { + type: 'boolean', + description: nls.localize('schema.folding.indendationBasedFolding.offSide', 'A language adheres to the off-side rule if blocks in that language are expressed by their indentation. If set, empty lines belong to the subsequent block.'), + } + } + } + } } + } }; let schemaRegistry = Registry.as(Extensions.JSONContribution); From abd5a7632461c66febbc70039852acc44f0e6ce5 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 20 Sep 2017 11:09:35 +0200 Subject: [PATCH 082/281] Test offSide indentRanges (for #3353) --- src/vs/editor/common/model/indentRanges.ts | 7 +-- .../common/model/textModelWithTokens.ts | 4 +- .../test/common/model/indentRanges.test.ts | 51 +++++++++++++------ 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/vs/editor/common/model/indentRanges.ts b/src/vs/editor/common/model/indentRanges.ts index 76a57dd540b..5bd47a667ac 100644 --- a/src/vs/editor/common/model/indentRanges.ts +++ b/src/vs/editor/common/model/indentRanges.ts @@ -5,8 +5,7 @@ 'use strict'; -import { ITokenizedModel } from 'vs/editor/common/editorCommon'; -import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; +import { IModel } from 'vs/editor/common/editorCommon'; export class IndentRange { _indentRangeBrand: void; @@ -30,11 +29,9 @@ export class IndentRange { } } -export function computeRanges(model: ITokenizedModel, minimumRangeSize: number = 1): IndentRange[] { +export function computeRanges(model: IModel, offSide: boolean, minimumRangeSize: number = 1): IndentRange[] { let result: IndentRange[] = []; - let foldingRules = LanguageConfigurationRegistry.getFoldingRules(model.getLanguageIdentifier().id); - let offSide = foldingRules && foldingRules.indendationBasedFolding && foldingRules.indendationBasedFolding.offSide; let previousRegions: { indent: number, line: number }[] = []; previousRegions.push({ indent: -1, line: model.getLineCount() + 1 }); // sentinel, to make sure there's at least one entry diff --git a/src/vs/editor/common/model/textModelWithTokens.ts b/src/vs/editor/common/model/textModelWithTokens.ts index cf6853eea35..14c19d4a080 100644 --- a/src/vs/editor/common/model/textModelWithTokens.ts +++ b/src/vs/editor/common/model/textModelWithTokens.ts @@ -843,7 +843,9 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke private _getIndentRanges(): IndentRange[] { if (!this._indentRanges) { - this._indentRanges = computeRanges(this); + let foldingRules = LanguageConfigurationRegistry.getFoldingRules(this._languageIdentifier.id); + let offSide = foldingRules && foldingRules.indendationBasedFolding && foldingRules.indendationBasedFolding.offSide; + this._indentRanges = computeRanges(this, offSide); } return this._indentRanges; } diff --git a/src/vs/editor/test/common/model/indentRanges.test.ts b/src/vs/editor/test/common/model/indentRanges.test.ts index 55b5e1ad6dd..6f13fd9c8f0 100644 --- a/src/vs/editor/test/common/model/indentRanges.test.ts +++ b/src/vs/editor/test/common/model/indentRanges.test.ts @@ -16,9 +16,9 @@ export interface IndentRange { } suite('Indentation Folding', () => { - function assertRanges(lines: string[], expected: IndentRange[]): void { + function assertRanges(lines: string[], expected: IndentRange[], offside): void { let model = Model.createFromString(lines.join('\n')); - let actual = computeRanges(model); + let actual = computeRanges(model, offside); actual.sort((r1, r2) => r1.startLineNumber - r2.startLineNumber); assert.deepEqual(actual, expected); model.dispose(); @@ -29,40 +29,48 @@ suite('Indentation Folding', () => { } test('Fold one level', () => { - assertRanges([ + let range = [ 'A', ' A', ' A', ' A' - ], [r(1, 4, 0)]); + ]; + assertRanges(range, [r(1, 4, 0)], true); + assertRanges(range, [r(1, 4, 0)], false); }); test('Fold two levels', () => { - assertRanges([ + let range = [ 'A', ' A', ' A', ' A', ' A' - ], [r(1, 5, 0), r(3, 5, 2)]); + ]; + assertRanges(range, [r(1, 5, 0), r(3, 5, 2)], true); + assertRanges(range, [r(1, 5, 0), r(3, 5, 2)], false); }); test('Fold three levels', () => { - assertRanges([ + let range = [ 'A', ' A', ' A', ' A', 'A' - ], [r(1, 4, 0), r(2, 4, 2), r(3, 4, 4)]); + ]; + assertRanges(range, [r(1, 4, 0), r(2, 4, 2), r(3, 4, 4)], true); + assertRanges(range, [r(1, 4, 0), r(2, 4, 2), r(3, 4, 4)], false); }); test('Fold decreasing indent', () => { - assertRanges([ + let range = [ ' A', ' A', 'A' - ], []); + ]; + assertRanges(range, [], true); + assertRanges(range, [], false); }); test('Fold Java', () => { @@ -80,7 +88,7 @@ suite('Indentation Folding', () => { /*11*/ 'interface B {', /*12*/ ' void bar();', /*13*/ '}', - ], [r(1, 9, 0), r(2, 4, 2), r(7, 8, 2), r(11, 12, 0)]); + ], [r(1, 9, 0), r(2, 4, 2), r(7, 8, 2), r(11, 12, 0)], false); }); test('Fold Javadoc', () => { @@ -92,9 +100,9 @@ suite('Indentation Folding', () => { /* 5*/ ' void foo() {', /* 6*/ ' }', /* 7*/ '}', - ], [r(1, 3, 0), r(4, 6, 0)]); + ], [r(1, 3, 0), r(4, 6, 0)], false); }); - test('Fold Whitespace', () => { + test('Fold Whitespace Java', () => { assertRanges([ /* 1*/ 'class A {', /* 2*/ '', @@ -104,7 +112,20 @@ suite('Indentation Folding', () => { /* 6*/ ' }', /* 7*/ ' ', /* 8*/ '}', - ], [r(1, 7, 0), r(3, 5, 2)]); + ], [r(1, 7, 0), r(3, 5, 2)], false); + }); + + test('Fold Whitespace Python', () => { + assertRanges([ + /* 1*/ 'def a:', + /* 2*/ ' pass', + /* 3*/ ' ', + /* 4*/ ' def b:', + /* 5*/ ' pass', + /* 6*/ ' ', + /* 7*/ ' ', + /* 8*/ 'def c: # since there was a deintent here' + ], [r(1, 5, 0), r(4, 5, 2)], true); }); test('Fold Tabs', () => { @@ -117,6 +138,6 @@ suite('Indentation Folding', () => { /* 6*/ ' \t}', /* 7*/ ' ', /* 8*/ '}', - ], [r(1, 7, 0), r(3, 5, 4)]); + ], [r(1, 7, 0), r(3, 5, 4)], false); }); }); From 216979006adf94ab6f8502a15ff37b3fcf31fd8c Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 20 Sep 2017 11:14:56 +0200 Subject: [PATCH 083/281] Fix merging issue with #3353 --- src/vs/editor/common/editorCommon.ts | 10 +++++----- src/vs/editor/common/model/indentRanges.ts | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index 4cebd942285..ab9db53d0ce 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -591,6 +591,11 @@ export interface ITextModel { */ getLinesContent(): string[]; + /** + * @internal + */ + getIndentLevel(lineNumber: number): number; + /** * Get the end of line sequence predominantly used in the text buffer. * @return EOL char sequence (e.g.: '\n' or '\r\n'). @@ -899,11 +904,6 @@ export interface ITokenizedModel extends ITextModel { */ matchBracket(position: IPosition): [Range, Range]; - /** - * @internal - */ - getIndentLevel(lineNumber: number): number; - /** * @internal */ diff --git a/src/vs/editor/common/model/indentRanges.ts b/src/vs/editor/common/model/indentRanges.ts index 5bd47a667ac..a26176a5817 100644 --- a/src/vs/editor/common/model/indentRanges.ts +++ b/src/vs/editor/common/model/indentRanges.ts @@ -5,7 +5,7 @@ 'use strict'; -import { IModel } from 'vs/editor/common/editorCommon'; +import { ITextModel } from 'vs/editor/common/editorCommon'; export class IndentRange { _indentRangeBrand: void; @@ -29,7 +29,7 @@ export class IndentRange { } } -export function computeRanges(model: IModel, offSide: boolean, minimumRangeSize: number = 1): IndentRange[] { +export function computeRanges(model: ITextModel, offSide: boolean, minimumRangeSize: number = 1): IndentRange[] { let result: IndentRange[] = []; From efb01c62bbf605fbec748710c42f6a1e9b308b80 Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 20 Sep 2017 11:36:16 +0200 Subject: [PATCH 084/281] remove some schema === 'file' checks --- src/vs/platform/workspace/common/workspace.ts | 4 ++-- src/vs/workbench/parts/files/browser/fileActions.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index 1ebcb21877d..b03e37e9e5f 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -190,13 +190,13 @@ export class Workspace implements IWorkspace { return null; } - return this._foldersMap.findSubstr(resource.scheme === 'file' ? resource.fsPath : resource.authority); + return this._foldersMap.findSubstr(resource.toString()); } private updateFoldersMap(): void { this._foldersMap = new TrieMap(); for (const folder of this.folders) { - this._foldersMap.insert(folder.uri.scheme === 'file' ? folder.uri.fsPath : folder.uri.authority, folder); + this._foldersMap.insert(folder.uri.toString(), folder); } } diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index 63bb24e78dd..30b6d67ec62 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -1210,7 +1210,7 @@ export class GlobalCompareResourcesAction extends Action { } label = paths.basename(resource.fsPath); - description = resource.scheme === 'file' ? labels.getPathLabel(paths.dirname(resource.fsPath), this.contextService, this.environmentService) : void 0; + description = labels.getPathLabel(resources.dirname(resource), this.contextService, this.environmentService); return { input, resource, label, description }; }).filter(p => !!p); From ccb631c756878ca7c24acf663403b003db6ed332 Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 20 Sep 2017 12:03:17 +0200 Subject: [PATCH 085/281] explorer: expand root folder properly fixes #31195 --- .../parts/files/browser/views/explorerView.ts | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index 9a909c26683..d59a6116a2d 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -32,7 +32,7 @@ import { FileStat, Model } from 'vs/workbench/parts/files/common/explorerModel'; import { IListService } from 'vs/platform/list/browser/listService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -166,7 +166,7 @@ export class ExplorerView extends CollapsibleView { }; this.toDispose.push(this.themeService.onDidFileIconThemeChange(onFileIconThemeChange)); - this.toDispose.push(this.contextService.onDidChangeWorkspaceFolders(() => this.refreshFromEvent())); + this.toDispose.push(this.contextService.onDidChangeWorkspaceFolders((e) => this.refreshFromEvent(e.added))); onFileIconThemeChange(this.themeService.getFileIconTheme()); } @@ -676,11 +676,11 @@ export class ExplorerView extends CollapsibleView { })); } - private refreshFromEvent(): void { + private refreshFromEvent(newRoots: WorkspaceFolder[] = []): void { if (this.isVisible()) { this.explorerRefreshDelayer.trigger(() => { if (!this.explorerViewer.getHighlight()) { - return this.doRefresh(); + return this.doRefresh(newRoots); } return TPromise.as(null); @@ -722,7 +722,7 @@ export class ExplorerView extends CollapsibleView { }); } - private doRefresh(): TPromise { + private doRefresh(newRoots: WorkspaceFolder[] = []): TPromise { const targetsToResolve: { root: FileStat, resource: URI, options: { resolveTo: URI[] } }[] = []; this.model.roots.forEach(root => { const rootAndTargets = { root, resource: root.resource, options: { resolveTo: [] } }; @@ -732,9 +732,8 @@ export class ExplorerView extends CollapsibleView { let targetsToExpand: URI[] = []; if (this.settings[ExplorerView.MEMENTO_EXPANDED_FOLDER_RESOURCES]) { targetsToExpand = this.settings[ExplorerView.MEMENTO_EXPANDED_FOLDER_RESOURCES].map((e: string) => URI.parse(e)); - } else if (this.model.roots.length === 1) { - targetsToExpand = this.model.roots.map(root => root.resource); // always expand if there is just one root } + targetsToExpand.push(...newRoots.map(r => r.uri)); // First time refresh: Receive target through active editor input or selection and also include settings from previous session if (!this.isCreated) { @@ -784,16 +783,11 @@ export class ExplorerView extends CollapsibleView { modelStats.forEach((modelStat, index) => FileStat.mergeLocalWithDisk(modelStat, this.model.roots[index])); const input = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER ? this.model.roots[0] : this.model; + const statsToExpand = this.explorerViewer.getExpandedElements().concat(targetsToExpand.map(target => this.model.findClosest(target))); if (input === this.explorerViewer.getInput()) { - return this.explorerViewer.refresh(); + return this.explorerViewer.refresh().then(() => this.explorerViewer.expandAll(statsToExpand)); } - // Preserve expanded elements if tree input changed. - // If it is a brand new tree just expand elements from memento - const expanded = this.explorerViewer.getExpandedElements(); - const statsToExpand = expanded.length ? [this.model.roots[0]].concat(expanded) : - targetsToExpand.map(expand => this.model.findClosest(expand)); - // Display roots only when multi folder workspace // Make sure to expand all folders that where expanded in the previous session return this.explorerViewer.setInput(input).then(() => this.explorerViewer.expandAll(statsToExpand)); From d718ff099b63c7d2085ebf7fe43d0725a8238fb7 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 20 Sep 2017 11:51:04 +0200 Subject: [PATCH 086/281] fix bulb resolve for remote providers --- .../services/files/electron-browser/remoteFileService.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 134751d2f76..d4746609149 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -177,8 +177,7 @@ export class RemoteFileService extends FileService { if (group[0].resource.scheme === Schemas.file) { promises.push(super.resolveFiles(group)); } else { - await this._extensionService.onReady(); - const provider = this._provider.get(group[0].resource.scheme); + const provider = await this._withProvider(group[0].resource); if (provider) { promises.push(this._doResolveFiles(provider, group)); } From 89c4a713f7bccdbec4ec6616afcf378bae958557 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 20 Sep 2017 12:06:37 +0200 Subject: [PATCH 087/281] use IWorkspaceEditingServce to add workspace folder, support to store uris in the workspace file --- src/vs/code/electron-main/windows.ts | 11 +++-- src/vs/code/node/windowsFinder.ts | 6 +-- src/vs/platform/workspace/common/workspace.ts | 14 +++++- .../workspace/test/common/workspace.test.ts | 44 ++++++++++--------- .../platform/workspaces/common/workspaces.ts | 29 +++++++++++- .../electron-main/workspacesMainService.ts | 16 ++++--- src/vs/platform/workspaces/node/workspaces.ts | 6 +-- .../workspacesMainService.test.ts | 34 +++++++------- .../electron-browser/mainThreadFileSystem.ts | 15 ++----- .../test/node/configuration.test.ts | 5 ++- .../workspace/node/workspaceEditingService.ts | 23 ++++++---- .../api/extHostConfiguration.test.ts | 4 +- 12 files changed, 125 insertions(+), 82 deletions(-) diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index d29017c2752..caefb5901bd 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -29,7 +29,7 @@ import { IWindowsMainService, IOpenConfiguration, IWindowsCountChangedEvent } fr import { IHistoryMainService } from 'vs/platform/history/common/history'; import { IProcessEnvironment, isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IWorkspacesMainService, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, WORKSPACE_FILTER, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesMainService, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, WORKSPACE_FILTER, isSingleFolderWorkspaceIdentifier, isIRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; @@ -1820,11 +1820,16 @@ class WorkspacesManager { } else { const resolvedWorkspace = this.workspacesService.resolveWorkspaceSync(workspace.configPath); if (resolvedWorkspace && resolvedWorkspace.folders.length > 0) { - defaultPath = dirname(resolvedWorkspace.folders[0].path); + for (const folder of resolvedWorkspace.folders) { + if (isIRawFileWorkspaceFolder(folder)) { + defaultPath = dirname(folder.path); + break; + } + } } } } return defaultPath; } -} \ No newline at end of file +} diff --git a/src/vs/code/node/windowsFinder.ts b/src/vs/code/node/windowsFinder.ts index d8b0d1e93d4..b392f823066 100644 --- a/src/vs/code/node/windowsFinder.ts +++ b/src/vs/code/node/windowsFinder.ts @@ -10,7 +10,7 @@ import * as fs from 'fs'; import * as platform from 'vs/base/common/platform'; import * as paths from 'vs/base/common/paths'; import { OpenContext } from 'vs/platform/windows/common/windows'; -import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IResolvedWorkspace } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IResolvedWorkspace, isIRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; export interface ISimpleWindow { openedWorkspace?: IWorkspaceIdentifier; @@ -62,7 +62,7 @@ function findWindowOnFilePath(windows: W[], filePath: s for (let i = 0; i < workspaceWindows.length; i++) { const window = workspaceWindows[i]; const resolvedWorkspace = workspaceResolver(window.openedWorkspace); - if (resolvedWorkspace && resolvedWorkspace.folders.some(folder => paths.isEqualOrParent(filePath, folder.path, !platform.isLinux /* ignorecase */))) { + if (resolvedWorkspace && resolvedWorkspace.folders.some(folder => isIRawFileWorkspaceFolder(folder) && paths.isEqualOrParent(filePath, folder.path, !platform.isLinux /* ignorecase */))) { return window; } } @@ -164,4 +164,4 @@ export function findWindowOnWorkspaceOrFolderPath(windo return false; })[0]; -} \ No newline at end of file +} diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index b03e37e9e5f..96e88c59ea9 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -9,7 +9,7 @@ import * as paths from 'vs/base/common/paths'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { TrieMap } from 'vs/base/common/map'; import Event from 'vs/base/common/event'; -import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, IStoredWorkspaceFolder, isIRawFileWorkspaceFolder, isIRawUriWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { coalesce, distinct } from 'vs/base/common/arrays'; import { isLinux } from 'vs/base/common/platform'; @@ -213,7 +213,17 @@ export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], function parseWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo: URI): WorkspaceFolder[] { return configuredFolders.map((configuredFolder, index) => { - const uri = toUri(configuredFolder.path, relativeTo); + let uri: URI; + if (isIRawFileWorkspaceFolder(configuredFolder)) { + uri = toUri(configuredFolder.path, relativeTo); + } else if (isIRawUriWorkspaceFolder(configuredFolder)) { + try { + uri = URI.parse(configuredFolder.uri); + } catch (e) { + console.warn(e); + // ignore + } + } if (!uri) { return void 0; } diff --git a/src/vs/platform/workspace/test/common/workspace.test.ts b/src/vs/platform/workspace/test/common/workspace.test.ts index f81c9186eb9..d1a2250f4ff 100644 --- a/src/vs/platform/workspace/test/common/workspace.test.ts +++ b/src/vs/platform/workspace/test/common/workspace.test.ts @@ -8,6 +8,7 @@ import * as assert from 'assert'; import { Workspace, WorkspaceFolder, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import URI from 'vs/base/common/uri'; +import { IRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; suite('Workspace', () => { @@ -51,7 +52,7 @@ suite('Workspace', () => { assert.equal(actual.length, 1); assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath); - assert.equal(actual[0].raw.path, '/src/test'); + assert.equal((actual[0].raw).path, '/src/test'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test'); }); @@ -61,7 +62,7 @@ suite('Workspace', () => { assert.equal(actual.length, 1); assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath); - assert.equal(actual[0].raw.path, './test'); + assert.equal((actual[0].raw).path, './test'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test'); }); @@ -70,8 +71,9 @@ suite('Workspace', () => { const actual = toWorkspaceFolders([{ path: '/src/test', name: 'hello' }]); assert.equal(actual.length, 1); + assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath); - assert.equal(actual[0].raw.path, '/src/test'); + assert.equal((actual[0].raw).path, '/src/test'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'hello'); }); @@ -81,17 +83,17 @@ suite('Workspace', () => { assert.equal(actual.length, 3); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal(actual[0].raw.path, '/src/test2'); + assert.equal((actual[0].raw).path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath); - assert.equal(actual[1].raw.path, '/src/test3'); + assert.equal((actual[1].raw).path, '/src/test3'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'test3'); assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath); - assert.equal(actual[2].raw.path, '/src/test1'); + assert.equal((actual[2].raw).path, '/src/test1'); assert.equal(actual[2].index, 2); assert.equal(actual[2].name, 'test1'); }); @@ -101,17 +103,17 @@ suite('Workspace', () => { assert.equal(actual.length, 3); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal(actual[0].raw.path, '/src/test2'); + assert.equal((actual[0].raw).path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath); - assert.equal(actual[1].raw.path, '/src/test3'); + assert.equal((actual[1].raw).path, '/src/test3'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'noName'); assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath); - assert.equal(actual[2].raw.path, '/src/test1'); + assert.equal((actual[2].raw).path, '/src/test1'); assert.equal(actual[2].index, 2); assert.equal(actual[2].name, 'test1'); }); @@ -121,17 +123,17 @@ suite('Workspace', () => { assert.equal(actual.length, 3); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal(actual[0].raw.path, '/src/test2'); + assert.equal((actual[0].raw).path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/abc/test3').fsPath); - assert.equal(actual[1].raw.path, '/abc/test3'); + assert.equal((actual[1].raw).path, '/abc/test3'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'noName'); assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath); - assert.equal(actual[2].raw.path, './test1'); + assert.equal((actual[2].raw).path, './test1'); assert.equal(actual[2].index, 2); assert.equal(actual[2].name, 'test1'); }); @@ -141,12 +143,12 @@ suite('Workspace', () => { assert.equal(actual.length, 2); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal(actual[0].raw.path, '/src/test2'); + assert.equal((actual[0].raw).path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/src/test1').fsPath); - assert.equal(actual[1].raw.path, '/src/test1'); + assert.equal((actual[1].raw).path, '/src/test1'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'test1'); }); @@ -156,17 +158,17 @@ suite('Workspace', () => { assert.equal(actual.length, 3); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal(actual[0].raw.path, '/src/test2'); + assert.equal((actual[0].raw).path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath); - assert.equal(actual[1].raw.path, '/src/test3'); + assert.equal((actual[1].raw).path, '/src/test3'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'noName'); assert.equal(actual[2].uri.fsPath, URI.file('/abc/test1').fsPath); - assert.equal(actual[2].raw.path, '/abc/test1'); + assert.equal((actual[2].raw).path, '/abc/test1'); assert.equal(actual[2].index, 2); assert.equal(actual[2].name, 'test1'); }); @@ -176,17 +178,17 @@ suite('Workspace', () => { assert.equal(actual.length, 3); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal(actual[0].raw.path, '/src/test2'); + assert.equal((actual[0].raw).path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath); - assert.equal(actual[1].raw.path, './test3'); + assert.equal((actual[1].raw).path, './test3'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'test3'); assert.equal(actual[2].uri.fsPath, URI.file('/abc/test1').fsPath); - assert.equal(actual[2].raw.path, '/abc/test1'); + assert.equal((actual[2].raw).path, '/abc/test1'); assert.equal(actual[2].index, 2); assert.equal(actual[2].name, 'test1'); }); @@ -197,4 +199,4 @@ suite('Workspace', () => { }; } -}); \ No newline at end of file +}); diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index 44d42a64d14..fe70d79cf6d 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -32,11 +32,36 @@ export interface IWorkspaceIdentifier { configPath: string; } -export interface IStoredWorkspaceFolder { +export function isIStoredWorkspaceFolder(thing: any): thing is IStoredWorkspaceFolder { + return isIRawFileWorkspaceFolder(thing) || isIRawUriWorkspaceFolder(thing); +} + +export function isIRawFileWorkspaceFolder(thing: any): thing is IRawFileWorkspaceFolder { + return thing + && typeof thing === 'object' + && typeof thing.path === 'string' + && (!thing.name || typeof thing.name === 'string'); +} + +export function isIRawUriWorkspaceFolder(thing: any): thing is IRawUriWorkspaceFolder { + return thing + && typeof thing === 'object' + && typeof thing.uri === 'string' + && (!thing.name || typeof thing.name === 'string'); +} + +export interface IRawFileWorkspaceFolder { path: string; name?: string; } +export interface IRawUriWorkspaceFolder { + uri: string; + name?: string; +} + +export type IStoredWorkspaceFolder = IRawFileWorkspaceFolder | IRawUriWorkspaceFolder; + export interface IStoredWorkspace { folders: IStoredWorkspaceFolder[]; } @@ -105,4 +130,4 @@ export function isWorkspaceIdentifier(obj: any): obj is IWorkspaceIdentifier { const workspaceIdentifier = obj as IWorkspaceIdentifier; return workspaceIdentifier && typeof workspaceIdentifier.id === 'string' && typeof workspaceIdentifier.configPath === 'string'; -} \ No newline at end of file +} diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index c5b552022a3..678cdae8c2f 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -5,7 +5,7 @@ 'use strict'; -import { IWorkspacesMainService, IWorkspaceIdentifier, IStoredWorkspace, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesMainService, IWorkspaceIdentifier, IStoredWorkspace, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, isIRawFileWorkspaceFolder, isIStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { TPromise } from 'vs/base/common/winjs.base'; import { isParent } from 'vs/platform/files/common/files'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -77,7 +77,7 @@ export class WorkspacesMainService implements IWorkspacesMainService { // relative paths get resolved against the workspace location workspace.folders.forEach(folder => { - if (!isAbsolute(folder.path)) { + if (isIRawFileWorkspaceFolder(folder) && !isAbsolute(folder.path)) { folder.path = resolve(dirname(path), folder.path); } }); @@ -106,7 +106,7 @@ export class WorkspacesMainService implements IWorkspacesMainService { // Filter out folders which do not have a path set if (Array.isArray(storedWorkspace.folders)) { - storedWorkspace.folders = storedWorkspace.folders.filter(folder => !!folder.path); + storedWorkspace.folders = storedWorkspace.folders.filter(folder => isIStoredWorkspaceFolder(folder)); } // Validate @@ -200,11 +200,13 @@ export class WorkspacesMainService implements IWorkspacesMainService { // is a parent of the location of the workspace file itself. Otherwise keep // using absolute paths. storedWorkspace.folders.forEach(folder => { - if (!isAbsolute(folder.path)) { - folder.path = resolve(sourceConfigFolder, folder.path); // relative paths get resolved against the workspace location + if (isIRawFileWorkspaceFolder(folder)) { + if (!isAbsolute(folder.path)) { + folder.path = resolve(sourceConfigFolder, folder.path); // relative paths get resolved against the workspace location + } + folder.path = massageFolderPathForWorkspace(folder.path, targetConfigFolder, storedWorkspace.folders); } - folder.path = massageFolderPathForWorkspace(folder.path, targetConfigFolder, storedWorkspace.folders); }); // Preserve as much of the existing workspace as possible by using jsonEdit @@ -270,4 +272,4 @@ export class WorkspacesMainService implements IWorkspacesMainService { return untitledWorkspaces; } -} \ No newline at end of file +} diff --git a/src/vs/platform/workspaces/node/workspaces.ts b/src/vs/platform/workspaces/node/workspaces.ts index 95757880908..2abee91e7bf 100644 --- a/src/vs/platform/workspaces/node/workspaces.ts +++ b/src/vs/platform/workspaces/node/workspaces.ts @@ -5,7 +5,7 @@ 'use strict'; -import { IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { IStoredWorkspaceFolder, isIRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { isWindows, isLinux } from 'vs/base/common/platform'; import { isAbsolute, relative } from 'path'; import { isEqualOrParent, normalize } from 'vs/base/common/paths'; @@ -56,11 +56,11 @@ function shouldUseSlashForPath(storedFolders: IStoredWorkspaceFolder[]): boolean let useSlashesForPath = !isWindows; if (isWindows) { storedFolders.forEach(folder => { - if (!useSlashesForPath && folder.path.indexOf(SLASH) >= 0) { + if (isIRawFileWorkspaceFolder(folder) && !useSlashesForPath && folder.path.indexOf(SLASH) >= 0) { useSlashesForPath = true; } }); } return useSlashesForPath; -} \ No newline at end of file +} diff --git a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts index 03bddbec9e3..ef04b06ee94 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts @@ -14,7 +14,7 @@ import pfs = require('vs/base/node/pfs'); import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { parseArgs } from 'vs/platform/environment/node/argv'; import { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; -import { IStoredWorkspace, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IStoredWorkspace, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, IWorkspaceIdentifier, IRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { LogMainService } from 'vs/platform/log/common/log'; import URI from 'vs/base/common/uri'; @@ -66,8 +66,8 @@ suite('WorkspacesMainService', () => { const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace; assert.equal(ws.folders.length, 2); // - assert.equal(ws.folders[0].path, process.cwd()); - assert.equal(ws.folders[1].path, os.tmpdir()); + assert.equal((ws.folders[0]).path, process.cwd()); + assert.equal((ws.folders[1]).path, os.tmpdir()); done(); }); @@ -81,8 +81,8 @@ suite('WorkspacesMainService', () => { const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace; assert.equal(ws.folders.length, 2); // - assert.equal(ws.folders[0].path, process.cwd()); - assert.equal(ws.folders[1].path, os.tmpdir()); + assert.equal((ws.folders[0]).path, process.cwd()); + assert.equal((ws.folders[1]).path, os.tmpdir()); }); test('resolveWorkspaceSync', done => { @@ -138,7 +138,7 @@ suite('WorkspacesMainService', () => { fs.writeFileSync(workspace.configPath, JSON.stringify({ folders: [{ path: './ticino-playground/lib' }] })); const resolved = service.resolveWorkspaceSync(workspace.configPath); - assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); + assert.equal(URI.file((resolved.folders[0]).path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); done(); }); @@ -149,7 +149,7 @@ suite('WorkspacesMainService', () => { fs.writeFileSync(workspace.configPath, JSON.stringify({ folders: [{ path: './ticino-playground/lib/../other' }] })); const resolved = service.resolveWorkspaceSync(workspace.configPath); - assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'other')).fsPath); + assert.equal(URI.file((resolved.folders[0]).path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'other')).fsPath); done(); }); @@ -160,7 +160,7 @@ suite('WorkspacesMainService', () => { fs.writeFileSync(workspace.configPath, JSON.stringify({ folders: [{ path: 'ticino-playground/lib' }] })); const resolved = service.resolveWorkspaceSync(workspace.configPath); - assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); + assert.equal(URI.file((resolved.folders[0]).path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); done(); }); @@ -171,7 +171,7 @@ suite('WorkspacesMainService', () => { fs.writeFileSync(workspace.configPath, '{ "folders": [ { "path": "./ticino-playground/lib" } , ] }'); // trailing comma const resolved = service.resolveWorkspaceSync(workspace.configPath); - assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); + assert.equal(URI.file((resolved.folders[0]).path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); done(); }); @@ -200,9 +200,9 @@ suite('WorkspacesMainService', () => { const ws = JSON.parse(fs.readFileSync(savedWorkspace.configPath).toString()) as IStoredWorkspace; assert.equal(ws.folders.length, 3); - assert.equal(ws.folders[0].path, process.cwd()); // absolute - assert.equal(ws.folders[1].path, '.'); // relative - assert.equal(ws.folders[2].path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative + assert.equal((ws.folders[0]).path, process.cwd()); // absolute + assert.equal((ws.folders[1]).path, '.'); // relative + assert.equal((ws.folders[2]).path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative assert.equal(savedWorkspace, savedEvent.workspace); assert.equal(workspace.configPath, savedEvent.oldConfigPath); @@ -232,9 +232,9 @@ suite('WorkspacesMainService', () => { const ws = JSON.parse(fs.readFileSync(newSavedWorkspace.configPath).toString()) as IStoredWorkspace; assert.equal(ws.folders.length, 3); - assert.equal(ws.folders[0].path, process.cwd()); // absolute path because outside of tmpdir - assert.equal(ws.folders[1].path, '.'); // relative path because inside of tmpdir - assert.equal(ws.folders[2].path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative + assert.equal((ws.folders[0]).path, process.cwd()); // absolute path because outside of tmpdir + assert.equal((ws.folders[1]).path, '.'); // relative path because inside of tmpdir + assert.equal((ws.folders[2]).path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative extfs.delSync(workspaceConfigPath); extfs.delSync(newWorkspaceConfigPath); @@ -286,7 +286,7 @@ suite('WorkspacesMainService', () => { assert.equal(newSavedWorkspace.configPath, newWorkspaceConfigPath); const ws = JSON.parse(fs.readFileSync(newSavedWorkspace.configPath).toString()) as IStoredWorkspace; - assert.ok(ws.folders.every(f => f.path.indexOf('\\') < 0)); + assert.ok(ws.folders.every(f => (f).path.indexOf('\\') < 0)); extfs.delSync(workspaceConfigPath); extfs.delSync(newWorkspaceConfigPath); @@ -350,4 +350,4 @@ suite('WorkspacesMainService', () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts index 2699aee0f75..51decb5ec71 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts @@ -12,7 +12,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import { IProgress } from 'vs/platform/progress/common/progress'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; @extHostNamedCustomer(MainContext.MainThreadFileSystem) export class MainThreadFileSystem implements MainThreadFileSystemShape { @@ -24,7 +24,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { constructor( extHostContext: IExtHostContext, @IFileService private readonly _fileService: IFileService, - @IWorkspaceContextService private readonly _workspaceEditService: IWorkspaceContextService + @IWorkspaceEditingService private readonly _workspaceEditService: IWorkspaceEditingService ) { this._proxy = extHostContext.get(ExtHostContext.ExtHostFileSystem); } @@ -43,16 +43,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { } $onDidAddFileSystemRoot(uri: URI): void { - const folders = this._workspaceEditService.getWorkspace().folders.slice(0); - folders.push({ - uri, - name: uri.authority, - index: folders.length, - raw: null - }); - (this._workspaceEditService.getWorkspace()).folders = folders; - (this._workspaceEditService).onFoldersChanged(); - (this._workspaceEditService)._onDidChangeWorkspaceFolders.fire(null); + this._workspaceEditService.addFolders([uri]); } $onFileSystemChange(handle: number, changes: IFileChange[]): void { diff --git a/src/vs/workbench/services/configuration/test/node/configuration.test.ts b/src/vs/workbench/services/configuration/test/node/configuration.test.ts index 32fc370158e..4f3611e7529 100644 --- a/src/vs/workbench/services/configuration/test/node/configuration.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configuration.test.ts @@ -22,6 +22,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'v import { WorkspaceService } from 'vs/workbench/services/configuration/node/configuration'; import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; class SettingsTestEnvironmentService extends EnvironmentService { @@ -100,7 +101,7 @@ suite('WorkspaceContextService - Folder', () => { assert.equal(actual.folders[0].uri.fsPath, URI.file(workspaceResource).fsPath); assert.equal(actual.folders[0].name, workspaceName); assert.equal(actual.folders[0].index, 0); - assert.equal(actual.folders[0].raw.path.toLowerCase(), workspaceResource.toLowerCase()); + assert.equal((actual.folders[0].raw).path.toLowerCase(), workspaceResource.toLowerCase()); assert.ok(!actual.configuration); }); @@ -529,4 +530,4 @@ suite('WorkspaceConfigurationService - Node', () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts index e1789dfa8af..fffd49b0bf2 100644 --- a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts @@ -12,7 +12,7 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/ import { IWindowsService, IWindowService, IEnterWorkspaceResult } from 'vs/platform/windows/common/windows'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; -import { IWorkspacesService, IStoredWorkspaceFolder, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesService, IStoredWorkspaceFolder, IWorkspaceIdentifier, isIStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { dirname } from 'path'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { massageFolderPathForWorkspace } from 'vs/platform/workspaces/node/workspaces'; @@ -26,6 +26,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { BackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; +import { Schemas } from 'vs/base/common/network'; export class WorkspaceEditingService implements IWorkspaceEditingService { @@ -58,14 +59,20 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { const workspaceConfigFolder = dirname(this.contextService.getWorkspace().configuration.fsPath); - foldersToAdd.forEach(foldersToAdd => { - if (this.contains(currentWorkspaceFolderUris, foldersToAdd)) { + foldersToAdd.forEach(folderToAdd => { + if (this.contains(currentWorkspaceFolderUris, folderToAdd)) { return; // already existing } - storedFoldersToAdd.push({ - path: massageFolderPathForWorkspace(foldersToAdd.fsPath, workspaceConfigFolder, currentStoredFolders) - }); + if (folderToAdd.scheme === Schemas.file) { + storedFoldersToAdd.push({ + path: massageFolderPathForWorkspace(folderToAdd.fsPath, workspaceConfigFolder, currentStoredFolders) + }); + } else { + storedFoldersToAdd.push({ + uri: folderToAdd.toString() + }); + } }); if (storedFoldersToAdd.length > 0) { @@ -84,7 +91,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { const currentStoredFolders = currentWorkspaceFolders.map(folder => folder.raw); const newStoredFolders: IStoredWorkspaceFolder[] = currentStoredFolders.filter((folder, index) => { - if (!folder.path) { + if (!isIStoredWorkspaceFolder(folder)) { return true; // keep entries which are unrelated } @@ -186,4 +193,4 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { return this.jsonEditingService.write(URI.file(toWorkspace.configPath), { key: 'settings', value: targetWorkspaceConfiguration }, true); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts index 20792c4a191..b3f0a3ed68a 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts @@ -16,7 +16,7 @@ import { ConfigurationModel } from 'vs/platform/configuration/common/configurati import { TestThreadService } from './testThreadService'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { IRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; suite('ExtHostConfiguration', function () { @@ -405,7 +405,7 @@ suite('ExtHostConfiguration', function () { .then(() => assert.ok(false), err => { /* expecting rejection */ }); }); - function aWorkspaceFolder(raw: IStoredWorkspaceFolder, index: number, name: string = ''): WorkspaceFolder { + function aWorkspaceFolder(raw: IRawFileWorkspaceFolder, index: number, name: string = ''): WorkspaceFolder { return { uri: URI.file(raw.path), index, From a97196e477e1a0e8bae70e8a69a79adae51b0665 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 20 Sep 2017 12:21:25 +0200 Subject: [PATCH 088/281] use more proper types for workspace on main side --- src/vs/code/electron-main/windows.ts | 2 +- src/vs/code/node/windowsFinder.ts | 2 +- src/vs/code/test/node/windowsFinder.test.ts | 3 ++- src/vs/platform/workspaces/common/workspaces.ts | 7 +++---- .../electron-main/workspacesMainService.ts | 9 +++++++-- .../test/electron-main/workspacesMainService.test.ts | 12 ++++++------ 6 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index d29017c2752..967b5d51b66 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -1820,7 +1820,7 @@ class WorkspacesManager { } else { const resolvedWorkspace = this.workspacesService.resolveWorkspaceSync(workspace.configPath); if (resolvedWorkspace && resolvedWorkspace.folders.length > 0) { - defaultPath = dirname(resolvedWorkspace.folders[0].path); + defaultPath = dirname(resolvedWorkspace.folders[0].uri.fsPath); } } } diff --git a/src/vs/code/node/windowsFinder.ts b/src/vs/code/node/windowsFinder.ts index d8b0d1e93d4..6d17ad333a3 100644 --- a/src/vs/code/node/windowsFinder.ts +++ b/src/vs/code/node/windowsFinder.ts @@ -62,7 +62,7 @@ function findWindowOnFilePath(windows: W[], filePath: s for (let i = 0; i < workspaceWindows.length; i++) { const window = workspaceWindows[i]; const resolvedWorkspace = workspaceResolver(window.openedWorkspace); - if (resolvedWorkspace && resolvedWorkspace.folders.some(folder => paths.isEqualOrParent(filePath, folder.path, !platform.isLinux /* ignorecase */))) { + if (resolvedWorkspace && resolvedWorkspace.folders.some(folder => paths.isEqualOrParent(filePath, folder.uri.fsPath, !platform.isLinux /* ignorecase */))) { return window; } } diff --git a/src/vs/code/test/node/windowsFinder.test.ts b/src/vs/code/test/node/windowsFinder.test.ts index 0651a98d6b2..2c0b84336ff 100644 --- a/src/vs/code/test/node/windowsFinder.test.ts +++ b/src/vs/code/test/node/windowsFinder.test.ts @@ -9,6 +9,7 @@ import path = require('path'); import { findBestWindowOrFolderForFile, ISimpleWindow, IBestWindowOrFolderOptions } from 'vs/code/node/windowsFinder'; import { OpenContext } from 'vs/platform/windows/common/windows'; import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; const fixturesFolder = require.toUrl('./fixtures'); @@ -24,7 +25,7 @@ function options(custom?: Partial>): I reuseWindow: false, context: OpenContext.CLI, codeSettingsFolder: '_vscode', - workspaceResolver: workspace => { return workspace === testWorkspace ? { id: testWorkspace.id, configPath: workspace.configPath, folders: [{ path: path.join(fixturesFolder, 'vscode_workspace_1_folder') }, { path: path.join(fixturesFolder, 'vscode_workspace_2_folder') }] } : null; }, + workspaceResolver: workspace => { return workspace === testWorkspace ? { id: testWorkspace.id, configPath: workspace.configPath, folders: toWorkspaceFolders([{ path: path.join(fixturesFolder, 'vscode_workspace_1_folder') }, { path: path.join(fixturesFolder, 'vscode_workspace_2_folder') }]) } : null; }, ...custom }; } diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index 44d42a64d14..bd9d29dc731 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -14,6 +14,7 @@ import { isLinux } from 'vs/base/common/platform'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import Event from 'vs/base/common/event'; import { tildify, getPathLabel } from 'vs/base/common/labels'; +import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; export const IWorkspacesMainService = createDecorator('workspacesMainService'); export const IWorkspacesService = createDecorator('workspacesService'); @@ -37,12 +38,10 @@ export interface IStoredWorkspaceFolder { name?: string; } -export interface IStoredWorkspace { - folders: IStoredWorkspaceFolder[]; +export interface IResolvedWorkspace extends IWorkspaceIdentifier { + folders: WorkspaceFolder[]; } -export interface IResolvedWorkspace extends IWorkspaceIdentifier, IStoredWorkspace { } - export interface IWorkspaceSavedEvent { workspace: IWorkspaceIdentifier; oldConfigPath: string; diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index c5b552022a3..5f40e430e13 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -5,7 +5,7 @@ 'use strict'; -import { IWorkspacesMainService, IWorkspaceIdentifier, IStoredWorkspace, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesMainService, IWorkspaceIdentifier, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { TPromise } from 'vs/base/common/winjs.base'; import { isParent } from 'vs/platform/files/common/files'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -23,6 +23,11 @@ import * as json from 'vs/base/common/json'; import * as jsonEdit from 'vs/base/common/jsonEdit'; import { applyEdit } from 'vs/base/common/jsonFormatter'; import { massageFolderPathForWorkspace } from 'vs/platform/workspaces/node/workspaces'; +import { toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; + +export interface IStoredWorkspace { + folders: IStoredWorkspaceFolder[]; +} export class WorkspacesMainService implements IWorkspacesMainService { @@ -85,7 +90,7 @@ export class WorkspacesMainService implements IWorkspacesMainService { return { id: this.getWorkspaceId(path), configPath: path, - folders: workspace.folders + folders: toWorkspaceFolders(workspace.folders) }; } catch (error) { this.logService.log(error.toString()); diff --git a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts index 03bddbec9e3..fa958affd34 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts @@ -13,8 +13,8 @@ import extfs = require('vs/base/node/extfs'); import pfs = require('vs/base/node/pfs'); import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { parseArgs } from 'vs/platform/environment/node/argv'; -import { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; -import { IStoredWorkspace, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { WorkspacesMainService, IStoredWorkspace } from 'vs/platform/workspaces/electron-main/workspacesMainService'; +import { WORKSPACE_EXTENSION, IWorkspaceSavedEvent, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { LogMainService } from 'vs/platform/log/common/log'; import URI from 'vs/base/common/uri'; @@ -138,7 +138,7 @@ suite('WorkspacesMainService', () => { fs.writeFileSync(workspace.configPath, JSON.stringify({ folders: [{ path: './ticino-playground/lib' }] })); const resolved = service.resolveWorkspaceSync(workspace.configPath); - assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); + assert.equal(resolved.folders[0].uri.fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); done(); }); @@ -149,7 +149,7 @@ suite('WorkspacesMainService', () => { fs.writeFileSync(workspace.configPath, JSON.stringify({ folders: [{ path: './ticino-playground/lib/../other' }] })); const resolved = service.resolveWorkspaceSync(workspace.configPath); - assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'other')).fsPath); + assert.equal(resolved.folders[0].uri.fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'other')).fsPath); done(); }); @@ -160,7 +160,7 @@ suite('WorkspacesMainService', () => { fs.writeFileSync(workspace.configPath, JSON.stringify({ folders: [{ path: 'ticino-playground/lib' }] })); const resolved = service.resolveWorkspaceSync(workspace.configPath); - assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); + assert.equal(resolved.folders[0].uri.fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); done(); }); @@ -171,7 +171,7 @@ suite('WorkspacesMainService', () => { fs.writeFileSync(workspace.configPath, '{ "folders": [ { "path": "./ticino-playground/lib" } , ] }'); // trailing comma const resolved = service.resolveWorkspaceSync(workspace.configPath); - assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); + assert.equal(resolved.folders[0].uri.fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); done(); }); From dd86c6f9ca2f7a7a7f31588e6791197d3e7b102c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 20 Sep 2017 12:24:30 +0200 Subject: [PATCH 089/281] Revert "use IWorkspaceEditingServce to add workspace folder, support to store uris in the workspace file" This reverts commit 89c4a713f7bccdbec4ec6616afcf378bae958557. --- src/vs/code/electron-main/windows.ts | 11 ++--- src/vs/code/node/windowsFinder.ts | 6 +-- src/vs/platform/workspace/common/workspace.ts | 14 +----- .../workspace/test/common/workspace.test.ts | 44 +++++++++---------- .../platform/workspaces/common/workspaces.ts | 29 +----------- .../electron-main/workspacesMainService.ts | 16 +++---- src/vs/platform/workspaces/node/workspaces.ts | 6 +-- .../workspacesMainService.test.ts | 34 +++++++------- .../electron-browser/mainThreadFileSystem.ts | 15 +++++-- .../test/node/configuration.test.ts | 5 +-- .../workspace/node/workspaceEditingService.ts | 23 ++++------ .../api/extHostConfiguration.test.ts | 4 +- 12 files changed, 82 insertions(+), 125 deletions(-) diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index caefb5901bd..d29017c2752 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -29,7 +29,7 @@ import { IWindowsMainService, IOpenConfiguration, IWindowsCountChangedEvent } fr import { IHistoryMainService } from 'vs/platform/history/common/history'; import { IProcessEnvironment, isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IWorkspacesMainService, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, WORKSPACE_FILTER, isSingleFolderWorkspaceIdentifier, isIRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesMainService, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, WORKSPACE_FILTER, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; @@ -1820,16 +1820,11 @@ class WorkspacesManager { } else { const resolvedWorkspace = this.workspacesService.resolveWorkspaceSync(workspace.configPath); if (resolvedWorkspace && resolvedWorkspace.folders.length > 0) { - for (const folder of resolvedWorkspace.folders) { - if (isIRawFileWorkspaceFolder(folder)) { - defaultPath = dirname(folder.path); - break; - } - } + defaultPath = dirname(resolvedWorkspace.folders[0].path); } } } return defaultPath; } -} +} \ No newline at end of file diff --git a/src/vs/code/node/windowsFinder.ts b/src/vs/code/node/windowsFinder.ts index b392f823066..d8b0d1e93d4 100644 --- a/src/vs/code/node/windowsFinder.ts +++ b/src/vs/code/node/windowsFinder.ts @@ -10,7 +10,7 @@ import * as fs from 'fs'; import * as platform from 'vs/base/common/platform'; import * as paths from 'vs/base/common/paths'; import { OpenContext } from 'vs/platform/windows/common/windows'; -import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IResolvedWorkspace, isIRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IResolvedWorkspace } from 'vs/platform/workspaces/common/workspaces'; export interface ISimpleWindow { openedWorkspace?: IWorkspaceIdentifier; @@ -62,7 +62,7 @@ function findWindowOnFilePath(windows: W[], filePath: s for (let i = 0; i < workspaceWindows.length; i++) { const window = workspaceWindows[i]; const resolvedWorkspace = workspaceResolver(window.openedWorkspace); - if (resolvedWorkspace && resolvedWorkspace.folders.some(folder => isIRawFileWorkspaceFolder(folder) && paths.isEqualOrParent(filePath, folder.path, !platform.isLinux /* ignorecase */))) { + if (resolvedWorkspace && resolvedWorkspace.folders.some(folder => paths.isEqualOrParent(filePath, folder.path, !platform.isLinux /* ignorecase */))) { return window; } } @@ -164,4 +164,4 @@ export function findWindowOnWorkspaceOrFolderPath(windo return false; })[0]; -} +} \ No newline at end of file diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index 96e88c59ea9..b03e37e9e5f 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -9,7 +9,7 @@ import * as paths from 'vs/base/common/paths'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { TrieMap } from 'vs/base/common/map'; import Event from 'vs/base/common/event'; -import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, IStoredWorkspaceFolder, isIRawFileWorkspaceFolder, isIRawUriWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { coalesce, distinct } from 'vs/base/common/arrays'; import { isLinux } from 'vs/base/common/platform'; @@ -213,17 +213,7 @@ export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], function parseWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo: URI): WorkspaceFolder[] { return configuredFolders.map((configuredFolder, index) => { - let uri: URI; - if (isIRawFileWorkspaceFolder(configuredFolder)) { - uri = toUri(configuredFolder.path, relativeTo); - } else if (isIRawUriWorkspaceFolder(configuredFolder)) { - try { - uri = URI.parse(configuredFolder.uri); - } catch (e) { - console.warn(e); - // ignore - } - } + const uri = toUri(configuredFolder.path, relativeTo); if (!uri) { return void 0; } diff --git a/src/vs/platform/workspace/test/common/workspace.test.ts b/src/vs/platform/workspace/test/common/workspace.test.ts index d1a2250f4ff..f81c9186eb9 100644 --- a/src/vs/platform/workspace/test/common/workspace.test.ts +++ b/src/vs/platform/workspace/test/common/workspace.test.ts @@ -8,7 +8,6 @@ import * as assert from 'assert'; import { Workspace, WorkspaceFolder, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import URI from 'vs/base/common/uri'; -import { IRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; suite('Workspace', () => { @@ -52,7 +51,7 @@ suite('Workspace', () => { assert.equal(actual.length, 1); assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath); - assert.equal((actual[0].raw).path, '/src/test'); + assert.equal(actual[0].raw.path, '/src/test'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test'); }); @@ -62,7 +61,7 @@ suite('Workspace', () => { assert.equal(actual.length, 1); assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath); - assert.equal((actual[0].raw).path, './test'); + assert.equal(actual[0].raw.path, './test'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test'); }); @@ -71,9 +70,8 @@ suite('Workspace', () => { const actual = toWorkspaceFolders([{ path: '/src/test', name: 'hello' }]); assert.equal(actual.length, 1); - assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath); - assert.equal((actual[0].raw).path, '/src/test'); + assert.equal(actual[0].raw.path, '/src/test'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'hello'); }); @@ -83,17 +81,17 @@ suite('Workspace', () => { assert.equal(actual.length, 3); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal((actual[0].raw).path, '/src/test2'); + assert.equal(actual[0].raw.path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath); - assert.equal((actual[1].raw).path, '/src/test3'); + assert.equal(actual[1].raw.path, '/src/test3'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'test3'); assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath); - assert.equal((actual[2].raw).path, '/src/test1'); + assert.equal(actual[2].raw.path, '/src/test1'); assert.equal(actual[2].index, 2); assert.equal(actual[2].name, 'test1'); }); @@ -103,17 +101,17 @@ suite('Workspace', () => { assert.equal(actual.length, 3); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal((actual[0].raw).path, '/src/test2'); + assert.equal(actual[0].raw.path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath); - assert.equal((actual[1].raw).path, '/src/test3'); + assert.equal(actual[1].raw.path, '/src/test3'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'noName'); assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath); - assert.equal((actual[2].raw).path, '/src/test1'); + assert.equal(actual[2].raw.path, '/src/test1'); assert.equal(actual[2].index, 2); assert.equal(actual[2].name, 'test1'); }); @@ -123,17 +121,17 @@ suite('Workspace', () => { assert.equal(actual.length, 3); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal((actual[0].raw).path, '/src/test2'); + assert.equal(actual[0].raw.path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/abc/test3').fsPath); - assert.equal((actual[1].raw).path, '/abc/test3'); + assert.equal(actual[1].raw.path, '/abc/test3'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'noName'); assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath); - assert.equal((actual[2].raw).path, './test1'); + assert.equal(actual[2].raw.path, './test1'); assert.equal(actual[2].index, 2); assert.equal(actual[2].name, 'test1'); }); @@ -143,12 +141,12 @@ suite('Workspace', () => { assert.equal(actual.length, 2); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal((actual[0].raw).path, '/src/test2'); + assert.equal(actual[0].raw.path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/src/test1').fsPath); - assert.equal((actual[1].raw).path, '/src/test1'); + assert.equal(actual[1].raw.path, '/src/test1'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'test1'); }); @@ -158,17 +156,17 @@ suite('Workspace', () => { assert.equal(actual.length, 3); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal((actual[0].raw).path, '/src/test2'); + assert.equal(actual[0].raw.path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath); - assert.equal((actual[1].raw).path, '/src/test3'); + assert.equal(actual[1].raw.path, '/src/test3'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'noName'); assert.equal(actual[2].uri.fsPath, URI.file('/abc/test1').fsPath); - assert.equal((actual[2].raw).path, '/abc/test1'); + assert.equal(actual[2].raw.path, '/abc/test1'); assert.equal(actual[2].index, 2); assert.equal(actual[2].name, 'test1'); }); @@ -178,17 +176,17 @@ suite('Workspace', () => { assert.equal(actual.length, 3); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal((actual[0].raw).path, '/src/test2'); + assert.equal(actual[0].raw.path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath); - assert.equal((actual[1].raw).path, './test3'); + assert.equal(actual[1].raw.path, './test3'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'test3'); assert.equal(actual[2].uri.fsPath, URI.file('/abc/test1').fsPath); - assert.equal((actual[2].raw).path, '/abc/test1'); + assert.equal(actual[2].raw.path, '/abc/test1'); assert.equal(actual[2].index, 2); assert.equal(actual[2].name, 'test1'); }); @@ -199,4 +197,4 @@ suite('Workspace', () => { }; } -}); +}); \ No newline at end of file diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index fe70d79cf6d..44d42a64d14 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -32,36 +32,11 @@ export interface IWorkspaceIdentifier { configPath: string; } -export function isIStoredWorkspaceFolder(thing: any): thing is IStoredWorkspaceFolder { - return isIRawFileWorkspaceFolder(thing) || isIRawUriWorkspaceFolder(thing); -} - -export function isIRawFileWorkspaceFolder(thing: any): thing is IRawFileWorkspaceFolder { - return thing - && typeof thing === 'object' - && typeof thing.path === 'string' - && (!thing.name || typeof thing.name === 'string'); -} - -export function isIRawUriWorkspaceFolder(thing: any): thing is IRawUriWorkspaceFolder { - return thing - && typeof thing === 'object' - && typeof thing.uri === 'string' - && (!thing.name || typeof thing.name === 'string'); -} - -export interface IRawFileWorkspaceFolder { +export interface IStoredWorkspaceFolder { path: string; name?: string; } -export interface IRawUriWorkspaceFolder { - uri: string; - name?: string; -} - -export type IStoredWorkspaceFolder = IRawFileWorkspaceFolder | IRawUriWorkspaceFolder; - export interface IStoredWorkspace { folders: IStoredWorkspaceFolder[]; } @@ -130,4 +105,4 @@ export function isWorkspaceIdentifier(obj: any): obj is IWorkspaceIdentifier { const workspaceIdentifier = obj as IWorkspaceIdentifier; return workspaceIdentifier && typeof workspaceIdentifier.id === 'string' && typeof workspaceIdentifier.configPath === 'string'; -} +} \ No newline at end of file diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index 678cdae8c2f..c5b552022a3 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -5,7 +5,7 @@ 'use strict'; -import { IWorkspacesMainService, IWorkspaceIdentifier, IStoredWorkspace, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, isIRawFileWorkspaceFolder, isIStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesMainService, IWorkspaceIdentifier, IStoredWorkspace, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace } from 'vs/platform/workspaces/common/workspaces'; import { TPromise } from 'vs/base/common/winjs.base'; import { isParent } from 'vs/platform/files/common/files'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -77,7 +77,7 @@ export class WorkspacesMainService implements IWorkspacesMainService { // relative paths get resolved against the workspace location workspace.folders.forEach(folder => { - if (isIRawFileWorkspaceFolder(folder) && !isAbsolute(folder.path)) { + if (!isAbsolute(folder.path)) { folder.path = resolve(dirname(path), folder.path); } }); @@ -106,7 +106,7 @@ export class WorkspacesMainService implements IWorkspacesMainService { // Filter out folders which do not have a path set if (Array.isArray(storedWorkspace.folders)) { - storedWorkspace.folders = storedWorkspace.folders.filter(folder => isIStoredWorkspaceFolder(folder)); + storedWorkspace.folders = storedWorkspace.folders.filter(folder => !!folder.path); } // Validate @@ -200,13 +200,11 @@ export class WorkspacesMainService implements IWorkspacesMainService { // is a parent of the location of the workspace file itself. Otherwise keep // using absolute paths. storedWorkspace.folders.forEach(folder => { - if (isIRawFileWorkspaceFolder(folder)) { - if (!isAbsolute(folder.path)) { - folder.path = resolve(sourceConfigFolder, folder.path); // relative paths get resolved against the workspace location - } - folder.path = massageFolderPathForWorkspace(folder.path, targetConfigFolder, storedWorkspace.folders); + if (!isAbsolute(folder.path)) { + folder.path = resolve(sourceConfigFolder, folder.path); // relative paths get resolved against the workspace location } + folder.path = massageFolderPathForWorkspace(folder.path, targetConfigFolder, storedWorkspace.folders); }); // Preserve as much of the existing workspace as possible by using jsonEdit @@ -272,4 +270,4 @@ export class WorkspacesMainService implements IWorkspacesMainService { return untitledWorkspaces; } -} +} \ No newline at end of file diff --git a/src/vs/platform/workspaces/node/workspaces.ts b/src/vs/platform/workspaces/node/workspaces.ts index 2abee91e7bf..95757880908 100644 --- a/src/vs/platform/workspaces/node/workspaces.ts +++ b/src/vs/platform/workspaces/node/workspaces.ts @@ -5,7 +5,7 @@ 'use strict'; -import { IStoredWorkspaceFolder, isIRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { isWindows, isLinux } from 'vs/base/common/platform'; import { isAbsolute, relative } from 'path'; import { isEqualOrParent, normalize } from 'vs/base/common/paths'; @@ -56,11 +56,11 @@ function shouldUseSlashForPath(storedFolders: IStoredWorkspaceFolder[]): boolean let useSlashesForPath = !isWindows; if (isWindows) { storedFolders.forEach(folder => { - if (isIRawFileWorkspaceFolder(folder) && !useSlashesForPath && folder.path.indexOf(SLASH) >= 0) { + if (!useSlashesForPath && folder.path.indexOf(SLASH) >= 0) { useSlashesForPath = true; } }); } return useSlashesForPath; -} +} \ No newline at end of file diff --git a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts index ef04b06ee94..03bddbec9e3 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts @@ -14,7 +14,7 @@ import pfs = require('vs/base/node/pfs'); import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { parseArgs } from 'vs/platform/environment/node/argv'; import { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; -import { IStoredWorkspace, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, IWorkspaceIdentifier, IRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { IStoredWorkspace, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { LogMainService } from 'vs/platform/log/common/log'; import URI from 'vs/base/common/uri'; @@ -66,8 +66,8 @@ suite('WorkspacesMainService', () => { const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace; assert.equal(ws.folders.length, 2); // - assert.equal((ws.folders[0]).path, process.cwd()); - assert.equal((ws.folders[1]).path, os.tmpdir()); + assert.equal(ws.folders[0].path, process.cwd()); + assert.equal(ws.folders[1].path, os.tmpdir()); done(); }); @@ -81,8 +81,8 @@ suite('WorkspacesMainService', () => { const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace; assert.equal(ws.folders.length, 2); // - assert.equal((ws.folders[0]).path, process.cwd()); - assert.equal((ws.folders[1]).path, os.tmpdir()); + assert.equal(ws.folders[0].path, process.cwd()); + assert.equal(ws.folders[1].path, os.tmpdir()); }); test('resolveWorkspaceSync', done => { @@ -138,7 +138,7 @@ suite('WorkspacesMainService', () => { fs.writeFileSync(workspace.configPath, JSON.stringify({ folders: [{ path: './ticino-playground/lib' }] })); const resolved = service.resolveWorkspaceSync(workspace.configPath); - assert.equal(URI.file((resolved.folders[0]).path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); + assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); done(); }); @@ -149,7 +149,7 @@ suite('WorkspacesMainService', () => { fs.writeFileSync(workspace.configPath, JSON.stringify({ folders: [{ path: './ticino-playground/lib/../other' }] })); const resolved = service.resolveWorkspaceSync(workspace.configPath); - assert.equal(URI.file((resolved.folders[0]).path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'other')).fsPath); + assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'other')).fsPath); done(); }); @@ -160,7 +160,7 @@ suite('WorkspacesMainService', () => { fs.writeFileSync(workspace.configPath, JSON.stringify({ folders: [{ path: 'ticino-playground/lib' }] })); const resolved = service.resolveWorkspaceSync(workspace.configPath); - assert.equal(URI.file((resolved.folders[0]).path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); + assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); done(); }); @@ -171,7 +171,7 @@ suite('WorkspacesMainService', () => { fs.writeFileSync(workspace.configPath, '{ "folders": [ { "path": "./ticino-playground/lib" } , ] }'); // trailing comma const resolved = service.resolveWorkspaceSync(workspace.configPath); - assert.equal(URI.file((resolved.folders[0]).path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); + assert.equal(URI.file(resolved.folders[0].path).fsPath, URI.file(path.join(path.dirname(workspace.configPath), 'ticino-playground', 'lib')).fsPath); done(); }); @@ -200,9 +200,9 @@ suite('WorkspacesMainService', () => { const ws = JSON.parse(fs.readFileSync(savedWorkspace.configPath).toString()) as IStoredWorkspace; assert.equal(ws.folders.length, 3); - assert.equal((ws.folders[0]).path, process.cwd()); // absolute - assert.equal((ws.folders[1]).path, '.'); // relative - assert.equal((ws.folders[2]).path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative + assert.equal(ws.folders[0].path, process.cwd()); // absolute + assert.equal(ws.folders[1].path, '.'); // relative + assert.equal(ws.folders[2].path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative assert.equal(savedWorkspace, savedEvent.workspace); assert.equal(workspace.configPath, savedEvent.oldConfigPath); @@ -232,9 +232,9 @@ suite('WorkspacesMainService', () => { const ws = JSON.parse(fs.readFileSync(newSavedWorkspace.configPath).toString()) as IStoredWorkspace; assert.equal(ws.folders.length, 3); - assert.equal((ws.folders[0]).path, process.cwd()); // absolute path because outside of tmpdir - assert.equal((ws.folders[1]).path, '.'); // relative path because inside of tmpdir - assert.equal((ws.folders[2]).path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative + assert.equal(ws.folders[0].path, process.cwd()); // absolute path because outside of tmpdir + assert.equal(ws.folders[1].path, '.'); // relative path because inside of tmpdir + assert.equal(ws.folders[2].path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative extfs.delSync(workspaceConfigPath); extfs.delSync(newWorkspaceConfigPath); @@ -286,7 +286,7 @@ suite('WorkspacesMainService', () => { assert.equal(newSavedWorkspace.configPath, newWorkspaceConfigPath); const ws = JSON.parse(fs.readFileSync(newSavedWorkspace.configPath).toString()) as IStoredWorkspace; - assert.ok(ws.folders.every(f => (f).path.indexOf('\\') < 0)); + assert.ok(ws.folders.every(f => f.path.indexOf('\\') < 0)); extfs.delSync(workspaceConfigPath); extfs.delSync(newWorkspaceConfigPath); @@ -350,4 +350,4 @@ suite('WorkspacesMainService', () => { }); }); }); -}); +}); \ No newline at end of file diff --git a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts index 51decb5ec71..2699aee0f75 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts @@ -12,7 +12,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import { IProgress } from 'vs/platform/progress/common/progress'; -import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @extHostNamedCustomer(MainContext.MainThreadFileSystem) export class MainThreadFileSystem implements MainThreadFileSystemShape { @@ -24,7 +24,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { constructor( extHostContext: IExtHostContext, @IFileService private readonly _fileService: IFileService, - @IWorkspaceEditingService private readonly _workspaceEditService: IWorkspaceEditingService + @IWorkspaceContextService private readonly _workspaceEditService: IWorkspaceContextService ) { this._proxy = extHostContext.get(ExtHostContext.ExtHostFileSystem); } @@ -43,7 +43,16 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { } $onDidAddFileSystemRoot(uri: URI): void { - this._workspaceEditService.addFolders([uri]); + const folders = this._workspaceEditService.getWorkspace().folders.slice(0); + folders.push({ + uri, + name: uri.authority, + index: folders.length, + raw: null + }); + (this._workspaceEditService.getWorkspace()).folders = folders; + (this._workspaceEditService).onFoldersChanged(); + (this._workspaceEditService)._onDidChangeWorkspaceFolders.fire(null); } $onFileSystemChange(handle: number, changes: IFileChange[]): void { diff --git a/src/vs/workbench/services/configuration/test/node/configuration.test.ts b/src/vs/workbench/services/configuration/test/node/configuration.test.ts index 4f3611e7529..32fc370158e 100644 --- a/src/vs/workbench/services/configuration/test/node/configuration.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configuration.test.ts @@ -22,7 +22,6 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'v import { WorkspaceService } from 'vs/workbench/services/configuration/node/configuration'; import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { IRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; class SettingsTestEnvironmentService extends EnvironmentService { @@ -101,7 +100,7 @@ suite('WorkspaceContextService - Folder', () => { assert.equal(actual.folders[0].uri.fsPath, URI.file(workspaceResource).fsPath); assert.equal(actual.folders[0].name, workspaceName); assert.equal(actual.folders[0].index, 0); - assert.equal((actual.folders[0].raw).path.toLowerCase(), workspaceResource.toLowerCase()); + assert.equal(actual.folders[0].raw.path.toLowerCase(), workspaceResource.toLowerCase()); assert.ok(!actual.configuration); }); @@ -530,4 +529,4 @@ suite('WorkspaceConfigurationService - Node', () => { }); }); }); -}); +}); \ No newline at end of file diff --git a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts index fffd49b0bf2..e1789dfa8af 100644 --- a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts @@ -12,7 +12,7 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/ import { IWindowsService, IWindowService, IEnterWorkspaceResult } from 'vs/platform/windows/common/windows'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; -import { IWorkspacesService, IStoredWorkspaceFolder, IWorkspaceIdentifier, isIStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesService, IStoredWorkspaceFolder, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { dirname } from 'path'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { massageFolderPathForWorkspace } from 'vs/platform/workspaces/node/workspaces'; @@ -26,7 +26,6 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { BackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; -import { Schemas } from 'vs/base/common/network'; export class WorkspaceEditingService implements IWorkspaceEditingService { @@ -59,20 +58,14 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { const workspaceConfigFolder = dirname(this.contextService.getWorkspace().configuration.fsPath); - foldersToAdd.forEach(folderToAdd => { - if (this.contains(currentWorkspaceFolderUris, folderToAdd)) { + foldersToAdd.forEach(foldersToAdd => { + if (this.contains(currentWorkspaceFolderUris, foldersToAdd)) { return; // already existing } - if (folderToAdd.scheme === Schemas.file) { - storedFoldersToAdd.push({ - path: massageFolderPathForWorkspace(folderToAdd.fsPath, workspaceConfigFolder, currentStoredFolders) - }); - } else { - storedFoldersToAdd.push({ - uri: folderToAdd.toString() - }); - } + storedFoldersToAdd.push({ + path: massageFolderPathForWorkspace(foldersToAdd.fsPath, workspaceConfigFolder, currentStoredFolders) + }); }); if (storedFoldersToAdd.length > 0) { @@ -91,7 +84,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { const currentStoredFolders = currentWorkspaceFolders.map(folder => folder.raw); const newStoredFolders: IStoredWorkspaceFolder[] = currentStoredFolders.filter((folder, index) => { - if (!isIStoredWorkspaceFolder(folder)) { + if (!folder.path) { return true; // keep entries which are unrelated } @@ -193,4 +186,4 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { return this.jsonEditingService.write(URI.file(toWorkspace.configPath), { key: 'settings', value: targetWorkspaceConfiguration }, true); } -} +} \ No newline at end of file diff --git a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts index b3f0a3ed68a..20792c4a191 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts @@ -16,7 +16,7 @@ import { ConfigurationModel } from 'vs/platform/configuration/common/configurati import { TestThreadService } from './testThreadService'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { IRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; suite('ExtHostConfiguration', function () { @@ -405,7 +405,7 @@ suite('ExtHostConfiguration', function () { .then(() => assert.ok(false), err => { /* expecting rejection */ }); }); - function aWorkspaceFolder(raw: IRawFileWorkspaceFolder, index: number, name: string = ''): WorkspaceFolder { + function aWorkspaceFolder(raw: IStoredWorkspaceFolder, index: number, name: string = ''): WorkspaceFolder { return { uri: URI.file(raw.path), index, From d089cc7e2ed4f1a48a406889f0d7c403296695d1 Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 20 Sep 2017 12:31:30 +0200 Subject: [PATCH 090/281] explorerView: remove fsPath use --- .../parts/files/browser/views/explorerView.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index 835b87bc02d..dd5570cf3db 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -10,8 +10,8 @@ import { Builder, $ } from 'vs/base/browser/builder'; import URI from 'vs/base/common/uri'; import { ThrottledDelayer } from 'vs/base/common/async'; import errors = require('vs/base/common/errors'); -import labels = require('vs/base/common/labels'); import paths = require('vs/base/common/paths'); +import resources = require('vs/base/common/resources'); import glob = require('vs/base/common/glob'); import { Action, IAction } from 'vs/base/common/actions'; import { prepareActions } from 'vs/workbench/browser/actions'; @@ -133,7 +133,7 @@ export class ExplorerView extends CollapsibleView { const titleSpan = $('span').appendTo(titleDiv); const setHeader = () => { const workspace = this.contextService.getWorkspace(); - const title = workspace.folders.map(folder => labels.getPathLabel(folder.uri.fsPath, void 0, this.environmentService)).join(); + const title = workspace.folders.map(folder => folder.name).join(); titleSpan.text(this.name).title(title); }; this.toDispose.push(this.contextService.onDidChangeWorkspaceName(() => setHeader())); @@ -456,7 +456,7 @@ export class ExplorerView extends CollapsibleView { // Add if (e.operation === FileOperation.CREATE || e.operation === FileOperation.IMPORT || e.operation === FileOperation.COPY) { const addedElement = e.target; - const parentResource = URI.file(paths.dirname(addedElement.resource.fsPath)); + const parentResource = resources.dirname(addedElement.resource); const parents = this.model.findAll(parentResource); if (parents.length) { @@ -491,8 +491,8 @@ export class ExplorerView extends CollapsibleView { const oldResource = e.resource; const newElement = e.target; - const oldParentResource = URI.file(paths.dirname(oldResource.fsPath)); - const newParentResource = URI.file(paths.dirname(newElement.resource.fsPath)); + const oldParentResource = resources.dirname(oldResource); + const newParentResource = resources.dirname(newElement.resource); // Only update focus if renamed/moved element is selected let restoreFocus = false; @@ -773,7 +773,7 @@ export class ExplorerView extends CollapsibleView { return FileStat.create({ resource: targetsToResolve[index].resource, - name: paths.basename(targetsToResolve[index].resource.fsPath), + name: resources.basenameOrAuthority(targetsToResolve[index].resource), mtime: 0, etag: undefined, isDirectory: true, @@ -814,7 +814,7 @@ export class ExplorerView extends CollapsibleView { // Drop those path which are parents of the current one for (let i = resolvedDirectories.length - 1; i >= 0; i--) { const resource = resolvedDirectories[i]; - if (paths.isEqualOrParent(stat.resource.fsPath, resource.fsPath, !isLinux /* ignorecase */)) { + if (resources.isEqualOrParent(stat.resource, resource, !isLinux /* ignorecase */)) { resolvedDirectories.splice(i); } } From cb576b0a4ca209c4ee91370ed0eb8b10591d109a Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 20 Sep 2017 12:34:29 +0200 Subject: [PATCH 091/281] remove usage of URI.file #34296 --- .../parts/execution/electron-browser/execution.contribution.ts | 3 ++- src/vs/workbench/parts/search/browser/searchActions.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts b/src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts index 2d8142bf0e8..36a53527512 100644 --- a/src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts +++ b/src/vs/workbench/parts/execution/electron-browser/execution.contribution.ts @@ -13,6 +13,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import paths = require('vs/base/common/paths'); +import resources = require('vs/base/common/resources'); import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions, ActionBarContributor } from 'vs/workbench/browser/actions'; import uri from 'vs/base/common/uri'; import { explorerItemToFileResource } from 'vs/workbench/parts/files/common/files'; @@ -192,7 +193,7 @@ export class ExplorerViewerActionContributor extends ActionBarContributor { // We want the parent unless this resource is a directory if (!fileResource.isDirectory) { - resource = uri.file(paths.dirname(resource.fsPath)); + resource = resources.dirname(resource); } const configuration = this.configurationService.getConfiguration(); diff --git a/src/vs/workbench/parts/search/browser/searchActions.ts b/src/vs/workbench/parts/search/browser/searchActions.ts index 3b328409d7d..3c684f0cda2 100644 --- a/src/vs/workbench/parts/search/browser/searchActions.ts +++ b/src/vs/workbench/parts/search/browser/searchActions.ts @@ -7,6 +7,7 @@ import nls = require('vs/nls'); import DOM = require('vs/base/browser/dom'); import errors = require('vs/base/common/errors'); import paths = require('vs/base/common/paths'); +import resources = require('vs/base/common/resources'); import { TPromise } from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; import { Action } from 'vs/base/common/actions'; @@ -376,7 +377,7 @@ export const findInFolderCommand = (accessor: ServicesAccessor, resource?: URI) if (focused) { const file = explorerItemToFileResource(focused); if (file) { - resource = file.isDirectory ? file.resource : URI.file(paths.dirname(file.resource.fsPath)); + resource = file.isDirectory ? file.resource : resources.dirname(file.resource); } } } From b901a39262ed4a4aea113bea481e8c273b11b763 Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 20 Sep 2017 13:02:08 +0200 Subject: [PATCH 092/281] explorer: fix expand --- .../parts/files/browser/views/explorerView.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index d59a6116a2d..b6e37336889 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -194,7 +194,11 @@ export class ExplorerView extends CollapsibleView { this.onConfigurationUpdated(configuration); // Load and Fill Viewer - return this.doRefresh().then(() => { + let targetsToExpand = []; + if (this.settings[ExplorerView.MEMENTO_EXPANDED_FOLDER_RESOURCES]) { + targetsToExpand = this.settings[ExplorerView.MEMENTO_EXPANDED_FOLDER_RESOURCES].map((e: string) => URI.parse(e)); + } + return this.doRefresh(targetsToExpand).then(() => { // When the explorer viewer is loaded, listen to changes to the editor input this.toDispose.push(this.editorGroupService.onEditorsChanged(() => this.onEditorsChanged())); @@ -680,7 +684,7 @@ export class ExplorerView extends CollapsibleView { if (this.isVisible()) { this.explorerRefreshDelayer.trigger(() => { if (!this.explorerViewer.getHighlight()) { - return this.doRefresh(newRoots); + return this.doRefresh(newRoots.map(r => r.uri)); } return TPromise.as(null); @@ -722,19 +726,13 @@ export class ExplorerView extends CollapsibleView { }); } - private doRefresh(newRoots: WorkspaceFolder[] = []): TPromise { + private doRefresh(targetsToExpand: URI[] = []): TPromise { const targetsToResolve: { root: FileStat, resource: URI, options: { resolveTo: URI[] } }[] = []; this.model.roots.forEach(root => { const rootAndTargets = { root, resource: root.resource, options: { resolveTo: [] } }; targetsToResolve.push(rootAndTargets); }); - let targetsToExpand: URI[] = []; - if (this.settings[ExplorerView.MEMENTO_EXPANDED_FOLDER_RESOURCES]) { - targetsToExpand = this.settings[ExplorerView.MEMENTO_EXPANDED_FOLDER_RESOURCES].map((e: string) => URI.parse(e)); - } - targetsToExpand.push(...newRoots.map(r => r.uri)); - // First time refresh: Receive target through active editor input or selection and also include settings from previous session if (!this.isCreated) { const activeFile = this.getActiveFile(); From 255b12d5c5b2fd1dfa6a92da337b7a31581e5e43 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 19 Sep 2017 19:41:32 +0200 Subject: [PATCH 093/281] :lipstick: --- src/vs/workbench/browser/parts/views/views2.ts | 17 ++++++++--------- .../parts/scm/electron-browser/scmViewlet.ts | 8 ++++++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/browser/parts/views/views2.ts b/src/vs/workbench/browser/parts/views/views2.ts index 1721592a293..867209cab85 100644 --- a/src/vs/workbench/browser/parts/views/views2.ts +++ b/src/vs/workbench/browser/parts/views/views2.ts @@ -129,11 +129,6 @@ export class PanelViewlet extends Viewlet { private panelItems: IViewletPanelItem[] = []; private panelview: PanelView; - // TODO@Joao make this into method so people can override it - protected get isSingleView(): boolean { - return this.options.showHeaderInTitleWhenSingleView && this.panelItems.length === 1; - } - protected get length(): number { return this.panelItems.length; } @@ -157,7 +152,7 @@ export class PanelViewlet extends Viewlet { getTitle(): string { let title = Registry.as(Extensions.Viewlets).getViewlet(this.getId()).name; - if (this.isSingleView) { + if (this.isSingleView()) { title += ': ' + this.panelItems[0].panel.title; } @@ -165,7 +160,7 @@ export class PanelViewlet extends Viewlet { } getActions(): IAction[] { - if (this.isSingleView) { + if (this.isSingleView()) { return this.panelItems[0].panel.getActions(); } @@ -173,7 +168,7 @@ export class PanelViewlet extends Viewlet { } getSecondaryActions(): IAction[] { - if (this.isSingleView) { + if (this.isSingleView()) { return this.panelItems[0].panel.getSecondaryActions(); } @@ -257,13 +252,17 @@ export class PanelViewlet extends Viewlet { } private updateViewHeaders(): void { - if (this.isSingleView) { + if (this.isSingleView()) { this.panelItems[0].panel.headerVisible = false; } else { this.panelItems.forEach(i => i.panel.headerVisible = true); } } + protected isSingleView(): boolean { + return this.options.showHeaderInTitleWhenSingleView && this.panelItems.length === 1; + } + dispose(): void { super.dispose(); this.panelItems.forEach(i => i.disposable.dispose()); diff --git a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts index c88fb426b53..94a38c10b26 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts @@ -789,7 +789,7 @@ export class SCMViewlet extends PanelViewlet implements IViewModel { } getActions(): IAction[] { - if (this.isSingleView && this.repositories.length === 1) { + if (this.isSingleView()) { const [panel] = this.repositoryPanels; return panel.getActions(); } @@ -800,7 +800,7 @@ export class SCMViewlet extends PanelViewlet implements IViewModel { getSecondaryActions(): IAction[] { let result: IAction[]; - if (this.isSingleView && this.repositories.length === 1) { + if (this.isSingleView()) { const [panel] = this.repositoryPanels; result = [ @@ -865,6 +865,10 @@ export class SCMViewlet extends PanelViewlet implements IViewModel { } } + protected isSingleView(): boolean { + return super.isSingleView() && this.repositories.length === 1; + } + dispose(): void { this.disposables = dispose(this.disposables); this.mainPanelDisposable.dispose(); From a090257dfd8ce0d6dd55394cf020319c66314138 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 19 Sep 2017 19:42:41 +0200 Subject: [PATCH 094/281] views2 > panelViewlet --- .../browser/parts/views/{views2.ts => panelViewlet.ts} | 0 src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/vs/workbench/browser/parts/views/{views2.ts => panelViewlet.ts} (100%) diff --git a/src/vs/workbench/browser/parts/views/views2.ts b/src/vs/workbench/browser/parts/views/panelViewlet.ts similarity index 100% rename from src/vs/workbench/browser/parts/views/views2.ts rename to src/vs/workbench/browser/parts/views/panelViewlet.ts diff --git a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts index 94a38c10b26..15d3c109f1a 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts @@ -13,7 +13,7 @@ import { basename } from 'vs/base/common/paths'; import { onUnexpectedError } from 'vs/base/common/errors'; import { IDisposable, dispose, combinedDisposable, empty as EmptyDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { Builder, Dimension } from 'vs/base/browser/builder'; -import { PanelViewlet, ViewletPanel } from 'vs/workbench/browser/parts/views/views2'; +import { PanelViewlet, ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet'; import { append, $, addClass, toggleClass, trackFocus } from 'vs/base/browser/dom'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { List } from 'vs/base/browser/ui/list/listWidget'; From 01dade32b7c69e5395b65ccea9320258d63d7d25 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 20 Sep 2017 13:36:47 +0200 Subject: [PATCH 095/281] fix #34645 --- extensions/git/src/git.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 3cd0dadfdac..6600d727131 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -66,7 +66,7 @@ function findSpecificGit(path: string): Promise { const buffers: Buffer[] = []; const child = cp.spawn(path, ['--version']); child.stdout.on('data', (b: Buffer) => buffers.push(b)); - child.on('error', e); + child.on('error', cpErrorHandler(e)); child.on('exit', code => code ? e(new Error('Not found')) : c({ path, version: parseVersion(Buffer.concat(buffers).toString('utf8').trim()) })); }); } @@ -159,6 +159,20 @@ export interface IExecutionResult { stderr: string; } +function cpErrorHandler(cb: (reason?: any) => void): (reason?: any) => void { + return err => { + if (/ENOENT/.test(err.message)) { + err = new GitError({ + error: err, + message: 'Failed to execute git (ENOENT)', + gitErrorCode: GitErrorCodes.NotAGitRepository + }); + } + + cb(err); + }; +} + async function exec(child: cp.ChildProcess, options: any = {}): Promise { if (!child.stdout || !child.stderr) { throw new GitError({ @@ -183,7 +197,7 @@ async function exec(child: cp.ChildProcess, options: any = {}): Promise([ new Promise((c, e) => { - once(child, 'error', e); + once(child, 'error', cpErrorHandler(e)); once(child, 'exit', c); }), new Promise(c => { @@ -919,7 +933,7 @@ export class Repository { child.stderr.setEncoding('utf8'); child.stderr.on('data', raw => stderrData.push(raw as string)); - child.on('error', e); + child.on('error', cpErrorHandler(e)); child.on('exit', onExit); }); } From b9bf9c360aa9d0e8a44bb1090a19dbe5b42f6c37 Mon Sep 17 00:00:00 2001 From: YukiUeda Date: Wed, 20 Sep 2017 20:58:33 +0900 Subject: [PATCH 096/281] Delete comment out --- .../themes/solarized-dark-color-theme.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json index 4144eeed162..2f0f20d0d9d 100644 --- a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json +++ b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json @@ -364,9 +364,9 @@ // "editor.inactiveSelectionBackground": "", // "editor.lineHighlightBorder": "", // "editor.rangeHighlightBackground": "", - // "editor.selectionHighlightBackground": "#0FF0F0", - // "editor.wordHighlightBackground": "#ff0000", - // "editor.wordHighlightStrongBackground": "#00ff00", + "editor.selectionHighlightBackground": "#005A6FAA", + "editor.wordHighlightBackground": "#004454AA", + "editor.wordHighlightStrongBackground": "#005A6FAA", // Editor: Suggest // "editorSuggestWidget.background": "", From 893660b1c986f105a9793da27fce0ed53c1c5d4e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 20 Sep 2017 14:58:25 +0200 Subject: [PATCH 097/281] call addFolder when a provider adds a new root --- .../api/electron-browser/mainThreadFileSystem.ts | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts index 2699aee0f75..51decb5ec71 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts @@ -12,7 +12,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import { IProgress } from 'vs/platform/progress/common/progress'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; @extHostNamedCustomer(MainContext.MainThreadFileSystem) export class MainThreadFileSystem implements MainThreadFileSystemShape { @@ -24,7 +24,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { constructor( extHostContext: IExtHostContext, @IFileService private readonly _fileService: IFileService, - @IWorkspaceContextService private readonly _workspaceEditService: IWorkspaceContextService + @IWorkspaceEditingService private readonly _workspaceEditService: IWorkspaceEditingService ) { this._proxy = extHostContext.get(ExtHostContext.ExtHostFileSystem); } @@ -43,16 +43,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { } $onDidAddFileSystemRoot(uri: URI): void { - const folders = this._workspaceEditService.getWorkspace().folders.slice(0); - folders.push({ - uri, - name: uri.authority, - index: folders.length, - raw: null - }); - (this._workspaceEditService.getWorkspace()).folders = folders; - (this._workspaceEditService).onFoldersChanged(); - (this._workspaceEditService)._onDidChangeWorkspaceFolders.fire(null); + this._workspaceEditService.addFolders([uri]); } $onFileSystemChange(handle: number, changes: IFileChange[]): void { From 492ae2a0230bda6a033fa02c9d925836ec732352 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 20 Sep 2017 15:06:30 +0200 Subject: [PATCH 098/281] Workspace folder picker command (for #32936) (#34648) * Workspace folder picker command (for #32936) * fix test * make this proper API --- .../vscode-api-tests/src/commands.test.ts | 2 +- .../vscode-api-tests/src/window.test.ts | 12 +++++++++ src/vs/vscode.proposed.d.ts | 27 ++++++++++++++++++- src/vs/workbench/api/node/extHost.api.impl.ts | 5 +++- src/vs/workbench/api/node/extHostQuickOpen.ts | 23 ++++++++++++++-- 5 files changed, 64 insertions(+), 5 deletions(-) diff --git a/extensions/vscode-api-tests/src/commands.test.ts b/extensions/vscode-api-tests/src/commands.test.ts index 47b4d85f347..0d92795d241 100644 --- a/extensions/vscode-api-tests/src/commands.test.ts +++ b/extensions/vscode-api-tests/src/commands.test.ts @@ -134,4 +134,4 @@ suite('commands namespace tests', () => { return Promise.all([a, b, c, d]); }); -}); +}); \ No newline at end of file diff --git a/extensions/vscode-api-tests/src/window.test.ts b/extensions/vscode-api-tests/src/window.test.ts index 275ac5ee5ca..c197808fd9e 100644 --- a/extensions/vscode-api-tests/src/window.test.ts +++ b/extensions/vscode-api-tests/src/window.test.ts @@ -349,6 +349,18 @@ suite('window namespace tests', () => { return Promise.all([a, b]); }); + test('showWorkspaceFolderPick', function () { + const p = (window).showWorkspaceFolderPick(undefined); + + return commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem').then(() => { + return p.then(workspace => { + assert.ok(true); + }, error => { + assert.ok(false); + }); + }); + }); + test('Default value for showInput Box accepted even if fails validateInput, #33691', function () { const result = window.showInputBox({ validateInput: (value: string) => { diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 9c413707718..cadf55ea65c 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -23,6 +23,31 @@ declare module 'vscode' { export namespace window { export function showOpenDialog(options: OpenDialogOptions): Thenable; export function showSaveDialog(options: SaveDialogOptions): Thenable; + + /** + * Shows a selection list of [workspace folders](#workspace.workspaceFolders) to pick from. + * Returns `undefined` if no folder is open. + * + * @param options Configures the behavior of the workspace folder list. + * @return A promise that resolves to the workspace folder or `undefined`. + */ + export function showWorkspaceFolderPick(options?: WorkspaceFolderPickOptions): Thenable; + } + + /** + * Options to configure the behaviour of the [workspace folder](#WorkspaceFolder) pick UI. + */ + export interface WorkspaceFolderPickOptions { + + /** + * An optional string to show as place holder in the input box to guide the user what to pick on. + */ + placeHolder?: string; + + /** + * Set to `true` to keep the picker open when focus moves to another part of the editor or to another window. + */ + ignoreFocusOut?: boolean; } // todo@joh discover files etc @@ -172,4 +197,4 @@ declare module 'vscode' { export namespace languages { export function registerColorProvider(selector: DocumentSelector, provider: DocumentColorProvider): Disposable; } -} +} \ No newline at end of file diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 215451c68f6..c5707a083c4 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -94,7 +94,7 @@ export function createApiFactory( const extHostDiagnostics = threadService.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(threadService)); const languageFeatures = threadService.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(threadService, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics)); const extHostFileSystemEvent = threadService.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService()); - const extHostQuickOpen = threadService.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(threadService)); + const extHostQuickOpen = threadService.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(threadService, extHostWorkspace, extHostCommands)); const extHostTerminalService = threadService.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(threadService)); const extHostSCM = threadService.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(threadService, extHostCommands)); const extHostTask = threadService.set(ExtHostContext.ExtHostTask, new ExtHostTask(threadService, extHostWorkspace)); @@ -347,6 +347,9 @@ export function createApiFactory( showQuickPick(items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken) { return extHostQuickOpen.showQuickPick(items, options, token); }, + showWorkspaceFolderPick(options: vscode.WorkspaceFolderPickOptions) { + return extHostQuickOpen.showWorkspaceFolderPick(options); + }, showInputBox(options?: vscode.InputBoxOptions, token?: vscode.CancellationToken) { return extHostQuickOpen.showInput(options, token); }, diff --git a/src/vs/workbench/api/node/extHostQuickOpen.ts b/src/vs/workbench/api/node/extHostQuickOpen.ts index edaaf12385d..75acd008704 100644 --- a/src/vs/workbench/api/node/extHostQuickOpen.ts +++ b/src/vs/workbench/api/node/extHostQuickOpen.ts @@ -7,19 +7,26 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { wireCancellationToken } from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { QuickPickOptions, QuickPickItem, InputBoxOptions } from 'vscode'; +import { QuickPickOptions, QuickPickItem, InputBoxOptions, WorkspaceFolderPickOptions, WorkspaceFolder } from 'vscode'; import { MainContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, MyQuickPickItems, IMainContext } from './extHost.protocol'; +import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands'; export type Item = string | QuickPickItem; export class ExtHostQuickOpen implements ExtHostQuickOpenShape { private _proxy: MainThreadQuickOpenShape; + private _workspace: ExtHostWorkspace; + private _commands: ExtHostCommands; + private _onDidSelectItem: (handle: number) => void; private _validateInput: (input: string) => string; - constructor(mainContext: IMainContext) { + constructor(mainContext: IMainContext, workspace: ExtHostWorkspace, commands: ExtHostCommands) { this._proxy = mainContext.get(MainContext.MainThreadQuickOpen); + this._workspace = workspace; + this._commands = commands; } showQuickPick(itemsOrItemsPromise: string[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable; @@ -117,4 +124,16 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape { } return undefined; } + + // ---- workspace folder picker + + showWorkspaceFolderPick(options?: WorkspaceFolderPickOptions, token = CancellationToken.None): Thenable { + return this._commands.executeCommand('_workbench.pickWorkspaceFolder', [options]).then((folder: WorkspaceFolder) => { + if (!folder) { + return undefined; + } + + return this._workspace.getWorkspaceFolders().filter(folder => folder.uri.toString() === folder.uri.toString())[0]; + }); + } } From 04139fac350afbf23e93edecad412b2a06abdea7 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 20 Sep 2017 12:32:58 +0200 Subject: [PATCH 099/281] Rename to IWorkspaceFolder --- .../standalone/browser/simpleServices.ts | 6 +-- src/vs/platform/workspace/common/workspace.ts | 34 ++++++++-------- .../workspace/test/common/workspace.test.ts | 4 +- .../platform/workspaces/common/workspaces.ts | 4 +- src/vs/workbench/api/node/extHost.protocol.ts | 4 +- src/vs/workbench/parts/debug/common/debug.ts | 10 ++--- .../debugConfigurationManager.ts | 4 +- .../debug/electron-browser/debugService.ts | 10 ++--- .../debug/electron-browser/rawDebugSession.ts | 4 +- .../parts/debug/node/debugAdapter.ts | 4 +- .../parts/debug/test/common/mockDebug.ts | 8 ++-- .../extensions/browser/extensionsActions.ts | 4 +- .../electron-browser/extensionTipsService.ts | 4 +- .../parts/files/browser/views/explorerView.ts | 4 +- .../preferences/browser/preferencesActions.ts | 4 +- .../parts/tasks/common/taskService.ts | 4 +- .../parts/tasks/common/taskSystem.ts | 4 +- src/vs/workbench/parts/tasks/common/tasks.ts | 12 +++--- .../electron-browser/task.contribution.ts | 40 +++++++++---------- .../parts/tasks/node/taskConfiguration.ts | 10 ++--- .../electron-browser/configuration.test.ts | 4 +- .../configuration/node/configuration.ts | 14 +++---- .../common/configurationResolver.ts | 10 ++--- .../node/configurationResolverService.ts | 32 +++++++-------- .../node/configurationResolverService.test.ts | 4 +- .../files/test/node/fileService.test.ts | 4 +- .../api/extHostConfiguration.test.ts | 4 +- .../api/extHostWorkspace.test.ts | 4 +- .../workbench/test/workbenchTestServices.ts | 6 +-- 29 files changed, 130 insertions(+), 130 deletions(-) diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 23ed80e4d83..97f3a7f14aa 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -18,7 +18,7 @@ import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingReso import { IKeybindingEvent, KeybindingSource, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IConfirmation, IMessageService } from 'vs/platform/message/common/message'; -import { IWorkspaceContextService, IWorkspace, WorkbenchState, WorkspaceFolder, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, IWorkspace, WorkbenchState, IWorkspaceFolder, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { Selection } from 'vs/editor/common/core/selection'; @@ -552,7 +552,7 @@ export class SimpleWorkspaceContextService implements IWorkspaceContextService { return WorkbenchState.EMPTY; } - public getWorkspaceFolder(resource: URI): WorkspaceFolder { + public getWorkspaceFolder(resource: URI): IWorkspaceFolder { return resource && resource.scheme === SimpleWorkspaceContextService.SCHEME ? this.workspace.folders[0] : void 0; } @@ -560,7 +560,7 @@ export class SimpleWorkspaceContextService implements IWorkspaceContextService { return resource && resource.scheme === SimpleWorkspaceContextService.SCHEME; } - public toResource(workspaceRelativePath: string, workspaceFolder: WorkspaceFolder): URI { + public toResource(workspaceRelativePath: string, workspaceFolder: IWorkspaceFolder): URI { return URI.file(workspaceRelativePath); } diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index b03e37e9e5f..755eb652c21 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -22,9 +22,9 @@ export enum WorkbenchState { } export interface IWorkspaceFoldersChangeEvent { - added: WorkspaceFolder[]; - removed: WorkspaceFolder[]; - changed: WorkspaceFolder[]; + added: IWorkspaceFolder[]; + removed: IWorkspaceFolder[]; + changed: IWorkspaceFolder[]; } export interface IWorkspaceContextService { @@ -64,7 +64,7 @@ export interface IWorkspaceContextService { * Returns the folder for the given resource from the workspace. * Can be null if there is no workspace or the resource is not inside the workspace. */ - getWorkspaceFolder(resource: URI): WorkspaceFolder; + getWorkspaceFolder(resource: URI): IWorkspaceFolder; /** * Return `true` if the current workspace has the given identifier otherwise `false`. @@ -79,7 +79,7 @@ export interface IWorkspaceContextService { /** * Given a workspace relative path and workspace folder, returns the resource with the absolute path. */ - toResource: (workspaceRelativePath: string, workspaceFolder: WorkspaceFolder) => URI; + toResource: (workspaceRelativePath: string, workspaceFolder: IWorkspaceFolder) => URI; } export interface IWorkspace { @@ -97,7 +97,7 @@ export interface IWorkspace { /** * Folders in the workspace. */ - readonly folders: WorkspaceFolder[]; + readonly folders: IWorkspaceFolder[]; /** * the location of the workspace configuration @@ -105,7 +105,7 @@ export interface IWorkspace { readonly configuration?: URI; } -export interface WorkspaceFolder { +export interface IWorkspaceFolder { /** * The associated URI for this workspace folder. @@ -131,13 +131,13 @@ export interface WorkspaceFolder { export class Workspace implements IWorkspace { - private _foldersMap: TrieMap = new TrieMap(); - private _folders: WorkspaceFolder[]; + private _foldersMap: TrieMap = new TrieMap(); + private _folders: IWorkspaceFolder[]; constructor( private _id: string, private _name: string = '', - folders: WorkspaceFolder[] = [], + folders: IWorkspaceFolder[] = [], private _configuration: URI = null, private _ctime?: number ) { @@ -152,11 +152,11 @@ export class Workspace implements IWorkspace { this.folders = workspace.folders; } - public get folders(): WorkspaceFolder[] { + public get folders(): IWorkspaceFolder[] { return this._folders; } - public set folders(folders: WorkspaceFolder[]) { + public set folders(folders: IWorkspaceFolder[]) { this._folders = folders; this.updateFoldersMap(); } @@ -185,7 +185,7 @@ export class Workspace implements IWorkspace { this._configuration = configuration; } - public getFolder(resource: URI): WorkspaceFolder { + public getFolder(resource: URI): IWorkspaceFolder { if (!resource) { return null; } @@ -194,7 +194,7 @@ export class Workspace implements IWorkspace { } private updateFoldersMap(): void { - this._foldersMap = new TrieMap(); + this._foldersMap = new TrieMap(); for (const folder of this.folders) { this._foldersMap.insert(folder.uri.toString(), folder); } @@ -205,13 +205,13 @@ export class Workspace implements IWorkspace { } } -export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo?: URI): WorkspaceFolder[] { +export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo?: URI): IWorkspaceFolder[] { let workspaceFolders = parseWorkspaceFolders(configuredFolders, relativeTo); return ensureUnique(coalesce(workspaceFolders)) .map(({ uri, raw, name }, index) => ({ uri, raw, name: name || paths.basename(uri.fsPath), index })); } -function parseWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo: URI): WorkspaceFolder[] { +function parseWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo: URI): IWorkspaceFolder[] { return configuredFolders.map((configuredFolder, index) => { const uri = toUri(configuredFolder.path, relativeTo); if (!uri) { @@ -233,6 +233,6 @@ function toUri(path: string, relativeTo: URI): URI { return null; } -function ensureUnique(folders: WorkspaceFolder[]): WorkspaceFolder[] { +function ensureUnique(folders: IWorkspaceFolder[]): IWorkspaceFolder[] { return distinct(folders, folder => isLinux ? folder.uri.fsPath : folder.uri.fsPath.toLowerCase()); } diff --git a/src/vs/platform/workspace/test/common/workspace.test.ts b/src/vs/platform/workspace/test/common/workspace.test.ts index f81c9186eb9..b25db238f1e 100644 --- a/src/vs/platform/workspace/test/common/workspace.test.ts +++ b/src/vs/platform/workspace/test/common/workspace.test.ts @@ -6,7 +6,7 @@ 'use strict'; import * as assert from 'assert'; -import { Workspace, WorkspaceFolder, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; +import { Workspace, IWorkspaceFolder, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import URI from 'vs/base/common/uri'; suite('Workspace', () => { @@ -191,7 +191,7 @@ suite('Workspace', () => { assert.equal(actual[2].name, 'test1'); }); - function aWorkspaceFolder(uri: URI, index: number = 0): WorkspaceFolder { + function aWorkspaceFolder(uri: URI, index: number = 0): IWorkspaceFolder { return { uri, raw: { path: uri.fsPath }, index, name: '' }; diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index bd9d29dc731..51b846f937f 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -14,7 +14,7 @@ import { isLinux } from 'vs/base/common/platform'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import Event from 'vs/base/common/event'; import { tildify, getPathLabel } from 'vs/base/common/labels'; -import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; export const IWorkspacesMainService = createDecorator('workspacesMainService'); export const IWorkspacesService = createDecorator('workspacesService'); @@ -39,7 +39,7 @@ export interface IStoredWorkspaceFolder { } export interface IResolvedWorkspace extends IWorkspaceIdentifier { - folders: WorkspaceFolder[]; + folders: IWorkspaceFolder[]; } export interface IWorkspaceSavedEvent { diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index b2c0b08a943..5dfdba9d121 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -47,7 +47,7 @@ import { ITreeItem } from 'vs/workbench/common/views'; import { ThemeColor } from 'vs/platform/theme/common/themeService'; import { IDisposable } from 'vs/base/common/lifecycle'; import { SerializedError } from 'vs/base/common/errors'; -import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IStat, IFileChange } from 'vs/platform/files/common/files'; export interface IEnvironment { @@ -65,7 +65,7 @@ export interface IEnvironment { export interface IWorkspaceData { id: string; name: string; - folders: WorkspaceFolder[]; + folders: IWorkspaceFolder[]; } export interface IInitData { diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index 6cb4347fe67..687d891b493 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -17,7 +17,7 @@ import { ISuggestion } from 'vs/editor/common/modes'; import { Source } from 'vs/workbench/parts/debug/common/debugSource'; import { Range, IRange } from 'vs/editor/common/core/range'; import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; export const VIEWLET_ID = 'workbench.view.debug'; @@ -88,7 +88,7 @@ export interface IExpression extends IReplElement, IExpressionContainer { } export interface ISession { - root: WorkspaceFolder; + root: IWorkspaceFolder; stackTrace(args: DebugProtocol.StackTraceArguments): TPromise; exceptionInfo(args: DebugProtocol.ExceptionInfoArguments): TPromise; scopes(args: DebugProtocol.ScopesArguments): TPromise; @@ -422,7 +422,7 @@ export interface ILaunch { */ uri: uri; - workspace: WorkspaceFolder; + workspace: IWorkspaceFolder; /** * Returns a configuration with the specified name. @@ -585,12 +585,12 @@ export interface IDebugService { * Also saves all files, manages if compounds are present in the configuration * and calls the startSessionCommand if an adapter registered it. */ - startDebugging(root: WorkspaceFolder, configOrName?: IConfig | string, noDebug?: boolean): TPromise; + startDebugging(root: IWorkspaceFolder, configOrName?: IConfig | string, noDebug?: boolean): TPromise; /** * Creates a new debug process. Depending on the configuration will either 'launch' or 'attach'. */ - createProcess(root: WorkspaceFolder, config: IConfig): TPromise; + createProcess(root: IWorkspaceFolder, config: IConfig): TPromise; /** * Find process by ID. diff --git a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts index 5d892d5f946..cb3a63ce624 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts @@ -26,7 +26,7 @@ import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/plat import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IFileService } from 'vs/platform/files/common/files'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IWorkspaceContextService, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IDebugConfigurationProvider, IRawAdapter, ICompound, IDebugConfiguration, DEBUG_SCHEME, IConfig, IEnvConfig, IGlobalConfig, IConfigurationManager, ILaunch } from 'vs/workbench/parts/debug/common/debug'; @@ -473,7 +473,7 @@ class Launch implements ILaunch { constructor( private configurationManager: ConfigurationManager, - public workspace: WorkspaceFolder, + public workspace: IWorkspaceFolder, @IFileService private fileService: IFileService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IConfigurationService private configurationService: IConfigurationService, diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 2370ea76f51..9ea9e9781bb 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -46,7 +46,7 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IWorkspaceContextService, WorkbenchState, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ILogEntry, EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL, EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost'; import { IBroadcastService, IBroadcast } from 'vs/platform/broadcast/electron-browser/broadcastService'; @@ -623,7 +623,7 @@ export class DebugService implements debug.IDebugService { return this.model.evaluateWatchExpressions(this.viewModel.focusedProcess, this.viewModel.focusedStackFrame); } - public startDebugging(root: WorkspaceFolder, configOrName?: debug.IConfig | string, noDebug = false, topCompoundName?: string): TPromise { + public startDebugging(root: IWorkspaceFolder, configOrName?: debug.IConfig | string, noDebug = false, topCompoundName?: string): TPromise { // make sure to save all files and that the configuration is up to date return this.extensionService.activateByEvent('onDebug').then(() => this.textFileService.saveAll().then(() => this.configurationService.reloadConfiguration().then(() => @@ -730,7 +730,7 @@ export class DebugService implements debug.IDebugService { return null; } - public createProcess(root: WorkspaceFolder, config: debug.IConfig): TPromise { + public createProcess(root: IWorkspaceFolder, config: debug.IConfig): TPromise { return this.textFileService.saveAll().then(() => (this.configurationManager.selectedLaunch ? this.configurationManager.selectedLaunch.resolveConfiguration(config) : TPromise.as(config)).then(resolvedConfig => { if (!resolvedConfig) { @@ -800,7 +800,7 @@ export class DebugService implements debug.IDebugService { ); } - private doCreateProcess(root: WorkspaceFolder, configuration: debug.IConfig, sessionId = generateUuid()): TPromise { + private doCreateProcess(root: IWorkspaceFolder, configuration: debug.IConfig, sessionId = generateUuid()): TPromise { configuration.__sessionId = sessionId; this.updateStateAndEmit(sessionId, debug.State.Initializing); this.inDebugMode.set(true); @@ -925,7 +925,7 @@ export class DebugService implements debug.IDebugService { }); } - private runPreLaunchTask(root: WorkspaceFolder, taskName: string): TPromise { + private runPreLaunchTask(root: IWorkspaceFolder, taskName: string): TPromise { if (!taskName) { return TPromise.as(null); } diff --git a/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts b/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts index 035a4b72ad5..3a5f8153adc 100644 --- a/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts +++ b/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts @@ -22,7 +22,7 @@ import debug = require('vs/workbench/parts/debug/common/debug'); import { Adapter } from 'vs/workbench/parts/debug/node/debugAdapter'; import { V8Protocol } from 'vs/workbench/parts/debug/node/v8Protocol'; import { IOutputService } from 'vs/workbench/parts/output/common/output'; -import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { ExtensionsChannelId } from 'vs/platform/extensionManagement/common/extensionManagement'; import { TerminalSupport } from 'vs/workbench/parts/debug/electron-browser/terminalSupport'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -71,7 +71,7 @@ export class RawDebugSession extends V8Protocol implements debug.ISession { private debugServerPort: number, private adapter: Adapter, private customTelemetryService: ITelemetryService, - public root: WorkspaceFolder, + public root: IWorkspaceFolder, @IMessageService private messageService: IMessageService, @ITelemetryService private telemetryService: ITelemetryService, @IOutputService private outputService: IOutputService, diff --git a/src/vs/workbench/parts/debug/node/debugAdapter.ts b/src/vs/workbench/parts/debug/node/debugAdapter.ts index faa649ea280..a403b824a7c 100644 --- a/src/vs/workbench/parts/debug/node/debugAdapter.ts +++ b/src/vs/workbench/parts/debug/node/debugAdapter.ts @@ -14,7 +14,7 @@ import * as objects from 'vs/base/common/objects'; import * as paths from 'vs/base/common/paths'; import * as platform from 'vs/base/common/platform'; import { IJSONSchema, IJSONSchemaSnippet } from 'vs/base/common/jsonSchema'; -import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IConfig, IRawAdapter, IAdapterExecutable, INTERNAL_CONSOLE_OPTIONS_SCHEMA } from 'vs/workbench/parts/debug/common/debug'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; @@ -35,7 +35,7 @@ export class Adapter { public hasConfigurationProvider = false; - public getAdapterExecutable(root: WorkspaceFolder, verifyAgainstFS = true): TPromise { + public getAdapterExecutable(root: IWorkspaceFolder, verifyAgainstFS = true): TPromise { if (this.rawAdapter.adapterExecutableCommand) { return this.commandService.executeCommand(this.rawAdapter.adapterExecutableCommand, root.uri.toString()).then(ad => { diff --git a/src/vs/workbench/parts/debug/test/common/mockDebug.ts b/src/vs/workbench/parts/debug/test/common/mockDebug.ts index 177358f5521..26b2b0b7c71 100644 --- a/src/vs/workbench/parts/debug/test/common/mockDebug.ts +++ b/src/vs/workbench/parts/debug/test/common/mockDebug.ts @@ -7,7 +7,7 @@ import uri from 'vs/base/common/uri'; import Event, { Emitter } from 'vs/base/common/event'; import { TPromise } from 'vs/base/common/winjs.base'; import * as debug from 'vs/workbench/parts/debug/common/debug'; -import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; export class MockDebugService implements debug.IDebugService { public _serviceBrand: any; @@ -88,11 +88,11 @@ export class MockDebugService implements debug.IDebugService { return TPromise.as(null); } - public startDebugging(root: WorkspaceFolder, configOrName?: debug.IConfig | string, noDebug?: boolean): TPromise { + public startDebugging(root: IWorkspaceFolder, configOrName?: debug.IConfig | string, noDebug?: boolean): TPromise { return TPromise.as(null); } - public createProcess(root: WorkspaceFolder, config: debug.IConfig): TPromise { + public createProcess(root: IWorkspaceFolder, config: debug.IConfig): TPromise { return TPromise.as(null); } @@ -129,7 +129,7 @@ export class MockSession implements debug.ISession { return 'mockrawsession'; } - public root: WorkspaceFolder; + public root: IWorkspaceFolder; public getLengthInSeconds(): number { return 100; diff --git a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts index d631f79db21..531618cd8f2 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts @@ -26,7 +26,7 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Query } from 'vs/workbench/parts/extensions/common/extensionQuery'; import { IFileService, IContent } from 'vs/platform/files/common/files'; -import { IWorkspaceContextService, WorkbenchState, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { IExtensionService, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import URI from 'vs/base/common/uri'; @@ -1410,7 +1410,7 @@ export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends Abstrac } public run(): TPromise { - return this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND) + return this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND) .then(workspaceFolder => { if (workspaceFolder) { return this.openExtensionsFile(this.contextService.toResource(paths.join('.vscode', 'extensions.json'), workspaceFolder)); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts index 0676fc1ba02..538f56523ca 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts @@ -19,7 +19,7 @@ import { IChoiceService, IMessageService } from 'vs/platform/message/common/mess import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ShowRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction } from 'vs/workbench/parts/extensions/browser/extensionsActions'; import Severity from 'vs/base/common/severity'; -import { IWorkspaceContextService, WorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { Schemas } from 'vs/base/common/network'; import { IFileService } from 'vs/platform/files/common/files'; import { IExtensionsConfiguration, ConfigurationKey } from 'vs/workbench/parts/extensions/common/extensions'; @@ -84,7 +84,7 @@ export class ExtensionTipsService implements IExtensionTipsService { return TPromise.as([]); } - private resolveWorkspaceFolderRecommendations(workspaceFolder: WorkspaceFolder): TPromise { + private resolveWorkspaceFolderRecommendations(workspaceFolder: IWorkspaceFolder): TPromise { return this.fileService.resolveContent(this.contextService.toResource(paths.join('.vscode', 'extensions.json'), workspaceFolder)) .then(content => this.processWorkspaceRecommendations(json.parse(content.value, [])), err => []); } diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index b2b8d890596..755418e131e 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -32,7 +32,7 @@ import { FileStat, Model } from 'vs/workbench/parts/files/common/explorerModel'; import { IListService } from 'vs/platform/list/browser/listService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; -import { IWorkspaceContextService, WorkbenchState, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -680,7 +680,7 @@ export class ExplorerView extends CollapsibleView { })); } - private refreshFromEvent(newRoots: WorkspaceFolder[] = []): void { + private refreshFromEvent(newRoots: IWorkspaceFolder[] = []): void { if (this.isVisible()) { this.explorerRefreshDelayer.trigger(() => { if (!this.explorerViewer.getHighlight()) { diff --git a/src/vs/workbench/parts/preferences/browser/preferencesActions.ts b/src/vs/workbench/parts/preferences/browser/preferencesActions.ts index c1e222a04dd..f120d63a291 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesActions.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesActions.ts @@ -12,7 +12,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IQuickOpenService, IPickOpenEntry, IFilePickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen'; import { IPreferencesService } from 'vs/workbench/parts/preferences/common/preferences'; -import { IWorkspaceContextService, WorkbenchState, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { PICK_WORKSPACE_FOLDER_COMMAND } from 'vs/workbench/browser/actions/workspaceActions'; @@ -128,7 +128,7 @@ export class OpenFolderSettingsAction extends Action { } public run(): TPromise { - return this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND) + return this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND) .then(workspaceFolder => { if (workspaceFolder) { return this.preferencesService.openFolderSettings(workspaceFolder.uri); diff --git a/src/vs/workbench/parts/tasks/common/taskService.ts b/src/vs/workbench/parts/tasks/common/taskService.ts index 3710927f7c4..57ca26da803 100644 --- a/src/vs/workbench/parts/tasks/common/taskService.ts +++ b/src/vs/workbench/parts/tasks/common/taskService.ts @@ -10,7 +10,7 @@ import { IEventEmitter } from 'vs/base/common/eventEmitter'; import { LinkedMap } from 'vs/base/common/map'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { Task, ContributedTask, CustomTask, TaskSet, TaskSorter } from 'vs/workbench/parts/tasks/common/tasks'; import { ITaskSummary, TaskEvent, TaskType, TaskTerminateResponse } from 'vs/workbench/parts/tasks/common/taskSystem'; @@ -57,7 +57,7 @@ export interface ITaskService extends IEventEmitter { /** * @param identifier The task's name, label or defined identifier. */ - getTask(workspaceFolder: WorkspaceFolder | string, identifier: string): TPromise; + getTask(workspaceFolder: IWorkspaceFolder | string, identifier: string): TPromise; getTasksForGroup(group: string): TPromise; getRecentlyUsedTasks(): LinkedMap; createSorter(): TaskSorter; diff --git a/src/vs/workbench/parts/tasks/common/taskSystem.ts b/src/vs/workbench/parts/tasks/common/taskSystem.ts index 11b78e506ef..50c34926ecf 100644 --- a/src/vs/workbench/parts/tasks/common/taskSystem.ts +++ b/src/vs/workbench/parts/tasks/common/taskSystem.ts @@ -9,7 +9,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { TerminateResponse } from 'vs/base/common/processes'; import { IEventEmitter } from 'vs/base/common/eventEmitter'; -import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { Task } from './tasks'; @@ -104,7 +104,7 @@ export interface TaskEvent { } export interface ITaskResolver { - resolve(workspaceFolder: WorkspaceFolder, identifier: string): Task; + resolve(workspaceFolder: IWorkspaceFolder, identifier: string): Task; } export interface TaskTerminateResponse extends TerminateResponse { diff --git a/src/vs/workbench/parts/tasks/common/tasks.ts b/src/vs/workbench/parts/tasks/common/tasks.ts index 898c6b9b5d3..12c20adf3a3 100644 --- a/src/vs/workbench/parts/tasks/common/tasks.ts +++ b/src/vs/workbench/parts/tasks/common/tasks.ts @@ -11,7 +11,7 @@ import * as Objects from 'vs/base/common/objects'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ProblemMatcher } from 'vs/platform/markers/common/problemMatcher'; -import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; export interface ShellConfiguration { /** @@ -231,7 +231,7 @@ export namespace TaskSourceKind { } export interface TaskSourceConfigElement { - workspaceFolder: WorkspaceFolder; + workspaceFolder: IWorkspaceFolder; file: string; index: number; element: any; @@ -249,7 +249,7 @@ export interface ExtensionTaskSource { readonly label: string; readonly extension: string; readonly scope: TaskScope; - readonly workspaceFolder: WorkspaceFolder | undefined; + readonly workspaceFolder: IWorkspaceFolder | undefined; } export interface ExtensionTaskSourceTransfer { @@ -269,7 +269,7 @@ export interface TaskIdentifier { } export interface TaskDependency { - workspaceFolder: WorkspaceFolder; + workspaceFolder: IWorkspaceFolder; task: string; } @@ -432,7 +432,7 @@ export namespace Task { } } - export function getWorkspaceFolder(task: Task): WorkspaceFolder | undefined { + export function getWorkspaceFolder(task: Task): IWorkspaceFolder | undefined { if (CustomTask.is(task)) { return task._source.config.workspaceFolder; } else if (ContributedTask.is(task)) { @@ -506,7 +506,7 @@ export class TaskSorter { private _order: Map = new Map(); - constructor(workspaceFolders: WorkspaceFolder[]) { + constructor(workspaceFolders: IWorkspaceFolder[]) { for (let i = 0; i < workspaceFolders.length; i++) { this._order.set(workspaceFolders[i].uri.toString(), i); } diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index b86ab02f64c..a23135e551a 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -66,7 +66,7 @@ import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { IConfigurationEditingService, ConfigurationTarget, IConfigurationValue } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IWorkspaceContextService, WorkbenchState, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IOutputService, IOutputChannelRegistry, Extensions as OutputExt, IOutputChannel } from 'vs/workbench/parts/output/common/output'; @@ -618,11 +618,11 @@ interface WorkspaceTaskResult { } interface WorkspaceFolderTaskResult extends WorkspaceTaskResult { - workspaceFolder: WorkspaceFolder; + workspaceFolder: IWorkspaceFolder; } interface WorkspaceFolderConfigurationResult { - workspaceFolder: WorkspaceFolder; + workspaceFolder: IWorkspaceFolder; config: TaskConfig.ExternalTaskRunnerConfiguration; hasErrors: boolean; } @@ -641,7 +641,7 @@ class TaskMap { this._store.forEach(callback); } - public get(workspaceFolder: WorkspaceFolder | string): Task[] { + public get(workspaceFolder: IWorkspaceFolder | string): Task[] { let result: Task[] = Types.isString(workspaceFolder) ? this._store.get(workspaceFolder) : this._store.get(workspaceFolder.uri.toString()); if (!result) { result = []; @@ -650,11 +650,11 @@ class TaskMap { return result; } - public has(workspaceFolder: WorkspaceFolder): boolean { + public has(workspaceFolder: IWorkspaceFolder): boolean { return this._store.has(workspaceFolder.uri.toString()); } - public add(workspaceFolder: WorkspaceFolder | string, ...task: Task[]): void { + public add(workspaceFolder: IWorkspaceFolder | string, ...task: Task[]): void { let values = Types.isString(workspaceFolder) ? this._store.get(workspaceFolder) : this._store.get(workspaceFolder.uri.toString()); if (!values) { values = []; @@ -702,7 +702,7 @@ class TaskService extends EventEmitter implements ITaskService { private _configHasErrors: boolean; private _schemaVersion: JsonSchemaVersion; private _executionEngine: ExecutionEngine; - private _workspaceFolders: WorkspaceFolder[]; + private _workspaceFolders: IWorkspaceFolder[]; private _providers: Map; private _workspaceTasksPromise: TPromise>; @@ -860,7 +860,7 @@ class TaskService extends EventEmitter implements ITaskService { return this._providers.delete(handle); } - public getTask(folder: WorkspaceFolder | string, alias: string): TPromise { + public getTask(folder: IWorkspaceFolder | string, alias: string): TPromise { return this.getGroupedTasks().then((map) => { let values = map.get(folder); if (!values) { @@ -1217,7 +1217,7 @@ class TaskService extends EventEmitter implements ITaskService { }); } - private writeConfiguration(workspaceFolder: WorkspaceFolder, value: IConfigurationValue): TPromise { + private writeConfiguration(workspaceFolder: IWorkspaceFolder, value: IConfigurationValue): TPromise { if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { return this.configurationEditingService.writeConfiguration(ConfigurationTarget.WORKSPACE, value); } else if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { @@ -1272,7 +1272,7 @@ class TaskService extends EventEmitter implements ITaskService { } }); let resolver: ITaskResolver = { - resolve: (workspaceFolder: WorkspaceFolder, alias: string) => { + resolve: (workspaceFolder: IWorkspaceFolder, alias: string) => { let data = resolverData.get(workspaceFolder.uri.toString()); if (!data) { return undefined; @@ -1328,7 +1328,7 @@ class TaskService extends EventEmitter implements ITaskService { } }); return { - resolve: (workspaceFolder: WorkspaceFolder, alias: string) => { + resolve: (workspaceFolder: IWorkspaceFolder, alias: string) => { let data = resolverData.get(workspaceFolder.uri.toString()); if (!data) { return undefined; @@ -1599,7 +1599,7 @@ class TaskService extends EventEmitter implements ITaskService { } } - private computeWorkspaceFolderTasks(workspaceFolder: WorkspaceFolder): TPromise { + private computeWorkspaceFolderTasks(workspaceFolder: IWorkspaceFolder): TPromise { return (this._executionEngine === ExecutionEngine.Process ? this.computeLegacyConfiguration(workspaceFolder) : this.computeConfiguration(workspaceFolder)). @@ -1633,12 +1633,12 @@ class TaskService extends EventEmitter implements ITaskService { }); } - private computeConfiguration(workspaceFolder: WorkspaceFolder): TPromise { + private computeConfiguration(workspaceFolder: IWorkspaceFolder): TPromise { let { config, hasParseErrors } = this.getConfiguration(workspaceFolder); return TPromise.as({ workspaceFolder, config, hasErrors: hasParseErrors }); } - private computeLegacyConfiguration(workspaceFolder: WorkspaceFolder): TPromise { + private computeLegacyConfiguration(workspaceFolder: IWorkspaceFolder): TPromise { let { config, hasParseErrors } = this.getConfiguration(workspaceFolder); if (hasParseErrors) { return TPromise.as({ workspaceFolder: workspaceFolder, hasErrors: true, config: undefined }); @@ -1678,13 +1678,13 @@ class TaskService extends EventEmitter implements ITaskService { } } - private computeWorkspaceFolders(): [WorkspaceFolder[], ExecutionEngine, JsonSchemaVersion] { - let workspaceFolders: WorkspaceFolder[] = []; + private computeWorkspaceFolders(): [IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion] { + let workspaceFolders: IWorkspaceFolder[] = []; let executionEngine = ExecutionEngine.Terminal; let schemaVersion = JsonSchemaVersion.V2_0_0; if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { - let workspaceFolder: WorkspaceFolder = this.contextService.getWorkspace().folders[0]; + let workspaceFolder: IWorkspaceFolder = this.contextService.getWorkspace().folders[0]; workspaceFolders.push(workspaceFolder); executionEngine = this.computeExecutionEngine(workspaceFolder); schemaVersion = this.computeJsonSchemaVersion(workspaceFolder); @@ -1703,7 +1703,7 @@ class TaskService extends EventEmitter implements ITaskService { return [workspaceFolders, executionEngine, schemaVersion]; } - private computeExecutionEngine(workspaceFolder: WorkspaceFolder): ExecutionEngine { + private computeExecutionEngine(workspaceFolder: IWorkspaceFolder): ExecutionEngine { let { config } = this.getConfiguration(workspaceFolder); if (!config) { return ExecutionEngine._default; @@ -1711,7 +1711,7 @@ class TaskService extends EventEmitter implements ITaskService { return TaskConfig.ExecutionEngine.from(config); } - private computeJsonSchemaVersion(workspaceFolder: WorkspaceFolder): JsonSchemaVersion { + private computeJsonSchemaVersion(workspaceFolder: IWorkspaceFolder): JsonSchemaVersion { let { config } = this.getConfiguration(workspaceFolder); if (!config) { return JsonSchemaVersion.V2_0_0; @@ -1719,7 +1719,7 @@ class TaskService extends EventEmitter implements ITaskService { return TaskConfig.JsonSchemaVersion.from(config); } - private getConfiguration(workspaceFolder: WorkspaceFolder): { config: TaskConfig.ExternalTaskRunnerConfiguration; hasParseErrors: boolean } { + private getConfiguration(workspaceFolder: IWorkspaceFolder): { config: TaskConfig.ExternalTaskRunnerConfiguration; hasParseErrors: boolean } { let result = this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? this.configurationService.getConfiguration('tasks', { resource: workspaceFolder.uri }) : undefined; diff --git a/src/vs/workbench/parts/tasks/node/taskConfiguration.ts b/src/vs/workbench/parts/tasks/node/taskConfiguration.ts index 5720bd9573e..fe0429bd85e 100644 --- a/src/vs/workbench/parts/tasks/node/taskConfiguration.ts +++ b/src/vs/workbench/parts/tasks/node/taskConfiguration.ts @@ -20,7 +20,7 @@ import { isNamedProblemMatcher, ProblemMatcherRegistry } from 'vs/platform/markers/common/problemMatcher'; -import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import * as Tasks from '../common/tasks'; import { TaskDefinitionRegistry } from '../common/taskDefinitionRegistry'; @@ -563,7 +563,7 @@ function _freeze(this: void, target: T, properties: MetaData[]): Read } interface ParseContext { - workspaceFolder: WorkspaceFolder; + workspaceFolder: IWorkspaceFolder; problemReporter: IProblemReporter; namedProblemMatchers: IStringDictionary; uuidMap: UUIDMap; @@ -1682,11 +1682,11 @@ class UUIDMap { class ConfigurationParser { - private workspaceFolder: WorkspaceFolder; + private workspaceFolder: IWorkspaceFolder; private problemReporter: IProblemReporter; private uuidMap: UUIDMap; - constructor(workspaceFolder: WorkspaceFolder, problemReporter: IProblemReporter, uuidMap: UUIDMap) { + constructor(workspaceFolder: IWorkspaceFolder, problemReporter: IProblemReporter, uuidMap: UUIDMap) { this.workspaceFolder = workspaceFolder; this.problemReporter = problemReporter; this.uuidMap = uuidMap; @@ -1791,7 +1791,7 @@ class ConfigurationParser { } let uuidMaps: Map = new Map(); -export function parse(workspaceFolder: WorkspaceFolder, configuration: ExternalTaskRunnerConfiguration, logger: IProblemReporter): ParseResult { +export function parse(workspaceFolder: IWorkspaceFolder, configuration: ExternalTaskRunnerConfiguration, logger: IProblemReporter): ParseResult { let uuidMap = uuidMaps.get(workspaceFolder.uri.toString()); if (!uuidMap) { uuidMap = new UUIDMap(); diff --git a/src/vs/workbench/parts/tasks/test/electron-browser/configuration.test.ts b/src/vs/workbench/parts/tasks/test/electron-browser/configuration.test.ts index 715c3e1c11a..8ffa18cdb49 100644 --- a/src/vs/workbench/parts/tasks/test/electron-browser/configuration.test.ts +++ b/src/vs/workbench/parts/tasks/test/electron-browser/configuration.test.ts @@ -12,12 +12,12 @@ import * as UUID from 'vs/base/common/uuid'; import * as Platform from 'vs/base/common/platform'; import { ValidationStatus } from 'vs/base/common/parsers'; import { ProblemMatcher, FileLocationKind, ProblemPattern, ApplyToKind } from 'vs/platform/markers/common/problemMatcher'; -import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import * as Tasks from 'vs/workbench/parts/tasks/common/tasks'; import { parse, ParseResult, IProblemReporter, ExternalTaskRunnerConfiguration, CustomTask } from 'vs/workbench/parts/tasks/node/taskConfiguration'; -const workspaceFolder: WorkspaceFolder = { +const workspaceFolder: IWorkspaceFolder = { uri: URI.file('/workspace/folderOne'), name: 'folderOne', index: 0, diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configuration.ts index a5199b8236c..5fb8a8f0b77 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configuration.ts @@ -17,7 +17,7 @@ import { RunOnceScheduler } from 'vs/base/common/async'; import { readFile, stat, writeFile } from 'vs/base/node/pfs'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import * as extfs from 'vs/base/node/extfs'; -import { IWorkspaceContextService, IWorkspace, Workspace, WorkbenchState, WorkspaceFolder, toWorkspaceFolders, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, IWorkspace, Workspace, WorkbenchState, IWorkspaceFolder, toWorkspaceFolders, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files'; import { isLinux } from 'vs/base/common/platform'; import { ConfigWatcher } from 'vs/base/node/config'; @@ -290,7 +290,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat return WorkbenchState.EMPTY; } - public getWorkspaceFolder(resource: URI): WorkspaceFolder { + public getWorkspaceFolder(resource: URI): IWorkspaceFolder { return this.workspace.getFolder(resource); } @@ -308,7 +308,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat return false; } - public toResource(workspaceRelativePath: string, workspaceFolder: WorkspaceFolder): URI { + public toResource(workspaceRelativePath: string, workspaceFolder: IWorkspaceFolder): URI { return URI.file(paths.join(workspaceFolder.uri.fsPath, workspaceRelativePath)); } @@ -443,7 +443,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat } } - private compareFolders(currentFolders: WorkspaceFolder[], newFolders: WorkspaceFolder[]): IWorkspaceFoldersChangeEvent { + private compareFolders(currentFolders: IWorkspaceFolder[], newFolders: IWorkspaceFolder[]): IWorkspaceFoldersChangeEvent { const result = { added: [], removed: [], changed: [] }; result.added = newFolders.filter(newFolder => !currentFolders.some(currentFolder => newFolder.uri.toString() === currentFolder.uri.toString())); @@ -472,14 +472,14 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat this.initCachesForFolders(this.workspace.folders); } - private initCachesForFolders(folders: WorkspaceFolder[]): void { + private initCachesForFolders(folders: IWorkspaceFolder[]): void { for (const folder of folders) { this.cachedFolderConfigs.set(folder.uri, this._register(new FolderConfiguration(folder.uri, this.workspaceSettingsRootFolder, this.getWorkbenchState() === WorkbenchState.WORKSPACE ? ConfigurationScope.RESOURCE : ConfigurationScope.WINDOW))); this.updateFolderConfiguration(folder, new FolderConfigurationModel(new FolderSettingsModel(null), [], ConfigurationScope.RESOURCE), false); } } - private updateConfiguration(folders: WorkspaceFolder[] = this.workspace.folders): TPromise { + private updateConfiguration(folders: IWorkspaceFolder[] = this.workspace.folders): TPromise { return TPromise.join([...folders.map(folder => this.cachedFolderConfigs.get(folder.uri).loadConfiguration() .then(configuration => this.updateFolderConfiguration(folder, configuration, true)))]) .then(changed => changed.reduce((result, value) => result || value, false)) @@ -545,7 +545,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat return TPromise.as(false); } - private updateFolderConfiguration(folder: WorkspaceFolder, folderConfiguration: FolderConfigurationModel, compare: boolean): boolean { + private updateFolderConfiguration(folder: IWorkspaceFolder, folderConfiguration: FolderConfigurationModel, compare: boolean): boolean { let configurationChanged = this._configuration.updateFolderConfiguration(folder.uri, folderConfiguration, compare); if (this.getWorkbenchState() === WorkbenchState.FOLDER) { // Workspace configuration changed diff --git a/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts b/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts index 9e191e760ec..e2dc0febf79 100644 --- a/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts @@ -6,7 +6,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IStringDictionary } from 'vs/base/common/collections'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; export const IConfigurationResolverService = createDecorator('configurationResolverService'); @@ -14,9 +14,9 @@ export interface IConfigurationResolverService { _serviceBrand: any; // TODO@Isidor improve this API - resolve(root: WorkspaceFolder, value: string): string; - resolve(root: WorkspaceFolder, value: string[]): string[]; - resolve(root: WorkspaceFolder, value: IStringDictionary): IStringDictionary; - resolveAny(root: WorkspaceFolder, value: T): T; + resolve(root: IWorkspaceFolder, value: string): string; + resolve(root: IWorkspaceFolder, value: string[]): string[]; + resolve(root: IWorkspaceFolder, value: IStringDictionary): IStringDictionary; + resolveAny(root: IWorkspaceFolder, value: T): T; resolveInteractiveVariables(configuration: any, interactiveVariablesMap: { [key: string]: string }): TPromise; } diff --git a/src/vs/workbench/services/configurationResolver/node/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/node/configurationResolverService.ts index 183fa02bf13..d5bb08cfbb4 100644 --- a/src/vs/workbench/services/configurationResolver/node/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/node/configurationResolverService.ts @@ -13,14 +13,14 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; -import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { toResource } from 'vs/workbench/common/editor'; export class ConfigurationResolverService implements IConfigurationResolverService { _serviceBrand: any; private _execPath: string; - private _lastWorkspaceFolder: WorkspaceFolder; + private _lastWorkspaceFolder: IWorkspaceFolder; constructor( envVariables: { [key: string]: string }, @@ -109,10 +109,10 @@ export class ConfigurationResolverService implements IConfigurationResolverServi return paths.normalize(fileResource.fsPath, true); } - public resolve(root: WorkspaceFolder, value: string): string; - public resolve(root: WorkspaceFolder, value: string[]): string[]; - public resolve(root: WorkspaceFolder, value: IStringDictionary): IStringDictionary; - public resolve(root: WorkspaceFolder, value: any): any { + public resolve(root: IWorkspaceFolder, value: string): string; + public resolve(root: IWorkspaceFolder, value: string[]): string[]; + public resolve(root: IWorkspaceFolder, value: IStringDictionary): IStringDictionary; + public resolve(root: IWorkspaceFolder, value: any): any { try { this._lastWorkspaceFolder = root; if (types.isString(value)) { @@ -128,8 +128,8 @@ export class ConfigurationResolverService implements IConfigurationResolverServi } } - public resolveAny(root: WorkspaceFolder, value: T): T; - public resolveAny(root: WorkspaceFolder, value: any): any { + public resolveAny(root: IWorkspaceFolder, value: T): T; + public resolveAny(root: IWorkspaceFolder, value: any): any { try { this._lastWorkspaceFolder = root; if (types.isString(value)) { @@ -145,7 +145,7 @@ export class ConfigurationResolverService implements IConfigurationResolverServi } } - private resolveString(root: WorkspaceFolder, value: string): string { + private resolveString(root: IWorkspaceFolder, value: string): string { let regexp = /\$\{(.*?)\}/g; const originalValue = value; const resolvedString = value.replace(regexp, (match: string, name: string) => { @@ -160,7 +160,7 @@ export class ConfigurationResolverService implements IConfigurationResolverServi return this.resolveConfigVariable(root, resolvedString, originalValue); } - private resolveConfigVariable(root: WorkspaceFolder, value: string, originalValue: string): string { + private resolveConfigVariable(root: IWorkspaceFolder, value: string, originalValue: string): string { const replacer = (match: string, name: string) => { let config = this.configurationService.getConfiguration(); let newValue: any; @@ -191,7 +191,7 @@ export class ConfigurationResolverService implements IConfigurationResolverServi return value.replace(/\$\{config:(.+?)\}/g, replacer); } - private resolveLiteral(root: WorkspaceFolder, values: IStringDictionary | string[]>): IStringDictionary | string[]> { + private resolveLiteral(root: IWorkspaceFolder, values: IStringDictionary | string[]>): IStringDictionary | string[]> { let result: IStringDictionary | string[]> = Object.create(null); Object.keys(values).forEach(key => { let value = values[key]; @@ -200,8 +200,8 @@ export class ConfigurationResolverService implements IConfigurationResolverServi return result; } - private resolveAnyLiteral(root: WorkspaceFolder, values: T): T; - private resolveAnyLiteral(root: WorkspaceFolder, values: any): any { + private resolveAnyLiteral(root: IWorkspaceFolder, values: T): T; + private resolveAnyLiteral(root: IWorkspaceFolder, values: any): any { let result: IStringDictionary | string[]> = Object.create(null); Object.keys(values).forEach(key => { let value = values[key]; @@ -210,12 +210,12 @@ export class ConfigurationResolverService implements IConfigurationResolverServi return result; } - private resolveArray(root: WorkspaceFolder, value: string[]): string[] { + private resolveArray(root: IWorkspaceFolder, value: string[]): string[] { return value.map(s => this.resolveString(root, s)); } - private resolveAnyArray(root: WorkspaceFolder, value: T[]): T[]; - private resolveAnyArray(root: WorkspaceFolder, value: any[]): any[] { + private resolveAnyArray(root: IWorkspaceFolder, value: T[]): T[]; + private resolveAnyArray(root: IWorkspaceFolder, value: any[]): any[] { return value.map(s => this.resolveAny(root, s)); } diff --git a/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts index 139e1c758b6..0f8f279cda8 100644 --- a/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts @@ -11,7 +11,7 @@ import { IConfigurationService, getConfigurationValue, IConfigurationOverrides, import { ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/node/configurationResolverService'; -import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { TestEnvironmentService, TestEditorService } from 'vs/workbench/test/workbenchTestServices'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; @@ -20,7 +20,7 @@ suite('Configuration Resolver Service', () => { let envVariables: { [key: string]: string } = { key1: 'Value for Key1', key2: 'Value for Key2' }; let mockCommandService: MockCommandService; let editorService: TestEditorService; - let workspace: WorkspaceFolder; + let workspace: IWorkspaceFolder; setup(() => { diff --git a/src/vs/workbench/services/files/test/node/fileService.test.ts b/src/vs/workbench/services/files/test/node/fileService.test.ts index d08e9e93cc4..b4ba620ede2 100644 --- a/src/vs/workbench/services/files/test/node/fileService.test.ts +++ b/src/vs/workbench/services/files/test/node/fileService.test.ts @@ -20,7 +20,7 @@ import encodingLib = require('vs/base/node/encoding'); import utils = require('vs/workbench/services/files/test/node/utils'); import { onError } from 'vs/base/test/common/utils'; import { TestContextService, TestTextResourceConfigurationService } from 'vs/workbench/test/workbenchTestServices'; -import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { Workspace, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; suite('FileService', () => { @@ -853,7 +853,7 @@ suite('FileService', () => { }); }); - function aWorkspaceFolder(path: string, index: number, name: string = ''): WorkspaceFolder { + function aWorkspaceFolder(path: string, index: number, name: string = ''): IWorkspaceFolder { return { uri: uri.file(path), index, diff --git a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts index 20792c4a191..c4fca1c3ef0 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts @@ -15,7 +15,7 @@ import { ConfigurationTarget, ConfigurationEditingErrorCode, ConfigurationEditin import { ConfigurationModel } from 'vs/platform/configuration/common/configuration'; import { TestThreadService } from './testThreadService'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; -import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; suite('ExtHostConfiguration', function () { @@ -405,7 +405,7 @@ suite('ExtHostConfiguration', function () { .then(() => assert.ok(false), err => { /* expecting rejection */ }); }); - function aWorkspaceFolder(raw: IStoredWorkspaceFolder, index: number, name: string = ''): WorkspaceFolder { + function aWorkspaceFolder(raw: IStoredWorkspaceFolder, index: number, name: string = ''): IWorkspaceFolder { return { uri: URI.file(raw.path), index, diff --git a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts index fcf619a2309..b57a2b3d8a2 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts @@ -11,7 +11,7 @@ import { basename } from 'path'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { TestThreadService } from './testThreadService'; import { normalize } from 'vs/base/common/paths'; -import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; suite('ExtHostWorkspace', function () { @@ -195,7 +195,7 @@ suite('ExtHostWorkspace', function () { sub.dispose(); }); - function aWorkspaceFolder(uri: URI, index: number, name: string = ''): WorkspaceFolder { + function aWorkspaceFolder(uri: URI, index: number, name: string = ''): IWorkspaceFolder { return { uri, index, diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 7f89866c96d..ada172ca08d 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -27,7 +27,7 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { IEditorInput, IEditorOptions, Position, Direction, IEditor, IResourceInput, ITextEditorSelection } from 'vs/platform/editor/common/editor'; import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { IMessageService, IConfirmation } from 'vs/platform/message/common/message'; -import { IWorkspaceContextService, IWorkspace as IWorkbenchWorkspace, WorkbenchState, WorkspaceFolder, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, IWorkspace as IWorkbenchWorkspace, WorkbenchState, IWorkspaceFolder, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; import { ILifecycleService, ShutdownEvent, ShutdownReason, StartupKind, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { EditorStacksModel } from 'vs/workbench/common/editor/editorStacksModel'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; @@ -97,7 +97,7 @@ export class TestContextService implements IWorkspaceContextService { return this._onDidChangeWorkbenchState.event; } - public getFolders(): WorkspaceFolder[] { + public getFolders(): IWorkspaceFolder[] { return this.workspace ? this.workspace.folders : []; } @@ -115,7 +115,7 @@ export class TestContextService implements IWorkspaceContextService { return this.workspace; } - public getWorkspaceFolder(resource: URI): WorkspaceFolder { + public getWorkspaceFolder(resource: URI): IWorkspaceFolder { return this.isInsideWorkspace(resource) ? this.workspace.folders[0] : null; } From 5fa7f9682a8b0bd9296bced6738cbb69511c2274 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 20 Sep 2017 15:06:43 +0200 Subject: [PATCH 100/281] Move toResource method to IWorkspaceFolder --- .../standalone/browser/simpleServices.ts | 4 +- src/vs/platform/workspace/common/workspace.ts | 63 ++++++++++++------- .../workspace/test/common/workspace.test.ts | 23 +++---- src/vs/workbench/api/node/extHost.protocol.ts | 4 +- src/vs/workbench/api/node/extHostWorkspace.ts | 4 +- .../parts/debug/browser/linkDetector.ts | 2 +- .../extensions/browser/extensionsActions.ts | 4 +- .../electron-browser/extensionTipsService.ts | 2 +- .../preferences/browser/preferencesService.ts | 4 +- .../electron-browser/task.contribution.ts | 10 +-- .../parts/tasks/node/processRunnerDetector.ts | 8 +-- .../electron-browser/configuration.test.ts | 9 ++- .../configuration/node/configuration.ts | 8 +-- .../node/configurationEditingService.ts | 4 +- .../test/node/configuration.test.ts | 1 - .../node/configurationResolverService.test.ts | 2 +- .../files/test/node/fileService.test.ts | 17 ++--- .../test/node/keybindingEditing.test.ts | 5 +- .../workspace/node/workspaceEditingService.ts | 2 +- .../api/extHostConfiguration.test.ts | 16 ++--- .../api/extHostWorkspace.test.ts | 31 +++++---- 21 files changed, 105 insertions(+), 118 deletions(-) diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 97f3a7f14aa..bad64ca55ae 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -18,7 +18,7 @@ import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingReso import { IKeybindingEvent, KeybindingSource, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IConfirmation, IMessageService } from 'vs/platform/message/common/message'; -import { IWorkspaceContextService, IWorkspace, WorkbenchState, IWorkspaceFolder, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, IWorkspace, WorkbenchState, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { Selection } from 'vs/editor/common/core/selection'; @@ -535,7 +535,7 @@ export class SimpleWorkspaceContextService implements IWorkspaceContextService { constructor() { const resource = URI.from({ scheme: SimpleWorkspaceContextService.SCHEME, authority: 'model', path: '/' }); - this.workspace = { id: '4064f6ec-cb38-4ad0-af64-ee6467e63c82', folders: [{ uri: resource, raw: { path: resource.toString() }, name: '', index: 0, }], name: resource.fsPath }; + this.workspace = { id: '4064f6ec-cb38-4ad0-af64-ee6467e63c82', folders: [new WorkspaceFolder({ uri: resource, name: '', index: 0 })], name: resource.fsPath }; } public getWorkspace(): IWorkspace { diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index 755eb652c21..00b3c8a61cd 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -75,11 +75,6 @@ export interface IWorkspaceContextService { * Returns if the provided resource is inside the workspace or not. */ isInsideWorkspace(resource: URI): boolean; - - /** - * Given a workspace relative path and workspace folder, returns the resource with the absolute path. - */ - toResource: (workspaceRelativePath: string, workspaceFolder: IWorkspaceFolder) => URI; } export interface IWorkspace { @@ -105,8 +100,7 @@ export interface IWorkspace { readonly configuration?: URI; } -export interface IWorkspaceFolder { - +export interface IWorkspaceFolderData { /** * The associated URI for this workspace folder. */ @@ -122,22 +116,25 @@ export interface IWorkspaceFolder { * The ordinal number of this workspace folder. */ readonly index: number; +} + +export interface IWorkspaceFolder extends IWorkspaceFolderData { /** - * The raw path of this workspace folder + * Given workspace folder relative path, returns the resource with the absolute path. */ - readonly raw: IStoredWorkspaceFolder; + toResource: (relativePath: string) => URI; } export class Workspace implements IWorkspace { - private _foldersMap: TrieMap = new TrieMap(); - private _folders: IWorkspaceFolder[]; + private _foldersMap: TrieMap = new TrieMap(); + private _folders: WorkspaceFolder[]; constructor( private _id: string, private _name: string = '', - folders: IWorkspaceFolder[] = [], + folders: WorkspaceFolder[] = [], private _configuration: URI = null, private _ctime?: number ) { @@ -152,11 +149,11 @@ export class Workspace implements IWorkspace { this.folders = workspace.folders; } - public get folders(): IWorkspaceFolder[] { + public get folders(): WorkspaceFolder[] { return this._folders; } - public set folders(folders: IWorkspaceFolder[]) { + public set folders(folders: WorkspaceFolder[]) { this._folders = folders; this.updateFoldersMap(); } @@ -194,7 +191,7 @@ export class Workspace implements IWorkspace { } private updateFoldersMap(): void { - this._foldersMap = new TrieMap(); + this._foldersMap = new TrieMap(); for (const folder of this.folders) { this._foldersMap.insert(folder.uri.toString(), folder); } @@ -205,19 +202,41 @@ export class Workspace implements IWorkspace { } } -export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo?: URI): IWorkspaceFolder[] { - let workspaceFolders = parseWorkspaceFolders(configuredFolders, relativeTo); - return ensureUnique(coalesce(workspaceFolders)) - .map(({ uri, raw, name }, index) => ({ uri, raw, name: name || paths.basename(uri.fsPath), index })); +export class WorkspaceFolder implements IWorkspaceFolder { + + readonly uri: URI; + readonly name: string; + readonly index: number; + + constructor(data: IWorkspaceFolderData, + readonly raw?: IStoredWorkspaceFolder) { + this.uri = data.uri; + this.index = data.index; + this.name = data.name; + } + + toResource(relativePath: string): URI { + return URI.file(paths.join(this.uri.fsPath, relativePath)); + } + + public toJSON(): IWorkspaceFolderData { + return { uri: this.uri, name: this.name, index: this.index }; + } } -function parseWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo: URI): IWorkspaceFolder[] { +export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo?: URI): WorkspaceFolder[] { + let workspaceFolders = parseWorkspaceFolders(configuredFolders, relativeTo); + return ensureUnique(coalesce(workspaceFolders)) + .map(({ uri, raw, name }, index) => new WorkspaceFolder({ uri, name: name || paths.basename(uri.fsPath), index }, raw)); +} + +function parseWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo: URI): WorkspaceFolder[] { return configuredFolders.map((configuredFolder, index) => { const uri = toUri(configuredFolder.path, relativeTo); if (!uri) { return void 0; } - return { uri, raw: configuredFolder, index, name: configuredFolder.name }; + return new WorkspaceFolder({ uri, name: configuredFolder.name, index }, configuredFolder); }); } @@ -233,6 +252,6 @@ function toUri(path: string, relativeTo: URI): URI { return null; } -function ensureUnique(folders: IWorkspaceFolder[]): IWorkspaceFolder[] { +function ensureUnique(folders: WorkspaceFolder[]): WorkspaceFolder[] { return distinct(folders, folder => isLinux ? folder.uri.fsPath : folder.uri.fsPath.toLowerCase()); } diff --git a/src/vs/platform/workspace/test/common/workspace.test.ts b/src/vs/platform/workspace/test/common/workspace.test.ts index b25db238f1e..130aebe39d6 100644 --- a/src/vs/platform/workspace/test/common/workspace.test.ts +++ b/src/vs/platform/workspace/test/common/workspace.test.ts @@ -6,14 +6,14 @@ 'use strict'; import * as assert from 'assert'; -import { Workspace, IWorkspaceFolder, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; +import { Workspace, toWorkspaceFolders, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import URI from 'vs/base/common/uri'; suite('Workspace', () => { test('getFolder returns the folder with given uri', () => { - const expected = aWorkspaceFolder(URI.file('/src/test')); - let testObject = new Workspace('', '', [aWorkspaceFolder(URI.file('/src/main')), expected, aWorkspaceFolder(URI.file('/src/code'))]); + const expected = new WorkspaceFolder({ uri: URI.file('/src/test'), name: '', index: 2 }); + let testObject = new Workspace('', '', [new WorkspaceFolder({ uri: URI.file('/src/main'), name: '', index: 0 }), expected, new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 2 })]); const actual = testObject.getFolder(expected.uri); @@ -21,8 +21,8 @@ suite('Workspace', () => { }); test('getFolder returns the folder if the uri is sub', () => { - const expected = aWorkspaceFolder(URI.file('/src/test')); - let testObject = new Workspace('', '', [expected, aWorkspaceFolder(URI.file('/src/main')), aWorkspaceFolder(URI.file('/src/code'))]); + const expected = new WorkspaceFolder({ uri: URI.file('/src/test'), name: '', index: 0 }); + let testObject = new Workspace('', '', [expected, new WorkspaceFolder({ uri: URI.file('/src/main'), name: '', index: 1 }), new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 2 })]); const actual = testObject.getFolder(URI.file('/src/test/a')); @@ -30,8 +30,8 @@ suite('Workspace', () => { }); test('getFolder returns the closest folder if the uri is sub', () => { - const expected = aWorkspaceFolder(URI.file('/src/test')); - let testObject = new Workspace('', '', [aWorkspaceFolder(URI.file('/src/code')), aWorkspaceFolder(URI.file('/src')), expected]); + const expected = new WorkspaceFolder({ uri: URI.file('/src/test'), name: '', index: 2 }); + let testObject = new Workspace('', '', [new WorkspaceFolder({ uri: URI.file('/src/main'), name: '', index: 0 }), new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 1 }), expected]); const actual = testObject.getFolder(URI.file('/src/test/a')); @@ -39,7 +39,7 @@ suite('Workspace', () => { }); test('getFolder returns null if the uri is not sub', () => { - let testObject = new Workspace('', '', [aWorkspaceFolder(URI.file('/src/code')), aWorkspaceFolder(URI.file('/src/test'))]); + let testObject = new Workspace('', '', [new WorkspaceFolder({ uri: URI.file('/src/test'), name: '', index: 0 }), new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 1 })]); const actual = testObject.getFolder(URI.file('/src/main/a')); @@ -190,11 +190,4 @@ suite('Workspace', () => { assert.equal(actual[2].index, 2); assert.equal(actual[2].name, 'test1'); }); - - function aWorkspaceFolder(uri: URI, index: number = 0): IWorkspaceFolder { - return { - uri, raw: { path: uri.fsPath }, index, name: '' - }; - } - }); \ No newline at end of file diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 5dfdba9d121..e71bcb49058 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -47,7 +47,7 @@ import { ITreeItem } from 'vs/workbench/common/views'; import { ThemeColor } from 'vs/platform/theme/common/themeService'; import { IDisposable } from 'vs/base/common/lifecycle'; import { SerializedError } from 'vs/base/common/errors'; -import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace'; import { IStat, IFileChange } from 'vs/platform/files/common/files'; export interface IEnvironment { @@ -65,7 +65,7 @@ export interface IEnvironment { export interface IWorkspaceData { id: string; name: string; - folders: IWorkspaceFolder[]; + folders: IWorkspaceFolderData[]; } export interface IInitData { diff --git a/src/vs/workbench/api/node/extHostWorkspace.ts b/src/vs/workbench/api/node/extHostWorkspace.ts index a87f6751751..d6027a8e703 100644 --- a/src/vs/workbench/api/node/extHostWorkspace.ts +++ b/src/vs/workbench/api/node/extHostWorkspace.ts @@ -9,7 +9,7 @@ import Event, { Emitter } from 'vs/base/common/event'; import { normalize } from 'vs/base/common/paths'; import { delta } from 'vs/base/common/arrays'; import { relative } from 'path'; -import { Workspace } from 'vs/platform/workspace/common/workspace'; +import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceData, ExtHostWorkspaceShape, MainContext, MainThreadWorkspaceShape, IMainContext } from './extHost.protocol'; import * as vscode from 'vscode'; import { compare } from 'vs/base/common/strings'; @@ -25,7 +25,7 @@ class Workspace2 extends Workspace { private readonly _structure = new TrieMap(s => s.split('/')); private constructor(data: IWorkspaceData) { - super(data.id, data.name, data.folders); + super(data.id, data.name, data.folders.map(folder => new WorkspaceFolder(folder))); // setup the workspace folder data structure this.folders.forEach(({ name, uri, index }) => { diff --git a/src/vs/workbench/parts/debug/browser/linkDetector.ts b/src/vs/workbench/parts/debug/browser/linkDetector.ts index 29dd86998c0..420c424b840 100644 --- a/src/vs/workbench/parts/debug/browser/linkDetector.ts +++ b/src/vs/workbench/parts/debug/browser/linkDetector.ts @@ -50,7 +50,7 @@ export class LinkDetector { if (workspaceFolder) { try { resource = (match && !strings.startsWith(match[0], 'http')) - && (match[2] || strings.startsWith(match[1], '/') ? uri.file(match[1]) : this.contextService.toResource(match[1], workspaceFolder)); // TODO@Michel TODO@Isidor (https://github.com/Microsoft/vscode/issues/29190) + && (match[2] || strings.startsWith(match[1], '/') ? uri.file(match[1]) : workspaceFolder.toResource(match[1])); // TODO@Michel TODO@Isidor (https://github.com/Microsoft/vscode/issues/29190) } catch (e) { } } diff --git a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts index 531618cd8f2..401f5b0e0a3 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts @@ -1370,7 +1370,7 @@ export class ConfigureWorkspaceRecommendedExtensionsAction extends AbstractConfi public run(event: any): TPromise { switch (this.contextService.getWorkbenchState()) { case WorkbenchState.FOLDER: - return this.openExtensionsFile(this.contextService.toResource(paths.join('.vscode', 'extensions.json'), this.contextService.getWorkspace().folders[0])); + return this.openExtensionsFile(this.contextService.getWorkspace().folders[0].toResource(paths.join('.vscode', 'extensions.json'))); case WorkbenchState.WORKSPACE: return this.openWorkspaceConfigurationFile(this.contextService.getWorkspace().configuration); } @@ -1413,7 +1413,7 @@ export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends Abstrac return this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND) .then(workspaceFolder => { if (workspaceFolder) { - return this.openExtensionsFile(this.contextService.toResource(paths.join('.vscode', 'extensions.json'), workspaceFolder)); + return this.openExtensionsFile(workspaceFolder.toResource(paths.join('.vscode', 'extensions.json'))); } return null; }); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts index 538f56523ca..3918fe5f9f0 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts @@ -85,7 +85,7 @@ export class ExtensionTipsService implements IExtensionTipsService { } private resolveWorkspaceFolderRecommendations(workspaceFolder: IWorkspaceFolder): TPromise { - return this.fileService.resolveContent(this.contextService.toResource(paths.join('.vscode', 'extensions.json'), workspaceFolder)) + return this.fileService.resolveContent(workspaceFolder.toResource(paths.join('.vscode', 'extensions.json'))) .then(content => this.processWorkspaceRecommendations(json.parse(content.value, [])), err => []); } diff --git a/src/vs/workbench/parts/preferences/browser/preferencesService.ts b/src/vs/workbench/parts/preferences/browser/preferencesService.ts index 05fe0487f3e..c975dfe62f8 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesService.ts @@ -320,10 +320,10 @@ export class PreferencesService extends Disposable implements IPreferencesServic return null; } const workspace = this.contextService.getWorkspace(); - return workspace.configuration || this.contextService.toResource(paths.join('.vscode', 'settings.json'), workspace.folders[0]); + return workspace.configuration || workspace.folders[0].toResource(paths.join('.vscode', 'settings.json')); case ConfigurationTarget.FOLDER: const folder = this.contextService.getWorkspaceFolder(resource); - return folder ? this.contextService.toResource(paths.join('.vscode', 'settings.json'), folder) : null; + return folder ? folder.toResource(paths.join('.vscode', 'settings.json')) : null; } return null; } diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index a23135e551a..4d9bb12abeb 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -118,7 +118,7 @@ abstract class OpenTaskConfigurationAction extends Action { } let sideBySide = !!(event && (event.ctrlKey || event.metaKey)); let configFileCreated = false; - return this.fileService.resolveFile(this.contextService.toResource('.vscode/tasks.json', this.contextService.getWorkspace().folders[0])).then((success) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) + return this.fileService.resolveFile(this.contextService.getWorkspace().folders[0].toResource('.vscode/tasks.json')).then((success) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) return success; }, (err: any) => { @@ -169,7 +169,7 @@ abstract class OpenTaskConfigurationAction extends Action { content = content.replace(/(\n)(\t+)/g, (_, s1, s2) => s1 + strings.repeat(' ', s2.length * editorConfig.editor.tabSize)); } configFileCreated = true; - return this.fileService.createFile(this.contextService.toResource('.vscode/tasks.json', this.contextService.getWorkspace().folders[0]), content).then((result) => { + return this.fileService.createFile(this.contextService.getWorkspace().folders[0].toResource('.vscode/tasks.json'), content).then((result) => { this.telemetryService.publicLog(TaskService.TemplateTelemetryEventName, { templateId: selection.id, autoDetect: selection.autoDetect @@ -1166,7 +1166,7 @@ class TaskService extends EventEmitter implements ITaskService { if (editorConfig.editor.insertSpaces) { content = content.replace(/(\n)(\t+)/g, (_, s1, s2) => s1 + strings.repeat(' ', s2.length * editorConfig.editor.tabSize)); } - promise = this.fileService.createFile(this.contextService.toResource('.vscode/tasks.json', workspaceFolder), content).then(() => { }); + promise = this.fileService.createFile(workspaceFolder.toResource('.vscode/tasks.json'), content).then(() => { }); } else { let value: IConfigurationValue = { key: undefined, value: undefined }; // We have a global task configuration @@ -1205,7 +1205,7 @@ class TaskService extends EventEmitter implements ITaskService { }; this.telemetryService.publicLog(TaskService.CustomizationTelemetryEventName, event); if (openConfig) { - let resource = this.contextService.toResource('.vscode/tasks.json', workspaceFolder); + let resource = workspaceFolder.toResource('.vscode/tasks.json'); this.editorService.openEditor({ resource: resource, options: { @@ -1228,7 +1228,7 @@ class TaskService extends EventEmitter implements ITaskService { } public openConfig(task: CustomTask): TPromise { - let resource = this.contextService.toResource(task._source.config.file, Task.getWorkspaceFolder(task)); + let resource = Task.getWorkspaceFolder(task).toResource(task._source.config.file); return this.editorService.openEditor({ resource: resource, options: { diff --git a/src/vs/workbench/parts/tasks/node/processRunnerDetector.ts b/src/vs/workbench/parts/tasks/node/processRunnerDetector.ts index 6a8926fec1d..03e29fb4ade 100644 --- a/src/vs/workbench/parts/tasks/node/processRunnerDetector.ts +++ b/src/vs/workbench/parts/tasks/node/processRunnerDetector.ts @@ -228,7 +228,7 @@ export class ProcessRunnerDetector { } private tryDetectGulp(list: boolean): TPromise { - return this.fileService.resolveFile(this.contextService.toResource('gulpfile.js', this.contextService.getWorkspace().folders[0])).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) + return this.fileService.resolveFile(this.contextService.getWorkspace().folders[0].toResource('gulpfile.js')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) let config = ProcessRunnerDetector.detectorConfig('gulp'); let process = new LineProcess('gulp', [config.arg, '--no-color'], true, { cwd: this._cwd }); return this.runDetection(process, 'gulp', true, config.matcher, ProcessRunnerDetector.DefaultProblemMatchers, list); @@ -238,7 +238,7 @@ export class ProcessRunnerDetector { } private tryDetectGrunt(list: boolean): TPromise { - return this.fileService.resolveFile(this.contextService.toResource('Gruntfile.js', this.contextService.getWorkspace().folders[0])).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) + return this.fileService.resolveFile(this.contextService.getWorkspace().folders[0].toResource('Gruntfile.js')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) let config = ProcessRunnerDetector.detectorConfig('grunt'); let process = new LineProcess('grunt', [config.arg, '--no-color'], true, { cwd: this._cwd }); return this.runDetection(process, 'grunt', true, config.matcher, ProcessRunnerDetector.DefaultProblemMatchers, list); @@ -253,10 +253,10 @@ export class ProcessRunnerDetector { let process = new LineProcess('jake', [config.arg], true, { cwd: this._cwd }); return this.runDetection(process, 'jake', true, config.matcher, ProcessRunnerDetector.DefaultProblemMatchers, list); }; - return this.fileService.resolveFile(this.contextService.toResource('Jakefile', this.contextService.getWorkspace().folders[0])).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) + return this.fileService.resolveFile(this.contextService.getWorkspace().folders[0].toResource('Jakefile')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) return run(); }, (err: any) => { - return this.fileService.resolveFile(this.contextService.toResource('Jakefile.js', this.contextService.getWorkspace().folders[0])).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) + return this.fileService.resolveFile(this.contextService.getWorkspace().folders[0].toResource('Jakefile.js')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) return run(); }, (err: any) => { return null; diff --git a/src/vs/workbench/parts/tasks/test/electron-browser/configuration.test.ts b/src/vs/workbench/parts/tasks/test/electron-browser/configuration.test.ts index 8ffa18cdb49..85d747f12c3 100644 --- a/src/vs/workbench/parts/tasks/test/electron-browser/configuration.test.ts +++ b/src/vs/workbench/parts/tasks/test/electron-browser/configuration.test.ts @@ -12,17 +12,16 @@ import * as UUID from 'vs/base/common/uuid'; import * as Platform from 'vs/base/common/platform'; import { ValidationStatus } from 'vs/base/common/parsers'; import { ProblemMatcher, FileLocationKind, ProblemPattern, ApplyToKind } from 'vs/platform/markers/common/problemMatcher'; -import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolder, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import * as Tasks from 'vs/workbench/parts/tasks/common/tasks'; import { parse, ParseResult, IProblemReporter, ExternalTaskRunnerConfiguration, CustomTask } from 'vs/workbench/parts/tasks/node/taskConfiguration'; -const workspaceFolder: IWorkspaceFolder = { +const workspaceFolder: IWorkspaceFolder = new WorkspaceFolder({ uri: URI.file('/workspace/folderOne'), name: 'folderOne', - index: 0, - raw: { path: '../folderOne', name: 'folderOne' } -}; + index: 0 +}); class ProblemReporter implements IProblemReporter { diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configuration.ts index 5fb8a8f0b77..c059683d670 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configuration.ts @@ -17,7 +17,7 @@ import { RunOnceScheduler } from 'vs/base/common/async'; import { readFile, stat, writeFile } from 'vs/base/node/pfs'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import * as extfs from 'vs/base/node/extfs'; -import { IWorkspaceContextService, IWorkspace, Workspace, WorkbenchState, IWorkspaceFolder, toWorkspaceFolders, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, Workspace, WorkbenchState, IWorkspaceFolder, toWorkspaceFolders, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files'; import { isLinux } from 'vs/base/common/platform'; import { ConfigWatcher } from 'vs/base/node/config'; @@ -271,7 +271,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat this._register(this.baseConfigurationService.onDidUpdateConfiguration(e => this.onBaseConfigurationChanged(e))); } - public getWorkspace(): IWorkspace { + public getWorkspace(): Workspace { return this.workspace; } @@ -308,10 +308,6 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat return false; } - public toResource(workspaceRelativePath: string, workspaceFolder: IWorkspaceFolder): URI { - return URI.file(paths.join(workspaceFolder.uri.fsPath, workspaceRelativePath)); - } - public getConfigurationData(): IConfigurationData { return this._configuration.toData(); } diff --git a/src/vs/workbench/services/configuration/node/configurationEditingService.ts b/src/vs/workbench/services/configuration/node/configurationEditingService.ts index 409fbff7b9f..fa81d5be3cf 100644 --- a/src/vs/workbench/services/configuration/node/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/node/configurationEditingService.ts @@ -338,7 +338,7 @@ export class ConfigurationEditingService implements IConfigurationEditingService return workspace.configuration; } if (workbenchState === WorkbenchState.FOLDER) { - return this.contextService.toResource(relativePath, workspace.folders[0]); + return workspace.folders[0].toResource(relativePath); } } @@ -346,7 +346,7 @@ export class ConfigurationEditingService implements IConfigurationEditingService if (resource) { const folder = this.contextService.getWorkspaceFolder(resource); if (folder) { - return this.contextService.toResource(relativePath, folder); + return folder.toResource(relativePath); } } } diff --git a/src/vs/workbench/services/configuration/test/node/configuration.test.ts b/src/vs/workbench/services/configuration/test/node/configuration.test.ts index 32fc370158e..0a49d55728a 100644 --- a/src/vs/workbench/services/configuration/test/node/configuration.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configuration.test.ts @@ -100,7 +100,6 @@ suite('WorkspaceContextService - Folder', () => { assert.equal(actual.folders[0].uri.fsPath, URI.file(workspaceResource).fsPath); assert.equal(actual.folders[0].name, workspaceName); assert.equal(actual.folders[0].index, 0); - assert.equal(actual.folders[0].raw.path.toLowerCase(), workspaceResource.toLowerCase()); assert.ok(!actual.configuration); }); diff --git a/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts index 0f8f279cda8..7841abf9606 100644 --- a/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts @@ -30,7 +30,7 @@ suite('Configuration Resolver Service', () => { uri: uri.parse('file:///VSCode/workspaceLocation'), name: 'hey', index: 0, - raw: undefined + toResource: () => null }; configurationResolverService = new ConfigurationResolverService(envVariables, editorService, TestEnvironmentService, new TestConfigurationService(), mockCommandService); }); diff --git a/src/vs/workbench/services/files/test/node/fileService.test.ts b/src/vs/workbench/services/files/test/node/fileService.test.ts index b4ba620ede2..6559d99dc1e 100644 --- a/src/vs/workbench/services/files/test/node/fileService.test.ts +++ b/src/vs/workbench/services/files/test/node/fileService.test.ts @@ -20,7 +20,7 @@ import encodingLib = require('vs/base/node/encoding'); import utils = require('vs/workbench/services/files/test/node/utils'); import { onError } from 'vs/base/test/common/utils'; import { TestContextService, TestTextResourceConfigurationService } from 'vs/workbench/test/workbenchTestServices'; -import { Workspace, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; suite('FileService', () => { @@ -38,7 +38,7 @@ suite('FileService', () => { return onError(error, done); } - service = new FileService(new TestContextService(new Workspace(testDir, testDir, [{ uri: uri.file(testDir), raw: { path: testDir }, index: 0, name: '' }])), new TestTextResourceConfigurationService(), new TestConfigurationService(), { disableWatcher: true }); + service = new FileService(new TestContextService(new Workspace(testDir, testDir, toWorkspaceFolders([{ path: testDir }]))), new TestTextResourceConfigurationService(), new TestConfigurationService(), { disableWatcher: true }); done(); }); }); @@ -784,7 +784,7 @@ suite('FileService', () => { const textResourceConfigurationService = new TestTextResourceConfigurationService(configurationService); - const _service = new FileService(new TestContextService(new Workspace(_testDir, _testDir, [aWorkspaceFolder(_testDir, 0)])), textResourceConfigurationService, configurationService, { + const _service = new FileService(new TestContextService(new Workspace(_testDir, _testDir, toWorkspaceFolders([{ path: _testDir }]))), textResourceConfigurationService, configurationService, { encodingOverride, disableWatcher: true }); @@ -811,7 +811,7 @@ suite('FileService', () => { const _sourceDir = require.toUrl('./fixtures/service'); const resource = uri.file(path.join(testDir, 'index.html')); - const _service = new FileService(new TestContextService(new Workspace(_testDir, _testDir, [aWorkspaceFolder(_testDir, 0)])), new TestTextResourceConfigurationService(), new TestConfigurationService(), { + const _service = new FileService(new TestContextService(new Workspace(_testDir, _testDir, toWorkspaceFolders([{ path: _testDir }]))), new TestTextResourceConfigurationService(), new TestConfigurationService(), { disableWatcher: true }); @@ -852,13 +852,4 @@ suite('FileService', () => { }); }); }); - - function aWorkspaceFolder(path: string, index: number, name: string = ''): IWorkspaceFolder { - return { - uri: uri.file(path), - index, - raw: { path: path }, - name - }; - } }); diff --git a/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts index de3d3e48d7e..9ee62bfdc44 100644 --- a/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts @@ -9,7 +9,6 @@ import assert = require('assert'); import os = require('os'); import path = require('path'); import fs = require('fs'); -import uri from 'vs/base/common/uri'; import * as json from 'vs/base/common/json'; import { OS } from 'vs/base/common/platform'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; @@ -18,7 +17,7 @@ import { KeyCode, SimpleKeybinding, ChordKeybinding } from 'vs/base/common/keyCo import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import extfs = require('vs/base/node/extfs'); import { TestTextFileService, TestEditorGroupService, TestLifecycleService, TestBackupFileService, TestContextService, TestTextResourceConfigurationService } from 'vs/workbench/test/workbenchTestServices'; -import { IWorkspaceContextService, Workspace } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import uuid = require('vs/base/common/uuid'); import { ConfigurationService } from 'vs/platform/configuration/node/configurationService'; import { FileService } from 'vs/workbench/services/files/node/fileService'; @@ -74,7 +73,7 @@ suite('Keybindings Editing', () => { instantiationService.stub(ITelemetryService, NullTelemetryService); instantiationService.stub(IModeService, ModeServiceImpl); instantiationService.stub(IModelService, instantiationService.createInstance(ModelServiceImpl)); - instantiationService.stub(IFileService, new FileService(new TestContextService(new Workspace(testDir, testDir, [{ uri: uri.file(testDir), raw: { path: testDir }, index: 0, name: '' }])), new TestTextResourceConfigurationService(), new TestConfigurationService(), { disableWatcher: true })); + instantiationService.stub(IFileService, new FileService(new TestContextService(new Workspace(testDir, testDir, toWorkspaceFolders([{ path: testDir }]))), new TestTextResourceConfigurationService(), new TestConfigurationService(), { disableWatcher: true })); instantiationService.stub(IUntitledEditorService, instantiationService.createInstance(UntitledEditorService)); instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); diff --git a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts index e1789dfa8af..bfcc892a5ac 100644 --- a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts @@ -33,7 +33,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { constructor( @IJSONEditingService private jsonEditingService: IJSONEditingService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, + @IWorkspaceContextService private contextService: WorkspaceService, @IEnvironmentService private environmentService: IEnvironmentService, @IWindowsService private windowsService: IWindowsService, @IWindowService private windowService: IWindowService, diff --git a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts index c4fca1c3ef0..a935f3c9eed 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts @@ -15,8 +15,7 @@ import { ConfigurationTarget, ConfigurationEditingErrorCode, ConfigurationEditin import { ConfigurationModel } from 'vs/platform/configuration/common/configuration'; import { TestThreadService } from './testThreadService'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; -import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceFolder, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; suite('ExtHostConfiguration', function () { @@ -133,7 +132,7 @@ suite('ExtHostConfiguration', function () { new class extends mock() { }, new ExtHostWorkspace(new TestThreadService(), { 'id': 'foo', - 'folders': [aWorkspaceFolder({ path: 'foo' }, 0)], + 'folders': [aWorkspaceFolder(URI.file('foo'), 0)], 'name': 'foo' }), { @@ -205,7 +204,7 @@ suite('ExtHostConfiguration', function () { new class extends mock() { }, new ExtHostWorkspace(new TestThreadService(), { 'id': 'foo', - 'folders': [aWorkspaceFolder({ path: firstRoot.path }, 0), aWorkspaceFolder({ path: secondRoot.path }, 1)], + 'folders': [aWorkspaceFolder(firstRoot, 0), aWorkspaceFolder(secondRoot, 1)], 'name': 'foo' }), { @@ -405,12 +404,7 @@ suite('ExtHostConfiguration', function () { .then(() => assert.ok(false), err => { /* expecting rejection */ }); }); - function aWorkspaceFolder(raw: IStoredWorkspaceFolder, index: number, name: string = ''): IWorkspaceFolder { - return { - uri: URI.file(raw.path), - index, - raw, - name - }; + function aWorkspaceFolder(uri: URI, index: number, name: string = ''): IWorkspaceFolder { + return new WorkspaceFolder({ uri, name, index }); } }); diff --git a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts index b57a2b3d8a2..d9874115a7c 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts @@ -11,7 +11,7 @@ import { basename } from 'path'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { TestThreadService } from './testThreadService'; import { normalize } from 'vs/base/common/paths'; -import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace'; suite('ExtHostWorkspace', function () { @@ -26,7 +26,7 @@ suite('ExtHostWorkspace', function () { test('asRelativePath', function () { - const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolder(URI.file('/Coding/Applications/NewsWoWBot'), 0)], name: 'Test' }); + const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/Applications/NewsWoWBot'), 0)], name: 'Test' }); assertAsRelativePath(ws, '/Coding/Applications/NewsWoWBot/bernd/das/brot', 'bernd/das/brot'); assertAsRelativePath(ws, '/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart', @@ -40,7 +40,7 @@ suite('ExtHostWorkspace', function () { test('asRelativePath, same paths, #11402', function () { const root = '/home/aeschli/workspaces/samples/docker'; const input = '/home/aeschli/workspaces/samples/docker'; - const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolder(URI.file(root), 0)], name: 'Test' }); + const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }); assertAsRelativePath(ws, (input), input); @@ -55,14 +55,14 @@ suite('ExtHostWorkspace', function () { }); test('asRelativePath, multiple folders', function () { - const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolder(URI.file('/Coding/One'), 0), aWorkspaceFolder(URI.file('/Coding/Two'), 1)], name: 'Test' }); + const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }); assertAsRelativePath(ws, '/Coding/One/file.txt', 'One/file.txt'); assertAsRelativePath(ws, '/Coding/Two/files/out.txt', 'Two/files/out.txt'); assertAsRelativePath(ws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt'); }); test('slightly inconsistent behaviour of asRelativePath and getWorkspaceFolder, #31553', function () { - const mrws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolder(URI.file('/Coding/One'), 0), aWorkspaceFolder(URI.file('/Coding/Two'), 1)], name: 'Test' }); + const mrws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }); assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt'); assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt', true); @@ -74,7 +74,7 @@ suite('ExtHostWorkspace', function () { assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', true); assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', false); - const srws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolder(URI.file('/Coding/One'), 0)], name: 'Test' }); + const srws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0)], name: 'Test' }); assertAsRelativePath(srws, '/Coding/One/file.txt', 'file.txt'); assertAsRelativePath(srws, '/Coding/One/file.txt', 'file.txt', false); assertAsRelativePath(srws, '/Coding/One/file.txt', 'One/file.txt', true); @@ -93,15 +93,15 @@ suite('ExtHostWorkspace', function () { ws = new ExtHostWorkspace(new TestThreadService(), undefined); assert.equal(ws.getPath(), undefined); - ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolder(URI.file('Folder'), 0), aWorkspaceFolder(URI.file('Another/Folder'), 1)] }); + ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('Folder'), 0), aWorkspaceFolderData(URI.file('Another/Folder'), 1)] }); assert.equal(ws.getPath().replace(/\\/g, '/'), '/Folder'); - ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolder(URI.file('/Folder'), 0)] }); + ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('/Folder'), 0)] }); assert.equal(ws.getPath().replace(/\\/g, '/'), '/Folder'); }); test('WorkspaceFolder has name and index', function () { - const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolder(URI.file('/Coding/One'), 0), aWorkspaceFolder(URI.file('/Coding/Two'), 1)], name: 'Test' }); + const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }); const [one, two] = ws.getWorkspaceFolders(); @@ -112,7 +112,7 @@ suite('ExtHostWorkspace', function () { }); test('getContainingWorkspaceFolder', function () { - const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolder(URI.file('/Coding/One'), 0), aWorkspaceFolder(URI.file('/Coding/Two'), 1), aWorkspaceFolder(URI.file('/Coding/Two/Nested'), 2)] }); + const ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1), aWorkspaceFolderData(URI.file('/Coding/Two/Nested'), 2)] }); let folder = ws.getWorkspaceFolder(URI.file('/foo/bar')); assert.equal(folder, undefined); @@ -157,7 +157,7 @@ suite('ExtHostWorkspace', function () { assert.equal(e.added.length, 1); assert.equal(e.added[0].uri.toString(), 'foo:bar'); }); - ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolder(URI.parse('foo:bar'), 0)] }); + ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }); sub.dispose(); sub = ws.onDidChangeWorkspace(e => { @@ -165,7 +165,7 @@ suite('ExtHostWorkspace', function () { assert.equal(e.added.length, 1); assert.equal(e.added[0].uri.toString(), 'foo:bar2'); }); - ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolder(URI.parse('foo:bar'), 0), aWorkspaceFolder(URI.parse('foo:bar2'), 1)] }); + ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar2'), 1)] }); sub.dispose(); sub = ws.onDidChangeWorkspace(e => { @@ -176,7 +176,7 @@ suite('ExtHostWorkspace', function () { assert.equal(e.added.length, 1); assert.equal(e.added[0].uri.toString(), 'foo:bar3'); }); - ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolder(URI.parse('foo:bar3'), 0)] }); + ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0)] }); sub.dispose(); }); @@ -195,13 +195,10 @@ suite('ExtHostWorkspace', function () { sub.dispose(); }); - function aWorkspaceFolder(uri: URI, index: number, name: string = ''): IWorkspaceFolder { + function aWorkspaceFolderData(uri: URI, index: number, name: string = ''): IWorkspaceFolderData { return { uri, index, - raw: { - path: uri.toString() - }, name: name || basename(uri.path) }; } From fdf14e7bb8c3fc9e39ad9b297ee8d917e297ebcf Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 20 Sep 2017 15:28:19 +0200 Subject: [PATCH 101/281] add index to IPickOpenItem --- src/vs/platform/quickOpen/common/quickOpen.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/platform/quickOpen/common/quickOpen.ts b/src/vs/platform/quickOpen/common/quickOpen.ts index 82277c2212e..c0611d3dde4 100644 --- a/src/vs/platform/quickOpen/common/quickOpen.ts +++ b/src/vs/platform/quickOpen/common/quickOpen.ts @@ -35,6 +35,7 @@ export interface IPickOpenEntry { } export interface IPickOpenItem { + index: number; remove: () => void; getId: () => string; getResource: () => uri; From 9e3efee0a10574df90599676ba5eae0f52c36d2e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 20 Sep 2017 15:20:03 +0200 Subject: [PATCH 102/281] add missing create options --- .../services/files/electron-browser/remoteFileService.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index d4746609149..6db7913332f 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -6,7 +6,7 @@ import URI from 'vs/base/common/uri'; import { FileService } from 'vs/workbench/services/files/electron-browser/fileService'; -import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation, IFileSystemProvider, IStat, FileType, IImportResult, FileChangesEvent } from 'vs/platform/files/common/files'; +import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation, IFileSystemProvider, IStat, FileType, IImportResult, FileChangesEvent, ICreateFileOptions } from 'vs/platform/files/common/files'; import { TPromise } from 'vs/base/common/winjs.base'; import { basename, join } from 'path'; import { IDisposable } from 'vs/base/common/lifecycle'; @@ -240,9 +240,9 @@ export class RemoteFileService extends FileService { // --- saving - async createFile(resource: URI, content?: string): TPromise { + async createFile(resource: URI, content?: string, options?: ICreateFileOptions): TPromise { if (resource.scheme === Schemas.file) { - return super.createFile(resource, content); + return super.createFile(resource, content, options); } else { const provider = await this._withProvider(resource); const stat = await this._doUpdateContent(provider, resource, content || '', {}); From c031ee17e8eaa8e48396f06b32ca3432275d199a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 20 Sep 2017 15:31:28 +0200 Subject: [PATCH 103/281] createFile errors when file is already there --- .../services/files/electron-browser/remoteFileService.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 6db7913332f..41756a57695 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -6,7 +6,7 @@ import URI from 'vs/base/common/uri'; import { FileService } from 'vs/workbench/services/files/electron-browser/fileService'; -import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation, IFileSystemProvider, IStat, FileType, IImportResult, FileChangesEvent, ICreateFileOptions } from 'vs/platform/files/common/files'; +import { IContent, IStreamContent, IFileStat, IResolveContentOptions, IUpdateContentOptions, IResolveFileOptions, IResolveFileResult, FileOperationEvent, FileOperation, IFileSystemProvider, IStat, FileType, IImportResult, FileChangesEvent, ICreateFileOptions, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; import { TPromise } from 'vs/base/common/winjs.base'; import { basename, join } from 'path'; import { IDisposable } from 'vs/base/common/lifecycle'; @@ -245,6 +245,9 @@ export class RemoteFileService extends FileService { return super.createFile(resource, content, options); } else { const provider = await this._withProvider(resource); + if (options && !options.overwrite && await this.existsFile(resource)) { + throw new FileOperationError('EEXIST', FileOperationResult.FILE_MODIFIED_SINCE); + } const stat = await this._doUpdateContent(provider, resource, content || '', {}); this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, stat)); return stat; From 0a39cbba524594f4f5d0e2ce22af8c3ff8aeb700 Mon Sep 17 00:00:00 2001 From: Greg Zimmerman Date: Wed, 20 Sep 2017 09:46:04 -0400 Subject: [PATCH 104/281] Fix Select-Object highlighting issue. --- .../powershell/syntaxes/PowershellSyntax.tmLanguage | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/extensions/powershell/syntaxes/PowershellSyntax.tmLanguage b/extensions/powershell/syntaxes/PowershellSyntax.tmLanguage index f54cf896b52..5a8c8f24ce3 100644 --- a/extensions/powershell/syntaxes/PowershellSyntax.tmLanguage +++ b/extensions/powershell/syntaxes/PowershellSyntax.tmLanguage @@ -246,7 +246,7 @@ match - (?<!\w)((?i:begin|break|catch|continue|data|define|do|dynamicparam|else|elseif|end|exit|finally|for|foreach(?!-object)|from|if|in|inlinescript|parallel|param|process|return|switch|throw|trap|try|until|using|var|where(?!=-object)|while)|%|\?)(?!\w) + (?<!\w)((?i:begin|break|catch|continue|data|define|do|dynamicparam|else|elseif|end|exit|finally|for|foreach(?!-object)|from|if|in|inlinescript|parallel|param|process|return|switch|throw|trap|try|until|using|var|where(?!-object)|while)|%|\?)(?!\w) name keyword.control.powershell @@ -426,6 +426,14 @@ name support.function.powershell + + comment + Builtin cmdlets with reserved verbs + match + (?<!\w)(?i:where-object)(?!\w) + name + support.function.powershell + commentEmbeddedDocs From 7c7eb9bfc6d2ffebe34e1c753b6af24d1729245c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 20 Sep 2017 12:06:37 +0200 Subject: [PATCH 105/281] Fix #34699 --- src/vs/code/electron-main/windows.ts | 21 +++++---- src/vs/code/node/windowsFinder.ts | 5 ++- src/vs/platform/workspace/common/workspace.ts | 14 +++++- .../workspace/test/common/workspace.test.ts | 44 ++++++++++--------- .../platform/workspaces/common/workspaces.ts | 33 +++++++++++++- .../electron-main/workspacesMainService.ts | 22 ++++------ src/vs/platform/workspaces/node/workspaces.ts | 6 +-- .../workspacesMainService.test.ts | 26 +++++------ .../configuration/node/configuration.ts | 33 ++++++++++---- .../test/node/configuration.test.ts | 2 +- .../workspace/node/workspaceEditingService.ts | 23 ++++++---- 11 files changed, 146 insertions(+), 83 deletions(-) diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 967b5d51b66..505bc50be4f 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -32,6 +32,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IWorkspacesMainService, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, WORKSPACE_FILTER, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; +import { Schemas } from 'vs/base/common/network'; enum WindowError { UNRESPONSIVE, @@ -1813,18 +1814,20 @@ class WorkspacesManager { } private getWorkspaceDialogDefaultPath(workspace?: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier): string { - let defaultPath: string; if (workspace) { if (isSingleFolderWorkspaceIdentifier(workspace)) { - defaultPath = dirname(workspace); - } else { - const resolvedWorkspace = this.workspacesService.resolveWorkspaceSync(workspace.configPath); - if (resolvedWorkspace && resolvedWorkspace.folders.length > 0) { - defaultPath = dirname(resolvedWorkspace.folders[0].uri.fsPath); + return dirname(workspace); + } + + const resolvedWorkspace = this.workspacesService.resolveWorkspaceSync(workspace.configPath); + if (resolvedWorkspace && resolvedWorkspace.folders.length > 0) { + for (const folder of resolvedWorkspace.folders) { + if (folder.uri.scheme === Schemas.file) { + return dirname(folder.uri.fsPath); + } } } } - - return defaultPath; + return void 0; } -} \ No newline at end of file +} diff --git a/src/vs/code/node/windowsFinder.ts b/src/vs/code/node/windowsFinder.ts index 6d17ad333a3..f45fa1fcb1c 100644 --- a/src/vs/code/node/windowsFinder.ts +++ b/src/vs/code/node/windowsFinder.ts @@ -11,6 +11,7 @@ import * as platform from 'vs/base/common/platform'; import * as paths from 'vs/base/common/paths'; import { OpenContext } from 'vs/platform/windows/common/windows'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IResolvedWorkspace } from 'vs/platform/workspaces/common/workspaces'; +import { Schemas } from 'vs/base/common/network'; export interface ISimpleWindow { openedWorkspace?: IWorkspaceIdentifier; @@ -62,7 +63,7 @@ function findWindowOnFilePath(windows: W[], filePath: s for (let i = 0; i < workspaceWindows.length; i++) { const window = workspaceWindows[i]; const resolvedWorkspace = workspaceResolver(window.openedWorkspace); - if (resolvedWorkspace && resolvedWorkspace.folders.some(folder => paths.isEqualOrParent(filePath, folder.uri.fsPath, !platform.isLinux /* ignorecase */))) { + if (resolvedWorkspace && resolvedWorkspace.folders.some(folder => folder.uri.scheme === Schemas.file && paths.isEqualOrParent(filePath, folder.uri.fsPath, !platform.isLinux /* ignorecase */))) { return window; } } @@ -164,4 +165,4 @@ export function findWindowOnWorkspaceOrFolderPath(windo return false; })[0]; -} \ No newline at end of file +} diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index 00b3c8a61cd..e816e4a9a16 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -9,7 +9,7 @@ import * as paths from 'vs/base/common/paths'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { TrieMap } from 'vs/base/common/map'; import Event from 'vs/base/common/event'; -import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, IStoredWorkspaceFolder, isRawFileWorkspaceFolder, isRawUriWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { coalesce, distinct } from 'vs/base/common/arrays'; import { isLinux } from 'vs/base/common/platform'; @@ -232,7 +232,17 @@ export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], function parseWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo: URI): WorkspaceFolder[] { return configuredFolders.map((configuredFolder, index) => { - const uri = toUri(configuredFolder.path, relativeTo); + let uri: URI; + if (isRawFileWorkspaceFolder(configuredFolder)) { + uri = toUri(configuredFolder.path, relativeTo); + } else if (isRawUriWorkspaceFolder(configuredFolder)) { + try { + uri = URI.parse(configuredFolder.uri); + } catch (e) { + console.warn(e); + // ignore + } + } if (!uri) { return void 0; } diff --git a/src/vs/platform/workspace/test/common/workspace.test.ts b/src/vs/platform/workspace/test/common/workspace.test.ts index 130aebe39d6..ac6f0caf17f 100644 --- a/src/vs/platform/workspace/test/common/workspace.test.ts +++ b/src/vs/platform/workspace/test/common/workspace.test.ts @@ -8,6 +8,7 @@ import * as assert from 'assert'; import { Workspace, toWorkspaceFolders, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import URI from 'vs/base/common/uri'; +import { IRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; suite('Workspace', () => { @@ -51,7 +52,7 @@ suite('Workspace', () => { assert.equal(actual.length, 1); assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath); - assert.equal(actual[0].raw.path, '/src/test'); + assert.equal((actual[0].raw).path, '/src/test'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test'); }); @@ -61,7 +62,7 @@ suite('Workspace', () => { assert.equal(actual.length, 1); assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath); - assert.equal(actual[0].raw.path, './test'); + assert.equal((actual[0].raw).path, './test'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test'); }); @@ -70,8 +71,9 @@ suite('Workspace', () => { const actual = toWorkspaceFolders([{ path: '/src/test', name: 'hello' }]); assert.equal(actual.length, 1); + assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath); - assert.equal(actual[0].raw.path, '/src/test'); + assert.equal((actual[0].raw).path, '/src/test'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'hello'); }); @@ -81,17 +83,17 @@ suite('Workspace', () => { assert.equal(actual.length, 3); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal(actual[0].raw.path, '/src/test2'); + assert.equal((actual[0].raw).path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath); - assert.equal(actual[1].raw.path, '/src/test3'); + assert.equal((actual[1].raw).path, '/src/test3'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'test3'); assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath); - assert.equal(actual[2].raw.path, '/src/test1'); + assert.equal((actual[2].raw).path, '/src/test1'); assert.equal(actual[2].index, 2); assert.equal(actual[2].name, 'test1'); }); @@ -101,17 +103,17 @@ suite('Workspace', () => { assert.equal(actual.length, 3); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal(actual[0].raw.path, '/src/test2'); + assert.equal((actual[0].raw).path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath); - assert.equal(actual[1].raw.path, '/src/test3'); + assert.equal((actual[1].raw).path, '/src/test3'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'noName'); assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath); - assert.equal(actual[2].raw.path, '/src/test1'); + assert.equal((actual[2].raw).path, '/src/test1'); assert.equal(actual[2].index, 2); assert.equal(actual[2].name, 'test1'); }); @@ -121,17 +123,17 @@ suite('Workspace', () => { assert.equal(actual.length, 3); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal(actual[0].raw.path, '/src/test2'); + assert.equal((actual[0].raw).path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/abc/test3').fsPath); - assert.equal(actual[1].raw.path, '/abc/test3'); + assert.equal((actual[1].raw).path, '/abc/test3'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'noName'); assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath); - assert.equal(actual[2].raw.path, './test1'); + assert.equal((actual[2].raw).path, './test1'); assert.equal(actual[2].index, 2); assert.equal(actual[2].name, 'test1'); }); @@ -141,12 +143,12 @@ suite('Workspace', () => { assert.equal(actual.length, 2); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal(actual[0].raw.path, '/src/test2'); + assert.equal((actual[0].raw).path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/src/test1').fsPath); - assert.equal(actual[1].raw.path, '/src/test1'); + assert.equal((actual[1].raw).path, '/src/test1'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'test1'); }); @@ -156,17 +158,17 @@ suite('Workspace', () => { assert.equal(actual.length, 3); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal(actual[0].raw.path, '/src/test2'); + assert.equal((actual[0].raw).path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath); - assert.equal(actual[1].raw.path, '/src/test3'); + assert.equal((actual[1].raw).path, '/src/test3'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'noName'); assert.equal(actual[2].uri.fsPath, URI.file('/abc/test1').fsPath); - assert.equal(actual[2].raw.path, '/abc/test1'); + assert.equal((actual[2].raw).path, '/abc/test1'); assert.equal(actual[2].index, 2); assert.equal(actual[2].name, 'test1'); }); @@ -176,18 +178,18 @@ suite('Workspace', () => { assert.equal(actual.length, 3); assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath); - assert.equal(actual[0].raw.path, '/src/test2'); + assert.equal((actual[0].raw).path, '/src/test2'); assert.equal(actual[0].index, 0); assert.equal(actual[0].name, 'test2'); assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath); - assert.equal(actual[1].raw.path, './test3'); + assert.equal((actual[1].raw).path, './test3'); assert.equal(actual[1].index, 1); assert.equal(actual[1].name, 'test3'); assert.equal(actual[2].uri.fsPath, URI.file('/abc/test1').fsPath); - assert.equal(actual[2].raw.path, '/abc/test1'); + assert.equal((actual[2].raw).path, '/abc/test1'); assert.equal(actual[2].index, 2); assert.equal(actual[2].name, 'test1'); }); -}); \ No newline at end of file +}); diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index 51b846f937f..adaac16ff0b 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -33,15 +33,44 @@ export interface IWorkspaceIdentifier { configPath: string; } -export interface IStoredWorkspaceFolder { +export function isStoredWorkspaceFolder(thing: any): thing is IStoredWorkspaceFolder { + return isRawFileWorkspaceFolder(thing) || isRawUriWorkspaceFolder(thing); +} + +export function isRawFileWorkspaceFolder(thing: any): thing is IRawFileWorkspaceFolder { + return thing + && typeof thing === 'object' + && typeof thing.path === 'string' + && (!thing.name || typeof thing.name === 'string'); +} + +export function isRawUriWorkspaceFolder(thing: any): thing is IRawUriWorkspaceFolder { + return thing + && typeof thing === 'object' + && typeof thing.uri === 'string' + && (!thing.name || typeof thing.name === 'string'); +} + +export interface IRawFileWorkspaceFolder { path: string; name?: string; } +export interface IRawUriWorkspaceFolder { + uri: string; + name?: string; +} + +export type IStoredWorkspaceFolder = IRawFileWorkspaceFolder | IRawUriWorkspaceFolder; + export interface IResolvedWorkspace extends IWorkspaceIdentifier { folders: IWorkspaceFolder[]; } +export interface IStoredWorkspace { + folders: IStoredWorkspaceFolder[]; +} + export interface IWorkspaceSavedEvent { workspace: IWorkspaceIdentifier; oldConfigPath: string; @@ -104,4 +133,4 @@ export function isWorkspaceIdentifier(obj: any): obj is IWorkspaceIdentifier { const workspaceIdentifier = obj as IWorkspaceIdentifier; return workspaceIdentifier && typeof workspaceIdentifier.id === 'string' && typeof workspaceIdentifier.configPath === 'string'; -} \ No newline at end of file +} diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index 5f40e430e13..1764e625a5f 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -5,7 +5,7 @@ 'use strict'; -import { IWorkspacesMainService, IWorkspaceIdentifier, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesMainService, IWorkspaceIdentifier, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isRawFileWorkspaceFolder, isStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { TPromise } from 'vs/base/common/winjs.base'; import { isParent } from 'vs/platform/files/common/files'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -24,6 +24,7 @@ import * as jsonEdit from 'vs/base/common/jsonEdit'; import { applyEdit } from 'vs/base/common/jsonFormatter'; import { massageFolderPathForWorkspace } from 'vs/platform/workspaces/node/workspaces'; import { toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; +import URI from 'vs/base/common/uri'; export interface IStoredWorkspace { folders: IStoredWorkspaceFolder[]; @@ -80,17 +81,10 @@ export class WorkspacesMainService implements IWorkspacesMainService { try { const workspace = this.doParseStoredWorkspace(path, contents); - // relative paths get resolved against the workspace location - workspace.folders.forEach(folder => { - if (!isAbsolute(folder.path)) { - folder.path = resolve(dirname(path), folder.path); - } - }); - return { id: this.getWorkspaceId(path), configPath: path, - folders: toWorkspaceFolders(workspace.folders) + folders: toWorkspaceFolders(workspace.folders, URI.file(dirname(path))) }; } catch (error) { this.logService.log(error.toString()); @@ -111,7 +105,7 @@ export class WorkspacesMainService implements IWorkspacesMainService { // Filter out folders which do not have a path set if (Array.isArray(storedWorkspace.folders)) { - storedWorkspace.folders = storedWorkspace.folders.filter(folder => !!folder.path); + storedWorkspace.folders = storedWorkspace.folders.filter(folder => isStoredWorkspaceFolder(folder)); } // Validate @@ -205,11 +199,13 @@ export class WorkspacesMainService implements IWorkspacesMainService { // is a parent of the location of the workspace file itself. Otherwise keep // using absolute paths. storedWorkspace.folders.forEach(folder => { - if (!isAbsolute(folder.path)) { - folder.path = resolve(sourceConfigFolder, folder.path); // relative paths get resolved against the workspace location + if (isRawFileWorkspaceFolder(folder)) { + if (!isAbsolute(folder.path)) { + folder.path = resolve(sourceConfigFolder, folder.path); // relative paths get resolved against the workspace location + } + folder.path = massageFolderPathForWorkspace(folder.path, targetConfigFolder, storedWorkspace.folders); } - folder.path = massageFolderPathForWorkspace(folder.path, targetConfigFolder, storedWorkspace.folders); }); // Preserve as much of the existing workspace as possible by using jsonEdit diff --git a/src/vs/platform/workspaces/node/workspaces.ts b/src/vs/platform/workspaces/node/workspaces.ts index 95757880908..8b149ff2693 100644 --- a/src/vs/platform/workspaces/node/workspaces.ts +++ b/src/vs/platform/workspaces/node/workspaces.ts @@ -5,7 +5,7 @@ 'use strict'; -import { IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { IStoredWorkspaceFolder, isRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { isWindows, isLinux } from 'vs/base/common/platform'; import { isAbsolute, relative } from 'path'; import { isEqualOrParent, normalize } from 'vs/base/common/paths'; @@ -56,11 +56,11 @@ function shouldUseSlashForPath(storedFolders: IStoredWorkspaceFolder[]): boolean let useSlashesForPath = !isWindows; if (isWindows) { storedFolders.forEach(folder => { - if (!useSlashesForPath && folder.path.indexOf(SLASH) >= 0) { + if (isRawFileWorkspaceFolder(folder) && !useSlashesForPath && folder.path.indexOf(SLASH) >= 0) { useSlashesForPath = true; } }); } return useSlashesForPath; -} \ No newline at end of file +} diff --git a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts index fa958affd34..918dd0ef819 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts @@ -14,7 +14,7 @@ import pfs = require('vs/base/node/pfs'); import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { parseArgs } from 'vs/platform/environment/node/argv'; import { WorkspacesMainService, IStoredWorkspace } from 'vs/platform/workspaces/electron-main/workspacesMainService'; -import { WORKSPACE_EXTENSION, IWorkspaceSavedEvent, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { WORKSPACE_EXTENSION, IWorkspaceSavedEvent, IWorkspaceIdentifier, IRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { LogMainService } from 'vs/platform/log/common/log'; import URI from 'vs/base/common/uri'; @@ -66,8 +66,8 @@ suite('WorkspacesMainService', () => { const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace; assert.equal(ws.folders.length, 2); // - assert.equal(ws.folders[0].path, process.cwd()); - assert.equal(ws.folders[1].path, os.tmpdir()); + assert.equal((ws.folders[0]).path, process.cwd()); + assert.equal((ws.folders[1]).path, os.tmpdir()); done(); }); @@ -81,8 +81,8 @@ suite('WorkspacesMainService', () => { const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace; assert.equal(ws.folders.length, 2); // - assert.equal(ws.folders[0].path, process.cwd()); - assert.equal(ws.folders[1].path, os.tmpdir()); + assert.equal((ws.folders[0]).path, process.cwd()); + assert.equal((ws.folders[1]).path, os.tmpdir()); }); test('resolveWorkspaceSync', done => { @@ -200,9 +200,9 @@ suite('WorkspacesMainService', () => { const ws = JSON.parse(fs.readFileSync(savedWorkspace.configPath).toString()) as IStoredWorkspace; assert.equal(ws.folders.length, 3); - assert.equal(ws.folders[0].path, process.cwd()); // absolute - assert.equal(ws.folders[1].path, '.'); // relative - assert.equal(ws.folders[2].path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative + assert.equal((ws.folders[0]).path, process.cwd()); // absolute + assert.equal((ws.folders[1]).path, '.'); // relative + assert.equal((ws.folders[2]).path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative assert.equal(savedWorkspace, savedEvent.workspace); assert.equal(workspace.configPath, savedEvent.oldConfigPath); @@ -232,9 +232,9 @@ suite('WorkspacesMainService', () => { const ws = JSON.parse(fs.readFileSync(newSavedWorkspace.configPath).toString()) as IStoredWorkspace; assert.equal(ws.folders.length, 3); - assert.equal(ws.folders[0].path, process.cwd()); // absolute path because outside of tmpdir - assert.equal(ws.folders[1].path, '.'); // relative path because inside of tmpdir - assert.equal(ws.folders[2].path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative + assert.equal((ws.folders[0]).path, process.cwd()); // absolute path because outside of tmpdir + assert.equal((ws.folders[1]).path, '.'); // relative path because inside of tmpdir + assert.equal((ws.folders[2]).path, path.relative(path.dirname(workspaceConfigPath), path.join(os.tmpdir(), 'somefolder'))); // relative extfs.delSync(workspaceConfigPath); extfs.delSync(newWorkspaceConfigPath); @@ -286,7 +286,7 @@ suite('WorkspacesMainService', () => { assert.equal(newSavedWorkspace.configPath, newWorkspaceConfigPath); const ws = JSON.parse(fs.readFileSync(newSavedWorkspace.configPath).toString()) as IStoredWorkspace; - assert.ok(ws.folders.every(f => f.path.indexOf('\\') < 0)); + assert.ok(ws.folders.every(f => (f).path.indexOf('\\') < 0)); extfs.delSync(workspaceConfigPath); extfs.delSync(newWorkspaceConfigPath); @@ -350,4 +350,4 @@ suite('WorkspacesMainService', () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configuration.ts index c059683d670..2552f3155f9 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configuration.ts @@ -212,16 +212,31 @@ contributionRegistry.registerSchema('vscode://schemas/workspaceConfig', { items: { type: 'object', default: { path: '' }, - properties: { - path: { - type: 'string', - description: nls.localize('workspaceConfig.folder.description', "A file path. e.g. `/root/folderA` or `./folderA` for a relative path that will be resolved against the location of the workspace file.") + oneOf: [{ + properties: { + path: { + type: 'string', + description: nls.localize('workspaceConfig.path.description', "A file path. e.g. `/root/folderA` or `./folderA` for a relative path that will be resolved against the location of the workspace file.") + }, + name: { + type: 'string', + description: nls.localize('workspaceConfig.name.description', "An optional name for the folder. ") + } }, - name: { - type: 'string', - description: nls.localize('workspaceConfig.name.description', "An optional name for the folder. ") - } - } + required: ['path'] + }, { + properties: { + uri: { + type: 'string', + description: nls.localize('workspaceConfig.uri.description', "URI of the folder") + }, + name: { + type: 'string', + description: nls.localize('workspaceConfig.name.description', "An optional name for the folder. ") + } + }, + required: ['uri'] + }] } }, 'settings': { diff --git a/src/vs/workbench/services/configuration/test/node/configuration.test.ts b/src/vs/workbench/services/configuration/test/node/configuration.test.ts index 0a49d55728a..8073bb82a98 100644 --- a/src/vs/workbench/services/configuration/test/node/configuration.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configuration.test.ts @@ -528,4 +528,4 @@ suite('WorkspaceConfigurationService - Node', () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts index bfcc892a5ac..2c30159804f 100644 --- a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts @@ -12,7 +12,7 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/ import { IWindowsService, IWindowService, IEnterWorkspaceResult } from 'vs/platform/windows/common/windows'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; -import { IWorkspacesService, IStoredWorkspaceFolder, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesService, IStoredWorkspaceFolder, IWorkspaceIdentifier, isStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { dirname } from 'path'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { massageFolderPathForWorkspace } from 'vs/platform/workspaces/node/workspaces'; @@ -26,6 +26,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { BackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; +import { Schemas } from 'vs/base/common/network'; export class WorkspaceEditingService implements IWorkspaceEditingService { @@ -58,14 +59,20 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { const workspaceConfigFolder = dirname(this.contextService.getWorkspace().configuration.fsPath); - foldersToAdd.forEach(foldersToAdd => { - if (this.contains(currentWorkspaceFolderUris, foldersToAdd)) { + foldersToAdd.forEach(folderToAdd => { + if (this.contains(currentWorkspaceFolderUris, folderToAdd)) { return; // already existing } - storedFoldersToAdd.push({ - path: massageFolderPathForWorkspace(foldersToAdd.fsPath, workspaceConfigFolder, currentStoredFolders) - }); + if (folderToAdd.scheme === Schemas.file) { + storedFoldersToAdd.push({ + path: massageFolderPathForWorkspace(folderToAdd.fsPath, workspaceConfigFolder, currentStoredFolders) + }); + } else { + storedFoldersToAdd.push({ + uri: folderToAdd.toString(true) + }); + } }); if (storedFoldersToAdd.length > 0) { @@ -84,7 +91,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { const currentStoredFolders = currentWorkspaceFolders.map(folder => folder.raw); const newStoredFolders: IStoredWorkspaceFolder[] = currentStoredFolders.filter((folder, index) => { - if (!folder.path) { + if (!isStoredWorkspaceFolder(folder)) { return true; // keep entries which are unrelated } @@ -186,4 +193,4 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { return this.jsonEditingService.write(URI.file(toWorkspace.configPath), { key: 'settings', value: targetWorkspaceConfiguration }, true); } -} \ No newline at end of file +} From 5e0c37dd738d6cb62b576348ad1d066acfa87015 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 20 Sep 2017 16:34:00 +0200 Subject: [PATCH 106/281] :lipstick: --- src/vs/platform/workspace/common/workspace.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index e816e4a9a16..7fd1b6a49ae 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -219,7 +219,7 @@ export class WorkspaceFolder implements IWorkspaceFolder { return URI.file(paths.join(this.uri.fsPath, relativePath)); } - public toJSON(): IWorkspaceFolderData { + toJSON(): IWorkspaceFolderData { return { uri: this.uri, name: this.name, index: this.index }; } } From 53190ab840d4ca21d31c3f70a5f2e1c0fb4e0f25 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 20 Sep 2017 16:46:40 +0200 Subject: [PATCH 107/281] Also listen to folders change event --- src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts index b8957f1342d..b53bba5f047 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts @@ -32,7 +32,8 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { @IFileService private readonly _fileService: IFileService ) { this._proxy = extHostContext.get(ExtHostContext.ExtHostWorkspace); - this._contextService.onDidChangeWorkbenchState(this._onDidChangeWorkspaceState, this, this._toDispose); + this._contextService.onDidChangeWorkspaceFolders(this._onDidChangeWorkspace, this, this._toDispose); + this._contextService.onDidChangeWorkbenchState(this._onDidChangeWorkspace, this, this._toDispose); } dispose(): void { @@ -46,7 +47,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { // --- workspace --- - private _onDidChangeWorkspaceState(): void { + private _onDidChangeWorkspace(): void { this._proxy.$acceptWorkspaceData(this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : this._contextService.getWorkspace()); } From 55490528e72501f4ec369e8445379920440cea2f Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 20 Sep 2017 16:53:48 +0200 Subject: [PATCH 108/281] have TrieMap and StringTrieMap for more flex --- src/vs/base/common/map.ts | 50 +++++++++++-------- src/vs/base/node/id.ts | 6 +-- src/vs/base/test/common/map.test.ts | 8 +-- .../test/common/testConfigurationService.ts | 4 +- src/vs/platform/workspace/common/workspace.ts | 6 +-- src/vs/workbench/api/node/extHost.api.impl.ts | 4 +- .../api/node/extHostExtensionService.ts | 8 +-- src/vs/workbench/api/node/extHostWorkspace.ts | 22 +++----- .../parts/search/common/searchModel.ts | 6 +-- .../electron-browser/remoteFileService.ts | 4 +- 10 files changed, 60 insertions(+), 58 deletions(-) diff --git a/src/vs/base/common/map.ts b/src/vs/base/common/map.ts index 003e893e7f8..24eb661cca8 100644 --- a/src/vs/base/common/map.ts +++ b/src/vs/base/common/map.ts @@ -227,22 +227,16 @@ class Node { readonly children = new Map>(); } -/** - * A trie map that allows for fast look up when keys are substrings - * to the actual search keys (dir/subdir-problem). - */ -export class TrieMap { +export class TrieMap { - static PathSplitter = (s: string) => s.split(/[\\/]/).filter(s => !!s); + private readonly _splitter: (key: K) => string[]; + private _root = new Node(); - private readonly _splitter: (s: string) => string[]; - private _root = new Node(); - - constructor(splitter: (s: string) => string[] = TrieMap.PathSplitter) { - this._splitter = s => splitter(s).filter(s => Boolean(s)); + constructor(splitter: (key: K) => string[]) { + this._splitter = key => splitter(key).filter(part => Boolean(part)); } - insert(path: string, element: E): void { + insert(path: K, element: V): void { const parts = this._splitter(path); let i = 0; @@ -258,9 +252,9 @@ export class TrieMap { } // create new nodes - let newNode: Node; + let newNode: Node; for (; i < parts.length; i++) { - newNode = new Node(); + newNode = new Node(); node.children.set(parts[i], newNode); node = newNode; } @@ -268,11 +262,11 @@ export class TrieMap { node.element = element; } - lookUp(path: string): E { + lookUp(path: K): V { const parts = this._splitter(path); let { children } = this._root; - let node: Node; + let node: Node; for (const part of parts) { node = children.get(part); if (!node) { @@ -284,10 +278,10 @@ export class TrieMap { return node.element; } - findSubstr(path: string): E { + findSubstr(path: K): V { const parts = this._splitter(path); - let lastNode: Node; + let lastNode: Node; let { children } = this._root; for (const part of parts) { const node = children.get(part); @@ -308,11 +302,11 @@ export class TrieMap { return undefined; } - findSuperstr(path: string): TrieMap { + findSuperstr(path: K): TrieMap { const parts = this._splitter(path); let { children } = this._root; - let node: Node; + let node: Node; for (const part of parts) { node = children.get(part); if (!node) { @@ -321,12 +315,26 @@ export class TrieMap { children = node.children; } - const result = new TrieMap(this._splitter); + const result = new TrieMap(this._splitter); result._root = node; return result; } } + +/** + * A trie map that allows for fast look up when keys are substrings + * to the actual search keys (dir/subdir-problem). + */ +export class StringTrieMap extends TrieMap { + + static PathSplitter = (s: string) => s.split(/[\\/]/).filter(s => !!s); + + constructor(splitter = StringTrieMap.PathSplitter) { + super(splitter); + } +} + export class ResourceMap { protected map: Map; diff --git a/src/vs/base/node/id.ts b/src/vs/base/node/id.ts index f8b65bfcbc9..a9ebc7c086f 100644 --- a/src/vs/base/node/id.ts +++ b/src/vs/base/node/id.ts @@ -9,7 +9,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as errors from 'vs/base/common/errors'; import * as uuid from 'vs/base/common/uuid'; import { networkInterfaces } from 'os'; -import { TrieMap } from 'vs/base/common/map'; +import { StringTrieMap } from 'vs/base/common/map'; // http://www.techrepublic.com/blog/data-center/mac-address-scorecard-for-common-virtual-machine-platforms/ // VMware ESX 3, Server, Workstation, Player 00-50-56, 00-0C-29, 00-05-69 @@ -23,12 +23,12 @@ import { TrieMap } from 'vs/base/common/map'; // Sun xVM VirtualBox 08-00-27 export const virtualMachineHint: { value(): number } = new class { - private _virtualMachineOUIs: TrieMap; + private _virtualMachineOUIs: StringTrieMap; private _value: number; private _isVirtualMachineMacAdress(mac: string): boolean { if (!this._virtualMachineOUIs) { - this._virtualMachineOUIs = new TrieMap(s => s.split(/[-:]/)); + this._virtualMachineOUIs = new StringTrieMap(s => s.split(/[-:]/)); // this._virtualMachineOUIs.insert('00-00-00', true); this._virtualMachineOUIs.insert('00-50-56', true); this._virtualMachineOUIs.insert('00-0C-29', true); diff --git a/src/vs/base/test/common/map.test.ts b/src/vs/base/test/common/map.test.ts index b26a2079943..aefb143c080 100644 --- a/src/vs/base/test/common/map.test.ts +++ b/src/vs/base/test/common/map.test.ts @@ -6,7 +6,7 @@ 'use strict'; -import { BoundedMap, TrieMap, ResourceMap } from 'vs/base/common/map'; +import { BoundedMap, StringTrieMap, ResourceMap } from 'vs/base/common/map'; import * as assert from 'assert'; import URI from 'vs/base/common/uri'; @@ -314,7 +314,7 @@ suite('Map', () => { test('TrieMap - basics', function () { - const map = new TrieMap(); + const map = new StringTrieMap(); map.insert('/user/foo/bar', 1); map.insert('/user/foo', 2); @@ -332,7 +332,7 @@ suite('Map', () => { test('TrieMap - lookup', function () { - const map = new TrieMap(); + const map = new StringTrieMap(); map.insert('/user/foo/bar', 1); map.insert('/user/foo', 2); map.insert('/user/foo/flip/flop', 3); @@ -346,7 +346,7 @@ suite('Map', () => { test('TrieMap - superstr', function () { - const map = new TrieMap(); + const map = new StringTrieMap(); map.insert('/user/foo/bar', 1); map.insert('/user/foo', 2); map.insert('/user/foo/flip/flop', 3); diff --git a/src/vs/platform/configuration/test/common/testConfigurationService.ts b/src/vs/platform/configuration/test/common/testConfigurationService.ts index e7f948d824c..976cb5840ad 100644 --- a/src/vs/platform/configuration/test/common/testConfigurationService.ts +++ b/src/vs/platform/configuration/test/common/testConfigurationService.ts @@ -5,7 +5,7 @@ 'use strict'; -import { TrieMap } from 'vs/base/common/map'; +import { StringTrieMap } from 'vs/base/common/map'; import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import { EventEmitter } from 'vs/base/common/eventEmitter'; @@ -17,7 +17,7 @@ export class TestConfigurationService extends EventEmitter implements IConfigura private configuration = Object.create(null); - private configurationByRoot: TrieMap = new TrieMap(); + private configurationByRoot: StringTrieMap = new StringTrieMap(); public reloadConfiguration(section?: string): TPromise { return TPromise.as(this.getConfiguration()); diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index 7fd1b6a49ae..46d4d312bf9 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -7,7 +7,7 @@ import URI from 'vs/base/common/uri'; import * as paths from 'vs/base/common/paths'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { TrieMap } from 'vs/base/common/map'; +import { StringTrieMap } from 'vs/base/common/map'; import Event from 'vs/base/common/event'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, IStoredWorkspaceFolder, isRawFileWorkspaceFolder, isRawUriWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { coalesce, distinct } from 'vs/base/common/arrays'; @@ -128,7 +128,7 @@ export interface IWorkspaceFolder extends IWorkspaceFolderData { export class Workspace implements IWorkspace { - private _foldersMap: TrieMap = new TrieMap(); + private _foldersMap: StringTrieMap = new StringTrieMap(); private _folders: WorkspaceFolder[]; constructor( @@ -191,7 +191,7 @@ export class Workspace implements IWorkspace { } private updateFoldersMap(): void { - this._foldersMap = new TrieMap(); + this._foldersMap = new StringTrieMap(); for (const folder of this.folders) { this._foldersMap.insert(folder.uri.toString(), folder); } diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index a49fe5869f2..7f06becd069 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -5,7 +5,7 @@ 'use strict'; import { Emitter } from 'vs/base/common/event'; -import { TrieMap } from 'vs/base/common/map'; +import { StringTrieMap } from 'vs/base/common/map'; import { score } from 'vs/editor/common/modes/languageSelector'; import * as Platform from 'vs/base/common/platform'; import * as errors from 'vs/base/common/errors'; @@ -652,7 +652,7 @@ export function initializeExtensionApi(extensionService: ExtHostExtensionService return extensionService.getExtensionPathIndex().then(trie => defineAPI(apiFactory, trie)); } -function defineAPI(factory: IExtensionApiFactory, extensionPaths: TrieMap): void { +function defineAPI(factory: IExtensionApiFactory, extensionPaths: StringTrieMap): void { // each extension is meant to get its own api implementation const extApiImpl = new Map(); diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index f13519818d8..d8ade5408f0 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -18,7 +18,7 @@ import { IExtensionMemento, ExtensionsActivator, ActivatedExtension, IExtensionA import { Barrier } from 'vs/workbench/services/extensions/node/barrier'; import { ExtHostThreadService } from 'vs/workbench/services/thread/node/extHostThreadService'; import { realpath } from 'fs'; -import { TrieMap } from 'vs/base/common/map'; +import { StringTrieMap } from 'vs/base/common/map'; class ExtensionMemento implements IExtensionMemento { @@ -116,7 +116,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { private readonly _storagePath: ExtensionStoragePath; private readonly _proxy: MainThreadExtensionServiceShape; private _activator: ExtensionsActivator; - private _extensionPathIndex: TPromise>; + private _extensionPathIndex: TPromise>; /** * This class is constructed manually because it is a service, so it doesn't use any ctor injection */ @@ -204,9 +204,9 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { } // create trie to enable fast 'filename -> extension id' look up - public getExtensionPathIndex(): TPromise> { + public getExtensionPathIndex(): TPromise> { if (!this._extensionPathIndex) { - const trie = new TrieMap(); + const trie = new StringTrieMap(); const extensions = this.getAllExtensionDescriptions().map(ext => { if (!ext.main) { return undefined; diff --git a/src/vs/workbench/api/node/extHostWorkspace.ts b/src/vs/workbench/api/node/extHostWorkspace.ts index d6027a8e703..7018fd88c07 100644 --- a/src/vs/workbench/api/node/extHostWorkspace.ts +++ b/src/vs/workbench/api/node/extHostWorkspace.ts @@ -8,7 +8,7 @@ import URI from 'vs/base/common/uri'; import Event, { Emitter } from 'vs/base/common/event'; import { normalize } from 'vs/base/common/paths'; import { delta } from 'vs/base/common/arrays'; -import { relative } from 'path'; +import { relative, dirname } from 'path'; import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceData, ExtHostWorkspaceShape, MainContext, MainThreadWorkspaceShape, IMainContext } from './extHost.protocol'; import * as vscode from 'vscode'; @@ -22,7 +22,7 @@ class Workspace2 extends Workspace { } private readonly _workspaceFolders: vscode.WorkspaceFolder[] = []; - private readonly _structure = new TrieMap(s => s.split('/')); + private readonly _structure = new TrieMap(uri => [uri.scheme, uri.authority].concat(uri.path.split('/'))); private constructor(data: IWorkspaceData) { super(data.id, data.name, data.folders.map(folder => new WorkspaceFolder(folder))); @@ -31,7 +31,7 @@ class Workspace2 extends Workspace { this.folders.forEach(({ name, uri, index }) => { const workspaceFolder = { name, uri, index }; this._workspaceFolders.push(workspaceFolder); - this._structure.insert(workspaceFolder.uri.toString(), workspaceFolder); + this._structure.insert(workspaceFolder.uri, workspaceFolder); }); } @@ -40,19 +40,13 @@ class Workspace2 extends Workspace { } getWorkspaceFolder(uri: URI): vscode.WorkspaceFolder { - let str = uri.toString(); - let folder = this._structure.lookUp(str); + let folder = this._structure.lookUp(uri); if (folder) { - // `uri` is a workspace folder so we - let parts = str.split('/'); - while (parts.length) { - if (parts.pop()) { - break; - } - } - str = parts.join('/'); + // `uri` is a workspace folder so we check for + // its parent + uri = uri.with({ path: dirname(uri.path) }); } - return this._structure.findSubstr(str); + return this._structure.findSubstr(uri); } } diff --git a/src/vs/workbench/parts/search/common/searchModel.ts b/src/vs/workbench/parts/search/common/searchModel.ts index 3c3da515ec3..de3d6e7eee1 100644 --- a/src/vs/workbench/parts/search/common/searchModel.ts +++ b/src/vs/workbench/parts/search/common/searchModel.ts @@ -11,7 +11,7 @@ import { RunOnceScheduler } from 'vs/base/common/async'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { TPromise, PPromise } from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; -import { values, ResourceMap, TrieMap } from 'vs/base/common/map'; +import { values, ResourceMap, StringTrieMap } from 'vs/base/common/map'; import Event, { Emitter, fromPromise, stopwatch, any } from 'vs/base/common/event'; import { ISearchService, ISearchProgressItem, ISearchComplete, ISearchQuery, IPatternInfo, IFileMatch } from 'vs/platform/search/common/search'; import { ReplacePattern } from 'vs/platform/search/common/replace'; @@ -496,7 +496,7 @@ export class SearchResult extends Disposable { public onChange: Event = this._onChange.event; private _folderMatches: FolderMatch[] = []; - private _folderMatchesMap: TrieMap = new TrieMap(); + private _folderMatchesMap: StringTrieMap = new StringTrieMap(); private _query: ISearchQuery = null; private _showHighlights: boolean; @@ -654,7 +654,7 @@ export class SearchResult extends Disposable { private disposeMatches(): void { this._folderMatches.forEach(folderMatch => folderMatch.dispose()); this._folderMatches = []; - this._folderMatchesMap = new TrieMap(); + this._folderMatchesMap = new StringTrieMap(); this._rangeHighlightDecorations.removeHighlightRange(); } diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 41756a57695..d34a4e9db69 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -15,7 +15,7 @@ import { compare } from 'vs/base/common/strings'; import { Schemas } from 'vs/base/common/network'; import { Progress } from 'vs/platform/progress/common/progress'; import { decodeStream, encode } from 'vs/base/node/encoding'; -import { TrieMap } from 'vs/base/common/map'; +import { StringTrieMap } from 'vs/base/common/map'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -61,7 +61,7 @@ function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse?: (stat export function toDeepIFileStat(provider: IFileSystemProvider, stat: IStat, to: URI[]): TPromise { - const trie = new TrieMap(); + const trie = new StringTrieMap(); trie.insert(stat.resource.toString(), true); if (!isFalsyOrEmpty(to)) { From d8ea1286aee792e33dc7e68b1319bfe6a56ffc78 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 20 Sep 2017 17:01:27 +0200 Subject: [PATCH 109/281] Fixes #34487 --- src/vs/workbench/node/extensionHostMain.ts | 118 +++++++++++++-------- 1 file changed, 71 insertions(+), 47 deletions(-) diff --git a/src/vs/workbench/node/extensionHostMain.ts b/src/vs/workbench/node/extensionHostMain.ts index ccd25d7eadb..a3f3d77b31a 100644 --- a/src/vs/workbench/node/extensionHostMain.ts +++ b/src/vs/workbench/node/extensionHostMain.ts @@ -18,6 +18,7 @@ import { DiskSearch } from 'vs/workbench/services/search/node/searchService'; import { IInitData, IEnvironment, IWorkspaceData, MainContext } from 'vs/workbench/api/node/extHost.protocol'; import * as errors from 'vs/base/common/errors'; import * as watchdog from 'native-watchdog'; +import * as glob from 'vs/base/common/glob'; // const nativeExit = process.exit.bind(process); process.exit = function () { @@ -149,64 +150,87 @@ export class ExtensionHostMain { return TPromise.as(null); } - const desiredFilesMap: { - [filename: string]: boolean; - } = {}; + return TPromise.join( + this._extensionService.getAllExtensionDescriptions().map((desc) => { + return this.handleWorkspaceContainsEagerExtension(desc); + }) + ).then(() => { }); + } - this._extensionService.getAllExtensionDescriptions().forEach((desc) => { - let activationEvents = desc.activationEvents; - if (!activationEvents) { - return; - } + private handleWorkspaceContainsEagerExtension(desc: IExtensionDescription): TPromise { + let activationEvents = desc.activationEvents; + if (!activationEvents) { + return TPromise.as(void 0); + } - for (let i = 0; i < activationEvents.length; i++) { - if (/^workspaceContains:/.test(activationEvents[i])) { - let fileName = activationEvents[i].substr('workspaceContains:'.length); - desiredFilesMap[fileName] = true; + const fileNames: string[] = []; + const globPatterns: string[] = []; + + for (let i = 0; i < activationEvents.length; i++) { + if (/^workspaceContains:/.test(activationEvents[i])) { + let fileNameOrGlob = activationEvents[i].substr('workspaceContains:'.length); + if (fileNameOrGlob.indexOf('*') >= 0 || fileNameOrGlob.indexOf('?') >= 0) { + globPatterns.push(fileNameOrGlob); + } else { + fileNames.push(fileNameOrGlob); } } - }); + } - const matchingPatterns = Object.keys(desiredFilesMap).map(p => { - // TODO: This is a bit hacky -- maybe this should be implemented by using something like - // `workspaceGlob` or something along those lines? - if (p.indexOf('*') > -1 || p.indexOf('?') > -1) { - if (!this._diskSearch) { - // Shut down this search process after 1s - this._diskSearch = new DiskSearch(false, 1000); - } + if (fileNames.length === 0 && globPatterns.length === 0) { + return TPromise.as(void 0); + } - const query: ISearchQuery = { - folderQueries: this._workspace.folders.map(folder => ({ folder: folder.uri })), - type: QueryType.File, - maxResults: 1, - includePattern: { [p]: true } - }; + let fileNamePromise = TPromise.join(fileNames.map((fileName) => this.activateIfFileName(desc.id, fileName))).then(() => { }); + let globPatternPromise = this.activateIfGlobPatterns(desc.id, globPatterns); - return this._diskSearch.search(query).then(result => result.results.length ? p : undefined); - } else { - // find exact path - return (async resolve => { - for (const { uri } of this._workspace.folders) { - if (await pfs.exists(join(uri.fsPath, p))) { - return p; - } - } - return undefined; - })(); + return TPromise.join([fileNamePromise, globPatternPromise]).then(() => { }); + } + + private async activateIfFileName(extensionId: string, fileName: string): TPromise { + // find exact path + + for (const { uri } of this._workspace.folders) { + if (await pfs.exists(join(uri.fsPath, fileName))) { + // the file was found + return ( + this._extensionService.activateById(extensionId, true) + .done(null, err => console.error(err)) + ); } + } + + return undefined; + } + + private async activateIfGlobPatterns(extensionId: string, globPatterns: string[]): TPromise { + if (!this._diskSearch) { + // Shut down this search process after 1s + this._diskSearch = new DiskSearch(false, 1000); + } + + let includes: glob.IExpression = {}; + globPatterns.forEach((globPattern) => { + includes[globPattern] = true; }); - return TPromise.join(matchingPatterns).then(patterns => { - patterns - .filter(p => p !== undefined) - .forEach(p => { - const activationEvent = `workspaceContains:${p}`; + const query: ISearchQuery = { + folderQueries: this._workspace.folders.map(folder => ({ folder: folder.uri })), + type: QueryType.File, + maxResults: 1, + includePattern: includes + }; - this._extensionService.activateByEvent(activationEvent, true) - .done(null, err => console.error(err)); - }); - }); + let result = await this._diskSearch.search(query); + if (result.results.length > 0) { + // a file was found matching one of the glob patterns + return ( + this._extensionService.activateById(extensionId, true) + .done(null, err => console.error(err)) + ); + } + + return TPromise.as(void 0); } private handleExtensionTests(): TPromise { From 1a6303d5b57a2b5417eb184dee882f8812e4833a Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 20 Sep 2017 17:20:10 +0200 Subject: [PATCH 110/281] fix bad merge --- src/vs/workbench/browser/labels.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 244b7a49abd..afcd51a8b91 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -6,7 +6,6 @@ 'use strict'; import uri from 'vs/base/common/uri'; -import paths = require('vs/base/common/paths'); import resources = require('vs/base/common/resources'); import { IconLabel, IIconLabelOptions, IIconLabelCreationOptions } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; @@ -222,14 +221,14 @@ export class FileLabel extends ResourceLabel { } if (!name) { - name = paths.basename(resource.fsPath); + name = resources.basenameOrAuthority(resource); } } - + let description: string; const hidePath = (options && options.hidePath) || (resource.scheme === Schemas.untitled && !this.untitledEditorService.hasAssociatedFilePath(resource)); - let rootProvider: IWorkspaceFolderProvider; if (!hidePath) { + let rootProvider: IWorkspaceFolderProvider; if (options && options.root) { rootProvider = { getWorkspaceFolder(): { uri } { return { uri: options.root }; }, @@ -238,13 +237,11 @@ export class FileLabel extends ResourceLabel { } else { rootProvider = this.contextService; } + + description = getPathLabel(resources.dirname(resource), rootProvider, this.environmentService); } - this.setLabel({ - resource, - name: (options && options.hideLabel) ? void 0 : resources.basenameOrAuthority(resource), - description: !hidePath ? getPathLabel(resources.dirname(resource), rootProvider, this.environmentService) : void 0 - }, options); + this.setLabel({ resource, name, description }, options); } } From 4e94d4ed6a58cbb8028ddac21673a46a310241cc Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 20 Sep 2017 17:36:09 +0200 Subject: [PATCH 111/281] Fix #31568 --- extensions/configuration-editing/package.json | 14 ++------ .../common/configurationRegistry.ts | 35 ++++++++----------- .../configuration/node/configuration.ts | 27 ++++++++++++-- 3 files changed, 42 insertions(+), 34 deletions(-) diff --git a/extensions/configuration-editing/package.json b/extensions/configuration-editing/package.json index 1fd34c23234..2217043af38 100644 --- a/extensions/configuration-editing/package.json +++ b/extensions/configuration-editing/package.json @@ -33,19 +33,11 @@ }, { "fileMatch": "vscode://defaultsettings/settings.json", - "url": "vscode://schemas/settings" - }, - { - "fileMatch": "vscode://defaultsettings/resourceSettings.json", - "url": "vscode://schemas/settings/resource" - }, - { - "fileMatch": "vscode://settings/workspaceSettings.json", - "url": "vscode://schemas/settings" + "url": "vscode://schemas/settings/default" }, { "fileMatch": "%APP_SETTINGS_HOME%/settings.json", - "url": "vscode://schemas/settings" + "url": "vscode://schemas/settings/user" }, { "fileMatch": "%APP_WORKSPACES_HOME%/*/workspace.json", @@ -61,7 +53,7 @@ }, { "fileMatch": "/.vscode/settings.json", - "url": "vscode://schemas/settings" + "url": "vscode://schemas/settings/folder" }, { "fileMatch": "/.vscode/launch.json", diff --git a/src/vs/platform/configuration/common/configurationRegistry.ts b/src/vs/platform/configuration/common/configurationRegistry.ts index d2495cce311..5dc5850c73f 100644 --- a/src/vs/platform/configuration/common/configurationRegistry.ts +++ b/src/vs/platform/configuration/common/configurationRegistry.ts @@ -11,6 +11,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import types = require('vs/base/common/types'); import * as strings from 'vs/base/common/strings'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; +import { clone } from 'vs/base/common/objects'; export const Extensions = { Configuration: 'base.contributions.configuration' @@ -81,33 +82,28 @@ export interface IDefaultConfigurationExtension { defaults: { [key: string]: {} }; } -export const schemaId = 'vscode://schemas/settings'; +export const settingsSchema: IJSONSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; +export const resourceSettingsSchema: IJSONSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; + export const editorConfigurationSchemaId = 'vscode://schemas/settings/editor'; -export const resourceConfigurationSchemaId = 'vscode://schemas/settings/resource'; const contributionRegistry = Registry.as(JSONExtensions.JSONContribution); class ConfigurationRegistry implements IConfigurationRegistry { private configurationContributors: IConfigurationNode[]; private configurationProperties: { [qualifiedKey: string]: IJSONSchema }; - private configurationSchema: IJSONSchema; private editorConfigurationSchema: IJSONSchema; - private resourceConfigurationSchema: IJSONSchema; private _onDidRegisterConfiguration: Emitter; private overrideIdentifiers: string[] = []; private overridePropertyPattern: string; constructor() { this.configurationContributors = []; - this.configurationSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; this.editorConfigurationSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Unknown editor configuration setting' }; - this.resourceConfigurationSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Not a resource configuration setting' }; this._onDidRegisterConfiguration = new Emitter(); this.configurationProperties = {}; this.computeOverridePropertyPattern(); - contributionRegistry.registerSchema(schemaId, this.configurationSchema); contributionRegistry.registerSchema(editorConfigurationSchemaId, this.editorConfigurationSchema); - contributionRegistry.registerSchema(resourceConfigurationSchemaId, this.resourceConfigurationSchema); } public get onDidRegisterConfiguration() { @@ -208,12 +204,15 @@ class ConfigurationRegistry implements IConfigurationRegistry { } private registerJSONConfiguration(configuration: IConfigurationNode) { - let configurationSchema = this.configurationSchema; function register(configuration: IConfigurationNode) { let properties = configuration.properties; if (properties) { for (let key in properties) { - configurationSchema.properties[key] = properties[key]; + settingsSchema.properties[key] = properties[key]; + resourceSettingsSchema.properties[key] = clone(properties[key]); + if (properties[key].scope !== ConfigurationScope.RESOURCE) { + resourceSettingsSchema.properties[key].doNotSuggest = true; + } } } let subNodes = configuration.allOf; @@ -222,19 +221,17 @@ class ConfigurationRegistry implements IConfigurationRegistry { } }; register(configuration); - contributionRegistry.registerSchema(schemaId, configurationSchema); } private updateSchemaForOverrideSettingsConfiguration(configuration: IConfigurationNode): void { if (configuration.id !== SETTINGS_OVERRRIDE_NODE_ID) { this.update(configuration); contributionRegistry.registerSchema(editorConfigurationSchemaId, this.editorConfigurationSchema); - contributionRegistry.registerSchema(resourceConfigurationSchemaId, this.resourceConfigurationSchema); } } private updateOverridePropertyPatternKey(): void { - let patternProperties: IJSONSchema = this.configurationSchema.patternProperties[this.overridePropertyPattern]; + let patternProperties: IJSONSchema = settingsSchema.patternProperties[this.overridePropertyPattern]; if (!patternProperties) { patternProperties = { type: 'object', @@ -243,10 +240,11 @@ class ConfigurationRegistry implements IConfigurationRegistry { $ref: editorConfigurationSchemaId }; } - delete this.configurationSchema.patternProperties[this.overridePropertyPattern]; + delete settingsSchema.patternProperties[this.overridePropertyPattern]; this.computeOverridePropertyPattern(); - this.configurationSchema.patternProperties[this.overridePropertyPattern] = patternProperties; - contributionRegistry.registerSchema(schemaId, this.configurationSchema); + + settingsSchema.patternProperties[this.overridePropertyPattern] = patternProperties; + resourceSettingsSchema.patternProperties[this.overridePropertyPattern] = patternProperties; } private update(configuration: IConfigurationNode): void { @@ -256,11 +254,6 @@ class ConfigurationRegistry implements IConfigurationRegistry { if (properties[key].overridable) { this.editorConfigurationSchema.properties[key] = this.getConfigurationProperties()[key]; } - switch (properties[key].scope) { - case ConfigurationScope.RESOURCE: - this.resourceConfigurationSchema.properties[key] = this.getConfigurationProperties()[key]; - break; - } } } let subNodes = configuration.allOf; diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configuration.ts index 2552f3155f9..797f44b66d3 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configuration.ts @@ -30,7 +30,7 @@ import { ConfigurationService as GlobalConfigurationService } from 'vs/platform/ import * as nls from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry'; -import { IConfigurationNode, IConfigurationRegistry, Extensions, editorConfigurationSchemaId, IDefaultConfigurationExtension, validateProperty, ConfigurationScope, schemaId } from 'vs/platform/configuration/common/configurationRegistry'; +import { IConfigurationNode, IConfigurationRegistry, Extensions, editorConfigurationSchemaId, IDefaultConfigurationExtension, validateProperty, ConfigurationScope, settingsSchema, resourceSettingsSchema } from 'vs/platform/configuration/common/configurationRegistry'; import { createHash } from 'crypto'; import { getWorkspaceLabel, IWorkspacesService, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; @@ -40,6 +40,11 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import product from 'vs/platform/node/product'; import pkg from 'vs/platform/node/package'; +const defaultSettingsSchemaId = 'vscode://schemas/settings/default'; +const userSettingsSchemaId = 'vscode://schemas/settings/user'; +const workspaceSettingsSchemaId = 'vscode://schemas/settings/workspace'; +const folderSettingsSchemaId = 'vscode://schemas/settings/folder'; + interface IStat { resource: URI; isDirectory?: boolean; @@ -243,7 +248,7 @@ contributionRegistry.registerSchema('vscode://schemas/workspaceConfig', { type: 'object', default: {}, description: nls.localize('workspaceConfig.settings.description', "Workspace settings"), - $ref: schemaId + $ref: workspaceSettingsSchemaId }, 'extensions': { type: 'object', @@ -284,6 +289,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat this.baseConfigurationService = this._register(new GlobalConfigurationService(environmentService)); this._register(this.baseConfigurationService.onDidUpdateConfiguration(e => this.onBaseConfigurationChanged(e))); + this._register(configurationRegistry.onDidRegisterConfiguration(e => this.registerConfigurationSchemas())); } public getWorkspace(): Workspace { @@ -468,6 +474,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat } private initializeConfiguration(trigger: boolean = true): TPromise { + this.registerConfigurationSchemas(); this.resetCaches(); return this.updateConfiguration() .then(() => { @@ -497,6 +504,22 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat .then(changed => this.updateWorkspaceConfiguration(true) || changed); } + private registerConfigurationSchemas(): void { + if (this.workspace) { + + contributionRegistry.registerSchema(defaultSettingsSchemaId, settingsSchema); + contributionRegistry.registerSchema(userSettingsSchemaId, settingsSchema); + + if (WorkbenchState.WORKSPACE === this.getWorkbenchState()) { + contributionRegistry.registerSchema(workspaceSettingsSchemaId, settingsSchema); + contributionRegistry.registerSchema(folderSettingsSchemaId, resourceSettingsSchema); + } else { + contributionRegistry.registerSchema(workspaceSettingsSchemaId, settingsSchema); + contributionRegistry.registerSchema(folderSettingsSchemaId, settingsSchema); + } + } + } + private onBaseConfigurationChanged({ source, sourceConfig }: IConfigurationServiceEvent): void { if (this.workspace) { if (source === ConfigurationSource.Default) { From e9c41816f7673cebf80b66a79301d95d27ac8756 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 20 Sep 2017 17:48:13 +0200 Subject: [PATCH 112/281] Settings button does not support touch (fixes #34678) --- .../parts/activitybar/activitybarActions.ts | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 639612c9d72..8add806cda5 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -672,22 +672,32 @@ export class GlobalActivityActionItem extends ActivityActionItem { // Context menus are triggered on mouse down so that an item can be picked // and executed with releasing the mouse over it this.$container.on(DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => { - DOM.EventHelper.stop(e, true); - - const event = new StandardMouseEvent(e); - this.showContextMenu({ x: event.posx, y: event.posy }); + this.onClick(e); }); + // Extra listener for keyboard interaction this.$container.on(DOM.EventType.KEY_UP, (e: KeyboardEvent) => { let event = new StandardKeyboardEvent(e); if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) { - DOM.EventHelper.stop(e, true); - - this.showContextMenu(this.$container.getHTMLElement()); + this.onClick(e); } }); } + public onClick(event?: MouseEvent | KeyboardEvent): void { + DOM.EventHelper.stop(event, true); + + let location: HTMLElement | { x: number, y: number }; + if (event instanceof MouseEvent) { + const mouseEvent = new StandardMouseEvent(event); + location = { x: mouseEvent.posx, y: mouseEvent.posy }; + } else { + location = this.$container.getHTMLElement(); + } + + this.showContextMenu(location); + } + private showContextMenu(location: HTMLElement | { x: number, y: number }): void { const globalAction = this._action as GlobalActivityAction; const activity = globalAction.activity as IGlobalActivity; From 81444f43fa7b697694e6f81acdbf8ae6eed758e3 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Wed, 20 Sep 2017 16:49:57 +0100 Subject: [PATCH 113/281] Add import statement snippet to .js(x) files (#34682) * Add import statement snippet to JS files This makes them consistent with TS files. * Add import statement snippet to jsx files --- extensions/javascript/snippets/javascript.json | 7 +++++++ extensions/javascript/snippets/javascriptreact.json | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/extensions/javascript/snippets/javascript.json b/extensions/javascript/snippets/javascript.json index bdae6179418..ec6c69161a3 100644 --- a/extensions/javascript/snippets/javascript.json +++ b/extensions/javascript/snippets/javascript.json @@ -137,5 +137,12 @@ "/// $0" ], "description": "Relative Reference to another File" + }, + "Import external module.": { + "prefix": "import statement", + "body": [ + "import { $0 } from \"${1:module}\";" + ], + "description": "Import external module." } } diff --git a/extensions/javascript/snippets/javascriptreact.json b/extensions/javascript/snippets/javascriptreact.json index 0566af20e7b..49d8cff0d09 100644 --- a/extensions/javascript/snippets/javascriptreact.json +++ b/extensions/javascript/snippets/javascriptreact.json @@ -137,5 +137,12 @@ "/// $0" ], "description": "Relative Reference to another File" + }, + "Import external module.": { + "prefix": "import statement", + "body": [ + "import { $0 } from \"${1:module}\";" + ], + "description": "Import external module." } } From 4163f3dd6f8598dabb79e9bf4015598ebf72b2fb Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 20 Sep 2017 18:01:55 +0200 Subject: [PATCH 114/281] Fix #32593 --- .../parts/preferences/browser/preferencesRenderers.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts index 142d611efc6..afe4390953e 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesRenderers.ts @@ -796,6 +796,10 @@ class EditSettingRenderer extends Disposable { let configurationNode = configurationMap[setting.key]; if (configurationNode) { if (this.isDefaultSettings()) { + if (setting.key === 'launch') { + // Do not show because of https://github.com/Microsoft/vscode/issues/32593 + return false; + } return true; } if (configurationNode.type === 'boolean' || configurationNode.enum) { From 90af6b4ed2c9322f40715ff6b1a96e3dd565e4d4 Mon Sep 17 00:00:00 2001 From: Erich Gamma Date: Wed, 20 Sep 2017 17:56:13 +0200 Subject: [PATCH 115/281] Adopt support for multiroot folders --- extensions/npm/package.json | 4 ++- extensions/npm/src/main.ts | 60 ++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 36 deletions(-) diff --git a/extensions/npm/package.json b/extensions/npm/package.json index 07387994960..183680250e8 100644 --- a/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -37,11 +37,13 @@ "on" ], "default": "on", + "scope": "resource", "description": "%config.npm.autoDetect%" }, "npm.runSilent": { "type": "boolean", - "default": false, + "default": false, + "scope": "resource", "description": "%config.npm.runSilent%" } } diff --git a/extensions/npm/src/main.ts b/extensions/npm/src/main.ts index 6c22119b342..3cf4df511fc 100644 --- a/extensions/npm/src/main.ts +++ b/extensions/npm/src/main.ts @@ -17,24 +17,14 @@ export function activate(_context: vscode.ExtensionContext): void { return; } - function onConfigurationChanged() { - let autoDetect = vscode.workspace.getConfiguration('npm').get('autoDetect'); - if (taskProvider && autoDetect === 'off') { - taskProvider.dispose(); - taskProvider = undefined; - } else if (!taskProvider && autoDetect === 'on') { - taskProvider = vscode.workspace.registerTaskProvider('npm', { - provideTasks: () => { - return provideNpmScripts(); - }, - resolveTask(_task: vscode.Task): vscode.Task | undefined { - return undefined; - } - }); + taskProvider = vscode.workspace.registerTaskProvider('npm', { + provideTasks: () => { + return provideNpmScripts(); + }, + resolveTask(_task: vscode.Task): vscode.Task | undefined { + return undefined; } - } - vscode.workspace.onDidChangeConfiguration(onConfigurationChanged); - onConfigurationChanged(); + }); } export function deactivate(): void { @@ -100,16 +90,20 @@ async function provideNpmScripts(): Promise { return emptyTasks; } - const isSingleRoot = folders.length === 1; - for (let i = 0; i < folders.length; i++) { - let tasks = await provideNpmScriptsForFolder(folders[i], isSingleRoot); - allTasks.push(...tasks); + if (isEnabled(folders[i])) { + let tasks = await provideNpmScriptsForFolder(folders[i]); + allTasks.push(...tasks); + } } return allTasks; } -async function provideNpmScriptsForFolder(folder: vscode.WorkspaceFolder, singleRoot: boolean): Promise { +function isEnabled(folder: vscode.WorkspaceFolder): boolean { + return vscode.workspace.getConfiguration('npm', folder.uri).get('autoDetect') === 'on'; +} + +async function provideNpmScriptsForFolder(folder: vscode.WorkspaceFolder): Promise { let rootPath = folder.uri.fsPath; let emptyTasks: vscode.Task[] = []; @@ -127,7 +121,7 @@ async function provideNpmScriptsForFolder(folder: vscode.WorkspaceFolder, single const result: vscode.Task[] = []; Object.keys(json.scripts).filter(isNotPreOrPostScript).forEach(each => { - const task = createTask(each, `run ${each}`, rootPath, folder.name, singleRoot); + const task = createTask(each, `run ${each}`, rootPath, folder); const lowerCaseTaskName = each.toLowerCase(); if (isBuildTask(lowerCaseTaskName)) { task.group = vscode.TaskGroup.Build; @@ -137,24 +131,21 @@ async function provideNpmScriptsForFolder(folder: vscode.WorkspaceFolder, single result.push(task); }); // always add npm install (without a problem matcher) - result.push(createTask('install', 'install', rootPath, folder.name, singleRoot, [])); + result.push(createTask('install', 'install', rootPath, folder, [])); return result; } catch (e) { return emptyTasks; } } -function createTask(script: string, cmd: string, rootPath: string, shortPath: string, singleRoot: boolean, matcher?: any): vscode.Task { +function createTask(script: string, cmd: string, rootPath: string, folder: vscode.WorkspaceFolder, matcher?: any): vscode.Task { - function getTaskName(script: string, shortPath: string, singleRoot: boolean) { - if (singleRoot) { - return script; - } - return `${script} - ${shortPath}`; + function getTaskName(script: string) { + return script; } - function getNpmCommandLine(cmd: string): string { - if (vscode.workspace.getConfiguration('npm').get('runSilent')) { + function getNpmCommandLine(folder: vscode.WorkspaceFolder, cmd: string): string { + if (vscode.workspace.getConfiguration('npm', folder.uri).get('runSilent')) { return `npm --silent ${cmd}`; } return `npm ${cmd}`; @@ -164,7 +155,6 @@ function createTask(script: string, cmd: string, rootPath: string, shortPath: st type: 'npm', script: script }; - let taskName = getTaskName(script, shortPath, singleRoot); - - return new vscode.Task(kind, taskName, 'npm', new vscode.ShellExecution(getNpmCommandLine(cmd), { cwd: rootPath }), matcher); + let taskName = getTaskName(script); + return new vscode.Task(kind, folder, taskName, 'npm', new vscode.ShellExecution(getNpmCommandLine(folder, cmd), { cwd: rootPath }), matcher); } \ No newline at end of file From c2947df7c18548f0dbe8021d3860a0e7edb4c0aa Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 20 Sep 2017 10:42:17 -0700 Subject: [PATCH 116/281] node-debug2@1.17.2 --- build/gulpfile.vscode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 81dd6d2a7a8..890a186c4ea 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -46,7 +46,7 @@ const nodeModules = ['electron', 'original-fs'] const builtInExtensions = [ { name: 'ms-vscode.node-debug', version: '1.17.8' }, - { name: 'ms-vscode.node-debug2', version: '1.17.1' } + { name: 'ms-vscode.node-debug2', version: '1.17.2' } ]; const excludedExtensions = [ From b348a6109729edfeb5319d24797aab3e9fdd95dc Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 20 Sep 2017 11:25:15 -0700 Subject: [PATCH 117/281] Fixes webview eating esc key Fixes #34612 --- .../parts/html/browser/webviewEditor.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/html/browser/webviewEditor.ts b/src/vs/workbench/parts/html/browser/webviewEditor.ts index e859ca71b30..60de417f8e7 100644 --- a/src/vs/workbench/parts/html/browser/webviewEditor.ts +++ b/src/vs/workbench/parts/html/browser/webviewEditor.ts @@ -23,7 +23,7 @@ export interface HtmlPreviewEditorViewState { } /** A context key that is set when a webview editor has focus. */ -export const KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS = new RawContextKey('webviewEditorFocus', undefined); +export const KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS = new RawContextKey('webviewEditorFocus', false); /** A context key that is set when a webview editor does not have focus. */ export const KEYBINDING_CONTEXT_WEBVIEWEDITOR_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS.toNegated(); /** A context key that is set when the find widget find input in webview editor webview is focused. */ @@ -31,6 +31,12 @@ export const KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED = new Ra /** A context key that is set when the find widget find input in webview editor webview is not focused. */ export const KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED.toNegated(); +/** A context key that is set when the find widget in a webview is visible. */ +export const KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE = new RawContextKey('webviewFindWidgetVisible', false); +/** A context key that is set when the find widget in a webview is not visible. */ +export const KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_NOT_VISIBLE: ContextKeyExpr = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.toNegated(); + + /** * This class is only intended to be subclassed and not instantiated. */ @@ -40,6 +46,7 @@ export abstract class WebviewEditor extends BaseWebviewEditor { protected _webview: WebView; protected content: HTMLElement; protected contextKey: IContextKey; + private findWidgetVisible: IContextKey; protected findInputFocusContextKey: IContextKey; constructor( @@ -53,16 +60,19 @@ export abstract class WebviewEditor extends BaseWebviewEditor { if (contextKeyService) { this.contextKey = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS.bindTo(contextKeyService); this.findInputFocusContextKey = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED.bindTo(contextKeyService); + this.findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(contextKeyService); } } public showFind() { if (this._webview) { this._webview.showFind(); + this.findWidgetVisible.set(true); } } public hideFind() { + this.findWidgetVisible.reset(); if (this._webview) { this._webview.hideFind(); } @@ -137,7 +147,9 @@ class HideWebViewEditorFindCommand extends Command { } const hideCommand = new HideWebViewEditorFindCommand({ id: 'editor.action.webvieweditor.hideFind', - precondition: KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS, + precondition: ContextKeyExpr.and( + KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS, + KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE), kbOpts: { primary: KeyCode.Escape } From e129b2c7df949747c2bc3d32a699a22ea4d76c53 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 20 Sep 2017 12:04:58 +0200 Subject: [PATCH 118/281] update bracket matching on language configuration change --- src/vs/editor/common/commonCodeEditor.ts | 2 +- .../editor/contrib/bracketMatching/common/bracketMatching.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/common/commonCodeEditor.ts b/src/vs/editor/common/commonCodeEditor.ts index e3f5394ff42..3ba662586fe 100644 --- a/src/vs/editor/common/commonCodeEditor.ts +++ b/src/vs/editor/common/commonCodeEditor.ts @@ -45,7 +45,7 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo public readonly onDidChangeModelLanguage: Event = this._onDidChangeModelLanguage.event; private readonly _onDidChangeModelLanguageConfiguration: Emitter = this._register(new Emitter()); - public readonly onDidChangeModelLanguageConfiguration: Event = this._onDidChangeModelLanguage.event; + public readonly onDidChangeModelLanguageConfiguration: Event = this._onDidChangeModelLanguageConfiguration.event; private readonly _onDidChangeModelOptions: Emitter = this._register(new Emitter()); public readonly onDidChangeModelOptions: Event = this._onDidChangeModelOptions.event; diff --git a/src/vs/editor/contrib/bracketMatching/common/bracketMatching.ts b/src/vs/editor/contrib/bracketMatching/common/bracketMatching.ts index 87cfca45bef..ac3d45aee32 100644 --- a/src/vs/editor/contrib/bracketMatching/common/bracketMatching.ts +++ b/src/vs/editor/contrib/bracketMatching/common/bracketMatching.ts @@ -94,6 +94,10 @@ export class BracketMatchingController extends Disposable implements editorCommo this._updateBracketsSoon.schedule(); })); this._register(editor.onDidChangeModel((e) => { this._decorations = []; this._updateBracketsSoon.schedule(); })); + this._register(editor.onDidChangeModelLanguageConfiguration((e) => { + this._lastBracketsData = []; + this._updateBracketsSoon.schedule(); + })); this._register(editor.onDidChangeConfiguration((e) => { this._matchBrackets = this._editor.getConfiguration().contribInfo.matchBrackets; if (!this._matchBrackets && this._decorations.length > 0) { From ce20acd13044b9c5c9d9483282701341c8a7c0ef Mon Sep 17 00:00:00 2001 From: rebornix Date: Wed, 20 Sep 2017 12:59:02 -0700 Subject: [PATCH 119/281] color space 0...1 --- extensions/css/client/src/cssMain.ts | 2 +- extensions/html/client/src/htmlMain.ts | 2 +- extensions/json/client/src/jsonMain.ts | 2 +- .../api/electron-browser/mainThreadLanguageFeatures.ts | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/css/client/src/cssMain.ts b/extensions/css/client/src/cssMain.ts index 5515147dc9f..3e0ba970b0d 100644 --- a/extensions/css/client/src/cssMain.ts +++ b/extensions/css/client/src/cssMain.ts @@ -65,7 +65,7 @@ export function activate(context: ExtensionContext) { return client.sendRequest(DocumentColorRequest.type, params).then(symbols => { return symbols.map(symbol => { let range = client.protocol2CodeConverter.asRange(symbol.range); - let color = new Color(symbol.color.red * 255, symbol.color.green * 255, symbol.color.blue * 255, symbol.color.alpha); + let color = new Color(symbol.color.red, symbol.color.green, symbol.color.blue, symbol.color.alpha); return new ColorInformation(range, color); }); }); diff --git a/extensions/html/client/src/htmlMain.ts b/extensions/html/client/src/htmlMain.ts index 943d064b9ba..627f771f7d1 100644 --- a/extensions/html/client/src/htmlMain.ts +++ b/extensions/html/client/src/htmlMain.ts @@ -82,7 +82,7 @@ export function activate(context: ExtensionContext) { return client.sendRequest(DocumentColorRequest.type, params).then(symbols => { return symbols.map(symbol => { let range = client.protocol2CodeConverter.asRange(symbol.range); - let color = new Color(symbol.color.red * 255, symbol.color.green * 255, symbol.color.blue * 255, symbol.color.alpha); + let color = new Color(symbol.color.red, symbol.color.green, symbol.color.blue, symbol.color.alpha); return new ColorInformation(range, color); }); }); diff --git a/extensions/json/client/src/jsonMain.ts b/extensions/json/client/src/jsonMain.ts index a650ed5aa23..6a06b7bcbb9 100644 --- a/extensions/json/client/src/jsonMain.ts +++ b/extensions/json/client/src/jsonMain.ts @@ -127,7 +127,7 @@ export function activate(context: ExtensionContext) { return client.sendRequest(DocumentColorRequest.type, params).then(symbols => { return symbols.map(symbol => { let range = client.protocol2CodeConverter.asRange(symbol.range); - let color = new Color(symbol.color.red * 255, symbol.color.green * 255, symbol.color.blue * 255, symbol.color.alpha); + let color = new Color(symbol.color.red, symbol.color.green, symbol.color.blue, symbol.color.alpha); return new ColorInformation(range, color); }); }); diff --git a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts index 9a2428c031d..6e9cb4f1961 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts @@ -292,9 +292,9 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha return documentColors.map(documentColor => { const [red, green, blue, alpha] = documentColor.color; const color = { - red: red / 255.0, - green: green / 255.0, - blue: blue / 255.0, + red: red, + green: green, + blue: blue, alpha }; From 084849c2fa1c63cdf04c4134f0d9cb09ae56affd Mon Sep 17 00:00:00 2001 From: rebornix Date: Wed, 20 Sep 2017 13:44:57 -0700 Subject: [PATCH 120/281] provideColorPresentations should have document in paramaters. --- extensions/css/client/src/cssMain.ts | 2 +- extensions/html/client/src/htmlMain.ts | 2 +- extensions/json/client/src/jsonMain.ts | 2 +- src/vs/editor/common/modes.ts | 2 +- src/vs/editor/contrib/colorPicker/common/color.ts | 4 ++-- src/vs/editor/contrib/hover/browser/modesContentHover.ts | 4 ++-- src/vs/monaco.d.ts | 2 +- src/vs/vscode.proposed.d.ts | 2 +- .../api/electron-browser/mainThreadLanguageFeatures.ts | 4 ++-- src/vs/workbench/api/node/extHost.protocol.ts | 2 +- src/vs/workbench/api/node/extHostLanguageFeatures.ts | 9 +++++---- 11 files changed, 18 insertions(+), 17 deletions(-) diff --git a/extensions/css/client/src/cssMain.ts b/extensions/css/client/src/cssMain.ts index 3e0ba970b0d..c8d307d9732 100644 --- a/extensions/css/client/src/cssMain.ts +++ b/extensions/css/client/src/cssMain.ts @@ -70,7 +70,7 @@ export function activate(context: ExtensionContext) { }); }); }, - provideColorPresentations(colorInfo: ColorInformation): ColorPresentation[] | Thenable { + provideColorPresentations(document: TextDocument, colorInfo: ColorInformation): ColorPresentation[] | Thenable { let result: ColorPresentation[] = []; let color = colorInfo.color; let label; diff --git a/extensions/html/client/src/htmlMain.ts b/extensions/html/client/src/htmlMain.ts index 627f771f7d1..39bf0e1a468 100644 --- a/extensions/html/client/src/htmlMain.ts +++ b/extensions/html/client/src/htmlMain.ts @@ -87,7 +87,7 @@ export function activate(context: ExtensionContext) { }); }); }, - provideColorPresentations(colorInfo: ColorInformation): ColorPresentation[] | Thenable { + provideColorPresentations(document: TextDocument, colorInfo: ColorInformation): ColorPresentation[] | Thenable { let result: ColorPresentation[] = []; let color = colorInfo.color; let label; diff --git a/extensions/json/client/src/jsonMain.ts b/extensions/json/client/src/jsonMain.ts index 6a06b7bcbb9..8ffdb77d52d 100644 --- a/extensions/json/client/src/jsonMain.ts +++ b/extensions/json/client/src/jsonMain.ts @@ -132,7 +132,7 @@ export function activate(context: ExtensionContext) { }); }); }, - provideColorPresentations(colorInfo: ColorInformation): ColorPresentation[] | Thenable { + provideColorPresentations(document: TextDocument, colorInfo: ColorInformation): ColorPresentation[] | Thenable { let result: ColorPresentation[] = []; let color = colorInfo.color; let label; diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 9c01e6aaafb..a67046cf0e4 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -728,7 +728,7 @@ export interface DocumentColorProvider { /** * Provide the string representations for a color. */ - provideColorPresentations(colorInfo: IColorInformation, token: CancellationToken): IColorPresentation[] | Thenable; + provideColorPresentations(model: editorCommon.IReadOnlyModel, colorInfo: IColorInformation, token: CancellationToken): IColorPresentation[] | Thenable; } export interface IResourceEdit { diff --git a/src/vs/editor/contrib/colorPicker/common/color.ts b/src/vs/editor/contrib/colorPicker/common/color.ts index d85a0375ba3..14309923337 100644 --- a/src/vs/editor/contrib/colorPicker/common/color.ts +++ b/src/vs/editor/contrib/colorPicker/common/color.ts @@ -27,6 +27,6 @@ export function getColors(model: IReadOnlyModel): TPromise { return TPromise.join(promises).then(() => colors); } -export function getColorPresentations(colorInfo: IColorInformation, provider: DocumentColorProvider): TPromise { - return asWinJsPromise(token => provider.provideColorPresentations(colorInfo, token)); +export function getColorPresentations(model: IReadOnlyModel, colorInfo: IColorInformation, provider: DocumentColorProvider): TPromise { + return asWinJsPromise(token => provider.provideColorPresentations(model, colorInfo, token)); } diff --git a/src/vs/editor/contrib/hover/browser/modesContentHover.ts b/src/vs/editor/contrib/hover/browser/modesContentHover.ts index 0e0ea6df661..acd18602e01 100644 --- a/src/vs/editor/contrib/hover/browser/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/browser/modesContentHover.ts @@ -325,7 +325,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { const model = new ColorPickerModel(color, [], 0); const widget = new ColorPickerWidget(fragment, model, this._editor.getConfiguration().pixelRatio); - getColorPresentations(colorInfo, msg.provider).then(colorPresentations => { + getColorPresentations(editorModel, colorInfo, msg.provider).then(colorPresentations => { model.colorPresentations = colorPresentations; const originalText = this._editor.getModel().getValueInRange(msg.range); model.guessColorPresentation(color, originalText); @@ -360,7 +360,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { }; const updateColorPresentations = (color: Color) => { - return getColorPresentations({ + return getColorPresentations(editorModel, { range: range, color: { red: color.rgba.r / 255, diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 8be006d7a8c..09311d8c968 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4904,7 +4904,7 @@ declare module monaco.languages { /** * Provide the string representations for a color. */ - provideColorPresentations(colorInfo: IColorInformation, token: CancellationToken): IColorPresentation[] | Thenable; + provideColorPresentations(model: editor.IReadOnlyModel, colorInfo: IColorInformation, token: CancellationToken): IColorPresentation[] | Thenable; } export interface IResourceEdit { diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 42f021d9f85..6ed9537d1b6 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -222,7 +222,7 @@ declare module 'vscode' { /** * Provide representations for a color. */ - provideColorPresentations(colorInfo: ColorInformation, token: CancellationToken): ProviderResult; + provideColorPresentations(document: TextDocument, colorInfo: ColorInformation, token: CancellationToken): ProviderResult; } export namespace languages { diff --git a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts index 6e9cb4f1961..525ded68a57 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts @@ -306,8 +306,8 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha }); }, - provideColorPresentations: (colorInfo, token) => { - return wireCancellationToken(token, proxy.$provideColorPresentations(handle, { + provideColorPresentations: (model, colorInfo, token) => { + return wireCancellationToken(token, proxy.$provideColorPresentations(handle, model.uri, { color: [colorInfo.color.red, colorInfo.color.green, colorInfo.color.blue, colorInfo.color.alpha], range: colorInfo.range })); diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index e71bcb49058..8c981201c27 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -559,7 +559,7 @@ export interface ExtHostLanguageFeaturesShape { $provideDocumentLinks(handle: number, resource: URI): TPromise; $resolveDocumentLink(handle: number, link: modes.ILink): TPromise; $provideDocumentColors(handle: number, resource: URI): TPromise; - $provideColorPresentations(handle: number, colorInfo: IRawColorInfo): TPromise; + $provideColorPresentations(handle: number, resource: URI, colorInfo: IRawColorInfo): TPromise; } export interface ExtHostQuickOpenShape { diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 6b4bfc769aa..a6733cc7695 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -729,7 +729,7 @@ class ColorProviderAdapter { }); } - provideColorPresentations(rawColorInfo: IRawColorInfo): TPromise { + provideColorPresentations(resource: URI, rawColorInfo: IRawColorInfo): TPromise { let colorInfo: vscode.ColorInformation = { range: TypeConverters.toRange(rawColorInfo.range), color: { @@ -739,7 +739,8 @@ class ColorProviderAdapter { alpha: rawColorInfo.color[3] } }; - return asWinJsPromise(token => this._provider.provideColorPresentations(colorInfo, token)).then(value => { + const doc = this._documents.getDocumentData(resource).document; + return asWinJsPromise(token => this._provider.provideColorPresentations(doc, colorInfo, token)).then(value => { return value.map(v => TypeConverters.ColorPresentation.from(v)); }); } @@ -1053,8 +1054,8 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColors(resource)); } - $provideColorPresentations(handle: number, colorInfo: IRawColorInfo): TPromise { - return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(colorInfo)); + $provideColorPresentations(handle: number, resource: URI, colorInfo: IRawColorInfo): TPromise { + return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(resource, colorInfo)); } // --- configuration From 7a3c6680abc80578648196b7283b9655cead8763 Mon Sep 17 00:00:00 2001 From: Ramya Rao Date: Wed, 20 Sep 2017 18:06:57 -0700 Subject: [PATCH 121/281] Look only in default paths for recommendations (#34528) --- src/vs/platform/node/product.ts | 2 +- .../electron-browser/extensionTipsService.ts | 61 ++++++++++--------- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/vs/platform/node/product.ts b/src/vs/platform/node/product.ts index 29c55f1e439..c2d0ab48510 100644 --- a/src/vs/platform/node/product.ts +++ b/src/vs/platform/node/product.ts @@ -26,7 +26,7 @@ export interface IProductConfiguration { }; extensionTips: { [id: string]: string; }; extensionImportantTips: { [id: string]: { name: string; pattern: string; }; }; - exeBasedExtensionTips: { [id: string]: string; }; + exeBasedExtensionTips: { [id: string]: any; }; extensionKeywords: { [extension: string]: string[]; }; extensionAllowedBadgeProviders: string[]; keymapExtensionTips: string[]; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts index 3918fe5f9f0..869c71175a9 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts @@ -26,7 +26,8 @@ import { IExtensionsConfiguration, ConfigurationKey } from 'vs/workbench/parts/e import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import * as fs from 'fs'; +import * as pfs from 'vs/base/node/pfs'; +import * as os from 'os'; import { flatten, distinct } from 'vs/base/common/arrays'; interface IExtensionsContent { @@ -68,6 +69,10 @@ export class ExtensionTipsService implements IExtensionTipsService { this._suggestTips(); this._suggestWorkspaceRecommendations(); + + // Executable based recommendations carry out a lot of file stats, so run them after 10 secs + // So that the startup is not affected + setTimeout(() => this._suggestBasedOnExecutables(this._exeBasedRecommendations), 10000); } getWorkspaceRecommendations(): TPromise { @@ -104,7 +109,7 @@ export class ExtensionTipsService implements IExtensionTipsService { const fileBased = Object.keys(this._fileBasedRecommendations) .filter(recommendation => allRecomendations.indexOf(recommendation) !== -1); - const exeBased = distinct(this._suggestBasedOnExecutables()); + const exeBased = distinct(this._exeBasedRecommendations); this.telemetryService.publicLog('extensionRecommendations:unfiltered', { fileBased, exeBased }); @@ -331,42 +336,38 @@ export class ExtensionTipsService implements IExtensionTipsService { }); } - private _suggestBasedOnExecutables(): string[] { - if (!process.env.PATH || this._exeBasedRecommendations.length > 0) { - return this._exeBasedRecommendations; - } - - let envpaths = process.env.PATH.split(process.platform === 'win32' ? ';' : ':'); + private _suggestBasedOnExecutables(recommendations: string[]): void { + const homeDir = os.homedir(); let foundExecutables: Set = new Set(); + let findExecutable = (exeName, path) => { + return pfs.fileExists(path).then(exists => { + if (!foundExecutables.has(exeName)) { + foundExecutables.add(exeName); + recommendations.push(...product.exeBasedExtensionTips[exeName]['recommendations']); + } + }); + }; + // Loop through recommended extensions forEach(product.exeBasedExtensionTips, entry => { - let executables = entry.value.split(','); + if (typeof entry.value !== 'object' || !Array.isArray(entry.value['recommendations'])) { + return; + } - // Loop through executables that would result in recommending current extension - for (let i = 0; i < executables.length; i++) { - if (!foundExecutables.has(executables[i])) { - - // Loop through paths in PATH to find current executable - for (let pathEntry of envpaths) { - let fullPath = paths.join(pathEntry, executables[i]); - if (process.platform === 'win32') { - fullPath += '.exe'; - } - if (fs.existsSync(fullPath)) { - foundExecutables.add(executables[i]); - break; - } - } - } - if (foundExecutables.has(executables[i])) { - this._exeBasedRecommendations.push(entry.key); - break; + let exeName = entry.key; + if (process.platform === 'win32') { + let windowsPath = entry.value['windowsPath']; + if (!windowsPath || typeof windowsPath !== 'string') { + return; } + windowsPath = windowsPath.replace('%USERPROFILE%', process.env['USERPROFILE']); + findExecutable(exeName, windowsPath); + } else { + findExecutable(exeName, paths.join('/usr/local/bin', exeName)); + findExecutable(exeName, paths.join(homeDir, exeName)); } }); - - return this._exeBasedRecommendations; } private setIgnoreRecommendationsConfig(configVal: boolean) { From b86108e54b31572d0f9678ffbd14f9ee8d3b3780 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 20 Sep 2017 13:48:21 -0700 Subject: [PATCH 122/281] Make display string optional in ts/js hover --- extensions/typescript/src/features/hoverProvider.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/extensions/typescript/src/features/hoverProvider.ts b/extensions/typescript/src/features/hoverProvider.ts index 9ee37c5954b..8b27c535292 100644 --- a/extensions/typescript/src/features/hoverProvider.ts +++ b/extensions/typescript/src/features/hoverProvider.ts @@ -36,10 +36,14 @@ export default class TypeScriptHoverProvider implements HoverProvider { } private static getContents(data: Proto.QuickInfoResponseBody) { + const parts = []; + + if (data.displayString) { + parts.push({ language: 'typescript', value: data.displayString }); + } + const tags = tagsMarkdownPreview(data.tags); - return [ - { language: 'typescript', value: data.displayString }, - data.documentation + (tags ? '\n\n' + tags : '') - ]; + parts.push(data.documentation + (tags ? '\n\n' + tags : '')); + return parts; } } \ No newline at end of file From 377eabe614740c071bd062fd2c3a9ac0e885b80e Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 8 Sep 2017 16:21:50 -0700 Subject: [PATCH 123/281] Add optional CompletionContext to provideCompletionItems Fixes #752 Adds a new overload of `provideCompletionItems` that takes a context argument. This context is currently used to provide the trigger character of the suggestion --- src/vs/editor/common/modes.ts | 9 ++- .../editor/contrib/suggest/browser/suggest.ts | 6 +- .../suggest/browser/suggestController.ts | 2 +- .../contrib/suggest/browser/suggestModel.ts | 24 +++++--- .../suggest/test/browser/suggestModel.test.ts | 56 +++++++++++++++---- .../standalone/browser/standaloneLanguages.ts | 34 +++++++++-- src/vs/monaco.d.ts | 19 ++++++- src/vs/vscode.d.ts | 18 +++++- .../mainThreadLanguageFeatures.ts | 4 +- src/vs/workbench/api/node/extHost.protocol.ts | 2 +- .../api/node/extHostLanguageFeatures.ts | 13 +++-- .../parts/debug/electron-browser/repl.ts | 2 +- 12 files changed, 148 insertions(+), 41 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index a67046cf0e4..b711553c164 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -247,6 +247,13 @@ export interface ISuggestResult { dispose?(): void; } +/** + * @internal + */ +export interface SuggestContext { + triggerCharacter?: string; +} + /** * @internal */ @@ -254,7 +261,7 @@ export interface ISuggestSupport { triggerCharacters?: string[]; - provideCompletionItems(model: editorCommon.IModel, position: Position, token: CancellationToken): ISuggestResult | Thenable; + provideCompletionItems(model: editorCommon.IModel, position: Position, context: SuggestContext, token: CancellationToken): ISuggestResult | Thenable; resolveCompletionItem?(model: editorCommon.IModel, position: Position, item: ISuggestion, token: CancellationToken): ISuggestion | Thenable; } diff --git a/src/vs/editor/contrib/suggest/browser/suggest.ts b/src/vs/editor/contrib/suggest/browser/suggest.ts index 3831064a10c..b899c5ffd34 100644 --- a/src/vs/editor/contrib/suggest/browser/suggest.ts +++ b/src/vs/editor/contrib/suggest/browser/suggest.ts @@ -12,7 +12,7 @@ import { onUnexpectedExternalError } from 'vs/base/common/errors'; import { TPromise } from 'vs/base/common/winjs.base'; import { IModel, IEditorContribution, ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import { CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; -import { ISuggestResult, ISuggestSupport, ISuggestion, SuggestRegistry } from 'vs/editor/common/modes'; +import { ISuggestResult, ISuggestSupport, ISuggestion, SuggestRegistry, SuggestContext } from 'vs/editor/common/modes'; import { Position, IPosition } from 'vs/editor/common/core/position'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -42,7 +42,7 @@ export function setSnippetSuggestSupport(support: ISuggestSupport): ISuggestSupp return old; } -export function provideSuggestionItems(model: IModel, position: Position, snippetConfig: SnippetConfig = 'bottom', onlyFrom?: ISuggestSupport[]): TPromise { +export function provideSuggestionItems(model: IModel, position: Position, snippetConfig: SnippetConfig = 'bottom', onlyFrom?: ISuggestSupport[], context?: SuggestContext): TPromise { const allSuggestions: ISuggestionItem[] = []; const acceptSuggestion = createSuggesionFilter(snippetConfig); @@ -73,7 +73,7 @@ export function provideSuggestionItems(model: IModel, position: Position, snippe return undefined; } - return asWinJsPromise(token => support.provideCompletionItems(model, position, token)).then(container => { + return asWinJsPromise(token => support.provideCompletionItems(model, position, context || {}, token)).then(container => { const len = allSuggestions.length; diff --git a/src/vs/editor/contrib/suggest/browser/suggestController.ts b/src/vs/editor/contrib/suggest/browser/suggestController.ts index 37a5ad50ff3..6f7fb7e9add 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestController.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestController.ts @@ -209,7 +209,7 @@ export class SuggestController implements IEditorContribution { } triggerSuggest(onlyFrom?: ISuggestSupport[]): void { - this._model.trigger(false, false, onlyFrom); + this._model.trigger({ auto: false }, false, onlyFrom); this._editor.revealLine(this._editor.getPosition().lineNumber, ScrollType.Smooth); this._editor.focus(); } diff --git a/src/vs/editor/contrib/suggest/browser/suggestModel.ts b/src/vs/editor/contrib/suggest/browser/suggestModel.ts index 69b20642956..49e513c551c 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestModel.ts @@ -31,6 +31,11 @@ export interface ISuggestEvent { auto: boolean; } +export interface SuggestTriggerContext { + auto: boolean; + triggerCharacter?: string; +} + export class LineContext { static shouldAutoTrigger(editor: ICommonCodeEditor): boolean { @@ -201,7 +206,7 @@ export class SuggestModel implements IDisposable { } } } - this.trigger(true, Boolean(this.completionModel), supports, items); + this.trigger({ auto: true, triggerCharacter: lastChar }, Boolean(this.completionModel), supports, items); } }); } @@ -237,7 +242,7 @@ export class SuggestModel implements IDisposable { if (!SuggestRegistry.has(this.editor.getModel())) { this.cancel(); } else { - this.trigger(this._state === State.Auto, true); + this.trigger({ auto: this._state === State.Auto }, true); } } } @@ -311,7 +316,7 @@ export class SuggestModel implements IDisposable { } this.triggerAutoSuggestPromise = null; - this.trigger(true); + this.trigger({ auto: true }); }); } } @@ -326,14 +331,14 @@ export class SuggestModel implements IDisposable { } } - public trigger(auto: boolean, retrigger: boolean = false, onlyFrom?: ISuggestSupport[], existingItems?: ISuggestionItem[]): void { + public trigger(context: SuggestTriggerContext, retrigger: boolean = false, onlyFrom?: ISuggestSupport[], existingItems?: ISuggestionItem[]): void { const model = this.editor.getModel(); if (!model) { return; } - + const auto = context.auto; const ctx = new LineContext(model, this.editor.getPosition(), auto); if (!LineContext.isInEditableRange(this.editor)) { @@ -350,7 +355,8 @@ export class SuggestModel implements IDisposable { this.requestPromise = provideSuggestionItems(model, this.editor.getPosition(), this.editor.getConfiguration().contribInfo.snippetSuggestions, - onlyFrom + onlyFrom, + context ).then(items => { this.requestPromise = null; @@ -394,7 +400,7 @@ export class SuggestModel implements IDisposable { if (ctx.column < this.context.column) { // typed -> moved cursor LEFT -> retrigger if still on a word if (ctx.leadingWord.word) { - this.trigger(this.context.auto, true); + this.trigger({ auto: this.context.auto }, true); } else { this.cancel(); } @@ -409,7 +415,7 @@ export class SuggestModel implements IDisposable { if (ctx.column > this.context.column && this.completionModel.incomplete && ctx.leadingWord.word.length !== 0) { // typed -> moved cursor RIGHT & incomple model & still on a word -> retrigger const { complete, incomplete } = this.completionModel.resolveIncompleteInfo(); - this.trigger(this._state === State.Auto, true, incomplete, complete); + this.trigger({ auto: this._state === State.Auto }, true, incomplete, complete); } else { // typed -> moved cursor RIGHT -> update UI @@ -425,7 +431,7 @@ export class SuggestModel implements IDisposable { if (LineContext.shouldAutoTrigger(this.editor) && this.context.leadingWord.endColumn < ctx.leadingWord.startColumn) { // retrigger when heading into a new word - this.trigger(this.context.auto, true); + this.trigger({ auto: this.context.auto }, true); return; } diff --git a/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts b/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts index 6bba3555808..9ba1e83a9a1 100644 --- a/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts +++ b/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts @@ -149,25 +149,25 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { // cancel on trigger assertEvent(model.onDidCancel, function () { - model.trigger(false); + model.trigger({ auto: false }); }, function (event) { assert.equal(event.retrigger, false); }), assertEvent(model.onDidCancel, function () { - model.trigger(false, true); + model.trigger({ auto: false }, true); }, function (event) { assert.equal(event.retrigger, true); }), assertEvent(model.onDidTrigger, function () { - model.trigger(true); + model.trigger({ auto: true }); }, function (event) { assert.equal(event.auto, true); }), assertEvent(model.onDidTrigger, function () { - model.trigger(false); + model.trigger({ auto: false }); }, function (event) { assert.equal(event.auto, false); }) @@ -183,12 +183,12 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { return withOracle(model => { return TPromise.join([ assertEvent(model.onDidCancel, function () { - model.trigger(true); + model.trigger({ auto: true }); }, function (event) { assert.equal(event.retrigger, false); }), assertEvent(model.onDidSuggest, function () { - model.trigger(false); + model.trigger({ auto: false }); }, function (event) { assert.equal(event.auto, false); assert.equal(event.isFrozen, false); @@ -239,7 +239,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { return assertEvent(model.onDidSuggest, () => { // make sure completionModel starts here! - model.trigger(true); + model.trigger({ auto: true }); }, event => { return assertEvent(model.onDidSuggest, () => { @@ -338,7 +338,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { editor.setPosition({ lineNumber: 1, column: 3 }); return assertEvent(model.onDidSuggest, () => { - model.trigger(false); + model.trigger({ auto: false }); }, event => { assert.equal(event.auto, false); assert.equal(event.isFrozen, false); @@ -363,7 +363,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { editor.setPosition({ lineNumber: 1, column: 3 }); return assertEvent(model.onDidSuggest, () => { - model.trigger(false); + model.trigger({ auto: false }); }, event => { assert.equal(event.auto, false); assert.equal(event.isFrozen, false); @@ -400,7 +400,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { editor.setPosition({ lineNumber: 1, column: 4 }); return assertEvent(model.onDidSuggest, () => { - model.trigger(false); + model.trigger({ auto: false }); }, event => { assert.equal(event.auto, false); assert.equal(event.completionModel.incomplete, true); @@ -437,7 +437,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { editor.setPosition({ lineNumber: 1, column: 4 }); return assertEvent(model.onDidSuggest, () => { - model.trigger(false); + model.trigger({ auto: false }); }, event => { assert.equal(event.auto, false); assert.equal(event.completionModel.incomplete, true); @@ -457,4 +457,38 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { }); }); }); + + test('Trigger characters is provided in suggest context', function () { + let triggerCharacter = ''; + disposables.push(SuggestRegistry.register({ scheme: 'test' }, { + triggerCharacters: ['.'], + provideCompletionItems(doc, pos, context) { + triggerCharacter = context.triggerCharacter; + return { + currentWord: '', + incomplete: false, + suggestions: [ + { + label: 'foo.bar', + type: 'property', + insertText: 'foo.bar', + overwriteBefore: pos.column - 1 + } + ] + }; + } + })); + + model.setValue(''); + + return withOracle((model, editor) => { + + return assertEvent(model.onDidSuggest, () => { + editor.setPosition({ lineNumber: 1, column: 1 }); + editor.trigger('keyboard', Handler.Type, { text: 'foo.' }); + }, event => { + assert.equal(triggerCharacter, '.'); + }); + }); + }); }); diff --git a/src/vs/editor/standalone/browser/standaloneLanguages.ts b/src/vs/editor/standalone/browser/standaloneLanguages.ts index d97e850f41c..41c1b68becc 100644 --- a/src/vs/editor/standalone/browser/standaloneLanguages.ts +++ b/src/vs/editor/standalone/browser/standaloneLanguages.ts @@ -373,8 +373,8 @@ export function registerCompletionItemProvider(languageId: string, provider: Com let adapter = new SuggestAdapter(provider); return modes.SuggestRegistry.register(languageId, { triggerCharacters: provider.triggerCharacters, - provideCompletionItems: (model: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken): Thenable => { - return adapter.provideCompletionItems(model, position, token); + provideCompletionItems: (model: editorCommon.IReadOnlyModel, position: Position, context: modes.SuggestContext, token: CancellationToken): Thenable => { + return adapter.provideCompletionItems(model, position, context, token); }, resolveCompletionItem: (model: editorCommon.IReadOnlyModel, position: Position, suggestion: modes.ISuggestion, token: CancellationToken): Thenable => { return adapter.resolveCompletionItem(model, position, suggestion, token); @@ -537,6 +537,23 @@ export interface CompletionList { */ items: CompletionItem[]; } + +/** + * Contains additional information about the context in which + * [completion provider](#CompletionItemProvider.provideCompletionItems) is triggered. + */ +export interface CompletionContext { + /** + * Character that triggered the completion item provider. + * + * Undefined if provider was not triggered by a character. + */ + triggerCharacter?: string; +} + +export type ProviderCompletionItems = (document: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken) => CompletionItem[] | Thenable | CompletionList | Thenable; +export type ProviderCompletionItemsForContext = (document: editorCommon.IReadOnlyModel, position: Position, context: CompletionContext, token: CancellationToken) => CompletionItem[] | Thenable | CompletionList | Thenable; + /** * The completion item provider interface defines the contract between extensions and * the [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). @@ -553,7 +570,7 @@ export interface CompletionItemProvider { /** * Provide completion items for the given position and document. */ - provideCompletionItems(model: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; + provideCompletionItems: ProviderCompletionItems | ProviderCompletionItemsForContext; /** * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) * or [details](#CompletionItem.detail). @@ -639,9 +656,14 @@ class SuggestAdapter { return suggestion; } - provideCompletionItems(model: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken): Thenable { - - return toThenable(this._provider.provideCompletionItems(model, position, token)).then(value => { + provideCompletionItems(model: editorCommon.IReadOnlyModel, position: Position, context: modes.SuggestContext, token: CancellationToken): Thenable { + let request: any; + if (this._provider.provideCompletionItems.length <= 3) { + request = (this._provider.provideCompletionItems as ProviderCompletionItems)(model, position, token); + } else { + request = (this._provider.provideCompletionItems as ProviderCompletionItemsForContext)(model, position, context, token); + } + return toThenable(request).then(value => { const result: modes.ISuggestResult = { suggestions: [] }; diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 09311d8c968..58eafd8e633 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4229,6 +4229,23 @@ declare module monaco.languages { items: CompletionItem[]; } + /** + * Contains additional information about the context in which + * [completion provider](#CompletionItemProvider.provideCompletionItems) is triggered. + */ + export interface CompletionContext { + /** + * Character that triggered the completion item provider. + * + * Undefined if provider was not triggered by a character. + */ + triggerCharacter?: string; + } + + export type ProviderCompletionItems = (document: editor.IReadOnlyModel, position: Position, token: CancellationToken) => CompletionItem[] | Thenable | CompletionList | Thenable; + + export type ProviderCompletionItemsForContext = (document: editor.IReadOnlyModel, position: Position, context: CompletionContext, token: CancellationToken) => CompletionItem[] | Thenable | CompletionList | Thenable; + /** * The completion item provider interface defines the contract between extensions and * the [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). @@ -4245,7 +4262,7 @@ declare module monaco.languages { /** * Provide completion items for the given position and document. */ - provideCompletionItems(model: editor.IReadOnlyModel, position: Position, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; + provideCompletionItems: ProviderCompletionItems | ProviderCompletionItemsForContext; /** * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) * or [details](#CompletionItem.detail). diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 47bcdcb64a5..49d7378c9ed 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2718,6 +2718,22 @@ declare module 'vscode' { constructor(items?: CompletionItem[], isIncomplete?: boolean); } + /** + * Contains additional information about the context in which + * [completion provider](#CompletionItemProvider.provideCompletionItems) is triggered. + */ + export interface CompletionContext { + /** + * Character that triggered the completion item provider. + * + * Undefined if provider was not triggered by a character. + */ + readonly triggerCharacter?: string; + } + + export type ProviderCompletionItems = (document: TextDocument, position: Position, token: CancellationToken) => ProviderResult; + export type ProviderCompletionItemsForContext = (document: TextDocument, position: Position, context: CompletionContext, token: CancellationToken) => ProviderResult; + /** * The completion item provider interface defines the contract between extensions and * [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). @@ -2743,7 +2759,7 @@ declare module 'vscode' { * @return An array of completions, a [completion list](#CompletionList), or a thenable that resolves to either. * The lack of a result can be signaled by returning `undefined`, `null`, or an empty array. */ - provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + provideCompletionItems: ProviderCompletionItems | ProviderCompletionItemsForContext; /** * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) diff --git a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts index 525ded68a57..757bab38cea 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts @@ -233,8 +233,8 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha this._registrations[handle] = modes.SuggestRegistry.register(selector, { triggerCharacters, - provideCompletionItems: (model: IReadOnlyModel, position: EditorPosition, token: CancellationToken): Thenable => { - return wireCancellationToken(token, this._proxy.$provideCompletionItems(handle, model.uri, position)).then(result => { + provideCompletionItems: (model: IReadOnlyModel, position: EditorPosition, context: modes.SuggestContext, token: CancellationToken): Thenable => { + return wireCancellationToken(token, this._proxy.$provideCompletionItems(handle, model.uri, position, context)).then(result => { if (!result) { return result; } diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 8c981201c27..61ae052f117 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -552,7 +552,7 @@ export interface ExtHostLanguageFeaturesShape { $provideWorkspaceSymbols(handle: number, search: string): TPromise; $resolveWorkspaceSymbol(handle: number, symbol: modes.SymbolInformation): TPromise; $provideRenameEdits(handle: number, resource: URI, position: IPosition, newName: string): TPromise; - $provideCompletionItems(handle: number, resource: URI, position: IPosition): TPromise; + $provideCompletionItems(handle: number, resource: URI, position: IPosition, context: modes.SuggestContext): TPromise; $resolveCompletionItem(handle: number, resource: URI, position: IPosition, suggestion: modes.ISuggestion): TPromise; $releaseCompletionItems(handle: number, id: number): void; $provideSignatureHelp(handle: number, resource: URI, position: IPosition): TPromise; diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index a6733cc7695..132af499967 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -486,12 +486,17 @@ class SuggestAdapter { this._provider = provider; } - provideCompletionItems(resource: URI, position: IPosition): TPromise { + provideCompletionItems(resource: URI, position: IPosition, context: modes.SuggestContext): TPromise { const doc = this._documents.getDocumentData(resource).document; const pos = TypeConverters.toPosition(position); - return asWinJsPromise(token => this._provider.provideCompletionItems(doc, pos, token)).then(value => { + return asWinJsPromise(token => { + if (this._provider.provideCompletionItems.length <= 3) { + return (this._provider.provideCompletionItems as vscode.ProviderCompletionItems)(doc, pos, token); + } + return (this._provider.provideCompletionItems as vscode.ProviderCompletionItemsForContext)(doc, pos, context, token); + }).then(value => { const _id = this._idPool++; @@ -1001,8 +1006,8 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideCompletionItems(handle: number, resource: URI, position: IPosition): TPromise { - return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(resource, position)); + $provideCompletionItems(handle: number, resource: URI, position: IPosition, context: modes.SuggestContext): TPromise { + return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(resource, position, context)); } $resolveCompletionItem(handle: number, resource: URI, position: IPosition, suggestion: modes.ISuggestion): TPromise { diff --git a/src/vs/workbench/parts/debug/electron-browser/repl.ts b/src/vs/workbench/parts/debug/electron-browser/repl.ts index b097d3a3652..a1a9c8250a5 100644 --- a/src/vs/workbench/parts/debug/electron-browser/repl.ts +++ b/src/vs/workbench/parts/debug/electron-browser/repl.ts @@ -180,7 +180,7 @@ export class Repl extends Panel implements IPrivateReplService { modes.SuggestRegistry.register({ scheme: debug.DEBUG_SCHEME }, { triggerCharacters: ['.'], - provideCompletionItems: (model: IReadOnlyModel, position: Position, token: CancellationToken): Thenable => { + provideCompletionItems: (model: IReadOnlyModel, position: Position, _context: modes.SuggestContext, token: CancellationToken): Thenable => { const word = this.replInput.getModel().getWordAtPosition(position); const overwriteBefore = word ? word.word.length : 0; const text = this.replInput.getModel().getLineContent(position.lineNumber); From 89773f358e0acd4ed93cb93dc9819067e1dbf9c2 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Sep 2017 09:05:06 -0700 Subject: [PATCH 124/281] Update based on comments --- .../editor/contrib/suggest/browser/suggest.ts | 4 +++- .../contrib/suggest/browser/suggestModel.ts | 4 +++- .../standalone/browser/standaloneLanguages.ts | 21 ++++++++----------- src/vs/monaco.d.ts | 9 +++----- src/vs/vscode.d.ts | 8 +++---- .../api/node/extHostLanguageFeatures.ts | 4 ++-- 6 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggest.ts b/src/vs/editor/contrib/suggest/browser/suggest.ts index b899c5ffd34..5aaf3048a86 100644 --- a/src/vs/editor/contrib/suggest/browser/suggest.ts +++ b/src/vs/editor/contrib/suggest/browser/suggest.ts @@ -42,6 +42,8 @@ export function setSnippetSuggestSupport(support: ISuggestSupport): ISuggestSupp return old; } +const emptySuggestContext: SuggestContext = {}; + export function provideSuggestionItems(model: IModel, position: Position, snippetConfig: SnippetConfig = 'bottom', onlyFrom?: ISuggestSupport[], context?: SuggestContext): TPromise { const allSuggestions: ISuggestionItem[] = []; @@ -73,7 +75,7 @@ export function provideSuggestionItems(model: IModel, position: Position, snippe return undefined; } - return asWinJsPromise(token => support.provideCompletionItems(model, position, context || {}, token)).then(container => { + return asWinJsPromise(token => support.provideCompletionItems(model, position, context || emptySuggestContext, token)).then(container => { const len = allSuggestions.length; diff --git a/src/vs/editor/contrib/suggest/browser/suggestModel.ts b/src/vs/editor/contrib/suggest/browser/suggestModel.ts index 49e513c551c..2e06afe6329 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestModel.ts @@ -356,7 +356,9 @@ export class SuggestModel implements IDisposable { this.requestPromise = provideSuggestionItems(model, this.editor.getPosition(), this.editor.getConfiguration().contribInfo.snippetSuggestions, onlyFrom, - context + { + triggerCharacter: context.triggerCharacter + } ).then(items => { this.requestPromise = null; diff --git a/src/vs/editor/standalone/browser/standaloneLanguages.ts b/src/vs/editor/standalone/browser/standaloneLanguages.ts index 41c1b68becc..a04d6b39933 100644 --- a/src/vs/editor/standalone/browser/standaloneLanguages.ts +++ b/src/vs/editor/standalone/browser/standaloneLanguages.ts @@ -546,14 +546,11 @@ export interface CompletionContext { /** * Character that triggered the completion item provider. * - * Undefined if provider was not triggered by a character. + * `undefined` if provider was not triggered by a character. */ triggerCharacter?: string; } -export type ProviderCompletionItems = (document: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken) => CompletionItem[] | Thenable | CompletionList | Thenable; -export type ProviderCompletionItemsForContext = (document: editorCommon.IReadOnlyModel, position: Position, context: CompletionContext, token: CancellationToken) => CompletionItem[] | Thenable | CompletionList | Thenable; - /** * The completion item provider interface defines the contract between extensions and * the [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). @@ -570,7 +567,9 @@ export interface CompletionItemProvider { /** * Provide completion items for the given position and document. */ - provideCompletionItems: ProviderCompletionItems | ProviderCompletionItemsForContext; + provideCompletionItems(document: editorCommon.IReadOnlyModel, position: Position, context: CompletionContext, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; + provideCompletionItems(document: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; + /** * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) * or [details](#CompletionItem.detail). @@ -657,13 +656,11 @@ class SuggestAdapter { } provideCompletionItems(model: editorCommon.IReadOnlyModel, position: Position, context: modes.SuggestContext, token: CancellationToken): Thenable { - let request: any; - if (this._provider.provideCompletionItems.length <= 3) { - request = (this._provider.provideCompletionItems as ProviderCompletionItems)(model, position, token); - } else { - request = (this._provider.provideCompletionItems as ProviderCompletionItemsForContext)(model, position, context, token); - } - return toThenable(request).then(value => { + const result = this._provider.provideCompletionItems.length <= 3 + ? this._provider.provideCompletionItems(model, position, token) + : this._provider.provideCompletionItems(model, position, context, token); + + return toThenable(result).then(value => { const result: modes.ISuggestResult = { suggestions: [] }; diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 58eafd8e633..63db57368ba 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4237,15 +4237,11 @@ declare module monaco.languages { /** * Character that triggered the completion item provider. * - * Undefined if provider was not triggered by a character. + * `undefined` if provider was not triggered by a character. */ triggerCharacter?: string; } - export type ProviderCompletionItems = (document: editor.IReadOnlyModel, position: Position, token: CancellationToken) => CompletionItem[] | Thenable | CompletionList | Thenable; - - export type ProviderCompletionItemsForContext = (document: editor.IReadOnlyModel, position: Position, context: CompletionContext, token: CancellationToken) => CompletionItem[] | Thenable | CompletionList | Thenable; - /** * The completion item provider interface defines the contract between extensions and * the [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). @@ -4262,7 +4258,8 @@ declare module monaco.languages { /** * Provide completion items for the given position and document. */ - provideCompletionItems: ProviderCompletionItems | ProviderCompletionItemsForContext; + provideCompletionItems(document: editor.IReadOnlyModel, position: Position, context: CompletionContext, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; + provideCompletionItems(document: editor.IReadOnlyModel, position: Position, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; /** * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) * or [details](#CompletionItem.detail). diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 49d7378c9ed..3552946a246 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2726,14 +2726,11 @@ declare module 'vscode' { /** * Character that triggered the completion item provider. * - * Undefined if provider was not triggered by a character. + * `undefined` if provider was not triggered by a character. */ readonly triggerCharacter?: string; } - export type ProviderCompletionItems = (document: TextDocument, position: Position, token: CancellationToken) => ProviderResult; - export type ProviderCompletionItemsForContext = (document: TextDocument, position: Position, context: CompletionContext, token: CancellationToken) => ProviderResult; - /** * The completion item provider interface defines the contract between extensions and * [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). @@ -2759,7 +2756,8 @@ declare module 'vscode' { * @return An array of completions, a [completion list](#CompletionList), or a thenable that resolves to either. * The lack of a result can be signaled by returning `undefined`, `null`, or an empty array. */ - provideCompletionItems: ProviderCompletionItems | ProviderCompletionItemsForContext; + provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + provideCompletionItems(document: TextDocument, position: Position, context: CompletionContext, token: CancellationToken): ProviderResult; /** * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 132af499967..bc177f72477 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -493,9 +493,9 @@ class SuggestAdapter { return asWinJsPromise(token => { if (this._provider.provideCompletionItems.length <= 3) { - return (this._provider.provideCompletionItems as vscode.ProviderCompletionItems)(doc, pos, token); + return this._provider.provideCompletionItems(doc, pos, token); } - return (this._provider.provideCompletionItems as vscode.ProviderCompletionItemsForContext)(doc, pos, context, token); + return this._provider.provideCompletionItems(doc, pos, context, token); }).then(value => { const _id = this._idPool++; From 0283831aff57ef1e01777af12c6ff64a33e7b5c4 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 12 Sep 2017 17:12:49 -0700 Subject: [PATCH 125/281] Fix interfaces and move the function types into namespaces --- .../vscode-api-tests/src/languages.test.ts | 2 +- src/vs/editor/common/modes.ts | 1 + .../editor/contrib/suggest/browser/suggest.ts | 6 +-- .../contrib/suggest/browser/suggestModel.ts | 3 +- .../suggest/test/browser/suggestModel.test.ts | 1 + .../standalone/browser/standaloneLanguages.ts | 22 +++++++-- src/vs/monaco.d.ts | 24 +++++++++- src/vs/vscode.d.ts | 47 +++++++++++++++---- .../api/node/extHostLanguageFeatures.ts | 4 +- 9 files changed, 89 insertions(+), 21 deletions(-) diff --git a/extensions/vscode-api-tests/src/languages.test.ts b/extensions/vscode-api-tests/src/languages.test.ts index 321b1b772f2..838436b3b54 100644 --- a/extensions/vscode-api-tests/src/languages.test.ts +++ b/extensions/vscode-api-tests/src/languages.test.ts @@ -69,7 +69,7 @@ suite('languages namespace tests', () => { let jsonDocumentFilter = [{ language: 'json', pattern: '**/package.json' }, { language: 'json', pattern: '**/bower.json' }, { language: 'json', pattern: '**/.bower.json' }]; let r1 = languages.registerCompletionItemProvider(jsonDocumentFilter, { - provideCompletionItems: (document: TextDocument, position: Position, token: CancellationToken): CompletionItem[] => { + provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): CompletionItem[] { let proposal = new CompletionItem('foo'); proposal.kind = CompletionItemKind.Property; ran = true; diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index b711553c164..ca04a29fe5d 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -251,6 +251,7 @@ export interface ISuggestResult { * @internal */ export interface SuggestContext { + trigger: 'auto' | 'manual'; triggerCharacter?: string; } diff --git a/src/vs/editor/contrib/suggest/browser/suggest.ts b/src/vs/editor/contrib/suggest/browser/suggest.ts index 5aaf3048a86..de99bc8d1e5 100644 --- a/src/vs/editor/contrib/suggest/browser/suggest.ts +++ b/src/vs/editor/contrib/suggest/browser/suggest.ts @@ -42,8 +42,6 @@ export function setSnippetSuggestSupport(support: ISuggestSupport): ISuggestSupp return old; } -const emptySuggestContext: SuggestContext = {}; - export function provideSuggestionItems(model: IModel, position: Position, snippetConfig: SnippetConfig = 'bottom', onlyFrom?: ISuggestSupport[], context?: SuggestContext): TPromise { const allSuggestions: ISuggestionItem[] = []; @@ -59,6 +57,8 @@ export function provideSuggestionItems(model: IModel, position: Position, snippe supports.unshift([_snippetSuggestSupport]); } + const suggestConext = context || { trigger: 'auto' }; + // add suggestions from contributed providers - providers are ordered in groups of // equal score and once a group produces a result the process stops let hasResult = false; @@ -75,7 +75,7 @@ export function provideSuggestionItems(model: IModel, position: Position, snippe return undefined; } - return asWinJsPromise(token => support.provideCompletionItems(model, position, context || emptySuggestContext, token)).then(container => { + return asWinJsPromise(token => support.provideCompletionItems(model, position, suggestConext, token)).then(container => { const len = allSuggestions.length; diff --git a/src/vs/editor/contrib/suggest/browser/suggestModel.ts b/src/vs/editor/contrib/suggest/browser/suggestModel.ts index 2e06afe6329..15b52091b05 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestModel.ts @@ -357,7 +357,8 @@ export class SuggestModel implements IDisposable { this.editor.getConfiguration().contribInfo.snippetSuggestions, onlyFrom, { - triggerCharacter: context.triggerCharacter + triggerCharacter: context.triggerCharacter, + trigger: context.auto ? 'auto' : 'manual' } ).then(items => { diff --git a/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts b/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts index 9ba1e83a9a1..c983f204053 100644 --- a/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts +++ b/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts @@ -463,6 +463,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { disposables.push(SuggestRegistry.register({ scheme: 'test' }, { triggerCharacters: ['.'], provideCompletionItems(doc, pos, context) { + assert.equal(context.trigger, 'auto'); triggerCharacter = context.triggerCharacter; return { currentWord: '', diff --git a/src/vs/editor/standalone/browser/standaloneLanguages.ts b/src/vs/editor/standalone/browser/standaloneLanguages.ts index a04d6b39933..78e9541da8e 100644 --- a/src/vs/editor/standalone/browser/standaloneLanguages.ts +++ b/src/vs/editor/standalone/browser/standaloneLanguages.ts @@ -543,6 +543,11 @@ export interface CompletionList { * [completion provider](#CompletionItemProvider.provideCompletionItems) is triggered. */ export interface CompletionContext { + /** + * How the completion was triggered. + */ + readonly trigger: 'auto' | 'manual'; + /** * Character that triggered the completion item provider. * @@ -551,6 +556,16 @@ export interface CompletionContext { triggerCharacter?: string; } +export namespace CompletionItemProvider { + export interface ProvideCompletionItems { + (document: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; + } + + export interface ProvideCompletionItemsForContext { + (document: editorCommon.IReadOnlyModel, position: Position, context: CompletionContext, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; + } +} + /** * The completion item provider interface defines the contract between extensions and * the [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). @@ -567,8 +582,7 @@ export interface CompletionItemProvider { /** * Provide completion items for the given position and document. */ - provideCompletionItems(document: editorCommon.IReadOnlyModel, position: Position, context: CompletionContext, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; - provideCompletionItems(document: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; + provideCompletionItems: CompletionItemProvider.ProvideCompletionItems | CompletionItemProvider.ProvideCompletionItemsForContext; /** * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) @@ -657,8 +671,8 @@ class SuggestAdapter { provideCompletionItems(model: editorCommon.IReadOnlyModel, position: Position, context: modes.SuggestContext, token: CancellationToken): Thenable { const result = this._provider.provideCompletionItems.length <= 3 - ? this._provider.provideCompletionItems(model, position, token) - : this._provider.provideCompletionItems(model, position, context, token); + ? (this._provider.provideCompletionItems as CompletionItemProvider.ProvideCompletionItems)(model, position, token) + : (this._provider.provideCompletionItems as CompletionItemProvider.ProvideCompletionItemsForContext)(model, position, context, token); return toThenable(result).then(value => { const result: modes.ISuggestResult = { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 63db57368ba..911e235a94d 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4234,6 +4234,10 @@ declare module monaco.languages { * [completion provider](#CompletionItemProvider.provideCompletionItems) is triggered. */ export interface CompletionContext { + /** + * How the completion was triggered. + */ + readonly trigger: 'auto' | 'manual'; /** * Character that triggered the completion item provider. * @@ -4242,6 +4246,23 @@ declare module monaco.languages { triggerCharacter?: string; } + export namespace CompletionItemProvider { + interface ProvideCompletionItems { + (document: editor.IReadOnlyModel, position: Position, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; + } + interface ProvideCompletionItemsForContext { + (document: editor.IReadOnlyModel, position: Position, context: CompletionContext, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; + } + } + + interface ProvideCompletionItems { + (document: editor.IReadOnlyModel, position: Position, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; + } + + interface ProvideCompletionItemsForContext { + (document: editor.IReadOnlyModel, position: Position, context: CompletionContext, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; + } + /** * The completion item provider interface defines the contract between extensions and * the [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). @@ -4258,8 +4279,7 @@ declare module monaco.languages { /** * Provide completion items for the given position and document. */ - provideCompletionItems(document: editor.IReadOnlyModel, position: Position, context: CompletionContext, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; - provideCompletionItems(document: editor.IReadOnlyModel, position: Position, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; + provideCompletionItems: CompletionItemProvider.ProvideCompletionItems | CompletionItemProvider.ProvideCompletionItemsForContext; /** * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) * or [details](#CompletionItem.detail). diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 3552946a246..4ba969a482d 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2723,6 +2723,11 @@ declare module 'vscode' { * [completion provider](#CompletionItemProvider.provideCompletionItems) is triggered. */ export interface CompletionContext { + /** + * How the completion was triggered. + */ + readonly trigger: 'auto' | 'manual'; + /** * Character that triggered the completion item provider. * @@ -2731,6 +2736,39 @@ declare module 'vscode' { readonly triggerCharacter?: string; } + + namespace CompletionItemProvider { + export interface ProvideCompletionItems { + /** + * Provide completion items for the given position and document. + * + * @deprecated Used [ProvideCompletionItemsForContext](#ProvideCompletionItemsForContext) instead + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * + * @return An array of completions, a [completion list](#CompletionList), or a thenable that resolves to either. + * The lack of a result can be signaled by returning `undefined`, `null`, or an empty array. + */ + (document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + } + + export interface ProvideCompletionItemsForContext { + /** + * Provide completion items for the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param context How the completion was triggered. + * @param token A cancellation token. + * + * @return An array of completions, a [completion list](#CompletionList), or a thenable that resolves to either. + * The lack of a result can be signaled by returning `undefined`, `null`, or an empty array. + */ + (document: TextDocument, position: Position, context: CompletionContext, token: CancellationToken): ProviderResult; + } + } /** * The completion item provider interface defines the contract between extensions and * [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). @@ -2749,15 +2787,8 @@ declare module 'vscode' { /** * Provide completion items for the given position and document. - * - * @param document The document in which the command was invoked. - * @param position The position at which the command was invoked. - * @param token A cancellation token. - * @return An array of completions, a [completion list](#CompletionList), or a thenable that resolves to either. - * The lack of a result can be signaled by returning `undefined`, `null`, or an empty array. */ - provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; - provideCompletionItems(document: TextDocument, position: Position, context: CompletionContext, token: CancellationToken): ProviderResult; + provideCompletionItems: CompletionItemProvider.ProvideCompletionItems | CompletionItemProvider.ProvideCompletionItemsForContext; /** * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index bc177f72477..3718f434c24 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -493,9 +493,9 @@ class SuggestAdapter { return asWinJsPromise(token => { if (this._provider.provideCompletionItems.length <= 3) { - return this._provider.provideCompletionItems(doc, pos, token); + return (this._provider.provideCompletionItems as vscode.CompletionItemProvider.ProvideCompletionItems)(doc, pos, token); } - return this._provider.provideCompletionItems(doc, pos, context, token); + return (this._provider.provideCompletionItems as vscode.CompletionItemProvider.ProvideCompletionItemsForContext)(doc, pos, context, token); }).then(value => { const _id = this._idPool++; From b34379e8f711ea6eb69cd86bfe1e5ea9639d8f52 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 20 Sep 2017 18:34:24 -0700 Subject: [PATCH 126/281] Take context as last argument --- .../standalone/browser/standaloneLanguages.ts | 17 +------- src/vs/monaco.d.ts | 19 +------- src/vs/vscode.d.ts | 43 ++++--------------- .../api/node/extHostLanguageFeatures.ts | 5 +-- 4 files changed, 13 insertions(+), 71 deletions(-) diff --git a/src/vs/editor/standalone/browser/standaloneLanguages.ts b/src/vs/editor/standalone/browser/standaloneLanguages.ts index 78e9541da8e..a362d640897 100644 --- a/src/vs/editor/standalone/browser/standaloneLanguages.ts +++ b/src/vs/editor/standalone/browser/standaloneLanguages.ts @@ -556,16 +556,6 @@ export interface CompletionContext { triggerCharacter?: string; } -export namespace CompletionItemProvider { - export interface ProvideCompletionItems { - (document: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; - } - - export interface ProvideCompletionItemsForContext { - (document: editorCommon.IReadOnlyModel, position: Position, context: CompletionContext, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; - } -} - /** * The completion item provider interface defines the contract between extensions and * the [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). @@ -582,7 +572,7 @@ export interface CompletionItemProvider { /** * Provide completion items for the given position and document. */ - provideCompletionItems: CompletionItemProvider.ProvideCompletionItems | CompletionItemProvider.ProvideCompletionItemsForContext; + provideCompletionItems(document: editorCommon.IReadOnlyModel, position: Position, token: CancellationToken, context: CompletionContext): CompletionItem[] | Thenable | CompletionList | Thenable; /** * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) @@ -670,10 +660,7 @@ class SuggestAdapter { } provideCompletionItems(model: editorCommon.IReadOnlyModel, position: Position, context: modes.SuggestContext, token: CancellationToken): Thenable { - const result = this._provider.provideCompletionItems.length <= 3 - ? (this._provider.provideCompletionItems as CompletionItemProvider.ProvideCompletionItems)(model, position, token) - : (this._provider.provideCompletionItems as CompletionItemProvider.ProvideCompletionItemsForContext)(model, position, context, token); - + const result = this._provider.provideCompletionItems(model, position, token, context); return toThenable(result).then(value => { const result: modes.ISuggestResult = { suggestions: [] diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 911e235a94d..d633e2bd6cb 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4246,23 +4246,6 @@ declare module monaco.languages { triggerCharacter?: string; } - export namespace CompletionItemProvider { - interface ProvideCompletionItems { - (document: editor.IReadOnlyModel, position: Position, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; - } - interface ProvideCompletionItemsForContext { - (document: editor.IReadOnlyModel, position: Position, context: CompletionContext, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; - } - } - - interface ProvideCompletionItems { - (document: editor.IReadOnlyModel, position: Position, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; - } - - interface ProvideCompletionItemsForContext { - (document: editor.IReadOnlyModel, position: Position, context: CompletionContext, token: CancellationToken): CompletionItem[] | Thenable | CompletionList | Thenable; - } - /** * The completion item provider interface defines the contract between extensions and * the [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). @@ -4279,7 +4262,7 @@ declare module monaco.languages { /** * Provide completion items for the given position and document. */ - provideCompletionItems: CompletionItemProvider.ProvideCompletionItems | CompletionItemProvider.ProvideCompletionItemsForContext; + provideCompletionItems(document: editor.IReadOnlyModel, position: Position, token: CancellationToken, context: CompletionContext): CompletionItem[] | Thenable | CompletionList | Thenable; /** * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) * or [details](#CompletionItem.detail). diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 4ba969a482d..bf5170ac593 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2736,39 +2736,6 @@ declare module 'vscode' { readonly triggerCharacter?: string; } - - namespace CompletionItemProvider { - export interface ProvideCompletionItems { - /** - * Provide completion items for the given position and document. - * - * @deprecated Used [ProvideCompletionItemsForContext](#ProvideCompletionItemsForContext) instead - * - * @param document The document in which the command was invoked. - * @param position The position at which the command was invoked. - * @param token A cancellation token. - * - * @return An array of completions, a [completion list](#CompletionList), or a thenable that resolves to either. - * The lack of a result can be signaled by returning `undefined`, `null`, or an empty array. - */ - (document: TextDocument, position: Position, token: CancellationToken): ProviderResult; - } - - export interface ProvideCompletionItemsForContext { - /** - * Provide completion items for the given position and document. - * - * @param document The document in which the command was invoked. - * @param position The position at which the command was invoked. - * @param context How the completion was triggered. - * @param token A cancellation token. - * - * @return An array of completions, a [completion list](#CompletionList), or a thenable that resolves to either. - * The lack of a result can be signaled by returning `undefined`, `null`, or an empty array. - */ - (document: TextDocument, position: Position, context: CompletionContext, token: CancellationToken): ProviderResult; - } - } /** * The completion item provider interface defines the contract between extensions and * [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). @@ -2787,8 +2754,16 @@ declare module 'vscode' { /** * Provide completion items for the given position and document. + * + * @param document The document in which the command was invoked. + * @param position The position at which the command was invoked. + * @param token A cancellation token. + * @param context How the completion was triggered. + * + * @return An array of completions, a [completion list](#CompletionList), or a thenable that resolves to either. + * The lack of a result can be signaled by returning `undefined`, `null`, or an empty array. */ - provideCompletionItems: CompletionItemProvider.ProvideCompletionItems | CompletionItemProvider.ProvideCompletionItemsForContext; + provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken, context: CompletionContext): ProviderResult; /** * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 3718f434c24..8ae31ac1f2c 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -492,10 +492,7 @@ class SuggestAdapter { const pos = TypeConverters.toPosition(position); return asWinJsPromise(token => { - if (this._provider.provideCompletionItems.length <= 3) { - return (this._provider.provideCompletionItems as vscode.CompletionItemProvider.ProvideCompletionItems)(doc, pos, token); - } - return (this._provider.provideCompletionItems as vscode.CompletionItemProvider.ProvideCompletionItemsForContext)(doc, pos, context, token); + return this._provider.provideCompletionItems(doc, pos, token, context); }).then(value => { const _id = this._idPool++; From 2f34618b87a85cc7524e5dc75cc92a4466d0c1c5 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 20 Sep 2017 19:13:03 -0700 Subject: [PATCH 127/281] Adding completion item kind enum --- src/vs/editor/common/modes.ts | 10 ++++++++- .../editor/contrib/suggest/browser/suggest.ts | 4 ++-- .../contrib/suggest/browser/suggestModel.ts | 4 ++-- .../suggest/test/browser/suggestModel.test.ts | 6 ++--- .../standalone/browser/standaloneLanguages.ts | 6 +++-- src/vs/monaco.d.ts | 10 ++++++++- src/vs/vscode.d.ts | 16 +++++++++++++- src/vs/workbench/api/node/extHost.api.impl.ts | 1 + .../api/node/extHostLanguageFeatures.ts | 2 +- .../api/node/extHostTypeConverters.ts | 22 +++++++++++++++++++ src/vs/workbench/api/node/extHostTypes.ts | 10 +++++++++ 11 files changed, 78 insertions(+), 13 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index ca04a29fe5d..9184a639da4 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -247,11 +247,19 @@ export interface ISuggestResult { dispose?(): void; } +/** + * How a suggest provider was triggered. + */ +export enum SuggestTriggerKind { + Invoke = 0, + TriggerCharacter = 1 +} + /** * @internal */ export interface SuggestContext { - trigger: 'auto' | 'manual'; + triggerKind: SuggestTriggerKind; triggerCharacter?: string; } diff --git a/src/vs/editor/contrib/suggest/browser/suggest.ts b/src/vs/editor/contrib/suggest/browser/suggest.ts index de99bc8d1e5..aea81522ddd 100644 --- a/src/vs/editor/contrib/suggest/browser/suggest.ts +++ b/src/vs/editor/contrib/suggest/browser/suggest.ts @@ -12,7 +12,7 @@ import { onUnexpectedExternalError } from 'vs/base/common/errors'; import { TPromise } from 'vs/base/common/winjs.base'; import { IModel, IEditorContribution, ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import { CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; -import { ISuggestResult, ISuggestSupport, ISuggestion, SuggestRegistry, SuggestContext } from 'vs/editor/common/modes'; +import { ISuggestResult, ISuggestSupport, ISuggestion, SuggestRegistry, SuggestContext, SuggestTriggerKind } from 'vs/editor/common/modes'; import { Position, IPosition } from 'vs/editor/common/core/position'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -57,7 +57,7 @@ export function provideSuggestionItems(model: IModel, position: Position, snippe supports.unshift([_snippetSuggestSupport]); } - const suggestConext = context || { trigger: 'auto' }; + const suggestConext = context || { triggerKind: SuggestTriggerKind.Invoke }; // add suggestions from contributed providers - providers are ordered in groups of // equal score and once a group produces a result the process stops diff --git a/src/vs/editor/contrib/suggest/browser/suggestModel.ts b/src/vs/editor/contrib/suggest/browser/suggestModel.ts index 15b52091b05..e71781a9f33 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestModel.ts @@ -11,7 +11,7 @@ import Event, { Emitter } from 'vs/base/common/event'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; import { ICommonCodeEditor, IModel, IWordAtPosition } from 'vs/editor/common/editorCommon'; -import { ISuggestSupport, SuggestRegistry, StandardTokenType } from 'vs/editor/common/modes'; +import { ISuggestSupport, SuggestRegistry, StandardTokenType, SuggestTriggerKind } from 'vs/editor/common/modes'; import { Position } from 'vs/editor/common/core/position'; import { provideSuggestionItems, getSuggestionComparator, ISuggestionItem } from './suggest'; import { CompletionModel } from './completionModel'; @@ -358,7 +358,7 @@ export class SuggestModel implements IDisposable { onlyFrom, { triggerCharacter: context.triggerCharacter, - trigger: context.auto ? 'auto' : 'manual' + triggerKind: context.triggerCharacter ? SuggestTriggerKind.TriggerCharacter : SuggestTriggerKind.Invoke } ).then(items => { diff --git a/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts b/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts index c983f204053..0964ab132cc 100644 --- a/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts +++ b/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts @@ -11,7 +11,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; import { Model } from 'vs/editor/common/model/model'; import { ICommonCodeEditor, Handler } from 'vs/editor/common/editorCommon'; -import { ISuggestSupport, ISuggestResult, SuggestRegistry } from 'vs/editor/common/modes'; +import { ISuggestSupport, ISuggestResult, SuggestRegistry, SuggestTriggerKind } from 'vs/editor/common/modes'; import { SuggestModel, LineContext } from 'vs/editor/contrib/suggest/browser/suggestModel'; import { MockCodeEditor, MockScopeLocation } from 'vs/editor/test/common/mocks/mockCodeEditor'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; @@ -458,12 +458,12 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { }); }); - test('Trigger characters is provided in suggest context', function () { + test('Trigger character is provided in suggest context', function () { let triggerCharacter = ''; disposables.push(SuggestRegistry.register({ scheme: 'test' }, { triggerCharacters: ['.'], provideCompletionItems(doc, pos, context) { - assert.equal(context.trigger, 'auto'); + assert.equal(context.triggerKind, SuggestTriggerKind.TriggerCharacter); triggerCharacter = context.triggerCharacter; return { currentWord: '', diff --git a/src/vs/editor/standalone/browser/standaloneLanguages.ts b/src/vs/editor/standalone/browser/standaloneLanguages.ts index a362d640897..78fe0aa3d37 100644 --- a/src/vs/editor/standalone/browser/standaloneLanguages.ts +++ b/src/vs/editor/standalone/browser/standaloneLanguages.ts @@ -546,7 +546,7 @@ export interface CompletionContext { /** * How the completion was triggered. */ - readonly trigger: 'auto' | 'manual'; + triggerKind: modes.SuggestTriggerKind; /** * Character that triggered the completion item provider. @@ -610,6 +610,7 @@ function convertKind(kind: CompletionItemKind): modes.SuggestionType { } return 'property'; } + class SuggestAdapter { private _provider: CompletionItemProvider; @@ -758,6 +759,7 @@ export function createMonacoLanguagesAPI(): typeof monaco.languages { DocumentHighlightKind: modes.DocumentHighlightKind, CompletionItemKind: CompletionItemKind, SymbolKind: modes.SymbolKind, - IndentAction: IndentAction + IndentAction: IndentAction, + SuggestTriggerKind: modes.SuggestTriggerKind }; } diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index d633e2bd6cb..d490e9c987e 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4237,7 +4237,7 @@ declare module monaco.languages { /** * How the completion was triggered. */ - readonly trigger: 'auto' | 'manual'; + triggerKind: SuggestTriggerKind; /** * Character that triggered the completion item provider. * @@ -4513,6 +4513,14 @@ declare module monaco.languages { provideHover(model: editor.IReadOnlyModel, position: Position, token: CancellationToken): Hover | Thenable; } + /** + * How a suggest provider was triggered. + */ + export enum SuggestTriggerKind { + Invoke = 0, + TriggerCharacter = 1, + } + /** * Represents a parameter of a callable-signature. A parameter can * have a label and a doc-comment. diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index bf5170ac593..f54331ff7fc 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2718,6 +2718,20 @@ declare module 'vscode' { constructor(items?: CompletionItem[], isIncomplete?: boolean); } + /** + * How a [completion provider](#CompletionItemProvider) was triggered + */ + export enum CompletionTriggerKind { + /** + * Completion was triggered normally. + */ + Invoke = 0, + /** + * Completion was triggered by a trigger character. + */ + TriggerCharacter = 1 + } + /** * Contains additional information about the context in which * [completion provider](#CompletionItemProvider.provideCompletionItems) is triggered. @@ -2726,7 +2740,7 @@ declare module 'vscode' { /** * How the completion was triggered. */ - readonly trigger: 'auto' | 'manual'; + readonly triggerKind: CompletionTriggerKind; /** * Character that triggered the completion item provider. diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 7f06becd069..eaf99b356ff 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -563,6 +563,7 @@ export function createApiFactory( CompletionItem: extHostTypes.CompletionItem, CompletionItemKind: extHostTypes.CompletionItemKind, CompletionList: extHostTypes.CompletionList, + CompletionTriggerKind: extHostTypes.CompletionTriggerKind, Diagnostic: extHostTypes.Diagnostic, DiagnosticSeverity: extHostTypes.DiagnosticSeverity, Disposable: extHostTypes.Disposable, diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 8ae31ac1f2c..9439c69b9b7 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -492,7 +492,7 @@ class SuggestAdapter { const pos = TypeConverters.toPosition(position); return asWinJsPromise(token => { - return this._provider.provideCompletionItems(doc, pos, token, context); + return this._provider.provideCompletionItems(doc, pos, token, TypeConverters.CompletionContext.from(context)); }).then(value => { const _id = this._idPool++; diff --git a/src/vs/workbench/api/node/extHostTypeConverters.ts b/src/vs/workbench/api/node/extHostTypeConverters.ts index d8aef198fd8..22d9b4cacf5 100644 --- a/src/vs/workbench/api/node/extHostTypeConverters.ts +++ b/src/vs/workbench/api/node/extHostTypeConverters.ts @@ -307,6 +307,28 @@ export function toDocumentHighlight(occurrence: modes.DocumentHighlight): types. return new types.DocumentHighlight(toRange(occurrence.range), occurrence.kind); } +export namespace CompletionTriggerKind { + export function from(kind: modes.SuggestTriggerKind) { + switch (kind) { + case modes.SuggestTriggerKind.TriggerCharacter: + return types.CompletionTriggerKind.TriggerCharacter; + + case modes.SuggestTriggerKind.Invoke: + default: + return types.CompletionTriggerKind.Invoke; + } + } +} + +export namespace CompletionContext { + export function from(context: modes.SuggestContext): types.CompletionContext { + return { + triggerKind: CompletionTriggerKind.from(context.triggerKind), + triggerCharacter: context.triggerCharacter + }; + } +} + export const CompletionItemKind = { from(kind: types.CompletionItemKind): modes.SuggestionType { diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index d63e57a1506..f84c4574eb5 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -879,6 +879,16 @@ export class SignatureHelp { } } +export enum CompletionTriggerKind { + Invoke = 0, + TriggerCharacter = 1 +} + +export interface CompletionContext { + triggerKind: CompletionTriggerKind; + triggerCharacter: string; +} + export enum CompletionItemKind { Text = 0, Method = 1, From dc0c1a1ebe80d541a39a37687f8f47465e8fbe73 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 20 Sep 2017 19:22:44 -0700 Subject: [PATCH 128/281] Revert chnage to languages.test --- extensions/vscode-api-tests/src/languages.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/vscode-api-tests/src/languages.test.ts b/extensions/vscode-api-tests/src/languages.test.ts index 838436b3b54..321b1b772f2 100644 --- a/extensions/vscode-api-tests/src/languages.test.ts +++ b/extensions/vscode-api-tests/src/languages.test.ts @@ -69,7 +69,7 @@ suite('languages namespace tests', () => { let jsonDocumentFilter = [{ language: 'json', pattern: '**/package.json' }, { language: 'json', pattern: '**/bower.json' }, { language: 'json', pattern: '**/.bower.json' }]; let r1 = languages.registerCompletionItemProvider(jsonDocumentFilter, { - provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): CompletionItem[] { + provideCompletionItems: (document: TextDocument, position: Position, token: CancellationToken): CompletionItem[] => { let proposal = new CompletionItem('foo'); proposal.kind = CompletionItemKind.Property; ran = true; From 336be693e5fb9738047923b20643f0cb7f065956 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 20 Sep 2017 19:28:20 -0700 Subject: [PATCH 129/281] Add note about trigger character --- src/vs/vscode.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index f54331ff7fc..a6000d74612 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2746,6 +2746,8 @@ declare module 'vscode' { * Character that triggered the completion item provider. * * `undefined` if provider was not triggered by a character. + * + * The trigger character is already in the document when the completion provider is triggered. */ readonly triggerCharacter?: string; } From 10237b64e69fe7b4c9641efe2d5421e495bb7528 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 21 Sep 2017 08:07:51 +0200 Subject: [PATCH 130/281] touch bar: reuse entries to avoid flickering --- src/vs/code/electron-main/window.ts | 106 ++++++++++++++++++---------- 1 file changed, 70 insertions(+), 36 deletions(-) diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 84ea2f76aeb..5484771bf86 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -94,6 +94,8 @@ export class CodeWindow implements ICodeWindow { private currentConfig: IWindowConfiguration; private pendingLoadConfig: IWindowConfiguration; + private touchBarGroups: Map; + constructor( config: IWindowCreationOptions, @ILogService private logService: ILogService, @@ -103,6 +105,7 @@ export class CodeWindow implements ICodeWindow { @IWorkspacesMainService private workspaceService: IWorkspacesMainService, @IBackupMainService private backupService: IBackupMainService ) { + this.touchBarGroups = new Map(); this._lastFocusTime = -1; this._readyState = ReadyState.NONE; this.whenReadyCallbacks = []; @@ -858,49 +861,80 @@ export class CodeWindow implements ICodeWindow { this._win.webContents.send(channel, ...args); } - public updateTouchBar(items: ICommandAction[][]): void { + public updateTouchBar(groups: ICommandAction[][]): void { if (!isMacintosh) { return; // only supported on macOS } - const groups: (Electron.TouchBarGroup | Electron.TouchBarSpacer)[] = []; - - items.forEach(itemGroup => { - if (itemGroup.length) { - - // Group Segments - const groupSegments = itemGroup.map(item => { - let icon: Electron.NativeImage; - if (item.iconPath) { - icon = nativeImage.createFromPath(item.iconPath); - if (icon.isEmpty()) { - icon = void 0; - } - } - - return { - label: !icon ? item.title as string : void 0, - icon - }; - }); - - // Group Touch Bar - const groupTouchBar = new TouchBar.TouchBarSegmentedControl({ - segments: groupSegments, - mode: 'buttons', - segmentStyle: 'automatic', - change: (selectedIndex) => { - this.sendWhenReady('vscode:runAction', itemGroup[selectedIndex].id); - } - }); - - // Push and add small space between groups - groups.push(groupTouchBar); - groups.push(new TouchBar.TouchBarSpacer({ size: 'small' })); + // Clean up previous groups no longer in use + const groupHashes: string[] = []; + groups.forEach(group => groupHashes.push(this.getTouchBarGroupHash(group))); + this.touchBarGroups.forEach((value, key) => { + if (groupHashes.indexOf(key) === -1) { + this.touchBarGroups.delete(key); } }); - this._win.setTouchBar(new TouchBar({ items: groups })); + // Build touchbar from groups + const touchBarGroups: (Electron.TouchBarGroup | Electron.TouchBarSpacer)[] = []; + groups.forEach(group => { + if (group.length) { + const groupHash = this.getTouchBarGroupHash(group); + + // To avoid flickering, we try to reuse the touch bar group + // as much as possible by checking for a previously created + // group that has the same number of items with same style. + let groupTouchBar: Electron.TouchBarSegmentedControl; + if (this.touchBarGroups.has(groupHash)) { + groupTouchBar = this.touchBarGroups.get(groupHash); + } else { + groupTouchBar = this.createTouchBarGroup(group); + this.touchBarGroups.set(groupHash, groupTouchBar); + } + + // Push and add small space between groups + touchBarGroups.push(groupTouchBar); + touchBarGroups.push(new TouchBar.TouchBarSpacer({ size: 'small' })); + } + }); + + this._win.setTouchBar(new TouchBar({ items: touchBarGroups })); + } + + private getTouchBarGroupHash(items: ICommandAction[]): string { + let id = ''; + items.forEach(item => id += (item.id + item.title + item.iconPath)); + + return id; + } + + private createTouchBarGroup(items: ICommandAction[]): Electron.TouchBarSegmentedControl { + + // Group Segments + const segments = items.map(item => { + let icon: Electron.NativeImage; + if (item.iconPath) { + icon = nativeImage.createFromPath(item.iconPath); + if (icon.isEmpty()) { + icon = void 0; + } + } + + return { + label: !icon ? item.title as string : void 0, + icon + }; + }); + + // Group Touch Bar + return new TouchBar.TouchBarSegmentedControl({ + segments, + mode: 'buttons', + segmentStyle: 'automatic', + change: (selectedIndex) => { + this.sendWhenReady('vscode:runAction', items[selectedIndex].id); + } + }); } public dispose(): void { From 447fea8845147d9415d354a6026f0aa7505167e6 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 21 Sep 2017 10:10:19 +0200 Subject: [PATCH 131/281] debt - make vscode.Uri compatibile with URI, declare private ctor --- src/vs/base/common/uri.ts | 216 +++++++++--------- src/vs/vscode.d.ts | 5 + src/vs/workbench/api/node/extHost.api.impl.ts | 4 +- 3 files changed, 121 insertions(+), 104 deletions(-) diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index 39ad9e80805..fbf1903da3f 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -21,6 +21,12 @@ function encodeNoop(str: string): string { } +const _empty = ''; +const _slash = '/'; +const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; +const _driveLetterPath = /^\/[a-zA-Z]:/; +const _upperCaseDrive = /^(\/)?([A-Z]:)/; + /** * Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986. * This class is a simple parser which creates the basic component paths @@ -53,12 +59,6 @@ export default class URI { && typeof (thing).scheme === 'string'; } - private static _empty = ''; - private static _slash = '/'; - private static _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; - private static _driveLetterPath = /^\/[a-zA-Z]:/; - private static _upperCaseDrive = /^(\/)?([A-Z]:)/; - /** * scheme is the 'http' part of 'http://www.msft.com/some/path?query#fragment'. * The part before the first colon. @@ -86,21 +86,18 @@ export default class URI { */ readonly fragment: string; - private _formatted: string = null; - private _fsPath: string = null; - /** * @internal */ - private constructor(scheme: string, authority: string, path: string, query: string, fragment: string) { + protected constructor(scheme: string, authority: string, path: string, query: string, fragment: string) { - this.scheme = scheme || URI._empty; - this.authority = authority || URI._empty; - this.path = path || URI._empty; - this.query = query || URI._empty; - this.fragment = fragment || URI._empty; + this.scheme = scheme || _empty; + this.authority = authority || _empty; + this.path = path || _empty; + this.query = query || _empty; + this.fragment = fragment || _empty; - this._validate(this); + URI._validate(this); } // ---- filesystem path ----------------------- @@ -112,24 +109,7 @@ export default class URI { * invalid characters and semantics. Will *not* look at the scheme of this URI. */ get fsPath(): string { - if (!this._fsPath) { - let value: string; - if (this.authority && this.path && this.scheme === 'file') { - // unc path: file://shares/c$/far/boo - value = `//${this.authority}${this.path}`; - } else if (URI._driveLetterPath.test(this.path)) { - // windows drive letter: file:///c:/far/boo - value = this.path[1].toLowerCase() + this.path.substr(2); - } else { - // other path - value = this.path; - } - if (platform.isWindows) { - value = value.replace(/\//g, '\\'); - } - this._fsPath = value; - } - return this._fsPath; + throw new Error('not implemented'); } // ---- modify to new ------------------------- @@ -176,43 +156,43 @@ export default class URI { return this; } - return new URI(scheme, authority, path, query, fragment); + return new UriWithCache(scheme, authority, path, query, fragment); } // ---- parse & validate ------------------------ public static parse(value: string): URI { - const match = URI._regexp.exec(value); + const match = _regexp.exec(value); if (!match) { - return new URI(URI._empty, URI._empty, URI._empty, URI._empty, URI._empty); + return new UriWithCache(_empty, _empty, _empty, _empty, _empty); } - return new URI( - match[2] || URI._empty, - decodeURIComponent(match[4] || URI._empty), - decodeURIComponent(match[5] || URI._empty), - decodeURIComponent(match[7] || URI._empty), - decodeURIComponent(match[9] || URI._empty), + return new UriWithCache( + match[2] || _empty, + decodeURIComponent(match[4] || _empty), + decodeURIComponent(match[5] || _empty), + decodeURIComponent(match[7] || _empty), + decodeURIComponent(match[9] || _empty), ); } public static file(path: string): URI { - let authority = URI._empty; + let authority = _empty; // normalize to fwd-slashes on windows, // on other systems bwd-slashes are valid // filename character, eg /f\oo/ba\r.txt if (platform.isWindows) { - path = path.replace(/\\/g, URI._slash); + path = path.replace(/\\/g, _slash); } // check for authority as used in UNC shares // or use the path as given - if (path[0] === URI._slash && path[0] === path[1]) { - let idx = path.indexOf(URI._slash, 2); + if (path[0] === _slash && path[0] === path[1]) { + let idx = path.indexOf(_slash, 2); if (idx === -1) { authority = path.substring(2); - path = URI._empty; + path = _empty; } else { authority = path.substring(2, idx); path = path.substring(idx); @@ -221,15 +201,15 @@ export default class URI { // Ensure that path starts with a slash // or that it is at least a slash - if (path[0] !== URI._slash) { - path = URI._slash + path; + if (path[0] !== _slash) { + path = _slash + path; } - return new URI('file', authority, path, URI._empty, URI._empty); + return new UriWithCache('file', authority, path, _empty, _empty); } public static from(components: { scheme?: string; authority?: string; path?: string; query?: string; fragment?: string }): URI { - return new URI( + return new UriWithCache( components.scheme, components.authority, components.path, @@ -242,7 +222,7 @@ export default class URI { private static _singleSlashStart = /^\//; private static _doubleSlashStart = /^\/\//; - private _validate(ret: URI): void { + private static _validate(ret: URI): void { // scheme, https://tools.ietf.org/html/rfc3986#section-3.1 // ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) if (ret.scheme && !URI._schemePattern.test(ret.scheme)) { @@ -273,15 +253,90 @@ export default class URI { * * @param skipEncoding Do not encode the result, default is `false` */ + public toString(skipEncoding: boolean = false): string { + throw new Error('not implemented'); + } + + public toJSON(): any { + const res = { + $mid: 1, + fsPath: this.fsPath, + external: this.toString(), + }; + + if (this.path) { + res.path = this.path; + } + + if (this.scheme) { + res.scheme = this.scheme; + } + + if (this.authority) { + res.authority = this.authority; + } + + if (this.query) { + res.query = this.query; + } + + if (this.fragment) { + res.fragment = this.fragment; + } + + return res; + } + + static revive(data: any): URI { + let result = new UriWithCache( + (data).scheme, + (data).authority, + (data).path, + (data).query, + (data).fragment + ); + result._fsPath = (data).fsPath; + result._formatted = (data).external; + return result; + } +} + + +class UriWithCache extends URI { + + _formatted: string = null; + _fsPath: string = null; + + get fsPath(): string { + if (!this._fsPath) { + let value: string; + if (this.authority && this.path && this.scheme === 'file') { + // unc path: file://shares/c$/far/boo + value = `//${this.authority}${this.path}`; + } else if (_driveLetterPath.test(this.path)) { + // windows drive letter: file:///c:/far/boo + value = this.path[1].toLowerCase() + this.path.substr(2); + } else { + // other path + value = this.path; + } + if (platform.isWindows) { + value = value.replace(/\//g, '\\'); + } + this._fsPath = value; + } + return this._fsPath; + } + public toString(skipEncoding: boolean = false): string { if (!skipEncoding) { if (!this._formatted) { - this._formatted = URI._asFormatted(this, false); + this._formatted = UriWithCache._asFormatted(this, false); } return this._formatted; } else { // we don't cache that - return URI._asFormatted(this, true); + return UriWithCache._asFormatted(this, true); } } @@ -323,7 +378,7 @@ export default class URI { } if (path) { // lower-case windows drive letters in /C:/fff or C:/fff - const m = URI._upperCaseDrive.exec(path); + const m = _upperCaseDrive.exec(path); if (m) { if (m[1]) { path = '/' + m[2].toLowerCase() + path.substr(3); // "/c:".length === 3 @@ -338,12 +393,12 @@ export default class URI { // cannot be parsed back again let lastIdx = 0; while (true) { - let idx = path.indexOf(URI._slash, lastIdx); + let idx = path.indexOf(_slash, lastIdx); if (idx === -1) { parts.push(encoder(path.substring(lastIdx))); break; } - parts.push(encoder(path.substring(lastIdx, idx)), URI._slash); + parts.push(encoder(path.substring(lastIdx, idx)), _slash); lastIdx = idx + 1; }; } @@ -354,50 +409,7 @@ export default class URI { parts.push('#', encoder(fragment)); } - return parts.join(URI._empty); - } - - public toJSON(): any { - const res = { - fsPath: this.fsPath, - external: this.toString(), - $mid: 1 - }; - - if (this.path) { - res.path = this.path; - } - - if (this.scheme) { - res.scheme = this.scheme; - } - - if (this.authority) { - res.authority = this.authority; - } - - if (this.query) { - res.query = this.query; - } - - if (this.fragment) { - res.fragment = this.fragment; - } - - return res; - } - - static revive(data: any): URI { - let result = new URI( - (data).scheme, - (data).authority, - (data).path, - (data).query, - (data).fragment - ); - result._fsPath = (data).fsPath; - result._formatted = (data).external; - return result; + return parts.join(_empty); } } diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 47bcdcb64a5..01c65895a1f 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1179,6 +1179,11 @@ declare module 'vscode' { */ static parse(value: string): Uri; + /** + * Use the `file` and `parse` factory functions to create new `Uri` objects. + */ + private constructor(scheme: string, authority: string, path: string, query: string, fragment: string); + /** * Scheme is the `http` part of `http://www.msft.com/some/path?query#fragment`. * The part before the first colon. diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 7f06becd069..c214f3d93cc 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -592,7 +592,7 @@ export function createApiFactory( TextEditorRevealType: extHostTypes.TextEditorRevealType, TextEditorSelectionChangeKind: extHostTypes.TextEditorSelectionChangeKind, DecorationRangeBehavior: extHostTypes.DecorationRangeBehavior, - Uri: URI, + Uri: URI, ViewColumn: extHostTypes.ViewColumn, WorkspaceEdit: extHostTypes.WorkspaceEdit, ProgressLocation: extHostTypes.ProgressLocation, @@ -609,7 +609,7 @@ export function createApiFactory( Task: extHostTypes.Task, ConfigurationTarget: extHostTypes.ConfigurationTarget, - // TODO@JOH + // TODO@JOH,remote FileChangeType: FileChangeType, FileType: FileType }; From 1da857a4417634ce55f686f0cd7c0c12697b680f Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 21 Sep 2017 10:12:32 +0200 Subject: [PATCH 132/281] debt - move more static props out --- src/vs/base/common/uri.ts | 60 +++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index fbf1903da3f..e5e97ac6342 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -21,6 +21,35 @@ function encodeNoop(str: string): string { } +const _schemePattern = /^\w[\w\d+.-]*$/; +const _singleSlashStart = /^\//; +const _doubleSlashStart = /^\/\//; + +function _validateUri(ret: URI): void { + // scheme, https://tools.ietf.org/html/rfc3986#section-3.1 + // ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + if (ret.scheme && !_schemePattern.test(ret.scheme)) { + throw new Error('[UriError]: Scheme contains illegal characters.'); + } + + // path, http://tools.ietf.org/html/rfc3986#section-3.3 + // If a URI contains an authority component, then the path component + // must either be empty or begin with a slash ("/") character. If a URI + // does not contain an authority component, then the path cannot begin + // with two slash characters ("//"). + if (ret.path) { + if (ret.authority) { + if (!_singleSlashStart.test(ret.path)) { + throw new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character'); + } + } else { + if (_doubleSlashStart.test(ret.path)) { + throw new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")'); + } + } + } +} + const _empty = ''; const _slash = '/'; const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; @@ -97,7 +126,7 @@ export default class URI { this.query = query || _empty; this.fragment = fragment || _empty; - URI._validate(this); + _validateUri(this); } // ---- filesystem path ----------------------- @@ -218,35 +247,6 @@ export default class URI { ); } - private static _schemePattern = /^\w[\w\d+.-]*$/; - private static _singleSlashStart = /^\//; - private static _doubleSlashStart = /^\/\//; - - private static _validate(ret: URI): void { - // scheme, https://tools.ietf.org/html/rfc3986#section-3.1 - // ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) - if (ret.scheme && !URI._schemePattern.test(ret.scheme)) { - throw new Error('[UriError]: Scheme contains illegal characters.'); - } - - // path, http://tools.ietf.org/html/rfc3986#section-3.3 - // If a URI contains an authority component, then the path component - // must either be empty or begin with a slash ("/") character. If a URI - // does not contain an authority component, then the path cannot begin - // with two slash characters ("//"). - if (ret.path) { - if (ret.authority) { - if (!URI._singleSlashStart.test(ret.path)) { - throw new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character'); - } - } else { - if (URI._doubleSlashStart.test(ret.path)) { - throw new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")'); - } - } - } - } - // ---- printing/externalize --------------------------- /** From 8e09e96481f85e2682ef226475dc628bc2614908 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 21 Sep 2017 10:43:24 +0200 Subject: [PATCH 133/281] Fix #34403 --- .../preferences/browser/keybindingsEditor.ts | 4 ++ .../browser/preferences.contribution.ts | 13 +++- .../preferences/browser/preferencesEditor.ts | 72 ++++++++++++++++++- .../preferences/browser/preferencesWidgets.ts | 22 ------ .../parts/preferences/common/preferences.ts | 5 ++ .../electron-browser/terminal.contribution.ts | 2 +- 6 files changed, 92 insertions(+), 26 deletions(-) diff --git a/src/vs/workbench/parts/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/parts/preferences/browser/keybindingsEditor.ts index acd16f4f9f3..895d2d310e4 100644 --- a/src/vs/workbench/parts/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/parts/preferences/browser/keybindingsEditor.ts @@ -251,6 +251,10 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.searchWidget.focus(); } + clearSearchResults(): void { + this.searchWidget.clear(); + } + showConflicts(keybindingEntry: IKeybindingItemEntry): TPromise { const value = `"${keybindingEntry.keybindingItem.keybinding.getAriaLabel()}"`; if (value !== this.searchWidget.getValue()) { diff --git a/src/vs/workbench/parts/preferences/browser/preferences.contribution.ts b/src/vs/workbench/parts/preferences/browser/preferences.contribution.ts index 5000a14e095..94b32bee5a8 100644 --- a/src/vs/workbench/parts/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/parts/preferences/browser/preferences.contribution.ts @@ -20,7 +20,7 @@ import { KeybindingsEditor, KeybindingsEditorInput } from 'vs/workbench/parts/pr import { OpenGlobalSettingsAction, OpenGlobalKeybindingsAction, OpenGlobalKeybindingsFileAction, OpenWorkspaceSettingsAction, OpenFolderSettingsAction, ConfigureLanguageBasedSettingsAction } from 'vs/workbench/parts/preferences/browser/preferencesActions'; import { IPreferencesService, IKeybindingsEditor, CONTEXT_KEYBINDING_FOCUS, CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_SEARCH, - KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SHOW_CONFLICTS, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS + KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SHOW_CONFLICTS, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS } from 'vs/workbench/parts/preferences/common/preferences'; import { PreferencesService } from 'vs/workbench/parts/preferences/browser/preferencesService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -246,4 +246,15 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, + weight: KeybindingsRegistry.WEIGHT.workbenchContrib(), + when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS), + primary: KeyCode.Escape, + handler: (accessor, args: any) => { + const editor = accessor.get(IWorkbenchEditorService).getActiveEditor() as IKeybindingsEditor; + editor.clearSearchResults(); + } +}); + Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(PreferencesContentProvider); \ No newline at end of file diff --git a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts index 4df30ec8542..1fe5312055f 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts @@ -23,7 +23,7 @@ import { CodeEditor } from 'vs/editor/browser/codeEditor'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IPreferencesService, ISettingsGroup, ISetting, IFilterResult, - CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, ISettingsEditorModel + CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, ISettingsEditorModel, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING } from 'vs/workbench/parts/preferences/common/preferences'; import { SettingsEditorModel, DefaultSettingsEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels'; import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; @@ -140,7 +140,6 @@ export class PreferencesEditor extends BaseEditor { focusKey: this.focusSettingsContextKey })); this._register(this.searchWidget.onDidChange(value => this.filterPreferences(value.trim()))); - this._register(this.searchWidget.onNavigate(shift => this.preferencesRenderers.focusNextPreference(!shift))); this._register(this.searchWidget.onFocus(() => this.lastFocusedWidget = this.searchWidget)); this.lastFocusedWidget = this.searchWidget; @@ -156,6 +155,24 @@ export class PreferencesEditor extends BaseEditor { this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => this.onWorkbenchStateChanged())); } + public clearSearchResults(): void { + if (this.searchWidget) { + this.searchWidget.clear(); + } + } + + public focusNextResult(): void { + if (this.preferencesRenderers) { + this.preferencesRenderers.focusNextPreference(true); + } + } + + public focusPreviousResult(): void { + if (this.preferencesRenderers) { + this.preferencesRenderers.focusNextPreference(false); + } + } + public setInput(newInput: PreferencesEditorInput, options?: EditorOptions): TPromise { this.defaultSettingsEditorContextKey.set(true); const oldInput = this.input; @@ -959,3 +976,54 @@ const focusSettingsFileEditorCommand = new FocusSettingsFileEditorCommand({ kbOpts: { primary: KeyCode.DownArrow } }); KeybindingsRegistry.registerCommandAndKeybindingRule(focusSettingsFileEditorCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib())); + +class ClearSearchResultsCommand extends SettingsCommand { + + public runCommand(accessor: ServicesAccessor, args: any): void { + const preferencesEditor = this.getPreferencesEditor(accessor); + if (preferencesEditor) { + preferencesEditor.clearSearchResults(); + } + } + +} +const clearSearchResultsCommand = new ClearSearchResultsCommand({ + id: SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, + precondition: CONTEXT_SETTINGS_SEARCH_FOCUS, + kbOpts: { primary: KeyCode.Escape } +}); +KeybindingsRegistry.registerCommandAndKeybindingRule(clearSearchResultsCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib())); + +class FocusNextSearchResultCommand extends SettingsCommand { + + public runCommand(accessor: ServicesAccessor, args: any): void { + const preferencesEditor = this.getPreferencesEditor(accessor); + if (preferencesEditor) { + preferencesEditor.focusNextResult(); + } + } + +} +const focusNextSearchResultCommand = new FocusNextSearchResultCommand({ + id: SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, + precondition: CONTEXT_SETTINGS_SEARCH_FOCUS, + kbOpts: { primary: KeyCode.Enter } +}); +KeybindingsRegistry.registerCommandAndKeybindingRule(focusNextSearchResultCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib())); + +class FocusPreviousSearchResultCommand extends SettingsCommand { + + public runCommand(accessor: ServicesAccessor, args: any): void { + const preferencesEditor = this.getPreferencesEditor(accessor); + if (preferencesEditor) { + preferencesEditor.focusPreviousResult(); + } + } + +} +const focusPreviousSearchResultCommand = new FocusPreviousSearchResultCommand({ + id: SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, + precondition: CONTEXT_SETTINGS_SEARCH_FOCUS, + kbOpts: { primary: KeyMod.Shift | KeyCode.Enter } +}); +KeybindingsRegistry.registerCommandAndKeybindingRule(focusPreviousSearchResultCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib())); diff --git a/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts index 6decbcc4dd9..068499282ba 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts @@ -399,9 +399,6 @@ export class SearchWidget extends Widget { private _onDidChange: Emitter = this._register(new Emitter()); public readonly onDidChange: Event = this._onDidChange.event; - private _onNavigate: Emitter = this._register(new Emitter()); - public readonly onNavigate: Event = this._onNavigate.event; - private _onFocus: Emitter = this._register(new Emitter()); public readonly onFocus: Event = this._onFocus.event; @@ -447,7 +444,6 @@ export class SearchWidget extends Widget { const searchInput = DOM.append(this.searchContainer, DOM.$('div.settings-search-input')); this.inputBox = this._register(this.createInputBox(searchInput)); this._register(this.inputBox.onDidChange(value => this._onDidChange.fire(value))); - this.onkeydown(this.inputBox.inputElement, (e) => this._onKeyDown(e)); } protected createInputBox(parent: HTMLElement): InputBox { @@ -504,24 +500,6 @@ export class SearchWidget extends Widget { return this.inputBox.value = value; } - private _onKeyDown(keyboardEvent: IKeyboardEvent): void { - let handled = false; - switch (keyboardEvent.keyCode) { - case KeyCode.Enter: - this._onNavigate.fire(keyboardEvent.shiftKey); - handled = true; - break; - case KeyCode.Escape: - this.clear(); - handled = true; - break; - } - if (handled) { - keyboardEvent.preventDefault(); - keyboardEvent.stopPropagation(); - } - } - public dispose(): void { if (this.options.focusKey) { this.options.focusKey.set(false); diff --git a/src/vs/workbench/parts/preferences/common/preferences.ts b/src/vs/workbench/parts/preferences/common/preferences.ts index 71e9d348b59..1b7200927c9 100644 --- a/src/vs/workbench/parts/preferences/common/preferences.ts +++ b/src/vs/workbench/parts/preferences/common/preferences.ts @@ -91,6 +91,7 @@ export interface IKeybindingsEditor extends IEditor { activeKeybindingEntry: IKeybindingItemEntry; search(filter: string): void; + clearSearchResults(): void; focusKeybindings(): void; defineKeybinding(keybindingEntry: IKeybindingItemEntry): TPromise; removeKeybinding(keybindingEntry: IKeybindingItemEntry): TPromise; @@ -118,8 +119,12 @@ export const CONTEXT_KEYBINDINGS_SEARCH_FOCUS = new RawContextKey('inKe export const CONTEXT_KEYBINDING_FOCUS = new RawContextKey('keybindingFocus', false); export const SETTINGS_EDITOR_COMMAND_SEARCH = 'settings.action.search'; +export const SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS = 'settings.action.clearSearchResults'; +export const SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING = 'settings.action.focusNextSetting'; +export const SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING = 'settings.action.focusPreviousSetting'; export const SETTINGS_EDITOR_COMMAND_FOCUS_FILE = 'settings.action.focusSettingsFile'; export const KEYBINDINGS_EDITOR_COMMAND_SEARCH = 'keybindings.editor.searchKeybindings'; +export const KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS = 'keybindings.editor.clearSearchResults'; export const KEYBINDINGS_EDITOR_COMMAND_DEFINE = 'keybindings.editor.defineKeybinding'; export const KEYBINDINGS_EDITOR_COMMAND_REMOVE = 'keybindings.editor.removeKeybinding'; export const KEYBINDINGS_EDITOR_COMMAND_RESET = 'keybindings.editor.resetKeybinding'; diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts index 9b937f11ea5..a3c434dacd3 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts @@ -343,7 +343,7 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusTerminalFin }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Find Widget', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(HideTerminalFindWidgetAction, HideTerminalFindWidgetAction.ID, HideTerminalFindWidgetAction.LABEL, { primary: KeyCode.Escape, - secondary: [KeyCode.Shift | KeyCode.Escape] + secondary: [KeyMod.Shift | KeyCode.Escape] }, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE)), 'Terminal: Hide Find Widget', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowNextFindTermTerminalFindWidgetAction, ShowNextFindTermTerminalFindWidgetAction.ID, ShowNextFindTermTerminalFindWidgetAction.LABEL, { primary: KeyMod.Alt | KeyCode.DownArrow From ad4b098a4aa4799e9f65e3c7aacd4215a8a08f03 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 21 Sep 2017 10:51:29 +0200 Subject: [PATCH 134/281] Cache content widgets dimensions (#34716) --- .../contentWidgets/contentWidgets.ts | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts index 15adceca2e1..4919348fae9 100644 --- a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts +++ b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts @@ -174,6 +174,9 @@ class Widget { private _position: IPosition; private _preference: ContentWidgetPositionPreference[]; + private _cachedDomNodeClientWidth: number; + private _cachedDomNodeClientHeight: number; + private _maxWidth: number; private _isVisible: boolean; private _renderData: Coordinate; @@ -194,11 +197,13 @@ class Widget { this._position = null; this._preference = null; + this._cachedDomNodeClientWidth = -1; + this._cachedDomNodeClientHeight = -1; + this._maxWidth = this._getMaxWidth(); this._isVisible = false; this._renderData = null; this.domNode.setPosition((this._fixedOverflowWidgets && this.allowEditorOverflow) ? 'fixed' : 'absolute'); - this._updateMaxWidth(); this.domNode.setVisibility('hidden'); this.domNode.setAttribute('widgetId', this.id); } @@ -210,22 +215,23 @@ class Widget { if (e.layoutInfo) { this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; this._contentWidth = this._context.configuration.editor.layoutInfo.contentWidth; - - this._updateMaxWidth(); + this._maxWidth = this._getMaxWidth(); } } - private _updateMaxWidth(): void { - const maxWidth = this.allowEditorOverflow - ? window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth - : this._contentWidth; - - this.domNode.setMaxWidth(maxWidth); + private _getMaxWidth(): number { + return ( + this.allowEditorOverflow + ? window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth + : this._contentWidth + ); } public setPosition(position: IPosition, preference: ContentWidgetPositionPreference[]): void { this._position = position; this._preference = preference; + this._cachedDomNodeClientWidth = -1; + this._cachedDomNodeClientHeight = -1; } private _layoutBoxInViewport(topLeft: Coordinate, width: number, height: number, ctx: RenderingContext): IBoxLayoutResult { @@ -348,14 +354,17 @@ class Widget { return; } - const domNode = this.domNode.domNode; - const width = domNode.clientWidth; - const height = domNode.clientHeight; + if (this._cachedDomNodeClientWidth === -1 || this._cachedDomNodeClientHeight === -1) { + const domNode = this.domNode.domNode; + this.domNode.setMaxWidth(this._maxWidth); + this._cachedDomNodeClientWidth = domNode.clientWidth; + this._cachedDomNodeClientHeight = domNode.clientHeight; + } if (this.allowEditorOverflow) { - placement = this._layoutBoxInPage(topLeft, width, height, ctx); + placement = this._layoutBoxInPage(topLeft, this._cachedDomNodeClientWidth, this._cachedDomNodeClientHeight, ctx); } else { - placement = this._layoutBoxInViewport(topLeft, width, height, ctx); + placement = this._layoutBoxInViewport(topLeft, this._cachedDomNodeClientWidth, this._cachedDomNodeClientHeight, ctx); } }; From c7630e18588f42975e286018e7691fc7c2047331 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 21 Sep 2017 10:46:59 +0200 Subject: [PATCH 135/281] add filters, #13807 --- src/vs/vscode.proposed.d.ts | 8 ++++--- .../api/electron-browser/mainThreadDialogs.ts | 21 +++++++++++++------ src/vs/workbench/api/node/extHost.protocol.ts | 6 ++++-- src/vs/workbench/api/node/extHostDialogs.ts | 4 ++-- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 6ed9537d1b6..b16f3b17adb 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -8,16 +8,18 @@ declare module 'vscode' { export interface OpenDialogOptions { - defaultResource?: Uri; + defaultUri?: Uri; openLabel?: string; openFiles?: boolean; openFolders?: boolean; openMany?: boolean; + filters: { [name: string]: string[] }; } export interface SaveDialogOptions { - defaultResource?: Uri; + defaultUri?: Uri; saveLabel?: string; + filters: { [name: string]: string[] }; } export namespace window { @@ -228,4 +230,4 @@ declare module 'vscode' { export namespace languages { export function registerColorProvider(selector: DocumentSelector, provider: DocumentColorProvider): Disposable; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/api/electron-browser/mainThreadDialogs.ts b/src/vs/workbench/api/electron-browser/mainThreadDialogs.ts index 1ec24d28977..b79710c297b 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDialogs.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDialogs.ts @@ -9,6 +9,7 @@ import { isFalsyOrEmpty } from 'vs/base/common/arrays'; import { MainThreadDiaglogsShape, MainContext, IExtHostContext, MainThreadDialogOpenOptions, MainThreadDialogSaveOptions } from '../node/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import { IWindowService } from 'vs/platform/windows/common/windows'; +import { forEach } from 'vs/base/common/collections'; @extHostNamedCustomer(MainContext.MainThreadDialogs) export class MainThreadDialogs implements MainThreadDiaglogsShape { @@ -26,7 +27,7 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape { $showOpenDialog(options: MainThreadDialogOpenOptions): TPromise { // TODO@joh what about remote dev setup? - if (options.defaultResource && options.defaultResource.scheme !== 'file') { + if (options.defaultUri && options.defaultUri.scheme !== 'file') { return TPromise.wrapError(new Error('bad path')); } return new TPromise(resolve => { @@ -39,7 +40,7 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape { $showSaveDialog(options: MainThreadDialogSaveOptions): TPromise { // TODO@joh what about remote dev setup? - if (options.defaultResource && options.defaultResource.scheme !== 'file') { + if (options.defaultUri && options.defaultUri.scheme !== 'file') { return TPromise.wrapError(new Error('bad path')); } return new TPromise(resolve => { @@ -57,8 +58,8 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape { if (options.openLabel) { result.buttonLabel = options.openLabel; } - if (options.defaultResource) { - result.defaultPath = options.defaultResource.fsPath; + if (options.defaultUri) { + result.defaultPath = options.defaultUri.fsPath; } if (!options.openFiles && !options.openFolders) { options.openFiles = true; @@ -72,6 +73,10 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape { if (options.openMany) { result.properties.push('multiSelections'); } + if (options.filters) { + result.filters = []; + forEach(options.filters, entry => result.filters.push({ name: entry.key, extensions: entry.value })); + } return result; } @@ -79,12 +84,16 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape { const result: Electron.SaveDialogOptions = { }; - if (options.defaultResource) { - result.defaultPath = options.defaultResource.fsPath; + if (options.defaultUri) { + result.defaultPath = options.defaultUri.fsPath; } if (options.saveLabel) { result.buttonLabel = options.saveLabel; } + if (options.filters) { + result.filters = []; + forEach(options.filters, entry => result.filters.push({ name: entry.key, extensions: entry.value })); + } return result; } } diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 61ae052f117..8c89933b9bb 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -116,16 +116,18 @@ export interface MainThreadDiagnosticsShape extends IDisposable { } export interface MainThreadDialogOpenOptions { - defaultResource?: URI; + defaultUri?: URI; openLabel?: string; openFiles?: boolean; openFolders?: boolean; openMany?: boolean; + filters: { [name: string]: string[] }; } export interface MainThreadDialogSaveOptions { - defaultResource?: URI; + defaultUri?: URI; saveLabel?: string; + filters: { [name: string]: string[] }; } export interface MainThreadDiaglogsShape extends IDisposable { diff --git a/src/vs/workbench/api/node/extHostDialogs.ts b/src/vs/workbench/api/node/extHostDialogs.ts index 48af26e7928..fc0bc2b807c 100644 --- a/src/vs/workbench/api/node/extHostDialogs.ts +++ b/src/vs/workbench/api/node/extHostDialogs.ts @@ -17,13 +17,13 @@ export class ExtHostDialogs { } showOpenDialog(options: vscode.OpenDialogOptions): Thenable { - return this._proxy.$showOpenDialog(options).then(filepaths => { + return this._proxy.$showOpenDialog(options).then(filepaths => { return filepaths && filepaths.map(URI.file); }); } showSaveDialog(options: vscode.SaveDialogOptions): Thenable { - return this._proxy.$showSaveDialog(options).then(filepath => { + return this._proxy.$showSaveDialog(options).then(filepath => { return filepath && URI.file(filepath); }); } From 97de616d0111c2604167000208853e0e7b4c3ea5 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 21 Sep 2017 10:55:26 +0200 Subject: [PATCH 136/281] add jsdoc, #13807 --- src/vs/vscode.proposed.d.ts | 69 +++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index b16f3b17adb..0f646e694b4 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -8,23 +8,88 @@ declare module 'vscode' { export interface OpenDialogOptions { + /** + * The resource the dialog shows when opened. + */ defaultUri?: Uri; + + /** + * A human-readable string for the open button. + */ openLabel?: string; + + /** + * Only allow to select files. *Note* that not all operating systems support + * to select files and folders in one dialog instance. + */ openFiles?: boolean; + + /** + * Only allow to select folders. *Note* that not all operating systems support + * to select files and folders in one dialog instance. + */ openFolders?: boolean; + + /** + * Allow to select many files or folders. + */ openMany?: boolean; + + /** + * A set of file filters that are shown in the dialog, e.g. + * ```ts + * { + * ['Images']: ['*.png', '*.jpg'] + * ['TypeScript']: ['*.ts', '*.tsx'] + * } + * ``` + */ filters: { [name: string]: string[] }; } + /** + * Options to configure the behaviour of a file save dialog + */ export interface SaveDialogOptions { + /** + * The resource the dialog shows when opened. + */ defaultUri?: Uri; + + /** + * A human-readable string for the save button. + */ saveLabel?: string; + + /** + * A set of file filters that are shown in the dialog, e.g. + * ```ts + * { + * ['Images']: ['*.png', '*.jpg'] + * ['TypeScript']: ['*.ts', '*.tsx'] + * } + * ``` + */ filters: { [name: string]: string[] }; } export namespace window { - export function showOpenDialog(options: OpenDialogOptions): Thenable; - export function showSaveDialog(options: SaveDialogOptions): Thenable; + + /** + * Shows a file open dialog to the user. + * + * @param options Options that control the dialog. + * @returns A promise that resolves to the selected resources or `undefined`. + */ + export function showOpenDialog(options: OpenDialogOptions): Thenable; + + /** + * Shows a file save dialog to the user. + * + * @param options Options that control the dialog. + * @returns A promise that resolves to the selected resource or `undefined`. + */ + export function showSaveDialog(options: SaveDialogOptions): Thenable; /** * Shows a selection list of [workspace folders](#workspace.workspaceFolders) to pick from. From 5b3b44613efe46a26c5ea8f3e035128efdef0663 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 21 Sep 2017 10:56:32 +0200 Subject: [PATCH 137/281] one more comment #13807 --- src/vs/vscode.proposed.d.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 0f646e694b4..0f5a2f26714 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -7,6 +7,9 @@ declare module 'vscode' { + /** + * Options to configure the behaviour of a file open dialog. + */ export interface OpenDialogOptions { /** * The resource the dialog shows when opened. @@ -48,7 +51,7 @@ declare module 'vscode' { } /** - * Options to configure the behaviour of a file save dialog + * Options to configure the behaviour of a file save dialog. */ export interface SaveDialogOptions { /** From 14699ba54eb57e73eb61a503421659eb04f41749 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 21 Sep 2017 11:08:54 +0200 Subject: [PATCH 138/281] add --install-source to cli process --- .../electron-browser/sharedProcessMain.ts | 4 ++-- src/vs/code/electron-main/app.ts | 2 +- src/vs/code/node/cli.ts | 5 ++++- src/vs/code/node/cliProcessMain.ts | 19 +++++++++++++++---- .../environment/common/environment.ts | 3 +++ src/vs/platform/environment/node/argv.ts | 3 ++- .../environment/node/environmentService.ts | 12 ++++++++++++ .../telemetry/node/commonProperties.ts | 3 ++- .../node/workbenchCommonProperties.ts | 4 ++-- .../electron-browser/commonProperties.test.ts | 8 +++++--- src/vs/workbench/electron-browser/shell.ts | 2 +- 11 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/vs/code/electron-browser/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcessMain.ts index ef7a31319cf..3e7149a8103 100644 --- a/src/vs/code/electron-browser/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcessMain.ts @@ -98,7 +98,7 @@ function main(server: Server, initData: ISharedProcessInitData): void { server.registerChannel('telemetryAppender', new TelemetryAppenderChannel(appender)); const services = new ServiceCollection(); - const { appRoot, extensionsPath, extensionDevelopmentPath, isBuilt, extensionTestsPath } = accessor.get(IEnvironmentService); + const { appRoot, extensionsPath, extensionDevelopmentPath, isBuilt, extensionTestsPath, installSource } = accessor.get(IEnvironmentService); if (isBuilt && !extensionDevelopmentPath && product.enableTelemetry) { const disableStorage = !!extensionTestsPath; // never keep any state when running extension tests! @@ -107,7 +107,7 @@ function main(server: Server, initData: ISharedProcessInitData): void { const config: ITelemetryServiceConfig = { appender, - commonProperties: resolveCommonProperties(product.commit, pkg.version) + commonProperties: resolveCommonProperties(product.commit, pkg.version, installSource) .then(result => Object.defineProperty(result, 'common.machineId', { get: () => storageService.get(machineIdStorageKey), enumerable: true diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 51b6db552f4..db62b2c15e1 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -294,7 +294,7 @@ export class CodeApplication { if (this.environmentService.isBuilt && !this.environmentService.isExtensionDevelopment && !!product.enableTelemetry) { const channel = getDelayedChannel(this.sharedProcessClient.then(c => c.getChannel('telemetryAppender'))); const appender = new TelemetryAppenderClient(channel); - const commonProperties = resolveCommonProperties(product.commit, pkg.version) + const commonProperties = resolveCommonProperties(product.commit, pkg.version, this.environmentService.installSource) .then(result => Object.defineProperty(result, 'common.machineId', { get: () => this.storageService.getItem(machineIdStorageKey), enumerable: true diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index 7476115fcee..f528cfe4ce4 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -17,7 +17,10 @@ import * as os from 'os'; import { whenDeleted } from 'vs/base/node/pfs'; function shouldSpawnCliProcess(argv: ParsedArgs): boolean { - return argv['list-extensions'] || !!argv['install-extension'] || !!argv['uninstall-extension']; + return !!argv['install-source'] + || !!argv['list-extensions'] + || !!argv['install-extension'] + || !!argv['uninstall-extension']; } interface IMainCli { diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 3ac32af3401..a09c9c3685e 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -7,6 +7,7 @@ import { localize } from 'vs/nls'; import product from 'vs/platform/node/product'; import pkg from 'vs/platform/node/package'; import * as path from 'path'; +import * as fs from 'fs'; import { TPromise } from 'vs/base/common/winjs.base'; import { sequence } from 'vs/base/common/async'; @@ -16,7 +17,7 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; -import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; +import { EnvironmentService, getInstallSourcePath } from 'vs/platform/environment/node/environmentService'; import { IExtensionManagementService, IExtensionGalleryService, IExtensionManifest, IGalleryExtension, LocalExtensionType } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; @@ -50,6 +51,7 @@ type Task = { (): TPromise }; class Main { constructor( + @IEnvironmentService private environmentService: IEnvironmentService, @IExtensionManagementService private extensionManagementService: IExtensionManagementService, @IExtensionGalleryService private extensionGalleryService: IExtensionGalleryService ) { } @@ -57,7 +59,9 @@ class Main { run(argv: ParsedArgs): TPromise { // TODO@joao - make this contributable - if (argv['list-extensions']) { + if (argv['install-source']) { + return this.setInstallSource(argv['install-source']); + } else if (argv['list-extensions']) { return this.listExtensions(argv['show-versions']); } else if (argv['install-extension']) { const arg = argv['install-extension']; @@ -71,6 +75,13 @@ class Main { return undefined; } + private setInstallSource(installSource: string): TPromise { + return new TPromise((c, e) => { + const path = getInstallSourcePath(this.environmentService.userDataPath); + fs.writeFile(path, installSource.slice(0, 30), 'utf8', err => err ? e(err) : c(null)); + }); + } + private listExtensions(showVersions: boolean): TPromise { return this.extensionManagementService.getInstalled(LocalExtensionType.User).then(extensions => { extensions.forEach(e => console.log(getId(e.manifest, showVersions))); @@ -161,7 +172,7 @@ export function main(argv: ParsedArgs): TPromise { const envService = accessor.get(IEnvironmentService); return TPromise.join([envService.appSettingsHome, envService.extensionsPath].map(p => mkdirp(p))).then(() => { - const { appRoot, extensionsPath, extensionDevelopmentPath, isBuilt } = envService; + const { appRoot, extensionsPath, extensionDevelopmentPath, isBuilt, installSource } = envService; const services = new ServiceCollection(); services.set(IConfigurationService, new SyncDescriptor(ConfigurationService)); @@ -183,7 +194,7 @@ export function main(argv: ParsedArgs): TPromise { const config: ITelemetryServiceConfig = { appender: combinedAppender(...appenders), - commonProperties: resolveCommonProperties(product.commit, pkg.version), + commonProperties: resolveCommonProperties(product.commit, pkg.version, installSource), piiPaths: [appRoot, extensionsPath] }; diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 0741cac9892..e236455b8d0 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -42,6 +42,7 @@ export interface ParsedArgs { 'skip-getting-started'?: boolean; 'sticky-quickopen'?: boolean; 'export-default-configuration'?: string; + 'install-source'?: string; } export const IEnvironmentService = createDecorator('environmentService'); @@ -102,4 +103,6 @@ export interface IEnvironmentService { sharedIPCHandle: string; nodeCachedDataDir: string; + + installSource: string; } diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 1bcf77bddbe..7b2b9c660c1 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -27,7 +27,8 @@ const options: minimist.Opts = { 'debugBrkSearch', 'open-url', 'enable-proposed-api', - 'export-default-configuration' + 'export-default-configuration', + 'install-source' ], boolean: [ 'help', diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index 01222188e6a..3e4a655e365 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -52,6 +52,10 @@ function getIPCHandle(userDataPath: string, type: string): string { } } +export function getInstallSourcePath(userDataPath: string): string { + return path.join(userDataPath, 'installSource'); +} + export class EnvironmentService implements IEnvironmentService { _serviceBrand: any; @@ -143,6 +147,8 @@ export class EnvironmentService implements IEnvironmentService { readonly machineUUID: string; + readonly installSource: string; + constructor(private _args: ParsedArgs, private _execPath: string) { const machineIdPath = path.join(this.userDataPath, 'machineid'); @@ -161,6 +167,12 @@ export class EnvironmentService implements IEnvironmentService { console.warn('Could not store machine ID'); } } + + try { + this.installSource = fs.readFileSync(getInstallSourcePath(this.userDataPath), 'utf8').slice(0, 30); + } catch (err) { + this.installSource = ''; + } } } diff --git a/src/vs/platform/telemetry/node/commonProperties.ts b/src/vs/platform/telemetry/node/commonProperties.ts index 5e6611497c3..ea27f5c5b6c 100644 --- a/src/vs/platform/telemetry/node/commonProperties.ts +++ b/src/vs/platform/telemetry/node/commonProperties.ts @@ -11,7 +11,7 @@ import * as uuid from 'vs/base/common/uuid'; export const machineIdStorageKey = 'telemetry.machineId'; export const machineIdIpcChannel = 'vscode:machineId'; -export function resolveCommonProperties(commit: string, version: string): TPromise<{ [name: string]: string; }> { +export function resolveCommonProperties(commit: string, version: string, source: string): TPromise<{ [name: string]: string; }> { const result: { [name: string]: string; } = Object.create(null); result['sessionID'] = uuid.generateUuid() + Date.now(); @@ -21,6 +21,7 @@ export function resolveCommonProperties(commit: string, version: string): TPromi result['common.platform'] = Platform.Platform[Platform.platform]; result['common.nodePlatform'] = process.platform; result['common.nodeArch'] = process.arch; + result['common.source'] = source; // dynamic properties which value differs on each call let seq = 0; diff --git a/src/vs/platform/telemetry/node/workbenchCommonProperties.ts b/src/vs/platform/telemetry/node/workbenchCommonProperties.ts index 58443e27c9b..c6a5772af49 100644 --- a/src/vs/platform/telemetry/node/workbenchCommonProperties.ts +++ b/src/vs/platform/telemetry/node/workbenchCommonProperties.ts @@ -14,8 +14,8 @@ import { resolveCommonProperties, machineIdStorageKey } from '../node/commonProp const SQM_KEY: string = '\\Software\\Microsoft\\SQMClient'; -export function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string, version: string): TPromise<{ [name: string]: string }> { - return resolveCommonProperties(commit, version).then(result => { +export function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string, version: string, source: string): TPromise<{ [name: string]: string }> { + return resolveCommonProperties(commit, version, source).then(result => { result['common.version.shell'] = process.versions && (process).versions['electron']; result['common.version.renderer'] = process.versions && (process).versions['chrome']; result['common.osVersion'] = os.release(); diff --git a/src/vs/platform/telemetry/test/electron-browser/commonProperties.test.ts b/src/vs/platform/telemetry/test/electron-browser/commonProperties.test.ts index 810f50728c5..d57e87fbec5 100644 --- a/src/vs/platform/telemetry/test/electron-browser/commonProperties.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/commonProperties.test.ts @@ -14,6 +14,7 @@ suite('Telemetry - common properties', function () { const commit = void 0; const version = void 0; + const source = void 0; let storageService; setup(() => { @@ -22,7 +23,7 @@ suite('Telemetry - common properties', function () { test('default', function () { - return resolveWorkbenchCommonProperties(storageService, commit, version).then(props => { + return resolveWorkbenchCommonProperties(storageService, commit, version, source).then(props => { assert.ok('commitHash' in props); assert.ok('sessionID' in props); @@ -37,6 +38,7 @@ suite('Telemetry - common properties', function () { // assert.ok('common.version.renderer' in first.data); assert.ok('common.osVersion' in props, 'osVersion'); assert.ok('version' in props); + assert.ok('common.source' in props); assert.ok('common.firstSessionDate' in props, 'firstSessionDate'); assert.ok('common.lastSessionDate' in props, 'lastSessionDate'); // conditional, see below, 'lastSessionDate'ow @@ -57,7 +59,7 @@ suite('Telemetry - common properties', function () { storageService.store('telemetry.lastSessionDate', new Date().toUTCString()); - return resolveWorkbenchCommonProperties(storageService, commit, version).then(props => { + return resolveWorkbenchCommonProperties(storageService, commit, version, source).then(props => { assert.ok('common.lastSessionDate' in props); // conditional, see below assert.ok('common.isNewSession' in props); @@ -66,7 +68,7 @@ suite('Telemetry - common properties', function () { }); test('values chance on ask', function () { - return resolveWorkbenchCommonProperties(storageService, commit, version).then(props => { + return resolveWorkbenchCommonProperties(storageService, commit, version, source).then(props => { let value1 = props['common.sequence']; let value2 = props['common.sequence']; assert.ok(value1 !== value2, 'seq'); diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index e188d34337d..fd99f05e00a 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -277,7 +277,7 @@ export class WorkbenchShell { const config: ITelemetryServiceConfig = { appender: new TelemetryAppenderClient(channel), - commonProperties: resolveWorkbenchCommonProperties(this.storageService, commit, version), + commonProperties: resolveWorkbenchCommonProperties(this.storageService, commit, version, this.environmentService.installSource), piiPaths: [this.environmentService.appRoot, this.environmentService.extensionsPath] }; From 04acf0fc0a7d564d247489b16280183bbb7e4d5f Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 21 Sep 2017 11:19:07 +0200 Subject: [PATCH 139/281] fix context for commands run from touchbar --- src/vs/code/electron-main/menus.ts | 24 ++++++++++++--------- src/vs/code/electron-main/window.ts | 8 +++---- src/vs/platform/windows/common/windows.ts | 5 +++++ src/vs/workbench/electron-browser/window.ts | 24 +++++++++++++++++---- 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 93a8260dcb5..3212e30b62a 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -10,7 +10,7 @@ import { isMacintosh, isLinux, isWindows, language } from 'vs/base/common/platfo import * as arrays from 'vs/base/common/arrays'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ipcMain as ipc, app, shell, dialog, Menu, MenuItem, BrowserWindow } from 'electron'; -import { OpenContext } from 'vs/platform/windows/common/windows'; +import { OpenContext, IRunActionInWindowRequest } from 'vs/platform/windows/common/windows'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IFilesConfiguration, AutoSaveConfiguration } from 'vs/platform/files/common/files'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -965,14 +965,14 @@ export class CodeMenu { const keyboardShortcutsUrl = isLinux ? product.keyboardShortcutsUrlLinux : isMacintosh ? product.keyboardShortcutsUrlMac : product.keyboardShortcutsUrlWin; arrays.coalesce([ - new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miWelcome', comment: ['&& denotes a mnemonic'] }, "&&Welcome")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'workbench.action.showWelcomePage'), enabled: (this.windowsService.getWindowCount() > 0) }), - new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miInteractivePlayground', comment: ['&& denotes a mnemonic'] }, "&&Interactive Playground")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'workbench.action.showInteractivePlayground'), enabled: (this.windowsService.getWindowCount() > 0) }), - product.documentationUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'workbench.action.openDocumentationUrl'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, - product.releaseNotesUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'update.showCurrentReleaseNotes'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, + new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miWelcome', comment: ['&& denotes a mnemonic'] }, "&&Welcome")), click: () => this.runActionInRenderer('workbench.action.showWelcomePage'), enabled: (this.windowsService.getWindowCount() > 0) }), + new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miInteractivePlayground', comment: ['&& denotes a mnemonic'] }, "&&Interactive Playground")), click: () => this.runActionInRenderer('workbench.action.showInteractivePlayground'), enabled: (this.windowsService.getWindowCount() > 0) }), + product.documentationUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation")), click: () => this.runActionInRenderer('workbench.action.openDocumentationUrl'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, + product.releaseNotesUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes")), click: () => this.runActionInRenderer('update.showCurrentReleaseNotes'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, __separator__(), - keyboardShortcutsUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'workbench.action.keybindingsReference'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, - product.introductoryVideosUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'workbench.action.openIntroductoryVideosUrl'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, - product.tipsAndTricksUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miTipsAndTricks', comment: ['&& denotes a mnemonic'] }, "&&Tips and Tricks")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'workbench.action.openTipsAndTricksUrl'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, + keyboardShortcutsUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference")), click: () => this.runActionInRenderer('workbench.action.keybindingsReference'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, + product.introductoryVideosUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos")), click: () => this.runActionInRenderer('workbench.action.openIntroductoryVideosUrl'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, + product.tipsAndTricksUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miTipsAndTricks', comment: ['&& denotes a mnemonic'] }, "&&Tips and Tricks")), click: () => this.runActionInRenderer('workbench.action.openTipsAndTricksUrl'), enabled: (this.windowsService.getWindowCount() > 0) }) : null, (product.introductoryVideosUrl || keyboardShortcutsUrl) ? __separator__() : null, product.twitterUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join us on Twitter")), click: () => this.openUrl(product.twitterUrl, 'openTwitterUrl') }) : null, product.requestFeatureUrl ? new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests")), click: () => this.openUrl(product.requestFeatureUrl, 'openUserVoiceUrl') }) : null, @@ -1113,7 +1113,7 @@ export class CodeMenu { commandId = this.isOptionClick(event) ? arg2[1] : arg2[0]; // support alternative action if we got multiple action Ids and the option key was pressed while invoking } - this.windowsService.sendToFocused('vscode:runAction', commandId); + this.runActionInRenderer(commandId); }; const enabled = typeof arg3 === 'boolean' ? arg3 : this.windowsService.getWindowCount() > 0; const checked = typeof arg4 === 'boolean' ? arg4 : false; @@ -1155,11 +1155,15 @@ export class CodeMenu { } // Finally execute command in Window - this.windowsService.sendToFocused('vscode:runAction', commandId); + this.runActionInRenderer(commandId); } })); } + private runActionInRenderer(id: string): void { + this.windowsService.sendToFocused('vscode:runAction', { id, from: 'menu' } as IRunActionInWindowRequest); + } + private withKeybinding(commandId: string, options: Electron.MenuItemConstructorOptions): Electron.MenuItemConstructorOptions { const binding = this.keybindingsResolver.getKeybinding(commandId); diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 5484771bf86..ce4af4dbc88 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -19,7 +19,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { parseArgs } from 'vs/platform/environment/node/argv'; import product from 'vs/platform/node/product'; import pkg from 'vs/platform/node/package'; -import { IWindowSettings, MenuBarVisibility, IWindowConfiguration, ReadyState } from 'vs/platform/windows/common/windows'; +import { IWindowSettings, MenuBarVisibility, IWindowConfiguration, ReadyState, IRunActionInWindowRequest } from 'vs/platform/windows/common/windows'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { KeyboardLayoutMonitor } from 'vs/code/electron-main/keyboard'; import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; @@ -443,9 +443,9 @@ export class CodeWindow implements ICodeWindow { } if (cmd === back) { - this.send('vscode:runAction', acrossEditors ? 'workbench.action.openPreviousRecentlyUsedEditor' : 'workbench.action.navigateBack'); + this.send('vscode:runAction', { id: acrossEditors ? 'workbench.action.openPreviousRecentlyUsedEditor' : 'workbench.action.navigateBack', from: 'mouse' } as IRunActionInWindowRequest); } else if (cmd === forward) { - this.send('vscode:runAction', acrossEditors ? 'workbench.action.openNextRecentlyUsedEditor' : 'workbench.action.navigateForward'); + this.send('vscode:runAction', { id: acrossEditors ? 'workbench.action.openNextRecentlyUsedEditor' : 'workbench.action.navigateForward', from: 'mouse' } as IRunActionInWindowRequest); } }); } @@ -932,7 +932,7 @@ export class CodeWindow implements ICodeWindow { mode: 'buttons', segmentStyle: 'automatic', change: (selectedIndex) => { - this.sendWhenReady('vscode:runAction', items[selectedIndex].id); + this.sendWhenReady('vscode:runAction', { id: items[selectedIndex].id, from: 'touchbar' }); } }); } diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index ee9e0250027..95846dfb1e0 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -253,4 +253,9 @@ export interface IWindowConfiguration extends ParsedArgs, IOpenFileRequest { perfStartTime?: number; perfAppReady?: number; perfWindowLoadTime?: number; +} + +export interface IRunActionInWindowRequest { + id: string; + from: 'menu' | 'touchbar' | 'mouse'; } \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index b0f2614a60b..79872402bda 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -25,7 +25,7 @@ import { IEditorGroupService } from 'vs/workbench/services/group/common/groupSer import { IMessageService } from 'vs/platform/message/common/message'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; -import { IWindowsService, IWindowService, IWindowSettings, IPath, IOpenFileRequest, IWindowsConfiguration, IAddFoldersRequest } from 'vs/platform/windows/common/windows'; +import { IWindowsService, IWindowService, IWindowSettings, IPath, IOpenFileRequest, IWindowsConfiguration, IAddFoldersRequest, IRunActionInWindowRequest } from 'vs/platform/windows/common/windows'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -127,9 +127,25 @@ export class ElectronWindow extends Themable { }); // Support runAction event - ipc.on('vscode:runAction', (event, actionId: string) => { - this.commandService.executeCommand(actionId, { from: 'menu' }).done(_ => { - this.telemetryService.publicLog('commandExecuted', { id: actionId, from: 'menu' }); + ipc.on('vscode:runAction', (event, request: IRunActionInWindowRequest) => { + const args: any[] = []; + + // If we run an action from the touchbar, we fill in the currently active resource + // as payload because the touch bar items are context aware depending on the editor + if (request.from === 'touchbar') { + const activeEditor = this.editorService.getActiveEditor(); + if (activeEditor) { + const resource = toResource(activeEditor.input, { supportSideBySide: true }); + if (resource) { + args.push(resource); + } + } + } else { + args.push({ from: request.from }); // TODO@telemetry this is a bit weird to send this to every action? + } + + this.commandService.executeCommand(request.id, ...args).done(_ => { + this.telemetryService.publicLog('commandExecuted', { id: request.id, from: request.from }); }, err => { this.messageService.show(Severity.Error, err); }); From 087059db910541e8d763a5af19b0dc6a0b663e2e Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Thu, 21 Sep 2017 11:40:29 +0200 Subject: [PATCH 140/281] UI polish for tasks in multi folder setup --- src/vs/code/electron-main/menus.ts | 4 +- src/vs/vscode.d.ts | 2 +- .../parts/tasks/browser/quickOpen.ts | 2 +- .../parts/tasks/common/taskService.ts | 2 +- .../electron-browser/task.contribution.ts | 602 ++++++++++-------- 5 files changed, 331 insertions(+), 281 deletions(-) diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 3212e30b62a..032972aafc9 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -1023,8 +1023,8 @@ export class CodeMenu { const terminateTask = this.createMenuItem(nls.localize({ key: 'miTerminateTask', comment: ['&& denotes a mnemonic'] }, "&&Terminate Task..."), 'workbench.action.tasks.terminate'); // const testTask = this.createMenuItem(nls.localize({ key: 'miTestTask', comment: ['&& denotes a mnemonic'] }, "Run Test T&&ask..."), 'workbench.action.tasks.test'); // const showTaskLog = this.createMenuItem(nls.localize({ key: 'miShowTaskLog', comment: ['&& denotes a mnemonic'] }, "&&Show Task Log"), 'workbench.action.tasks.showLog'); - const configureTask = this.createMenuItem(nls.localize({ key: 'miConfigureTask', comment: ['&& denotes a mnemonic'] }, "&&Configure Tasks"), 'workbench.action.tasks.configureTaskRunner'); - const configureBuildTask = this.createMenuItem(nls.localize({ key: 'miConfigureBuildTask', comment: ['&& denotes a mnemonic'] }, "Configure De&&fault Build Task"), 'workbench.action.tasks.configureDefaultBuildTask'); + const configureTask = this.createMenuItem(nls.localize({ key: 'miConfigureTask', comment: ['&& denotes a mnemonic'] }, "&&Configure Tasks..."), 'workbench.action.tasks.configureTaskRunner'); + const configureBuildTask = this.createMenuItem(nls.localize({ key: 'miConfigureBuildTask', comment: ['&& denotes a mnemonic'] }, "Configure De&&fault Build Task..."), 'workbench.action.tasks.configureDefaultBuildTask'); // const configureTestTask = this.createMenuItem(nls.localize({ key: 'miConfigureTestTask', comment: ['&& denotes a mnemonic'] }, "Configure Defau&< Test Task"), 'workbench.action.tasks.configureDefaultTestTask'); [ diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 06ada6a67be..044110c7891 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -3959,7 +3959,7 @@ declare module 'vscode' { * or '$eslint'. Problem matchers can be contributed by an extension using * the `problemMatchers` extension point. */ - constructor(taskDefinition: TaskDefinition, target: TaskScope.Global | TaskScope.Workspace | WorkspaceFolder, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]); + constructor(taskDefinition: TaskDefinition, target: WorkspaceFolder | TaskScope.Global | TaskScope.Workspace, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]); /** * The task's definition. diff --git a/src/vs/workbench/parts/tasks/browser/quickOpen.ts b/src/vs/workbench/parts/tasks/browser/quickOpen.ts index 4d44c449dc6..c0cbb0c12b6 100644 --- a/src/vs/workbench/parts/tasks/browser/quickOpen.ts +++ b/src/vs/workbench/parts/tasks/browser/quickOpen.ts @@ -30,7 +30,7 @@ export class TaskEntry extends Model.QuickOpenEntry { } public getDescription(): string { - if (!this.taskService.hasMultipleFolders()) { + if (!this.taskService.needsFolderQualification()) { return null; } let workspaceFolder = Task.getWorkspaceFolder(this.task); diff --git a/src/vs/workbench/parts/tasks/common/taskService.ts b/src/vs/workbench/parts/tasks/common/taskService.ts index 57ca26da803..fa001c1537d 100644 --- a/src/vs/workbench/parts/tasks/common/taskService.ts +++ b/src/vs/workbench/parts/tasks/common/taskService.ts @@ -62,7 +62,7 @@ export interface ITaskService extends IEventEmitter { getRecentlyUsedTasks(): LinkedMap; createSorter(): TaskSorter; - hasMultipleFolders(); + needsFolderQualification(); canCustomize(task: ContributedTask | CustomTask): boolean; customize(task: ContributedTask | CustomTask, properties?: {}, openConfig?: boolean): TPromise; openConfig(task: CustomTask): TPromise; diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index 4d9bb12abeb..de7a52799e7 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -30,14 +30,13 @@ import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; import { Registry } from 'vs/platform/registry/common/platform'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { SyncActionDescriptor, MenuRegistry } from 'vs/platform/actions/common/actions'; +import { MenuRegistry } from 'vs/platform/actions/common/actions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IEditor } from 'vs/platform/editor/common/editor'; import { IMessageService } from 'vs/platform/message/common/message'; import { IMarkerService, MarkerStatistics } from 'vs/platform/markers/common/markers'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IFileService } from 'vs/platform/files/common/files'; +import { IFileService, IFileStat } from 'vs/platform/files/common/files'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -55,11 +54,10 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import jsonContributionRegistry = require('vs/platform/jsonschemas/common/jsonContributionRegistry'); import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions'; import { IStatusbarItem, IStatusbarRegistry, Extensions as StatusbarExtensions, StatusbarItemDescriptor, StatusbarAlignment } from 'vs/workbench/browser/parts/statusbar/statusbar'; import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; -import { IQuickOpenService, IPickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen'; +import { IQuickOpenService, IPickOpenEntry, IPickOpenAction, IPickOpenItem } from 'vs/platform/quickOpen/common/quickOpen'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import Constants from 'vs/workbench/parts/markers/common/constants'; import { IPartService } from 'vs/workbench/services/part/common/partService'; @@ -95,152 +93,14 @@ import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions'; let $ = Builder.$; let tasksCategory = nls.localize('tasksCategory', "Tasks"); -abstract class OpenTaskConfigurationAction extends Action { - - constructor(id: string, label: string, - private taskService: ITaskService, - private configurationService: IConfigurationService, - private editorService: IWorkbenchEditorService, private fileService: IFileService, - private contextService: IWorkspaceContextService, private outputService: IOutputService, - private messageService: IMessageService, private quickOpenService: IQuickOpenService, - private environmentService: IEnvironmentService, - private configurationResolverService: IConfigurationResolverService, - private extensionService: IExtensionService, - private telemetryService: ITelemetryService) { - - super(id, label); - } - - public run(event?: any): TPromise { - if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { - this.messageService.show(Severity.Info, nls.localize('ConfigureTaskRunnerAction.noWorkspace', 'Tasks are only available on a workspace folder.')); - return TPromise.as(undefined); - } - let sideBySide = !!(event && (event.ctrlKey || event.metaKey)); - let configFileCreated = false; - return this.fileService.resolveFile(this.contextService.getWorkspace().folders[0].toResource('.vscode/tasks.json')).then((success) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) - - return success; - }, (err: any) => { - return this.quickOpenService.pick(taskTemplates, { placeHolder: nls.localize('ConfigureTaskRunnerAction.quickPick.template', 'Select a Task Runner') }).then(selection => { - if (!selection) { - return undefined; - } - let contentPromise: TPromise; - if (selection.autoDetect) { - const outputChannel = this.outputService.getChannel(TaskService.OutputChannelId); - outputChannel.show(true); - outputChannel.append(nls.localize('ConfigureTaskRunnerAction.autoDetecting', 'Auto detecting tasks for {0}', selection.id) + '\n'); - let detector = new ProcessRunnerDetector(this.fileService, this.contextService, this.configurationResolverService); - contentPromise = detector.detect(false, selection.id).then((value) => { - let config = value.config; - if (value.stderr && value.stderr.length > 0) { - value.stderr.forEach((line) => { - outputChannel.append(line + '\n'); - }); - if (config && (!config.tasks || config.tasks.length === 0)) { - this.messageService.show(Severity.Warning, nls.localize('ConfigureTaskRunnerAction.autoDetect', 'Auto detecting the task system failed. Using default template. Consult the task output for details.')); - return selection.content; - } else { - this.messageService.show(Severity.Warning, nls.localize('ConfigureTaskRunnerAction.autoDetectError', 'Auto detecting the task system produced errors. Consult the task output for details.')); - } - } - if (config) { - if (value.stdout && value.stdout.length > 0) { - value.stdout.forEach(line => outputChannel.append(line + '\n')); - } - let content = JSON.stringify(config, null, '\t'); - content = [ - '{', - '\t// See https://go.microsoft.com/fwlink/?LinkId=733558', - '\t// for the documentation about the tasks.json format', - ].join('\n') + content.substr(1); - return content; - } else { - return selection.content; - } - }); - } else { - contentPromise = TPromise.as(selection.content); - } - return contentPromise.then(content => { - let editorConfig = this.configurationService.getConfiguration(); - if (editorConfig.editor.insertSpaces) { - content = content.replace(/(\n)(\t+)/g, (_, s1, s2) => s1 + strings.repeat(' ', s2.length * editorConfig.editor.tabSize)); - } - configFileCreated = true; - return this.fileService.createFile(this.contextService.getWorkspace().folders[0].toResource('.vscode/tasks.json'), content).then((result) => { - this.telemetryService.publicLog(TaskService.TemplateTelemetryEventName, { - templateId: selection.id, - autoDetect: selection.autoDetect - }); - return result; - }); // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) - }); - /* 2.0 version - let content = selection.content; - let editorConfig = this.configurationService.getConfiguration(); - if (editorConfig.editor.insertSpaces) { - content = content.replace(/(\n)(\t+)/g, (_, s1, s2) => s1 + strings.repeat(' ', s2.length * editorConfig.editor.tabSize)); - } - configFileCreated = true; - return this.fileService.createFile(this.contextService.toResource('.vscode/tasks.json'), content); - */ - }); - }).then((stat) => { - if (!stat) { - return undefined; - } - // // (2) Open editor with configuration file - return this.editorService.openEditor({ - resource: stat.resource, - options: { - forceOpen: true, - pinned: configFileCreated // pin only if config file is created #8727 - } - }, sideBySide); - }, (error) => { - throw new Error(nls.localize('ConfigureTaskRunnerAction.failed', "Unable to create the 'tasks.json' file inside the '.vscode' folder. Consult the task output for details.")); - }); - } +namespace ConfigureTaskAction { + export const ID = 'workbench.action.tasks.configureTaskRunner'; + export const TEXT = nls.localize('ConfigureTaskRunnerAction.label', "Configure Task"); } -class ConfigureTaskRunnerAction extends OpenTaskConfigurationAction { - public static ID = 'workbench.action.tasks.configureTaskRunner'; - public static TEXT = nls.localize('ConfigureTaskRunnerAction.label', "Configure Task Runner"); - - constructor(id: string, label: string, - @ITaskService taskService: ITaskService, @IConfigurationService configurationService: IConfigurationService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IFileService fileService: IFileService, - @IWorkspaceContextService contextService: IWorkspaceContextService, @IOutputService outputService: IOutputService, - @IMessageService messageService: IMessageService, @IQuickOpenService quickOpenService: IQuickOpenService, - @IEnvironmentService environmentService: IEnvironmentService, - @IConfigurationResolverService configurationResolverService: IConfigurationResolverService, - @IExtensionService extensionService: IExtensionService, - @ITelemetryService telemetryService: ITelemetryService) { - super(id, label, taskService, configurationService, editorService, fileService, contextService, - outputService, messageService, quickOpenService, environmentService, configurationResolverService, - extensionService, telemetryService); - } -} - -class ConfigureBuildTaskAction extends OpenTaskConfigurationAction { - public static ID = 'workbench.action.tasks.configureBuildTask'; - public static TEXT = nls.localize('ConfigureBuildTaskAction.label', "Configure Build Task"); - - constructor(id: string, label: string, - @ITaskService taskService: ITaskService, @IConfigurationService configurationService: IConfigurationService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IFileService fileService: IFileService, - @IWorkspaceContextService contextService: IWorkspaceContextService, @IOutputService outputService: IOutputService, - @IMessageService messageService: IMessageService, @IQuickOpenService quickOpenService: IQuickOpenService, - @IEnvironmentService environmentService: IEnvironmentService, - @IConfigurationResolverService configurationResolverService: IConfigurationResolverService, - @IExtensionService extensionService: IExtensionService, - @ITelemetryService telemetryService: ITelemetryService) { - super(id, label, taskService, configurationService, editorService, fileService, contextService, - outputService, messageService, quickOpenService, environmentService, configurationResolverService, - extensionService, telemetryService); - } +namespace ConfigureBuildTaskAction { + export const ID = 'workbench.action.tasks.configureBuildTask'; + export const TEXT = nls.localize('ConfigureBuildTaskAction.label', "Configure Build Task"); } class CloseMessageAction extends Action { @@ -670,6 +530,10 @@ class TaskMap { } } +interface TaskQuickPickEntry extends IPickOpenEntry { + task: Task; +} + class TaskService extends EventEmitter implements ITaskService { // private static autoDetectTelemetryName: string = 'taskServer.autoDetect'; @@ -828,6 +692,10 @@ class TaskService extends EventEmitter implements ITaskService { this.runTestCommand(); }); + CommandsRegistry.registerCommand('workbench.action.tasks.configureTaskRunner', () => { + this.runConfigureTasks(); + }); + CommandsRegistry.registerCommand('workbench.action.tasks.configureDefaultBuildTask', () => { this.runConfigureDefaultBuildTask(); }); @@ -1042,7 +910,7 @@ class TaskService extends EventEmitter implements ITaskService { } if (entries.length > 0) { entries = entries.sort((a, b) => a.label.localeCompare(b.label)); - entries[0].separator = { border: true }; + entries[0].separator = { border: true, label: nls.localize('TaskService.associate', 'associate') }; entries.unshift( { label: nls.localize('TaskService.attachProblemMatcher.continueWithout', 'Continue without scanning the task output'), matcher: undefined }, { label: nls.localize('TaskService.attachProblemMatcher.never', 'Never scan the task output'), matcher: undefined, never: true }, @@ -1090,8 +958,8 @@ class TaskService extends EventEmitter implements ITaskService { }); } - public hasMultipleFolders(): boolean { - return this._workspaceFolders && this._workspaceFolders.length > 1; + public needsFolderQualification(): boolean { + return this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; } public canCustomize(task: Task): boolean { @@ -1695,8 +1563,9 @@ class TaskService extends EventEmitter implements ITaskService { } else { this._outputChannel.append(nls.localize( 'taskService.ignoreingFolder', - 'Ignoring task configurations for workspace folder {0}. Multi root folder support requires that all folders use task version 2.0.', + 'Ignoring task configurations for workspace folder {0}. Multi root folder support requires that all folders use task version 2.0.0\n', workspaceFolder.uri.fsPath)); + this._outputChannel.show(true); } } } @@ -1771,17 +1640,21 @@ class TaskService extends EventEmitter implements ITaskService { } public configureAction(): Action { - return new ConfigureTaskRunnerAction(ConfigureTaskRunnerAction.ID, ConfigureTaskRunnerAction.TEXT, this, - this.configurationService, this.editorService, this.fileService, this.contextService, - this.outputService, this.messageService, this.quickOpenService, this.environmentService, this.configurationResolverService, - this.extensionService, this.telemetryService); + let run = () => { this.runConfigureTasks(); return TPromise.as(undefined); }; + return new class extends Action { + constructor() { + super(ConfigureTaskAction.ID, ConfigureTaskAction.TEXT, undefined, true, run); + } + }; } private configureBuildTask(): Action { - return new ConfigureBuildTaskAction(ConfigureBuildTaskAction.ID, ConfigureBuildTaskAction.TEXT, this, - this.configurationService, this.editorService, this.fileService, this.contextService, - this.outputService, this.messageService, this.quickOpenService, this.environmentService, this.configurationResolverService, - this.extensionService, this.telemetryService); + let run = () => { this.runConfigureTasks(); return TPromise.as(undefined); }; + return new class extends Action { + constructor() { + super(ConfigureTaskAction.ID, ConfigureTaskAction.TEXT, undefined, true, run); + } + }; } public beforeShutdown(): boolean | TPromise { @@ -1882,16 +1755,13 @@ class TaskService extends EventEmitter implements ITaskService { return true; } - private showQuickPick(tasks: Task[], placeHolder: string, group: boolean = false, sort: boolean = false): TPromise { + private createTaskQuickPickEntries(tasks: Task[], group: boolean = false, sort: boolean = false): TaskQuickPickEntry[] { if (tasks === void 0 || tasks === null || tasks.length === 0) { - return TPromise.as(undefined); + return []; } - interface TaskQickPickEntry extends IPickOpenEntry { - task: Task; - } - const TaskQickPickEntry = (task: Task): TaskQickPickEntry => { + const TaskQuickPickEntry = (task: Task): TaskQuickPickEntry => { let description: string; - if (this.hasMultipleFolders) { + if (this.needsFolderQualification()) { let workspaceFolder = Task.getWorkspaceFolder(task); if (workspaceFolder) { description = `(${workspaceFolder.name})`; @@ -1899,24 +1769,40 @@ class TaskService extends EventEmitter implements ITaskService { } return { label: task._label, description, task }; }; - function fillEntries(entries: TaskQickPickEntry[], tasks: Task[], groupLabel: string, withBorder: boolean = false): void { + let taskService = this; + let action = new class extends Action implements IPickOpenAction { + constructor() { + super('configureAction', 'Configure Task', 'quick-open-task-configure', true); + } + public run(item: IPickOpenItem): TPromise { + let task: Task = item.getPayload(); + taskService.quickOpenService.close(); + if (ContributedTask.is(task)) { + taskService.customize(task, undefined, true); + } else if (CustomTask.is(task)) { + taskService.openConfig(task); + } + return TPromise.as(false); + } + }; + function fillEntries(entries: TaskQuickPickEntry[], tasks: Task[], groupLabel: string, withBorder: boolean = false): void { let first = true; for (let task of tasks) { + let entry: TaskQuickPickEntry = TaskQuickPickEntry(task); if (first) { first = false; - let entry = TaskQickPickEntry(task); entry.separator = { label: groupLabel, border: withBorder }; - entries.push(entry); - } else { - entries.push(TaskQickPickEntry(task)); } + entry.action = action; + entry.payload = task; + entries.push(entry); } } - let entries: TaskQickPickEntry[]; + let entries: TaskQuickPickEntry[]; if (group) { entries = []; if (tasks.length === 1) { - entries.push(TaskQickPickEntry(tasks[0])); + entries.push(TaskQuickPickEntry(tasks[0])); } else { let recentlyUsedTasks = this.getRecentlyUsedTasks(); let recent: Task[] = []; @@ -1953,9 +1839,25 @@ class TaskService extends EventEmitter implements ITaskService { const sorter = this.createSorter(); tasks = tasks.sort((a, b) => sorter.compare(a, b)); } - entries = tasks.map(task => TaskQickPickEntry(task)); + entries = tasks.map(task => TaskQuickPickEntry(task)); } - return this.quickOpenService.pick(entries, { placeHolder, autoFocus: { autoFocusFirstEntry: true } }).then(entry => entry ? entry.task : undefined); + return entries; + } + + private showQuickPick(tasks: TPromise | Task[], placeHolder: string, defaultEntry?: TaskQuickPickEntry, group: boolean = false, sort: boolean = false): TPromise { + let _createEntries = (): TPromise => { + if (Array.isArray(tasks)) { + return TPromise.as(this.createTaskQuickPickEntries(tasks, group, sort)); + } else { + return tasks.then((tasks) => this.createTaskQuickPickEntries(tasks, group, sort)); + } + }; + return this.quickOpenService.pick(_createEntries().then((entries) => { + if (entries.length === 0 && defaultEntry) { + entries.push(defaultEntry); + } + return entries; + }), { placeHolder, autoFocus: { autoFocusFirstEntry: true } }).then(entry => entry ? entry.task : undefined); } private runTaskCommand(accessor: ServicesAccessor, arg: any): void { @@ -1973,15 +1875,34 @@ class TaskService extends EventEmitter implements ITaskService { return; } } - this.quickOpenService.show('task '); + this.doRunTaskCommand(grouped.all()); }, () => { - this.quickOpenService.show('task '); + this.doRunTaskCommand(); }); } else { - this.quickOpenService.show('task '); + this.doRunTaskCommand(); } } + private doRunTaskCommand(tasks?: Task[]): void { + this.showQuickPick(tasks ? tasks : this.tasks(), + nls.localize('TaskService.pickRunTask', 'Select the task to run'), + { + label: nls.localize('TaslService.noEntryToRun', 'No task to run found. Configure Tasks...'), + task: null + }, + true).then((task) => { + if (task === void 0) { + return; + } + if (task === null) { + this.runConfigureTasks(); + } else { + this.run(task, { attachProblemMatcher: true }); + } + }); + } + private runBuildCommand(): void { if (!this.canRunCommand()) { return; @@ -1995,32 +1916,35 @@ class TaskService extends EventEmitter implements ITaskService { title: nls.localize('TaskService.fetchingBuildTasks', 'Fetching build tasks...') }; let promise = this.getTasksForGroup(TaskGroup.Build).then((tasks) => { - if (tasks.length === 0) { - this.messageService.show( - Severity.Info, - { - message: nls.localize('TaskService.noBuildTaskTerminal', 'No Build Task found. Press \'Configure Build Task\' to define one.'), - actions: [this.configureBuildTask(), new CloseMessageAction()] + if (tasks.length > 0) { + let primaries: Task[] = []; + for (let task of tasks) { + // We only have build tasks here + if (task.isDefaultGroupEntry) { + primaries.push(task); } - ); - return; - } - let primaries: Task[] = []; - for (let task of tasks) { - // We only have build tasks here - if (task.isDefaultGroupEntry) { - primaries.push(task); + } + if (primaries.length === 1) { + this.run(primaries[0]); + return; } } - if (primaries.length === 1) { - this.run(primaries[0]); - return; - } - this.showQuickPick(tasks, nls.localize('TaskService.pickBuildTask', 'Select the build task to run'), true).then((task) => { - if (task) { + this.showQuickPick(tasks, + nls.localize('TaskService.pickBuildTask', 'Select the build task to run'), + { + label: nls.localize('TaskService.noBuildTask', 'No build task to run found. Configure Tasks...'), + task: null + }, + true).then((task) => { + if (task === void 0) { + return; + } + if (task === null) { + this.runConfigureTasks(); + return; + } this.run(task, { attachProblemMatcher: true }); - } - }); + }); }); this.progressService.withProgress(options, () => promise); } @@ -2038,31 +1962,34 @@ class TaskService extends EventEmitter implements ITaskService { title: nls.localize('TaskService.fetchingTestTasks', 'Fetching test tasks...') }; let promise = this.getTasksForGroup(TaskGroup.Test).then((tasks) => { - if (tasks.length === 0) { - this.messageService.show( - Severity.Info, - { - message: nls.localize('TaskService.noTestTaskTerminal', 'No Test Task found. Press \'Configure Task Runner\' to define one.'), - actions: [this.configureAction(), new CloseMessageAction()] + if (tasks.length > 0) { + let primaries: Task[] = []; + for (let task of tasks) { + // We only have test task here. + if (task.isDefaultGroupEntry) { + primaries.push(task); } - ); - return; - } - let primaries: Task[] = []; - for (let task of tasks) { - // We only have test task here. - if (task.isDefaultGroupEntry) { - primaries.push(task); + } + if (primaries.length === 1) { + this.run(primaries[0]); + return; } } - if (primaries.length === 1) { - this.run(primaries[0]); - return; - } - this.showQuickPick(tasks, nls.localize('TaskService.pickTestTask', 'Select the test task to run'), true).then((task) => { - if (task) { - this.run(task); + this.showQuickPick(tasks, + nls.localize('TaskService.pickTestTask', 'Select the test task to run'), + { + label: nls.localize('TaskService.noTestTaskTerminal', 'No test task to run found. Configure Tasks...'), + task: null + }, true + ).then((task) => { + if (task === void 0) { + return; } + if (task === null) { + this.runConfigureTasks(); + return; + } + this.run(task); }); }); this.progressService.withProgress(options, () => promise); @@ -2073,16 +2000,18 @@ class TaskService extends EventEmitter implements ITaskService { return; } if (this.inTerminal()) { - this.getActiveTasks().then((activeTasks) => { - if (activeTasks.length === 0) { - this.messageService.show(Severity.Info, nls.localize('TaskService.noTaskRunning', 'No task is currently running.')); + this.showQuickPick(this.getActiveTasks(), + nls.localize('TaskService.tastToTerminate', 'Select task to terminate'), + { + label: nls.localize('TaskService.noTaskRunning', 'No task is currently running'), + task: null + }, + false, true + ).then(task => { + if (task === void 0 || task === null) { return; } - this.showQuickPick(activeTasks, nls.localize('TaskService.tastToTerminate', 'Select task to terminate'), false, true).then(task => { - if (task) { - this.terminate(task); - } - }); + this.terminate(task); }); } else { this.isActive().then((active) => { @@ -2109,16 +2038,18 @@ class TaskService extends EventEmitter implements ITaskService { return; } if (this.inTerminal()) { - this.getActiveTasks().then((activeTasks) => { - if (activeTasks.length === 0) { - this.messageService.show(Severity.Info, nls.localize('TaskService.noTaskToRestart', 'No task to restart.')); + this.showQuickPick(this.getActiveTasks(), + nls.localize('TaskService.tastToRestart', 'Select the task to restart'), + { + label: nls.localize('TaskService.noTaskToRestart', 'No task to restart'), + task: null + }, + false, true + ).then(task => { + if (task === void 0 || task === null) { return; } - this.showQuickPick(activeTasks, nls.localize('TaskService.tastToRestart', 'Select the task to restart'), false, true).then(task => { - if (task) { - this.restart(task); - } - }); + this.restart(task); }); } else { this.getActiveTasks().then((activeTasks) => { @@ -2131,6 +2062,127 @@ class TaskService extends EventEmitter implements ITaskService { } } + private runConfigureTasks(): void { + if (!this.canRunCommand()) { + return undefined; + } + let taskPromise: TPromise; + if (this._schemaVersion === JsonSchemaVersion.V2_0_0) { + taskPromise = this.getGroupedTasks(); + } else { + taskPromise = TPromise.as(new TaskMap()); + } + + let openTaskFile = (workspaceFolder: IWorkspaceFolder): void => { + let resource = workspaceFolder.toResource('.vscode/tasks.json'); + let configFileCreated = false; + this.fileService.resolveFile(resource).then((stat) => stat, () => undefined).then((stat) => { + if (stat) { + return stat.resource; + } + return this.quickOpenService.pick(taskTemplates, { placeHolder: nls.localize('TaskService.template', 'Select a Task Template') }).then((selection) => { + if (!selection) { + return undefined; + } + let content = selection.content; + let editorConfig = this.configurationService.getConfiguration(); + if (editorConfig.editor.insertSpaces) { + content = content.replace(/(\n)(\t+)/g, (_, s1, s2) => s1 + strings.repeat(' ', s2.length * editorConfig.editor.tabSize)); + } + configFileCreated = true; + return this.fileService.createFile(resource, content).then((result): URI => { + this.telemetryService.publicLog(TaskService.TemplateTelemetryEventName, { + templateId: selection.id, + autoDetect: selection.autoDetect + }); + return result.resource; + }); + }); + }).then((resource) => { + if (!resource) { + return; + } + this.editorService.openEditor({ + resource: resource, + options: { + forceOpen: true, + pinned: configFileCreated // pin only if config file is created #8727 + } + }, false); + }); + }; + + let configureTask = (task: Task): void => { + if (ContributedTask.is(task)) { + this.customize(task, undefined, true); + } else if (CustomTask.is(task)) { + this.openConfig(task); + } + }; + + function isTaskEntry(value: IPickOpenEntry): value is IPickOpenEntry & { task: Task } { + let candidate: IPickOpenEntry & { task: Task } = value as any; + return candidate && !!candidate.task; + } + + let stats = this.contextService.getWorkspace().folders.map>((folder) => { + return this.fileService.resolveFile(folder.toResource('.vscode/tasks.json')).then(stat => stat, () => undefined); + }); + + let createLabel = nls.localize('TaskService.createJsonFile', 'Create tasks.json file from template'); + let openLabel = nls.localize('TaskService.openJsonFile', 'Open tasks.json file'); + let entries = TPromise.join(stats).then((stats) => { + return taskPromise.then((taskMap) => { + type EntryType = (IPickOpenEntry & { task: Task; }) | (IPickOpenEntry & { folder: IWorkspaceFolder; }); + let entries: EntryType[] = []; + if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { + let tasks = taskMap.all(); + if (tasks.length > 0) { + tasks = tasks.sort((a, b) => a._label.localeCompare(b._label)); + entries = tasks.map(task => { return { label: task._label, task }; }); + } else { + let label = stats[0] !== void 0 ? openLabel : createLabel; + entries.push({ label, folder: this.contextService.getWorkspace().folders[0] }); + } + } else { + let folders = this.contextService.getWorkspace().folders; + let index = 0; + for (let folder of folders) { + let tasks = taskMap.get(folder); + if (tasks.length > 0) { + tasks = tasks.slice().sort((a, b) => a._label.localeCompare(b._label)); + for (let i = 0; i < tasks.length; i++) { + let entry: EntryType = { label: tasks[i]._label, task: tasks[i] }; + if (i === 0) { + entry.separator = { label: folder.name, border: index > 0 }; + } + entries.push(entry); + } + } else { + let label = stats[index] !== void 0 ? openLabel : createLabel; + let entry: EntryType = { label, folder: folder }; + entry.separator = { label: folder.name, border: index > 0 }; + entries.push(entry); + } + index++; + } + } + return entries; + }); + }); + + this.quickOpenService.pick(entries, { placeHolder: nls.localize('TaskService.pickTask', 'Select a task to configure'), autoFocus: { autoFocusFirstEntry: true } }).then((selection) => { + if (!selection) { + return; + } + if (isTaskEntry(selection)) { + configureTask(selection.task); + } else { + openTaskFile(selection.folder); + } + }); + } + private runConfigureDefaultBuildTask(): void { if (!this.canRunCommand()) { return; @@ -2138,10 +2190,11 @@ class TaskService extends EventEmitter implements ITaskService { if (this._schemaVersion === JsonSchemaVersion.V2_0_0) { this.tasks().then((tasks => { if (tasks.length === 0) { - this.configureBuildTask().run(); + this.runConfigureTasks(); return; } let defaultTask: Task; + let defaultEntry: TaskQuickPickEntry; for (let task of tasks) { if (task.group === TaskGroup.Build && task.isDefaultGroupEntry) { defaultTask = task; @@ -2149,20 +2202,27 @@ class TaskService extends EventEmitter implements ITaskService { } } if (defaultTask) { - this.messageService.show(Severity.Info, nls.localize('TaskService.defaultBuildTaskExists', '{0} is already marked as the default build task.', Task.getQualifiedLabel(defaultTask))); - return; + tasks = []; + defaultEntry = { + label: nls.localize('TaskService.defaultBuildTaskExists', '{0} is already marked as the default build task', Task.getQualifiedLabel(defaultTask)), + task: defaultTask + }; } - this.showQuickPick(tasks, nls.localize('TaskService.pickDefaultBuildTask', 'Select the task to be used as the default build task'), true).then((task) => { - if (!task) { - return; - } - if (!CompositeTask.is(task)) { - this.customize(task, { group: { kind: 'build', isDefault: true } }, true); - } - }); + this.showQuickPick(tasks, + nls.localize('TaskService.pickDefaultBuildTask', 'Select the task to be used as the default build task'), defaultEntry, true).then((task) => { + if (task === void 0) { + return; + } + if (task === defaultTask && CustomTask.is(task)) { + this.openConfig(task); + } + if (!CompositeTask.is(task)) { + this.customize(task, { group: { kind: 'build', isDefault: true } }, true); + } + }); })); } else { - this.configureBuildTask().run(); + this.runConfigureTasks(); } } @@ -2173,7 +2233,7 @@ class TaskService extends EventEmitter implements ITaskService { if (this._schemaVersion === JsonSchemaVersion.V2_0_0) { this.tasks().then((tasks => { if (tasks.length === 0) { - this.configureAction().run(); + this.runConfigureTasks(); } let defaultTask: Task; for (let task of tasks) { @@ -2186,7 +2246,7 @@ class TaskService extends EventEmitter implements ITaskService { this.messageService.show(Severity.Info, nls.localize('TaskService.defaultTestTaskExists', '{0} is already marked as the default test task.', Task.getQualifiedLabel(defaultTask))); return; } - this.showQuickPick(tasks, nls.localize('TaskService.pickDefaultTestTask', 'Select the task to be used as the default test task'), true).then((task) => { + this.showQuickPick(tasks, nls.localize('TaskService.pickDefaultTestTask', 'Select the task to be used as the default test task'), undefined, true).then((task) => { if (!task) { return; } @@ -2196,7 +2256,7 @@ class TaskService extends EventEmitter implements ITaskService { }); })); } else { - this.configureAction().run(); + this.runConfigureTasks(); } } @@ -2204,33 +2264,23 @@ class TaskService extends EventEmitter implements ITaskService { if (!this.canRunCommand()) { return; } - if (!this._taskSystem) { - this.messageService.show(Severity.Info, nls.localize('TaskService.noTaskIsRunning', 'No task is running.')); - return; - } - this.getActiveTasks().then((tasks) => { - if (tasks.length === 0) { - this.messageService.show(Severity.Info, nls.localize('TaskService.noTaskIsRunning', 'No task is running.')); - } else if (tasks.length === 1) { - if (this._taskSystem) { - this._taskSystem.revealTask(tasks[0]); - } - } else { - this.showQuickPick(tasks, nls.localize('TaskService.pickShowTask', 'Select the task to show its output'), false, true).then((task) => { - if (!task || !this._taskSystem) { - return; - } - this._taskSystem.revealTask(task); - }); + this.showQuickPick(this.getActiveTasks(), + nls.localize('TaskService.pickShowTask', 'Select the task to show its output'), + { + label: nls.localize('TaskService.noTaskIsRunning', 'No task is running'), + task: null + }, + false, true + ).then((task) => { + if (task === void 0 || task === null) { + return; } + this._taskSystem.revealTask(task); }); } } - -let workbenchActionsRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureTaskRunnerAction, ConfigureTaskRunnerAction.ID, ConfigureTaskRunnerAction.TEXT), 'Tasks: Configure Task Runner', tasksCategory); - +MenuRegistry.addCommand({ id: ConfigureTaskAction.ID, title: { value: ConfigureTaskAction.TEXT, original: 'Configure Task' }, category: { value: tasksCategory, original: 'Tasks' } }); MenuRegistry.addCommand({ id: 'workbench.action.tasks.showLog', title: { value: nls.localize('ShowLogAction.label', "Show Task Log"), original: 'Show Task Log' }, category: { value: tasksCategory, original: 'Tasks' } }); MenuRegistry.addCommand({ id: 'workbench.action.tasks.runTask', title: { value: nls.localize('RunTaskAction.label', "Run Task"), original: 'Run Task' }, category: { value: tasksCategory, original: 'Tasks' } }); MenuRegistry.addCommand({ id: 'workbench.action.tasks.restartTask', title: { value: nls.localize('RestartTaskAction.label', "Restart Running Task"), original: 'Restart Running Task' }, category: { value: tasksCategory, original: 'Tasks' } }); From 8fe1003f19220bdf7fc9b15f3b0dab102c5081eb Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 21 Sep 2017 11:47:34 +0200 Subject: [PATCH 141/281] make room for full debug toolbar --- .../parts/debug/electron-browser/debug.contribution.ts | 2 +- .../parts/files/browser/fileActions.contribution.ts | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts b/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts index 03821558d9f..6f21bf142ff 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts @@ -203,7 +203,7 @@ if (isMacintosh) { registerTouchBarEntry(StartAction.ID, StartAction.LABEL, 0, CONTEXT_NOT_IN_DEBUG_MODE, 'continue-tb.png'); registerTouchBarEntry(ContinueAction.ID, ContinueAction.LABEL, 0, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'continue-tb.png'); - registerTouchBarEntry(PauseAction.ID, PauseAction.LABEL, 1, CONTEXT_IN_DEBUG_MODE, 'pause-tb.png'); + registerTouchBarEntry(PauseAction.ID, PauseAction.LABEL, 1, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.notEquals('debugState', 'stopped')), 'pause-tb.png'); registerTouchBarEntry(StepOverAction.ID, StepOverAction.LABEL, 2, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'stepover-tb.png'); registerTouchBarEntry(StepIntoAction.ID, StepIntoAction.LABEL, 3, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'stepinto-tb.png'); registerTouchBarEntry(StepOutAction.ID, StepOutAction.LABEL, 4, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'stepout-tb.png'); diff --git a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts index 4eeeacc0311..150727ee766 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts @@ -26,7 +26,6 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { explorerItemToFileResource, ExplorerFocusCondition, FilesExplorerFocusCondition } from 'vs/workbench/parts/files/common/files'; -import URI from 'vs/base/common/uri'; class FilesViewerActionContributor extends ActionBarContributor { @@ -339,12 +338,4 @@ function appendSaveConflictEditorTitleAction(id: string, title: string, iconClas group: 'navigation', order }); -} - -// Touch Bar -if (isMacintosh) { - MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { - command: { id: GlobalNewUntitledFileAction.ID, title: GlobalNewUntitledFileAction.LABEL, iconPath: URI.parse(require.toUrl('vs/workbench/parts/files/browser/media/new-file-tb.png')).fsPath }, - group: '1_modification' - }); } \ No newline at end of file From 0bb671fd5382f1824d98433fa697636785387521 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 21 Sep 2017 11:55:33 +0200 Subject: [PATCH 142/281] fix #34464 --- src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts index 15d3c109f1a..af4cfb3ed80 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts @@ -595,6 +595,11 @@ export class RepositoryPanel extends ViewletPanel { private pin(): void { const activeEditor = this.editorService.getActiveEditor(); const activeEditorInput = this.editorService.getActiveEditorInput(); + + if (!activeEditor) { + return; + } + this.editorGroupService.pinEditor(activeEditor.position, activeEditorInput); } From 825e63f81a32a65c17a5965a03d5e1a0ed13531b Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 21 Sep 2017 12:00:17 +0200 Subject: [PATCH 143/281] Tweaks to content widgets renderings (#34716) --- src/vs/editor/browser/view/viewImpl.ts | 5 + .../contentWidgets/contentWidgets.ts | 98 +++++++++++++------ 2 files changed, 74 insertions(+), 29 deletions(-) diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts index 79cf5f2c105..1a53e3d9814 100644 --- a/src/vs/editor/browser/view/viewImpl.ts +++ b/src/vs/editor/browser/view/viewImpl.ts @@ -420,6 +420,11 @@ export class View extends ViewEventHandler { this._context.model ); + if (this.contentWidgets.shouldRender()) { + // Give the content widgets a chance to set their max width before a possible synchronous layout + this.contentWidgets.onBeforeRender(viewportData); + } + if (this.viewLines.shouldRender()) { this.viewLines.renderText(viewportData); this.viewLines.onDidRender(); diff --git a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts index 4919348fae9..93934f1131b 100644 --- a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts +++ b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts @@ -13,6 +13,7 @@ import { ViewContext } from 'vs/editor/common/view/viewContext'; import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; import { Position, IPosition } from 'vs/editor/common/core/position'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; +import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; class Coordinate { _coordinateBrand: void; @@ -73,6 +74,14 @@ export class ViewContentWidgets extends ViewPart { public onFlushed(e: viewEvents.ViewFlushedEvent): boolean { return true; } + public onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): boolean { + let keys = Object.keys(this._widgets); + for (let i = 0, len = keys.length; i < len; i++) { + const widgetId = keys[i]; + this._widgets[widgetId].onLineMappingChanged(e); + } + return true; + } public onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean { return true; } @@ -132,6 +141,14 @@ export class ViewContentWidgets extends ViewPart { return false; } + public onBeforeRender(viewportData: ViewportData): void { + let keys = Object.keys(this._widgets); + for (let i = 0, len = keys.length; i < len; i++) { + const widgetId = keys[i]; + this._widgets[widgetId].onBeforeRender(viewportData); + } + } + public prepareRender(ctx: RenderingContext): void { let keys = Object.keys(this._widgets); for (let i = 0, len = keys.length; i < len; i++) { @@ -173,11 +190,13 @@ class Widget { private _lineHeight: number; private _position: IPosition; + private _viewPosition: Position; private _preference: ContentWidgetPositionPreference[]; private _cachedDomNodeClientWidth: number; private _cachedDomNodeClientHeight: number; private _maxWidth: number; private _isVisible: boolean; + private _renderData: Coordinate; constructor(context: ViewContext, viewDomNode: FastDomNode, actual: IContentWidget) { @@ -195,7 +214,7 @@ class Widget { this._contentLeft = this._context.configuration.editor.layoutInfo.contentLeft; this._lineHeight = this._context.configuration.editor.lineHeight; - this._position = null; + this._setPosition(null); this._preference = null; this._cachedDomNodeClientWidth = -1; this._cachedDomNodeClientHeight = -1; @@ -206,6 +225,7 @@ class Widget { this.domNode.setPosition((this._fixedOverflowWidgets && this.allowEditorOverflow) ? 'fixed' : 'absolute'); this.domNode.setVisibility('hidden'); this.domNode.setAttribute('widgetId', this.id); + this.domNode.setMaxWidth(this._maxWidth); } public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): void { @@ -219,6 +239,23 @@ class Widget { } } + public onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): void { + this._setPosition(this._position); + } + + private _setPosition(position: IPosition): void { + this._position = position; + this._viewPosition = null; + + if (this._position) { + // Do not trust that widgets give a valid position + const validModelPosition = this._context.model.validateModelPosition(this._position); + if (this._context.model.coordinatesConverter.modelPositionIsVisible(validModelPosition)) { + this._viewPosition = this._context.model.coordinatesConverter.convertModelPositionToViewPosition(validModelPosition); + } + } + } + private _getMaxWidth(): number { return ( this.allowEditorOverflow @@ -228,7 +265,7 @@ class Widget { } public setPosition(position: IPosition, preference: ContentWidgetPositionPreference[]): void { - this._position = position; + this._setPosition(position); this._preference = preference; this._cachedDomNodeClientWidth = -1; this._cachedDomNodeClientHeight = -1; @@ -318,45 +355,36 @@ class Widget { return new Coordinate(topLeft.top, topLeft.left + this._contentLeft); } - private _getTopLeft(ctx: RenderingContext, position: Position): Coordinate { - const visibleRange = ctx.visibleRangeForPosition(position); + /** + * Compute `this._topLeft` + */ + private _getTopLeft(ctx: RenderingContext): Coordinate { + if (!this._viewPosition) { + return null; + } + + const visibleRange = ctx.visibleRangeForPosition(this._viewPosition); if (!visibleRange) { return null; } - const top = ctx.getVerticalOffsetForLineNumber(position.lineNumber) - ctx.scrollTop; + const top = ctx.getVerticalOffsetForLineNumber(this._viewPosition.lineNumber) - ctx.scrollTop; return new Coordinate(top, visibleRange.left); } - private _prepareRenderWidget(ctx: RenderingContext): Coordinate { - if (!this._position || !this._preference) { + private _prepareRenderWidget(topLeft: Coordinate, ctx: RenderingContext): Coordinate { + if (!topLeft) { return null; } - // Do not trust that widgets have a valid position - let validModelPosition = this._context.model.validateModelPosition(this._position); - - if (!this._context.model.coordinatesConverter.modelPositionIsVisible(validModelPosition)) { - // this position is hidden by the view model - return null; - } - - let position = this._context.model.coordinatesConverter.convertModelPositionToViewPosition(validModelPosition); - let placement: IBoxLayoutResult = null; let fetchPlacement = (): void => { if (placement) { return; } - const topLeft = this._getTopLeft(ctx, position); - if (!topLeft) { - return; - } - if (this._cachedDomNodeClientWidth === -1 || this._cachedDomNodeClientHeight === -1) { const domNode = this.domNode.domNode; - this.domNode.setMaxWidth(this._maxWidth); this._cachedDomNodeClientWidth = domNode.clientWidth; this._cachedDomNodeClientHeight = domNode.clientHeight; } @@ -391,11 +419,6 @@ class Widget { return new Coordinate(placement.belowTop, placement.left); } } else { - const topLeft = this._getTopLeft(ctx, position); - if (!topLeft) { - // Widget outside of viewport - return null; - } if (this.allowEditorOverflow) { return this._prepareRenderWidgetAtExactPositionOverflowing(topLeft); } else { @@ -407,8 +430,25 @@ class Widget { return null; } + /** + * On this first pass, we ensure that the content widget (if it is in the viewport) has the max width set correctly. + */ + public onBeforeRender(viewportData: ViewportData): void { + if (!this._viewPosition || !this._preference) { + return; + } + + if (this._viewPosition.lineNumber < viewportData.startLineNumber || this._viewPosition.lineNumber > viewportData.endLineNumber) { + // Outside of viewport + return; + } + + this.domNode.setMaxWidth(this._maxWidth); + } + public prepareRender(ctx: RenderingContext): void { - this._renderData = this._prepareRenderWidget(ctx); + const topLeft = this._getTopLeft(ctx); + this._renderData = this._prepareRenderWidget(topLeft, ctx); } public render(ctx: RestrictedRenderingContext): void { From 9b93a688a93f93db24b632fa2a31ae5f0767646a Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 21 Sep 2017 12:02:00 +0200 Subject: [PATCH 144/281] vscode.d.ts: add ColorPresentation constructor --- src/vs/vscode.proposed.d.ts | 7 +++++++ src/vs/workbench/api/node/extHostTypes.ts | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 0f5a2f26714..37f76762ed7 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -273,6 +273,13 @@ declare module 'vscode' { * selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves. */ additionalTextEdits?: TextEdit[]; + + /** + * Creates a new color presentation. + * + * @param label The label of this color presentation. + */ + constructor(label: string); } /** diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index f84c4574eb5..1db1c7986a9 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -1087,6 +1087,13 @@ export class ColorPresentation { label: string; textEdit?: TextEdit; additionalTextEdits?: TextEdit[]; + + constructor(label: string) { + if (!label || typeof label !== 'string') { + throw illegalArgument('label'); + } + this.label = label; + } } export enum ColorFormat { From 1cf7612e308dcaf62a6074ae055529a848bf472b Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 21 Sep 2017 12:03:08 +0200 Subject: [PATCH 145/281] [css] move colorpresentations to language server --- extensions/css/client/src/cssMain.ts | 56 +++++++--------------- extensions/css/npm-shrinkwrap.json | 28 +++++------ extensions/css/package.json | 7 ++- extensions/css/server/npm-shrinkwrap.json | 24 +++++----- extensions/css/server/package.json | 6 +-- extensions/css/server/src/cssServerMain.ts | 19 ++++++-- 6 files changed, 63 insertions(+), 77 deletions(-) diff --git a/extensions/css/client/src/cssMain.ts b/extensions/css/client/src/cssMain.ts index c8d307d9732..6b43c68252f 100644 --- a/extensions/css/client/src/cssMain.ts +++ b/extensions/css/client/src/cssMain.ts @@ -6,14 +6,13 @@ import * as path from 'path'; -import { languages, window, commands, ExtensionContext, TextDocument, ColorInformation, ColorPresentation, Color, TextEdit as CodeTextEdit } from 'vscode'; +import { languages, window, commands, ExtensionContext, TextDocument, ColorInformation, ColorPresentation, Color } from 'vscode'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, TextEdit } from 'vscode-languageclient'; -import { ConfigurationFeature } from 'vscode-languageclient/lib/proposed'; -import { DocumentColorRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; +import { ConfigurationFeature } from 'vscode-languageclient/lib/configuration.proposed'; +import { DocumentColorRequest, DocumentColorParams, ColorPresentationRequest, ColorPresentationParams } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; import * as nls from 'vscode-nls'; -import * as convert from 'color-convert'; let localize = nls.loadMessageBundle(); // this method is called when vs code is activated @@ -52,16 +51,13 @@ export function activate(context: ExtensionContext) { // client can be deactivated on extension deactivation context.subscriptions.push(disposable); - var _toTwoDigitHex = function (n: number): string { - const r = n.toString(16); - return r.length !== 2 ? '0' + r : r; - }; - client.onReady().then(_ => { // register color provider context.subscriptions.push(languages.registerColorProvider(documentSelector, { provideDocumentColors(document: TextDocument): Thenable { - let params = client.code2ProtocolConverter.asDocumentSymbolParams(document); + let params: DocumentColorParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document) + }; return client.sendRequest(DocumentColorRequest.type, params).then(symbols => { return symbols.map(symbol => { let range = client.protocol2CodeConverter.asRange(symbol.range); @@ -71,34 +67,18 @@ export function activate(context: ExtensionContext) { }); }, provideColorPresentations(document: TextDocument, colorInfo: ColorInformation): ColorPresentation[] | Thenable { - let result: ColorPresentation[] = []; - let color = colorInfo.color; - let label; - if (color.alpha === 1) { - label = `rgb(${Math.round(color.red * 255)}, ${Math.round(color.green * 255)}, ${Math.round(color.blue * 255)})`; - } else { - label = `rgba(${Math.round(color.red * 255)}, ${Math.round(color.green * 255)}, ${Math.round(color.blue * 255)}, ${color.alpha})`; - } - - result.push({ label: label, textEdit: new CodeTextEdit(colorInfo.range, label) }); - - if (color.alpha === 1) { - label = `#${_toTwoDigitHex(Math.round(color.red * 255))}${_toTwoDigitHex(Math.round(color.green * 255))}${_toTwoDigitHex(Math.round(color.blue * 255))}`; - } else { - label = `#${_toTwoDigitHex(Math.round(color.red * 255))}${_toTwoDigitHex(Math.round(color.green * 255))}${_toTwoDigitHex(Math.round(color.blue * 255))}${_toTwoDigitHex(Math.round(color.alpha * 255))}`; - } - - result.push({ label: label, textEdit: new CodeTextEdit(colorInfo.range, label) }); - - const hsl = convert.rgb.hsl(Math.round(color.red * 255), Math.round(color.green * 255), Math.round(color.blue * 255)); - if (color.alpha === 1) { - label = `hsl(${hsl[0]}, ${hsl[1]}%, ${hsl[2]}%)`; - } else { - label = `hsla(${hsl[0]}, ${hsl[1]}%, ${hsl[2]}%, ${color.alpha})`; - } - - result.push({ label: label, textEdit: new CodeTextEdit(colorInfo.range, label) }); - return result; + let params: ColorPresentationParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), + colorInfo: { range: client.code2ProtocolConverter.asRange(colorInfo.range), color: colorInfo.color } + }; + return client.sendRequest(ColorPresentationRequest.type, params).then(presentations => { + return presentations.map(p => { + let presentation = new ColorPresentation(p.label); + presentation.textEdit = p.textEdit && client.protocol2CodeConverter.asTextEdit(p.textEdit); + presentation.additionalTextEdits = p.additionalTextEdits && client.protocol2CodeConverter.asTextEdits(p.additionalTextEdits); + return presentation; + }); + }); } })); }); diff --git a/extensions/css/npm-shrinkwrap.json b/extensions/css/npm-shrinkwrap.json index 6ae15a5c670..0cb7377ce6d 100644 --- a/extensions/css/npm-shrinkwrap.json +++ b/extensions/css/npm-shrinkwrap.json @@ -2,30 +2,26 @@ "name": "css", "version": "0.1.0", "dependencies": { - "color-convert": { - "version": "0.5.3", - "from": "color-convert@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz" - }, + "vscode-jsonrpc": { - "version": "3.3.1", - "from": "vscode-jsonrpc@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.3.1.tgz" + "version": "3.4.0", + "from": "vscode-jsonrpc@>=3.4.0 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.4.0.tgz" }, "vscode-languageclient": { - "version": "3.4.0-next.17", + "version": "3.4.2", "from": "vscode-languageclient@next", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.4.0-next.17.tgz" + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.4.2.tgz" }, "vscode-languageserver-protocol": { - "version": "3.1.1", - "from": "vscode-languageserver-protocol@>=3.1.1 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.1.1.tgz" + "version": "3.4.2", + "from": "vscode-languageserver-protocol@next", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.4.2.tgz" }, "vscode-languageserver-types": { - "version": "3.3.0", - "from": "vscode-languageserver-types@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz" + "version": "3.4.0", + "from": "vscode-languageserver-types@>=3.4.0 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.4.0.tgz" }, "vscode-nls": { "version": "2.0.2", diff --git a/extensions/css/package.json b/extensions/css/package.json index 1f7e0681b1e..fa48af3a4fc 100644 --- a/extensions/css/package.json +++ b/extensions/css/package.json @@ -720,12 +720,11 @@ ] }, "dependencies": { - "color-convert": "^0.5.3", - "vscode-languageclient": "3.4.0-next.17", - "vscode-languageserver-protocol": "^3.1.1", + "vscode-languageclient": "^3.4.2", + "vscode-languageserver-protocol": "^3.4.2", "vscode-nls": "^2.0.2" }, "devDependencies": { "@types/node": "^6.0.51" } -} \ No newline at end of file +} diff --git a/extensions/css/server/npm-shrinkwrap.json b/extensions/css/server/npm-shrinkwrap.json index 2c2d280b1a2..348abc705e6 100644 --- a/extensions/css/server/npm-shrinkwrap.json +++ b/extensions/css/server/npm-shrinkwrap.json @@ -3,29 +3,29 @@ "version": "1.0.0", "dependencies": { "vscode-css-languageservice": { - "version": "2.1.6", + "version": "2.1.7", "from": "vscode-css-languageservice@next", - "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.1.6.tgz" + "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.1.7.tgz" }, "vscode-jsonrpc": { - "version": "3.3.1", - "from": "vscode-jsonrpc@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.3.1.tgz" + "version": "3.4.0", + "from": "vscode-jsonrpc@>=3.4.0 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.4.0.tgz" }, "vscode-languageserver": { - "version": "3.4.0-next.6", + "version": "3.4.2", "from": "vscode-languageserver@next", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.4.0-next.6.tgz" + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.4.2.tgz" }, "vscode-languageserver-protocol": { - "version": "3.1.1", - "from": "vscode-languageserver-protocol@>=3.1.1 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.1.1.tgz" + "version": "3.4.2", + "from": "vscode-languageserver-protocol@next", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.4.2.tgz" }, "vscode-languageserver-types": { - "version": "3.3.0", + "version": "3.4.0", "from": "vscode-languageserver-types@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz" + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.4.0.tgz" }, "vscode-nls": { "version": "2.0.2", diff --git a/extensions/css/server/package.json b/extensions/css/server/package.json index b62b50928bf..76d9afbecf9 100644 --- a/extensions/css/server/package.json +++ b/extensions/css/server/package.json @@ -8,9 +8,9 @@ "node": "*" }, "dependencies": { - "vscode-css-languageservice": "^2.1.6", - "vscode-languageserver": "3.4.0-next.6", - "vscode-languageserver-protocol": "^3.1.1" + "vscode-css-languageservice": "^2.1.7", + "vscode-languageserver": "^3.4.2", + "vscode-languageserver-protocol": "^3.4.2" }, "devDependencies": { "@types/node": "^6.0.51" diff --git a/extensions/css/server/src/cssServerMain.ts b/extensions/css/server/src/cssServerMain.ts index 0f4e8873e98..34f558429f3 100644 --- a/extensions/css/server/src/cssServerMain.ts +++ b/extensions/css/server/src/cssServerMain.ts @@ -5,11 +5,13 @@ 'use strict'; import { - createConnection, IConnection, TextDocuments, TextDocument, InitializeParams, InitializeResult, ServerCapabilities + createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, ServerCapabilities } from 'vscode-languageserver'; -import { GetConfigurationRequest } from 'vscode-languageserver-protocol/lib/protocol.configuration.proposed'; -import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; +import { TextDocument } from 'vscode-languageserver-types'; + +import { ConfigurationRequest } from 'vscode-languageserver-protocol/lib/protocol.configuration.proposed'; +import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities, ColorPresentationRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; import { getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService, LanguageSettings, LanguageService, Stylesheet } from 'vscode-css-languageservice'; import { getLanguageModelCache } from './languageModelCache'; @@ -96,7 +98,7 @@ function getDocumentSettings(textDocument: TextDocument): Thenable s[0]); + promise = connection.sendRequest(ConfigurationRequest.type, configRequestParam).then(s => s[0]); documentSettings[textDocument.uri] = promise; } return promise; @@ -211,6 +213,15 @@ connection.onRequest(DocumentColorRequest.type, params => { return []; }); +connection.onRequest(ColorPresentationRequest.type, params => { + let document = documents.get(params.textDocument.uri); + if (document) { + let stylesheet = stylesheets.get(document); + return getLanguageService(document).getColorPresentations(document, stylesheet, params.colorInfo); + } + return []; +}); + connection.onRenameRequest(renameParameters => { let document = documents.get(renameParameters.textDocument.uri); let stylesheet = stylesheets.get(document); From 42549722b00b34724cb906234bbd3d0f3a608a65 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 21 Sep 2017 12:21:53 +0200 Subject: [PATCH 146/281] clean up styler --- src/vs/platform/theme/common/styler.ts | 189 ++++++++++++------------- 1 file changed, 91 insertions(+), 98 deletions(-) diff --git a/src/vs/platform/theme/common/styler.ts b/src/vs/platform/theme/common/styler.ts index d5d4698e424..03ae2a5dc63 100644 --- a/src/vs/platform/theme/common/styler.ts +++ b/src/vs/platform/theme/common/styler.ts @@ -11,6 +11,10 @@ import { IDisposable } from 'vs/base/common/lifecycle'; export type styleFn = (colors: { [name: string]: ColorIdentifier }) => void; +export interface IStyleOverrides { + [color: string]: ColorIdentifier; +} + export interface IThemable { style: styleFn; } @@ -43,36 +47,43 @@ export function attachStyler(themeService: IThemeServic return themeService.onThemeChange(applyStyles); } -export function attachCheckboxStyler(widget: IThemable, themeService: IThemeService, style?: { inputActiveOptionBorderColor?: ColorIdentifier }): IDisposable { - return attachStyler(themeService, { - inputActiveOptionBorder: (style && style.inputActiveOptionBorderColor) || inputActiveOptionBorder - }, widget); +export interface ICheckboxStyleOverrides extends IStyleOverrides { + inputActiveOptionBorderColor?: ColorIdentifier; } -export function attachBadgeStyler(widget: IThemable, themeService: IThemeService, style?: - { - badgeBackground?: ColorIdentifier, - badgeForeground?: ColorIdentifier - }): IDisposable { +export function attachCheckboxStyler(widget: IThemable, themeService: IThemeService, style?: ICheckboxStyleOverrides): IDisposable { + return attachStyler(themeService, { + inputActiveOptionBorder: (style && style.inputActiveOptionBorderColor) || inputActiveOptionBorder + } as ICheckboxStyleOverrides, widget); +} + +export interface IBadgeStyleOverrides extends IStyleOverrides { + badgeBackground?: ColorIdentifier; + badgeForeground?: ColorIdentifier; +} + +export function attachBadgeStyler(widget: IThemable, themeService: IThemeService, style?: IBadgeStyleOverrides): IDisposable { return attachStyler(themeService, { badgeBackground: (style && style.badgeBackground) || badgeBackground, badgeForeground: (style && style.badgeForeground) || badgeForeground, badgeBorder: contrastBorder - }, widget); + } as IBadgeStyleOverrides, widget); } -export function attachInputBoxStyler(widget: IThemable, themeService: IThemeService, style?: - { - inputBackground?: ColorIdentifier, - inputForeground?: ColorIdentifier, - inputBorder?: ColorIdentifier, - inputValidationInfoBorder?: ColorIdentifier, - inputValidationInfoBackground?: ColorIdentifier, - inputValidationWarningBorder?: ColorIdentifier, - inputValidationWarningBackground?: ColorIdentifier, - inputValidationErrorBorder?: ColorIdentifier, - inputValidationErrorBackground?: ColorIdentifier - }): IDisposable { +export interface IInputBoxStyleOverrides extends IStyleOverrides { + inputBackground?: ColorIdentifier; + inputForeground?: ColorIdentifier; + inputBorder?: ColorIdentifier; + inputActiveOptionBorder?: ColorIdentifier; + inputValidationInfoBorder?: ColorIdentifier; + inputValidationInfoBackground?: ColorIdentifier; + inputValidationWarningBorder?: ColorIdentifier; + inputValidationWarningBackground?: ColorIdentifier; + inputValidationErrorBorder?: ColorIdentifier; + inputValidationErrorBackground?: ColorIdentifier; +} + +export function attachInputBoxStyler(widget: IThemable, themeService: IThemeService, style?: IInputBoxStyleOverrides): IDisposable { return attachStyler(themeService, { inputBackground: (style && style.inputBackground) || inputBackground, inputForeground: (style && style.inputForeground) || inputForeground, @@ -83,30 +94,24 @@ export function attachInputBoxStyler(widget: IThemable, themeService: IThemeServ inputValidationWarningBackground: (style && style.inputValidationWarningBackground) || inputValidationWarningBackground, inputValidationErrorBorder: (style && style.inputValidationErrorBorder) || inputValidationErrorBorder, inputValidationErrorBackground: (style && style.inputValidationErrorBackground) || inputValidationErrorBackground - }, widget); + } as IInputBoxStyleOverrides, widget); } -export function attachSelectBoxStyler(widget: IThemable, themeService: IThemeService, style?: { selectBackground?: ColorIdentifier, selectForeground?: ColorIdentifier, selectBorder?: ColorIdentifier }): IDisposable { +export interface ISelectBoxStyleOverrides extends IStyleOverrides { + selectBackground?: ColorIdentifier; + selectForeground?: ColorIdentifier; + selectBorder?: ColorIdentifier; +} + +export function attachSelectBoxStyler(widget: IThemable, themeService: IThemeService, style?: ISelectBoxStyleOverrides): IDisposable { return attachStyler(themeService, { selectBackground: (style && style.selectBackground) || selectBackground, selectForeground: (style && style.selectForeground) || selectForeground, selectBorder: (style && style.selectBorder) || selectBorder - }, widget); + } as ISelectBoxStyleOverrides, widget); } -export function attachFindInputBoxStyler(widget: IThemable, themeService: IThemeService, style?: - { - inputBackground?: ColorIdentifier, - inputForeground?: ColorIdentifier, - inputBorder?: ColorIdentifier, - inputActiveOptionBorder?: ColorIdentifier, - inputValidationInfoBorder?: ColorIdentifier, - inputValidationInfoBackground?: ColorIdentifier, - inputValidationWarningBorder?: ColorIdentifier, - inputValidationWarningBackground?: ColorIdentifier, - inputValidationErrorBorder?: ColorIdentifier, - inputValidationErrorBackground?: ColorIdentifier - }): IDisposable { +export function attachFindInputBoxStyler(widget: IThemable, themeService: IThemeService, style?: IInputBoxStyleOverrides): IDisposable { return attachStyler(themeService, { inputBackground: (style && style.inputBackground) || inputBackground, inputForeground: (style && style.inputForeground) || inputForeground, @@ -118,43 +123,19 @@ export function attachFindInputBoxStyler(widget: IThemable, themeService: ITheme inputValidationWarningBackground: (style && style.inputValidationWarningBackground) || inputValidationWarningBackground, inputValidationErrorBorder: (style && style.inputValidationErrorBorder) || inputValidationErrorBorder, inputValidationErrorBackground: (style && style.inputValidationErrorBackground) || inputValidationErrorBackground - }, widget); + } as IInputBoxStyleOverrides, widget); } -export function attachQuickOpenStyler(widget: IThemable, themeService: IThemeService, style?: { - foreground?: ColorIdentifier, - background?: ColorIdentifier, - borderColor?: ColorIdentifier, - widgetShadow?: ColorIdentifier, - progressBarBackground?: ColorIdentifier, - inputBackground?: ColorIdentifier, - inputForeground?: ColorIdentifier, - inputBorder?: ColorIdentifier, - inputValidationInfoBorder?: ColorIdentifier, - inputValidationInfoBackground?: ColorIdentifier, - inputValidationWarningBorder?: ColorIdentifier, - inputValidationWarningBackground?: ColorIdentifier, - inputValidationErrorBorder?: ColorIdentifier, - inputValidationErrorBackground?: ColorIdentifier - pickerGroupForeground?: ColorIdentifier, - pickerGroupBorder?: ColorIdentifier, - listFocusBackground?: ColorIdentifier, - listFocusForeground?: ColorIdentifier, - listActiveSelectionBackground?: ColorIdentifier, - listActiveSelectionForeground?: ColorIdentifier, - listFocusAndSelectionBackground?: ColorIdentifier, - listFocusAndSelectionForeground?: ColorIdentifier, - listInactiveSelectionBackground?: ColorIdentifier, - listInactiveSelectionForeground?: ColorIdentifier, - listInactiveFocusBackground?: ColorIdentifier, - listInactiveFocusForeground?: ColorIdentifier, - listHoverBackground?: ColorIdentifier, - listHoverForeground?: ColorIdentifier, - listDropBackground?: ColorIdentifier, - listFocusOutline?: ColorIdentifier, - listSelectionOutline?: ColorIdentifier, - listHoverOutline?: ColorIdentifier -}): IDisposable { +export interface IQuickOpenStyleOverrides extends IListStyleOverrides, IInputBoxStyleOverrides, IProgressBarStyleOverrides { + foreground?: ColorIdentifier; + background?: ColorIdentifier; + borderColor?: ColorIdentifier; + widgetShadow?: ColorIdentifier; + pickerGroupForeground?: ColorIdentifier; + pickerGroupBorder?: ColorIdentifier; +}; + +export function attachQuickOpenStyler(widget: IThemable, themeService: IThemeService, style?: IQuickOpenStyleOverrides): IDisposable { return attachStyler(themeService, { foreground: (style && style.foreground) || foreground, background: (style && style.background) || editorBackground, @@ -188,28 +169,30 @@ export function attachQuickOpenStyler(widget: IThemable, themeService: IThemeSer listFocusOutline: (style && style.listFocusOutline) || activeContrastBorder, listSelectionOutline: (style && style.listSelectionOutline) || activeContrastBorder, listHoverOutline: (style && style.listHoverOutline) || activeContrastBorder - }, widget); + } as IQuickOpenStyleOverrides, widget); } -export function attachListStyler(widget: IThemable, themeService: IThemeService, style?: { - listFocusBackground?: ColorIdentifier, - listFocusForeground?: ColorIdentifier, - listActiveSelectionBackground?: ColorIdentifier, - listActiveSelectionForeground?: ColorIdentifier, - listFocusAndSelectionBackground?: ColorIdentifier, - listFocusAndSelectionForeground?: ColorIdentifier, - listInactiveSelectionBackground?: ColorIdentifier, - listInactiveSelectionForeground?: ColorIdentifier, - listInactiveFocusBackground?: ColorIdentifier, - listInactiveFocusForeground?: ColorIdentifier, - listHoverBackground?: ColorIdentifier, - listHoverForeground?: ColorIdentifier, - listDropBackground?: ColorIdentifier, - listFocusOutline?: ColorIdentifier, - listInactiveFocusOutline?: ColorIdentifier, - listSelectionOutline?: ColorIdentifier, - listHoverOutline?: ColorIdentifier, -}): IDisposable { +export interface IListStyleOverrides extends IStyleOverrides { + listFocusBackground?: ColorIdentifier; + listFocusForeground?: ColorIdentifier; + listActiveSelectionBackground?: ColorIdentifier; + listActiveSelectionForeground?: ColorIdentifier; + listFocusAndSelectionBackground?: ColorIdentifier; + listFocusAndSelectionForeground?: ColorIdentifier; + listInactiveSelectionBackground?: ColorIdentifier; + listInactiveSelectionForeground?: ColorIdentifier; + listInactiveFocusBackground?: ColorIdentifier; + listInactiveFocusForeground?: ColorIdentifier; + listHoverBackground?: ColorIdentifier; + listHoverForeground?: ColorIdentifier; + listDropBackground?: ColorIdentifier; + listFocusOutline?: ColorIdentifier; + listInactiveFocusOutline?: ColorIdentifier; + listSelectionOutline?: ColorIdentifier; + listHoverOutline?: ColorIdentifier; +} + +export function attachListStyler(widget: IThemable, themeService: IThemeService, style?: IListStyleOverrides): IDisposable { return attachStyler(themeService, { listFocusBackground: (style && style.listFocusBackground) || listFocusBackground, listFocusForeground: (style && style.listFocusForeground) || listFocusForeground, @@ -228,22 +211,32 @@ export function attachListStyler(widget: IThemable, themeService: IThemeService, listSelectionOutline: (style && style.listSelectionOutline) || activeContrastBorder, listHoverOutline: (style && style.listHoverOutline) || activeContrastBorder, listInactiveFocusOutline: style && style.listInactiveFocusOutline // not defined by default, only opt-in - }, widget); + } as IListStyleOverrides, widget); } -export function attachButtonStyler(widget: IThemable, themeService: IThemeService, style?: { buttonForeground?: ColorIdentifier, buttonBackground?: ColorIdentifier, buttonHoverBackground?: ColorIdentifier }): IDisposable { +export interface IButtonStyleOverrides extends IStyleOverrides { + buttonForeground?: ColorIdentifier; + buttonBackground?: ColorIdentifier; + buttonHoverBackground?: ColorIdentifier; +} + +export function attachButtonStyler(widget: IThemable, themeService: IThemeService, style?: IButtonStyleOverrides): IDisposable { return attachStyler(themeService, { buttonForeground: (style && style.buttonForeground) || buttonForeground, buttonBackground: (style && style.buttonBackground) || buttonBackground, buttonHoverBackground: (style && style.buttonHoverBackground) || buttonHoverBackground, buttonBorder: contrastBorder - }, widget); + } as IButtonStyleOverrides, widget); } -export function attachProgressBarStyler(widget: IThemable, themeService: IThemeService, style?: { progressBarBackground?: ColorIdentifier }): IDisposable { +export interface IProgressBarStyleOverrides extends IStyleOverrides { + progressBarBackground?: ColorIdentifier; +} + +export function attachProgressBarStyler(widget: IThemable, themeService: IThemeService, style?: IProgressBarStyleOverrides): IDisposable { return attachStyler(themeService, { progressBarBackground: (style && style.progressBarBackground) || progressBarBackground - }, widget); + } as IProgressBarStyleOverrides, widget); } export function attachStylerCallback(themeService: IThemeService, colors: { [name: string]: ColorIdentifier }, callback: styleFn): IDisposable { From f30de2dcef4c1cc75866581ede16e1299efd18a6 Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Thu, 21 Sep 2017 12:35:01 +0200 Subject: [PATCH 147/281] Fixes #34732: Tasks - Multiroot folder - no all detected tasks presented in quick pick --- .../parts/tasks/browser/quickOpen.ts | 10 ++- src/vs/workbench/parts/tasks/common/tasks.ts | 61 +++++++++++++------ .../electron-browser/task.contribution.ts | 29 ++++++--- .../electron-browser/configuration.test.ts | 2 +- 4 files changed, 71 insertions(+), 31 deletions(-) diff --git a/src/vs/workbench/parts/tasks/browser/quickOpen.ts b/src/vs/workbench/parts/tasks/browser/quickOpen.ts index c0cbb0c12b6..a842937eeca 100644 --- a/src/vs/workbench/parts/tasks/browser/quickOpen.ts +++ b/src/vs/workbench/parts/tasks/browser/quickOpen.ts @@ -98,7 +98,12 @@ export abstract class QuickOpenHandler extends Quickopen.QuickOpenHandler { let configured: CustomTask[] = []; let detected: ContributedTask[] = []; let taskMap: IStringDictionary = Object.create(null); - tasks.forEach(task => taskMap[Task.getKey(task)] = task); + tasks.forEach(task => { + let key = Task.getRecentlyUsedKey(task); + if (key) { + taskMap[key] = task; + } + }); recentlyUsedTasks.keys().forEach(key => { let task = taskMap[key]; if (task) { @@ -106,7 +111,8 @@ export abstract class QuickOpenHandler extends Quickopen.QuickOpenHandler { } }); for (let task of tasks) { - if (!recentlyUsedTasks.has(Task.getKey(task))) { + let key = Task.getRecentlyUsedKey(task); + if (!key || !recentlyUsedTasks.has(key)) { if (CustomTask.is(task)) { configured.push(task); } else { diff --git a/src/vs/workbench/parts/tasks/common/tasks.ts b/src/vs/workbench/parts/tasks/common/tasks.ts index 12c20adf3a3..6f4def9b10b 100644 --- a/src/vs/workbench/parts/tasks/common/tasks.ts +++ b/src/vs/workbench/parts/tasks/common/tasks.ts @@ -227,7 +227,7 @@ export enum TaskScope { export namespace TaskSourceKind { export const Workspace: 'workspace' = 'workspace'; export const Extension: 'extension' = 'extension'; - export const Composite: 'composite' = 'composite'; + export const InMemory: 'inMemory' = 'inMemory'; } export interface TaskSourceConfigElement { @@ -256,12 +256,12 @@ export interface ExtensionTaskSourceTransfer { __workspaceFolder: URI; } -export interface CompositeTaskSource { - readonly kind: 'composite'; +export interface InMemoryTaskSource { + readonly kind: 'inMemory'; readonly label: string; } -export type TaskSource = WorkspaceTaskSource | ExtensionTaskSource | CompositeTaskSource; +export type TaskSource = WorkspaceTaskSource | ExtensionTaskSource | InMemoryTaskSource; export interface TaskIdentifier { _key: string; @@ -403,33 +403,58 @@ export namespace ContributedTask { } } -export interface CompositeTask extends CommonTask, ConfigurationProperties { +export interface InMemoryTask extends CommonTask, ConfigurationProperties { /** * Indicated the source of the task (e.g tasks.json or extension) */ - _source: CompositeTaskSource; + _source: InMemoryTaskSource; - type: 'composite'; + type: 'inMemory'; identifier: string; } -export namespace CompositeTask { - export function is(value: any): value is CompositeTask { - let candidate = value as CompositeTask; - return candidate && candidate._source && candidate._source.kind === TaskSourceKind.Composite; +export namespace InMemoryTask { + export function is(value: any): value is InMemoryTask { + let candidate = value as InMemoryTask; + return candidate && candidate._source && candidate._source.kind === TaskSourceKind.InMemory; } } -export type Task = CustomTask | ContributedTask | CompositeTask; +export type Task = CustomTask | ContributedTask | InMemoryTask; export namespace Task { - export function getKey(task: Task): string { - if (CustomTask.is(task) || CompositeTask.is(task)) { - return task.identifier; - } else { - return task.defines._key; + export function getRecentlyUsedKey(task: Task): string | undefined { + interface CustomKey { + type: string; + folder: string; + id: string; } + interface ContributedKey { + type: string; + scope: number; + folder?: string; + id: string; + } + if (InMemoryTask.is(task)) { + return undefined; + } + if (CustomTask.is(task)) { + let workspaceFolder = task._source.config.workspaceFolder; + if (!workspaceFolder) { + return undefined; + } + let key: CustomKey = { type: 'custom', folder: workspaceFolder.uri.toString(), id: task.identifier }; + return JSON.stringify(key); + } + if (ContributedTask.is(task)) { + let key: ContributedKey = { type: 'contributed', scope: task._source.scope, id: task.defines._key }; + if (task._source.scope === TaskScope.Folder && task._source.workspaceFolder) { + key.folder = task._source.workspaceFolder.uri.toString(); + } + return JSON.stringify(key); + } + return undefined; } export function getWorkspaceFolder(task: Task): IWorkspaceFolder | undefined { @@ -455,7 +480,7 @@ export namespace Task { } else { return 'workspace'; } - } else if (CompositeTask.is(task)) { + } else if (InMemoryTask.is(task)) { return 'composite'; } else { return 'unknown'; diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index de7a52799e7..91753e9ff9c 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -73,7 +73,7 @@ import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs import { ITerminalService } from 'vs/workbench/parts/terminal/common/terminal'; import { ITaskSystem, ITaskResolver, ITaskSummary, ITaskExecuteResult, TaskExecuteKind, TaskError, TaskErrors, TaskSystemEvents, TaskTerminateResponse } from 'vs/workbench/parts/tasks/common/taskSystem'; -import { Task, CustomTask, ConfiguringTask, ContributedTask, CompositeTask, TaskSet, TaskGroup, ExecutionEngine, JsonSchemaVersion, TaskSourceKind, TaskIdentifier, TaskSorter } from 'vs/workbench/parts/tasks/common/tasks'; +import { Task, CustomTask, ConfiguringTask, ContributedTask, InMemoryTask, TaskSet, TaskGroup, ExecutionEngine, JsonSchemaVersion, TaskSourceKind, TaskIdentifier, TaskSorter } from 'vs/workbench/parts/tasks/common/tasks'; import { ITaskService, TaskServiceEvents, ITaskProvider, TaskEvent, RunOptions, CustomizationProperties } from 'vs/workbench/parts/tasks/common/taskService'; import { templates as taskTemplates } from 'vs/workbench/parts/tasks/common/taskTemplates'; @@ -849,7 +849,7 @@ class TaskService extends EventEmitter implements ITaskService { throw new TaskError(Severity.Info, nls.localize('TaskServer.noTask', 'Requested task {0} to execute not found.', task.name), TaskErrors.TaskNotFound); } else { let resolver = this.createResolver(grouped); - if (options && options.attachProblemMatcher && this.shouldAttachProblemMatcher(task) && !CompositeTask.is(task)) { + if (options && options.attachProblemMatcher && this.shouldAttachProblemMatcher(task) && !InMemoryTask.is(task)) { return this.attachProblemMatcher(task).then((toExecute) => { if (toExecute) { return this.executeTask(toExecute, resolver); @@ -1164,11 +1164,11 @@ class TaskService extends EventEmitter implements ITaskService { return { task: extensionTasks[0], resolver }; } else { let id: string = UUID.generateUuid(); - let task: CompositeTask = { + let task: InMemoryTask = { _id: id, - _source: { kind: TaskSourceKind.Composite, label: 'composite' }, + _source: { kind: TaskSourceKind.InMemory, label: 'inMemory' }, _label: id, - type: 'composite', + type: 'inMemory', name: id, identifier: id, dependsOn: extensionTasks.map((task) => { return { workspaceFolder: Task.getWorkspaceFolder(task), task: task._id }; }) @@ -1213,7 +1213,10 @@ class TaskService extends EventEmitter implements ITaskService { return ProblemMatcherRegistry.onReady().then(() => { return this.textFileService.saveAll().then((value) => { // make sure all dirty files are saved let executeResult = this.getTaskSystem().run(task, resolver); - this.getRecentlyUsedTasks().set(Task.getKey(task), Task.getKey(task), Touch.First); + let key = Task.getRecentlyUsedKey(task); + if (key) { + this.getRecentlyUsedTasks().set(key, key, Touch.First); + } if (executeResult.kind === TaskExecuteKind.Active) { let active = executeResult.active; if (active.same) { @@ -1809,7 +1812,12 @@ class TaskService extends EventEmitter implements ITaskService { let configured: Task[] = []; let detected: Task[] = []; let taskMap: IStringDictionary = Object.create(null); - tasks.forEach(task => taskMap[Task.getKey(task)] = task); + tasks.forEach(task => { + let key = Task.getRecentlyUsedKey(task); + if (key) { + taskMap[key] = task; + } + }); recentlyUsedTasks.keys().forEach(key => { let task = taskMap[key]; if (task) { @@ -1817,7 +1825,8 @@ class TaskService extends EventEmitter implements ITaskService { } }); for (let task of tasks) { - if (!recentlyUsedTasks.has(Task.getKey(task))) { + let key = Task.getRecentlyUsedKey(task); + if (!key || !recentlyUsedTasks.has(key)) { if (task._source.kind === TaskSourceKind.Workspace) { configured.push(task); } else { @@ -2216,7 +2225,7 @@ class TaskService extends EventEmitter implements ITaskService { if (task === defaultTask && CustomTask.is(task)) { this.openConfig(task); } - if (!CompositeTask.is(task)) { + if (!InMemoryTask.is(task)) { this.customize(task, { group: { kind: 'build', isDefault: true } }, true); } }); @@ -2250,7 +2259,7 @@ class TaskService extends EventEmitter implements ITaskService { if (!task) { return; } - if (!CompositeTask.is(task)) { + if (!InMemoryTask.is(task)) { this.customize(task, { group: { kind: 'test', isDefault: true } }, true); } }); diff --git a/src/vs/workbench/parts/tasks/test/electron-browser/configuration.test.ts b/src/vs/workbench/parts/tasks/test/electron-browser/configuration.test.ts index 85d747f12c3..4d212d7fd89 100644 --- a/src/vs/workbench/parts/tasks/test/electron-browser/configuration.test.ts +++ b/src/vs/workbench/parts/tasks/test/electron-browser/configuration.test.ts @@ -458,7 +458,7 @@ function assertConfiguration(result: ParseResult, expected: Tasks.Task[]): void function assertTask(actual: Tasks.Task, expected: Tasks.Task) { assert.ok(actual._id); assert.strictEqual(actual.name, expected.name, 'name'); - if (!Tasks.CompositeTask.is(actual) && !Tasks.CompositeTask.is(expected)) { + if (!Tasks.InMemoryTask.is(actual) && !Tasks.InMemoryTask.is(expected)) { assertCommandConfiguration(actual.command, expected.command); } assert.strictEqual(actual.isBackground, expected.isBackground, 'isBackground'); From 5f91aa5683776ee34bb1d2aa2ab3c5a4bbdffcd3 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 21 Sep 2017 12:50:37 +0200 Subject: [PATCH 148/281] Fixes #34722: compute occurences when switching back to a file which had occurences --- .../wordHighlighter/common/wordHighlighter.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts b/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts index 2cd8cab8f8c..573f8f08a9e 100644 --- a/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts +++ b/src/vs/editor/contrib/wordHighlighter/common/wordHighlighter.ts @@ -116,6 +116,17 @@ class WordHighlighter { this.renderDecorationsTimer = -1; } + public hasDecorations(): boolean { + return (this._decorationIds.length > 0); + } + + public restore(): void { + if (!this.occurrencesHighlight) { + return; + } + this._run(); + } + private _removeDecorations(): void { if (this._decorationIds.length > 0) { // remove decorations @@ -162,6 +173,10 @@ class WordHighlighter { return; } + this._run(); + } + + private _run(): void { // no providers for this model if (!DocumentHighlightProviderRegistry.has(this.model)) { this._stopAll(); @@ -344,6 +359,19 @@ class WordHighlighterContribution implements editorCommon.IEditorContribution { return WordHighlighterContribution.ID; } + public saveViewState(): boolean { + if (this.wordHighligher.hasDecorations()) { + return true; + } + return false; + } + + public restoreViewState(state: boolean | undefined): void { + if (state) { + this.wordHighligher.restore(); + } + } + public dispose(): void { this.wordHighligher.dispose(); } From b545921af3549fd79fec289691f91ac1d2ccf960 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 21 Sep 2017 12:52:09 +0200 Subject: [PATCH 149/281] better default config (for #30864) --- .../workbench/services/configuration/node/configuration.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configuration.ts index 797f44b66d3..f2f7f20657e 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configuration.ts @@ -32,7 +32,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry'; import { IConfigurationNode, IConfigurationRegistry, Extensions, editorConfigurationSchemaId, IDefaultConfigurationExtension, validateProperty, ConfigurationScope, settingsSchema, resourceSettingsSchema } from 'vs/platform/configuration/common/configurationRegistry'; import { createHash } from 'crypto'; -import { getWorkspaceLabel, IWorkspacesService, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { getWorkspaceLabel, IWorkspacesService, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspace } from 'vs/platform/workspaces/common/workspaces'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; @@ -636,7 +636,10 @@ class WorkspaceConfiguration extends Disposable { this._workspaceConfigurationWatcherDisposables = dispose(this._workspaceConfigurationWatcherDisposables); return new TPromise((c, e) => { this._workspaceConfigurationWatcher = new ConfigWatcher(this._workspaceConfigPath.fsPath, { - changeBufferDelay: 300, onError: error => errors.onUnexpectedError(error), defaultConfig: new WorkspaceConfigurationModel(null, this._workspaceConfigPath.fsPath), parse: (content: string, parseErrors: any[]) => { + changeBufferDelay: 300, + onError: error => errors.onUnexpectedError(error), + defaultConfig: new WorkspaceConfigurationModel(JSON.stringify({ folders: [] } as IStoredWorkspace, null, '\t'), this._workspaceConfigPath.fsPath), + parse: (content: string, parseErrors: any[]) => { const workspaceConfigurationModel = new WorkspaceConfigurationModel(content, this._workspaceConfigPath.fsPath); parseErrors = [...workspaceConfigurationModel.errors]; return workspaceConfigurationModel; From 883a04e825e144098c4c6327ea1fe2b4bb4bb9f0 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 21 Sep 2017 12:54:51 +0200 Subject: [PATCH 150/281] Do not search for empty glob patterns (#34487) --- src/vs/workbench/node/extensionHostMain.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/node/extensionHostMain.ts b/src/vs/workbench/node/extensionHostMain.ts index a3f3d77b31a..c08dd047c5d 100644 --- a/src/vs/workbench/node/extensionHostMain.ts +++ b/src/vs/workbench/node/extensionHostMain.ts @@ -204,6 +204,10 @@ export class ExtensionHostMain { } private async activateIfGlobPatterns(extensionId: string, globPatterns: string[]): TPromise { + if (globPatterns.length === 0) { + return TPromise.as(void 0); + } + if (!this._diskSearch) { // Shut down this search process after 1s this._diskSearch = new DiskSearch(false, 1000); From 8641e8407ab06b281d577b51b417c87204b02d68 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 21 Sep 2017 12:04:16 +0200 Subject: [PATCH 151/281] modesContentHover: remove console log --- src/vs/editor/contrib/hover/browser/modesContentHover.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/editor/contrib/hover/browser/modesContentHover.ts b/src/vs/editor/contrib/hover/browser/modesContentHover.ts index acd18602e01..bb0601afb80 100644 --- a/src/vs/editor/contrib/hover/browser/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/browser/modesContentHover.ts @@ -335,7 +335,6 @@ export class ModesContentHoverWidget extends ContentHoverWidget { let newRange; if (model.presentation.textEdit) { textEdits = [model.presentation.textEdit]; - console.log('insert text'); newRange = new Range( model.presentation.textEdit.range.startLineNumber, model.presentation.textEdit.range.startColumn, From 0e3d8542a1287bbeec795e12b1ef8c5de3d60fd8 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 21 Sep 2017 12:57:40 +0200 Subject: [PATCH 152/281] [json] provide colorpresentations in language server --- extensions/json/client/src/jsonMain.ts | 40 ++++++++++---------- extensions/json/npm-shrinkwrap.json | 24 ++++++------ extensions/json/package.json | 4 +- extensions/json/server/npm-shrinkwrap.json | 26 ++++++------- extensions/json/server/package.json | 7 ++-- extensions/json/server/src/jsonServerMain.ts | 11 +++++- 6 files changed, 60 insertions(+), 52 deletions(-) diff --git a/extensions/json/client/src/jsonMain.ts b/extensions/json/client/src/jsonMain.ts index 8ffdb77d52d..e1e94e1de80 100644 --- a/extensions/json/client/src/jsonMain.ts +++ b/extensions/json/client/src/jsonMain.ts @@ -6,11 +6,11 @@ import * as path from 'path'; -import { workspace, languages, ExtensionContext, extensions, Uri, TextDocument, ColorInformation, Color, ColorPresentation, TextEdit } from 'vscode'; +import { workspace, languages, ExtensionContext, extensions, Uri, TextDocument, ColorInformation, Color, ColorPresentation } from 'vscode'; import { LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType, DidChangeConfigurationNotification } from 'vscode-languageclient'; import TelemetryReporter from 'vscode-extension-telemetry'; -import { ConfigurationFeature } from 'vscode-languageclient/lib/proposed'; -import { DocumentColorRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; +import { ConfigurationFeature } from 'vscode-languageclient/lib/configuration.proposed'; +import { DocumentColorRequest, DocumentColorParams, ColorPresentationParams, ColorPresentationRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; import * as nls from 'vscode-nls'; @@ -116,14 +116,12 @@ export function activate(context: ExtensionContext) { client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociation(context)); - var _toTwoDigitHex = function (n: number): string { - const r = n.toString(16); - return r.length !== 2 ? '0' + r : r; - }; // register color provider context.subscriptions.push(languages.registerColorProvider(documentSelector, { provideDocumentColors(document: TextDocument): Thenable { - let params = client.code2ProtocolConverter.asDocumentSymbolParams(document); + let params: DocumentColorParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document) + }; return client.sendRequest(DocumentColorRequest.type, params).then(symbols => { return symbols.map(symbol => { let range = client.protocol2CodeConverter.asRange(symbol.range); @@ -132,19 +130,19 @@ export function activate(context: ExtensionContext) { }); }); }, - provideColorPresentations(document: TextDocument, colorInfo: ColorInformation): ColorPresentation[] | Thenable { - let result: ColorPresentation[] = []; - let color = colorInfo.color; - let label; - - if (color.alpha === 1) { - label = `#${_toTwoDigitHex(Math.round(color.red * 255))}${_toTwoDigitHex(Math.round(color.green * 255))}${_toTwoDigitHex(Math.round(color.blue * 255))}`; - } else { - label = `#${_toTwoDigitHex(Math.round(color.red * 255))}${_toTwoDigitHex(Math.round(color.green * 255))}${_toTwoDigitHex(Math.round(color.blue * 255))}${_toTwoDigitHex(Math.round(color.alpha * 255))}`; - } - - result.push({ label: label, textEdit: new TextEdit(colorInfo.range, label) }); - return result; + provideColorPresentations(document: TextDocument, colorInfo: ColorInformation): Thenable { + let params: ColorPresentationParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), + colorInfo: { range: client.code2ProtocolConverter.asRange(colorInfo.range), color: colorInfo.color } + }; + return client.sendRequest(ColorPresentationRequest.type, params).then(presentations => { + return presentations.map(p => { + let presentation = new ColorPresentation(p.label); + presentation.textEdit = p.textEdit && client.protocol2CodeConverter.asTextEdit(p.textEdit); + presentation.additionalTextEdits = p.additionalTextEdits && client.protocol2CodeConverter.asTextEdits(p.additionalTextEdits); + return presentation; + }); + }); } })); }); diff --git a/extensions/json/npm-shrinkwrap.json b/extensions/json/npm-shrinkwrap.json index 4caf64d28b7..2b10b555249 100644 --- a/extensions/json/npm-shrinkwrap.json +++ b/extensions/json/npm-shrinkwrap.json @@ -13,24 +13,24 @@ "resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.8.tgz" }, "vscode-jsonrpc": { - "version": "3.3.1", - "from": "vscode-jsonrpc@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.3.1.tgz" + "version": "3.4.0", + "from": "vscode-jsonrpc@>=3.4.0 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.4.0.tgz" }, "vscode-languageclient": { - "version": "3.4.0-next.17", + "version": "3.4.2", "from": "vscode-languageclient@next", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.4.0-next.17.tgz" + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.4.2.tgz" }, "vscode-languageserver-protocol": { - "version": "3.1.1", - "from": "vscode-languageserver-protocol@>=3.1.1 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.1.1.tgz" + "version": "3.4.2", + "from": "vscode-languageserver-protocol@3.4.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.4.2.tgz" }, "vscode-languageserver-types": { - "version": "3.3.0", - "from": "vscode-languageserver-types@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz" + "version": "3.4.0", + "from": "vscode-languageserver-types@>=3.4.0 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.4.0.tgz" }, "vscode-nls": { "version": "2.0.2", @@ -43,4 +43,4 @@ "resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.3.tgz" } } -} +} \ No newline at end of file diff --git a/extensions/json/package.json b/extensions/json/package.json index ba30bb1045d..7d49798f446 100644 --- a/extensions/json/package.json +++ b/extensions/json/package.json @@ -133,8 +133,8 @@ }, "dependencies": { "vscode-extension-telemetry": "0.0.8", - "vscode-languageclient": "3.4.0-next.17", - "vscode-languageserver-protocol": "^3.1.1", + "vscode-languageclient": "^3.4.2", + "vscode-languageserver-protocol": "^3.4.2", "vscode-nls": "2.0.2" }, "devDependencies": { diff --git a/extensions/json/server/npm-shrinkwrap.json b/extensions/json/server/npm-shrinkwrap.json index 3bcdb83008a..31c46482d9a 100644 --- a/extensions/json/server/npm-shrinkwrap.json +++ b/extensions/json/server/npm-shrinkwrap.json @@ -43,29 +43,29 @@ "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.2.1.tgz" }, "vscode-json-languageservice": { - "version": "2.0.18", + "version": "2.0.20", "from": "vscode-json-languageservice@next", - "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-2.0.18.tgz" + "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-2.0.20.tgz" }, "vscode-jsonrpc": { - "version": "3.3.1", - "from": "vscode-jsonrpc@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.3.1.tgz" + "version": "3.4.0", + "from": "vscode-jsonrpc@>=3.4.0 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.4.0.tgz" }, "vscode-languageserver": { - "version": "3.4.0-next.6", + "version": "3.4.2", "from": "vscode-languageserver@next", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.4.0-next.6.tgz" + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.4.2.tgz" }, "vscode-languageserver-protocol": { - "version": "3.1.1", - "from": "vscode-languageserver-protocol@>=3.1.1 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.1.1.tgz" + "version": "3.4.2", + "from": "vscode-languageserver-protocol@3.4.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.4.2.tgz" }, "vscode-languageserver-types": { - "version": "3.3.0", - "from": "vscode-languageserver-types@>=3.0.3 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz" + "version": "3.4.0", + "from": "vscode-languageserver-types@3.4.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.4.0.tgz" }, "vscode-nls": { "version": "2.0.2", diff --git a/extensions/json/server/package.json b/extensions/json/server/package.json index 684e9c35d28..068d0e7174b 100644 --- a/extensions/json/server/package.json +++ b/extensions/json/server/package.json @@ -10,9 +10,10 @@ "dependencies": { "jsonc-parser": "^1.0.0", "request-light": "^0.2.1", - "vscode-json-languageservice": "^2.0.18", - "vscode-languageserver": "3.4.0-next.6", - "vscode-languageserver-protocol": "^3.1.1", + "vscode-json-languageservice": "^2.0.20", + "vscode-languageserver": "^3.4.2", + "vscode-languageserver-protocol": "^3.4.2", + "vscode-languageserver-types": "^3.4.0", "vscode-nls": "^2.0.2", "vscode-uri": "^1.0.1" }, diff --git a/extensions/json/server/src/jsonServerMain.ts b/extensions/json/server/src/jsonServerMain.ts index 4d1c416c41c..64b604093d9 100644 --- a/extensions/json/server/src/jsonServerMain.ts +++ b/extensions/json/server/src/jsonServerMain.ts @@ -10,7 +10,7 @@ import { DocumentRangeFormattingRequest, Disposable, ServerCapabilities } from 'vscode-languageserver'; -import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; +import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities, ColorPresentationRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; import { xhr, XHRResponse, configure as configureHttpRequests, getErrorStatusDescription } from 'request-light'; import fs = require('fs'); @@ -311,5 +311,14 @@ connection.onRequest(DocumentColorRequest.type, params => { return []; }); +connection.onRequest(ColorPresentationRequest.type, params => { + let document = documents.get(params.textDocument.uri); + if (document) { + let jsonDocument = getJSONDocument(document); + return languageService.getColorPresentations(document, jsonDocument, params.colorInfo); + } + return []; +}); + // Listen on the connection connection.listen(); \ No newline at end of file From c6686be2631cba4723f1e2d371be14dd01c891d6 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 21 Sep 2017 12:57:51 +0200 Subject: [PATCH 153/281] [html] provide colorpresentations in language server --- extensions/html/client/src/htmlMain.ts | 58 ++++++------------- extensions/html/npm-shrinkwrap.json | 28 ++++----- extensions/html/package.json | 7 +-- extensions/html/server/npm-shrinkwrap.json | 26 ++++----- extensions/html/server/package.json | 6 +- extensions/html/server/src/htmlServerMain.ts | 21 +++++-- extensions/html/server/src/modes/cssMode.ts | 6 +- .../html/server/src/modes/languageModes.ts | 5 +- 8 files changed, 77 insertions(+), 80 deletions(-) diff --git a/extensions/html/client/src/htmlMain.ts b/extensions/html/client/src/htmlMain.ts index 39bf0e1a468..2dc9899c125 100644 --- a/extensions/html/client/src/htmlMain.ts +++ b/extensions/html/client/src/htmlMain.ts @@ -6,15 +6,14 @@ import * as path from 'path'; -import { languages, ExtensionContext, IndentAction, Position, TextDocument, Color, ColorInformation, ColorPresentation, TextEdit } from 'vscode'; +import { languages, ExtensionContext, IndentAction, Position, TextDocument, Color, ColorInformation, ColorPresentation } from 'vscode'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, RequestType, TextDocumentPositionParams } from 'vscode-languageclient'; import { EMPTY_ELEMENTS } from './htmlEmptyTagsShared'; import { activateTagClosing } from './tagClosing'; import TelemetryReporter from 'vscode-extension-telemetry'; -import * as convert from 'color-convert'; -import { ConfigurationFeature } from 'vscode-languageclient/lib/proposed'; -import { DocumentColorRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; +import { ConfigurationFeature } from 'vscode-languageclient/lib/configuration.proposed'; +import { DocumentColorRequest, DocumentColorParams, ColorPresentationRequest, ColorPresentationParams } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; import * as nls from 'vscode-nls'; let localize = nls.loadMessageBundle(); @@ -68,17 +67,14 @@ export function activate(context: ExtensionContext) { let client = new LanguageClient('html', localize('htmlserver.name', 'HTML Language Server'), serverOptions, clientOptions); client.registerFeature(new ConfigurationFeature(client)); - var _toTwoDigitHex = function (n: number): string { - const r = n.toString(16); - return r.length !== 2 ? '0' + r : r; - }; - let disposable = client.start(); toDispose.push(disposable); client.onReady().then(() => { disposable = languages.registerColorProvider(documentSelector, { provideDocumentColors(document: TextDocument): Thenable { - let params = client.code2ProtocolConverter.asDocumentSymbolParams(document); + let params: DocumentColorParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document) + }; return client.sendRequest(DocumentColorRequest.type, params).then(symbols => { return symbols.map(symbol => { let range = client.protocol2CodeConverter.asRange(symbol.range); @@ -87,35 +83,19 @@ export function activate(context: ExtensionContext) { }); }); }, - provideColorPresentations(document: TextDocument, colorInfo: ColorInformation): ColorPresentation[] | Thenable { - let result: ColorPresentation[] = []; - let color = colorInfo.color; - let label; - if (color.alpha === 1) { - label = `rgb(${Math.round(color.red * 255)}, ${Math.round(color.green * 255)}, ${Math.round(color.blue * 255)})`; - } else { - label = `rgba(${Math.round(color.red * 255)}, ${Math.round(color.green * 255)}, ${Math.round(color.blue * 255)}, ${color.alpha})`; - } - - result.push({ label: label, textEdit: new TextEdit(colorInfo.range, label) }); - - if (color.alpha === 1) { - label = `#${_toTwoDigitHex(Math.round(color.red * 255))}${_toTwoDigitHex(Math.round(color.green * 255))}${_toTwoDigitHex(Math.round(color.blue * 255))}`; - } else { - label = `#${_toTwoDigitHex(Math.round(color.red * 255))}${_toTwoDigitHex(Math.round(color.green * 255))}${_toTwoDigitHex(Math.round(color.blue * 255))}${_toTwoDigitHex(Math.round(color.alpha * 255))}`; - } - - result.push({ label: label, textEdit: new TextEdit(colorInfo.range, label) }); - - const hsl = convert.rgb.hsl(Math.round(color.red * 255), Math.round(color.green * 255), Math.round(color.blue * 255)); - if (color.alpha === 1) { - label = `hsl(${hsl[0]}, ${hsl[1]}%, ${hsl[2]}%)`; - } else { - label = `hsla(${hsl[0]}, ${hsl[1]}%, ${hsl[2]}%, ${color.alpha})`; - } - - result.push({ label: label, textEdit: new TextEdit(colorInfo.range, label) }); - return result; + provideColorPresentations(document: TextDocument, colorInfo: ColorInformation): Thenable { + let params: ColorPresentationParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), + colorInfo: { range: client.code2ProtocolConverter.asRange(colorInfo.range), color: colorInfo.color } + }; + return client.sendRequest(ColorPresentationRequest.type, params).then(presentations => { + return presentations.map(p => { + let presentation = new ColorPresentation(p.label); + presentation.textEdit = p.textEdit && client.protocol2CodeConverter.asTextEdit(p.textEdit); + presentation.additionalTextEdits = p.additionalTextEdits && client.protocol2CodeConverter.asTextEdits(p.additionalTextEdits); + return presentation; + }); + }); } }); toDispose.push(disposable); diff --git a/extensions/html/npm-shrinkwrap.json b/extensions/html/npm-shrinkwrap.json index 4f5dd2f3686..f2c127f085f 100644 --- a/extensions/html/npm-shrinkwrap.json +++ b/extensions/html/npm-shrinkwrap.json @@ -2,39 +2,39 @@ "name": "html", "version": "0.1.0", "dependencies": { - "color-convert": { - "version": "0.5.3", - "from": "color-convert@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz" - }, "applicationinsights": { "version": "0.18.0", "from": "applicationinsights@0.18.0", "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-0.18.0.tgz" }, + "color-convert": { + "version": "0.5.3", + "from": "color-convert@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz" + }, "vscode-extension-telemetry": { "version": "0.0.8", "from": "vscode-extension-telemetry@>=0.0.8 <0.0.9", "resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.8.tgz" }, "vscode-jsonrpc": { - "version": "3.3.1", - "from": "vscode-jsonrpc@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.3.1.tgz" + "version": "3.4.0", + "from": "vscode-jsonrpc@>=3.4.0 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.4.0.tgz" }, "vscode-languageclient": { - "version": "3.4.0-next.17", + "version": "3.4.2", "from": "vscode-languageclient@next", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.4.0-next.17.tgz" + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.4.2.tgz" }, "vscode-languageserver-protocol": { - "version": "3.1.1", - "from": "vscode-languageserver-protocol@>=3.1.1 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.1.1.tgz" + "version": "3.4.2", + "from": "vscode-languageserver-protocol@3.4.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.4.2.tgz" }, "vscode-languageserver-types": { "version": "3.3.0", - "from": "vscode-languageserver-types@>=3.3.0 <4.0.0", + "from": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz", "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz" }, "vscode-nls": { diff --git a/extensions/html/package.json b/extensions/html/package.json index 240cb7d8d9f..6926ac3f85a 100644 --- a/extensions/html/package.json +++ b/extensions/html/package.json @@ -215,11 +215,10 @@ } }, "dependencies": { - "color-convert": "^0.5.3", "vscode-extension-telemetry": "0.0.8", - "vscode-languageclient": "3.4.0-next.17", - "vscode-languageserver-protocol": "^3.1.1", - "vscode-languageserver-types": "^3.3.0", + "vscode-languageclient": "^3.4.2", + "vscode-languageserver-protocol": "^3.4.2", + "vscode-languageserver-types": "^3.4.0", "vscode-nls": "2.0.2" }, "devDependencies": { diff --git a/extensions/html/server/npm-shrinkwrap.json b/extensions/html/server/npm-shrinkwrap.json index 52f9b38450f..6f187b944b3 100644 --- a/extensions/html/server/npm-shrinkwrap.json +++ b/extensions/html/server/npm-shrinkwrap.json @@ -3,9 +3,9 @@ "version": "1.0.0", "dependencies": { "vscode-css-languageservice": { - "version": "2.1.6", + "version": "2.1.7", "from": "vscode-css-languageservice@next", - "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.1.6.tgz" + "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-2.1.7.tgz" }, "vscode-html-languageservice": { "version": "2.0.8", @@ -13,24 +13,24 @@ "resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-2.0.8.tgz" }, "vscode-jsonrpc": { - "version": "3.3.1", - "from": "vscode-jsonrpc@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.3.1.tgz" + "version": "3.4.0", + "from": "vscode-jsonrpc@>=3.4.0 <4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.4.0.tgz" }, "vscode-languageserver": { - "version": "3.4.0-next.6", + "version": "3.4.2", "from": "vscode-languageserver@next", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.4.0-next.6.tgz" + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.4.2.tgz" }, "vscode-languageserver-protocol": { - "version": "3.1.1", - "from": "vscode-languageserver-protocol@>=3.1.1 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.1.1.tgz" + "version": "3.4.2", + "from": "vscode-languageserver-protocol@3.4.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.4.2.tgz" }, "vscode-languageserver-types": { - "version": "3.3.0", - "from": "vscode-languageserver-types@>=3.3.0 <4.0.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz" + "version": "3.4.0", + "from": "vscode-languageserver-types@3.4.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.4.0.tgz" }, "vscode-nls": { "version": "2.0.2", diff --git a/extensions/html/server/package.json b/extensions/html/server/package.json index 8bcae7d7d90..169a0320972 100644 --- a/extensions/html/server/package.json +++ b/extensions/html/server/package.json @@ -8,10 +8,10 @@ "node": "*" }, "dependencies": { - "vscode-css-languageservice": "^2.1.6", + "vscode-css-languageservice": "^2.1.7", "vscode-html-languageservice": "^2.0.8", - "vscode-languageserver": "3.4.0-next.6", - "vscode-languageserver-protocol": "^3.1.1", + "vscode-languageserver": "^3.4.2", + "vscode-languageserver-protocol": "^3.4.2", "vscode-languageserver-types": "^3.3.0", "vscode-nls": "^2.0.2", "vscode-uri": "^1.0.1" diff --git a/extensions/html/server/src/htmlServerMain.ts b/extensions/html/server/src/htmlServerMain.ts index 14ea13ba25c..3f7258197a8 100644 --- a/extensions/html/server/src/htmlServerMain.ts +++ b/extensions/html/server/src/htmlServerMain.ts @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, RequestType, DocumentRangeFormattingRequest, Disposable, DocumentSelector, GetConfigurationParams, TextDocumentPositionParams, ServerCapabilities, Position } from 'vscode-languageserver'; +import { createConnection, IConnection, TextDocuments, InitializeParams, InitializeResult, RequestType, DocumentRangeFormattingRequest, Disposable, DocumentSelector, TextDocumentPositionParams, ServerCapabilities, Position } from 'vscode-languageserver'; import { DocumentContext } from 'vscode-html-languageservice'; import { TextDocument, Diagnostic, DocumentLink, SymbolInformation } from 'vscode-languageserver-types'; import { getLanguageModes, LanguageModes, Settings } from './modes/languageModes'; -import { GetConfigurationRequest } from 'vscode-languageserver-protocol/lib/protocol.configuration.proposed'; -import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities, ColorInformation } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; +import { ConfigurationRequest, ConfigurationParams } from 'vscode-languageserver-protocol/lib/protocol.configuration.proposed'; +import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities, ColorInformation, ColorPresentationRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed'; import { format } from './modes/formatting'; import { pushAll } from './utils/arrays'; @@ -58,8 +58,8 @@ function getDocumentSettings(textDocument: TextDocument, needsDocumentSettings: let promise = documentSettings[textDocument.uri]; if (!promise) { let scopeUri = textDocument.uri; - let configRequestParam: GetConfigurationParams = { items: [{ scopeUri, section: 'css' }, { scopeUri, section: 'html' }, { scopeUri, section: 'javascript' }] }; - promise = connection.sendRequest(GetConfigurationRequest.type, configRequestParam).then(s => ({ css: s[0], html: s[1], javascript: s[2] })); + let configRequestParam: ConfigurationParams = { items: [{ scopeUri, section: 'css' }, { scopeUri, section: 'html' }, { scopeUri, section: 'javascript' }] }; + promise = connection.sendRequest(ConfigurationRequest.type, configRequestParam).then(s => ({ css: s[0], html: s[1], javascript: s[2] })); documentSettings[textDocument.uri] = promise; } return promise; @@ -323,6 +323,17 @@ connection.onRequest(DocumentColorRequest.type, params => { return infos; }); +connection.onRequest(ColorPresentationRequest.type, params => { + let document = documents.get(params.textDocument.uri); + if (document) { + let mode = languageModes.getModeAtPosition(document, params.colorInfo.range.start); + if (mode && mode.getColorPresentations) { + return mode.getColorPresentations(document, params.colorInfo); + } + } + return []; +}); + connection.onRequest(TagCloseRequest.type, params => { let document = documents.get(params.textDocument.uri); if (document) { diff --git a/extensions/html/server/src/modes/cssMode.ts b/extensions/html/server/src/modes/cssMode.ts index dcb221e83d5..0dc06cc10ba 100644 --- a/extensions/html/server/src/modes/cssMode.ts +++ b/extensions/html/server/src/modes/cssMode.ts @@ -7,7 +7,7 @@ import { LanguageModelCache, getLanguageModelCache } from '../languageModelCache'; import { TextDocument, Position } from 'vscode-languageserver-types'; import { getCSSLanguageService, Stylesheet } from 'vscode-css-languageservice'; -import { LanguageMode, Settings } from './languageModes'; +import { LanguageMode, Settings, ColorInformation } from './languageModes'; import { HTMLDocumentRegions, CSS_STYLE_RULE } from './embeddedSupport'; export function getCSSMode(documentRegions: LanguageModelCache): LanguageMode { @@ -54,6 +54,10 @@ export function getCSSMode(documentRegions: LanguageModelCache Location[]; format?: (document: TextDocument, range: Range, options: FormattingOptions, settings: Settings) => TextEdit[]; findDocumentColors?: (document: TextDocument) => ColorInformation[]; + getColorPresentations?: (document: TextDocument, colorInfo: ColorInformation) => ColorPresentation[]; doAutoClose?: (document: TextDocument, position: Position) => string; onDocumentRemoved(document: TextDocument): void; dispose(): void; From 88449158638f814a8c0bf43189f8a6cab4211495 Mon Sep 17 00:00:00 2001 From: Erich Gamma Date: Thu, 21 Sep 2017 13:56:42 +0200 Subject: [PATCH 154/281] ensure that the scheme is 'file' detecting scripts --- extensions/npm/src/main.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/extensions/npm/src/main.ts b/extensions/npm/src/main.ts index 3cf4df511fc..925622f2010 100644 --- a/extensions/npm/src/main.ts +++ b/extensions/npm/src/main.ts @@ -104,9 +104,13 @@ function isEnabled(folder: vscode.WorkspaceFolder): boolean { } async function provideNpmScriptsForFolder(folder: vscode.WorkspaceFolder): Promise { - let rootPath = folder.uri.fsPath; let emptyTasks: vscode.Task[] = []; + if (folder.uri.scheme !== 'file') { + return emptyTasks; + } + let rootPath = folder.uri.fsPath; + let packageJson = path.join(rootPath, 'package.json'); if (!await exists(packageJson)) { return emptyTasks; From 253d255f573b7bb0ca71018219a2ea31dce097dd Mon Sep 17 00:00:00 2001 From: isidor Date: Thu, 21 Sep 2017 15:52:27 +0200 Subject: [PATCH 155/281] debug: location of repl messages fixes #24490 --- .../parts/debug/browser/media/repl.css | 16 ++++++++ src/vs/workbench/parts/debug/common/debug.ts | 7 ++++ .../parts/debug/common/debugModel.ts | 38 ++++++++----------- .../parts/debug/common/debugSource.ts | 17 +++++++++ .../debug/electron-browser/debugService.ts | 16 +++++--- .../debug/electron-browser/replViewer.ts | 31 +++++++++++++-- 6 files changed, 94 insertions(+), 31 deletions(-) diff --git a/src/vs/workbench/parts/debug/browser/media/repl.css b/src/vs/workbench/parts/debug/browser/media/repl.css index 01c8566b02b..694cb4c9de8 100644 --- a/src/vs/workbench/parts/debug/browser/media/repl.css +++ b/src/vs/workbench/parts/debug/browser/media/repl.css @@ -36,6 +36,22 @@ font-size: 12px; } +.monaco-workbench.mac .repl .repl-tree .monaco-tree-row .output.expression.value-and-source { + display: flex; +} + + +.monaco-workbench.mac .repl .repl-tree .monaco-tree-row .output.expression.value-and-source .value { + flex: 1; +} + +.monaco-workbench.mac .repl .repl-tree .monaco-tree-row .output.expression.value-and-source .source { + margin-left: 4px; + margin-right: 8px; + cursor: pointer; + text-decoration: underline; +} + .monaco-workbench.windows .repl .repl-tree .monaco-tree-row .input.expression, .monaco-workbench.windows .repl .repl-tree .monaco-tree-row .output.expression, .monaco-workbench.linux .repl .repl-tree .monaco-tree-row .input.expression, diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index 687d891b493..465742b8560 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -73,6 +73,13 @@ export interface ITreeElement { export interface IReplElement extends ITreeElement { toString(): string; + sourceData?: IReplElementSource; +} + +export interface IReplElementSource { + source: Source; + lineNumber: number; + column: number; } export interface IExpressionContainer extends ITreeElement { diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index c104055acee..9d9f29b99d1 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -19,7 +19,7 @@ import { Range, IRange } from 'vs/editor/common/core/range'; import { ISuggestion } from 'vs/editor/common/modes'; import { Position } from 'vs/editor/common/core/position'; import { - ITreeElement, IExpression, IExpressionContainer, IProcess, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IModel, + ITreeElement, IExpression, IExpressionContainer, IProcess, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IModel, IReplElementSource, IConfig, ISession, IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IRawBreakpoint, IExceptionInfo, IReplElement, ProcessState } from 'vs/workbench/parts/debug/common/debug'; import { Source } from 'vs/workbench/parts/debug/common/debugSource'; @@ -30,7 +30,7 @@ const MAX_REPL_LENGTH = 10000; export abstract class AbstractOutputElement implements IReplElement { private static ID_COUNTER = 0; - constructor(private id = AbstractOutputElement.ID_COUNTER++) { + constructor(public sourceData: IReplElementSource, private id = AbstractOutputElement.ID_COUNTER++) { // noop } @@ -47,8 +47,9 @@ export class OutputElement extends AbstractOutputElement { constructor( public value: string, public severity: severity, + source: IReplElementSource, ) { - super(); + super(source); } public toString(): string { @@ -60,8 +61,8 @@ export class OutputNameValueElement extends AbstractOutputElement implements IEx private static MAX_CHILDREN = 1000; // upper bound of children per value - constructor(public name: string, public valueObj: any, public annotation?: string) { - super(); + constructor(public name: string, public valueObj: any, source?: IReplElementSource, public annotation?: string) { + super(source); } public get value(): string { @@ -379,18 +380,8 @@ export class StackFrame implements IStackFrame { } public openInEditor(editorService: IWorkbenchEditorService, preserveFocus?: boolean, sideBySide?: boolean): TPromise { - - return !this.source.available ? TPromise.as(null) : editorService.openEditor({ - resource: this.source.uri, - description: this.source.origin, - options: { - preserveFocus, - selection: this.range, - revealIfVisible: true, - revealInCenterIfOutsideViewport: true, - pinned: !preserveFocus && !this.source.inMemory - } - }, sideBySide); + return !this.source.available ? TPromise.as(null) : + this.source.openInEditor(editorService, this.range, preserveFocus, sideBySide); } } @@ -960,22 +951,23 @@ export class Model implements IModel { .then(() => this._onDidChangeREPLElements.fire()); } - public appendToRepl(output: string | IExpression, severity: severity): void { + public appendToRepl(output: string | IExpression, severity: severity, source?: IReplElementSource): void { if (typeof output === 'string') { const previousOutput = this.replElements.length && (this.replElements[this.replElements.length - 1] as OutputElement); - const toAdd = output.split('\n').map(line => new OutputElement(line, severity)); - if (previousOutput instanceof OutputElement && severity === previousOutput.severity && toAdd.length) { - previousOutput.value += toAdd.shift().value; - } - if (previousOutput && previousOutput.value === '' && previousOutput.severity !== severity) { + const toAdd = output.split('\n').map((line, index) => new OutputElement(line, severity, index === 0 ? source : undefined)); + if (previousOutput && previousOutput.value === '') { // remove potential empty lines between different output types this.replElements.pop(); } + if (previousOutput instanceof OutputElement && severity === previousOutput.severity && toAdd.length && toAdd[0].sourceData === previousOutput.sourceData) { + previousOutput.value += toAdd.shift().value; + } this.addReplElements(toAdd); } else { // TODO@Isidor hack, we should introduce a new type which is an output that can fetch children like an expression (output).severity = severity; + (output).sourceData = source; this.addReplElements([output]); } diff --git a/src/vs/workbench/parts/debug/common/debugSource.ts b/src/vs/workbench/parts/debug/common/debugSource.ts index 1d8e8f79c8f..2fab8508e1b 100644 --- a/src/vs/workbench/parts/debug/common/debugSource.ts +++ b/src/vs/workbench/parts/debug/common/debugSource.ts @@ -4,8 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; +import { TPromise } from 'vs/base/common/winjs.base'; import uri from 'vs/base/common/uri'; import { DEBUG_SCHEME } from 'vs/workbench/parts/debug/common/debug'; +import { IRange } from 'vs/editor/common/core/range'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Source"); @@ -46,4 +49,18 @@ export class Source { public get inMemory() { return this.uri.scheme === DEBUG_SCHEME; } + + public openInEditor(editorService: IWorkbenchEditorService, selection: IRange, preserveFocus?: boolean, sideBySide?: boolean): TPromise { + return !this.available ? TPromise.as(null) : editorService.openEditor({ + resource: this.uri, + description: this.origin, + options: { + preserveFocus, + selection, + revealIfVisible: true, + revealInCenterIfOutsideViewport: true, + pinned: !preserveFocus && !this.inMemory + } + }, sideBySide); + } } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 9ea9e9781bb..f88b0136dd8 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -199,7 +199,7 @@ export class DebugService implements debug.IDebugService { } // show object - this.logToRepl(new OutputNameValueElement((a).prototype, a, nls.localize('snapshotObj', "Only primitive values are shown for this object.")), sev); + this.logToRepl(new OutputNameValueElement((a).prototype, a, undefined, nls.localize('snapshotObj', "Only primitive values are shown for this object.")), sev); } // string: watch out for % replacement directive @@ -335,17 +335,23 @@ export class DebugService implements debug.IDebugService { return; } + const source = event.body.source ? { + lineNumber: event.body.line, + column: event.body.column, + source: process.getSource(event.body.source) + } : undefined; + if (event.body.variablesReference) { const container = new ExpressionContainer(process, event.body.variablesReference, generateUuid()); container.getChildren().then(children => { children.forEach(child => { // Since we can not display multiple trees in a row, we are displaying these variables one after the other (ignoring their names) child.name = null; - this.logToRepl(child, outputSeverity); + this.logToRepl(child, outputSeverity, source); }); }); } else if (typeof event.body.output === 'string') { - this.logToRepl(event.body.output, outputSeverity); + this.logToRepl(event.body.output, outputSeverity, source); } })); @@ -594,12 +600,12 @@ export class DebugService implements debug.IDebugService { this.model.removeReplExpressions(); } - public logToRepl(value: string | debug.IExpression, sev = severity.Info): void { + public logToRepl(value: string | debug.IExpression, sev = severity.Info, source?: debug.IReplElementSource): void { if (typeof value === 'string' && '[2J'.localeCompare(value) === 0) { // [2J is the ansi escape sequence for clearing the display http://ascii-table.com/ansi-escape-sequences.php this.model.removeReplExpressions(); } else { - this.model.appendToRepl(value, sev); + this.model.appendToRepl(value, sev, source); } } diff --git a/src/vs/workbench/parts/debug/electron-browser/replViewer.ts b/src/vs/workbench/parts/debug/electron-browser/replViewer.ts index bfe1493d1d1..6084cb72d04 100644 --- a/src/vs/workbench/parts/debug/electron-browser/replViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/replViewer.ts @@ -6,6 +6,8 @@ import * as nls from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { IAction } from 'vs/base/common/actions'; +import * as lifecycle from 'vs/base/common/lifecycle'; +import * as errors from 'vs/base/common/errors'; import { isFullWidthCharacter, removeAnsiEscapeCodes, endsWith } from 'vs/base/common/strings'; import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import * as dom from 'vs/base/browser/dom'; @@ -13,7 +15,7 @@ import severity from 'vs/base/common/severity'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { ITree, IAccessibilityProvider, ContextMenuEvent, IDataSource, IRenderer, IActionProvider } from 'vs/base/parts/tree/browser/tree'; import { ICancelableEvent } from 'vs/base/parts/tree/browser/treeDefaults'; -import { IExpressionContainer, IExpression } from 'vs/workbench/parts/debug/common/debug'; +import { IExpressionContainer, IExpression, IReplElementSource } from 'vs/workbench/parts/debug/common/debug'; import { Model, OutputNameValueElement, Expression, OutputElement, Variable } from 'vs/workbench/parts/debug/common/debugModel'; import { renderVariable, renderExpressionValue, IVariableTemplateData, BaseDebugController } from 'vs/workbench/parts/debug/electron-browser/debugViewer'; import { ClearReplAction } from 'vs/workbench/parts/debug/browser/debugActions'; @@ -63,6 +65,9 @@ interface IExpressionTemplateData { interface IValueOutputTemplateData { container: HTMLElement; value: HTMLElement; + source: HTMLElement; + getReplElementSource(): IReplElementSource; + toDispose: lifecycle.IDisposable[]; } interface IKeyValueOutputTemplateData { @@ -174,10 +179,25 @@ export class ReplExpressionsRenderer implements IRenderer { if (templateId === ReplExpressionsRenderer.VALUE_OUTPUT_TEMPLATE_ID) { let data: IValueOutputTemplateData = Object.create(null); dom.addClass(container, 'output'); - let expression = dom.append(container, $('.output.expression')); + let expression = dom.append(container, $('.output.expression.value-and-source')); data.container = container; data.value = dom.append(expression, $('span.value')); + data.source = dom.append(expression, $('.source')); + data.toDispose = []; + data.toDispose.push(dom.addDisposableListener(data.source, 'click', e => { + e.preventDefault(); + e.stopPropagation(); + const source = data.getReplElementSource(); + if (source) { + source.source.openInEditor(this.editorService, { + startLineNumber: source.lineNumber, + startColumn: source.column, + endLineNumber: source.lineNumber, + endColumn: source.column + }).done(undefined, errors.onUnexpectedError); + } + })); return data; } @@ -236,6 +256,9 @@ export class ReplExpressionsRenderer implements IRenderer { } dom.addClass(templateData.value, (output.severity === severity.Warning) ? 'warn' : (output.severity === severity.Error) ? 'error' : 'info'); + templateData.source.textContent = output.sourceData ? `${output.sourceData.source.name}:${output.sourceData.lineNumber}` : ''; + templateData.source.title = output.sourceData ? output.sourceData.source.uri.toString() : ''; + templateData.getReplElementSource = () => output.sourceData; } private renderOutputNameValue(tree: ITree, output: OutputNameValueElement, templateData: IKeyValueOutputTemplateData): void { @@ -352,7 +375,9 @@ export class ReplExpressionsRenderer implements IRenderer { } public disposeTemplate(tree: ITree, templateId: string, templateData: any): void { - // noop + if (templateData.toDispose) { + lifecycle.dispose(templateData.toDispose); + } } } From a72131a5d0dfed6b78e3a01b6dbe02c1152fe3fb Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 21 Sep 2017 15:57:06 +0200 Subject: [PATCH 156/281] Only paint the dirty image data rectangle (#34170) --- .../browser/viewParts/minimap/minimap.ts | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 71c534741ef..ab984ed37ec 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -709,7 +709,7 @@ export class Minimap extends ViewPart { const imageData = this._getBuffer(); // Render untouched lines by using last rendered data. - let needed = Minimap._renderUntouchedLines( + let [_dirtyY1, _dirtyY2, needed] = Minimap._renderUntouchedLines( imageData, startLineNumber, endLineNumber, @@ -744,9 +744,13 @@ export class Minimap extends ViewPart { dy += minimapLineHeight; } + const dirtyY1 = (_dirtyY1 === -1 ? 0 : _dirtyY1); + const dirtyY2 = (_dirtyY2 === -1 ? imageData.height : _dirtyY2); + const dirtyHeight = dirtyY2 - dirtyY1; + // Finally, paint to the canvas const ctx = this._canvas.domNode.getContext('2d'); - ctx.putImageData(imageData, 0, 0); + ctx.putImageData(imageData, 0, 0, 0, dirtyY1, imageData.width, dirtyHeight); // Save rendered data for reuse on next frame if possible return new RenderData( @@ -762,14 +766,14 @@ export class Minimap extends ViewPart { endLineNumber: number, minimapLineHeight: number, lastRenderData: RenderData, - ): boolean[] { + ): [number, number, boolean[]] { let needed: boolean[] = []; if (!lastRenderData) { for (let i = 0, len = endLineNumber - startLineNumber + 1; i < len; i++) { needed[i] = true; } - return needed; + return [-1, -1, needed]; } const _lastData = lastRenderData._get(); @@ -780,6 +784,10 @@ export class Minimap extends ViewPart { const WIDTH = target.width; const targetData = target.data; + const maxDestPixel = (endLineNumber - startLineNumber + 1) * minimapLineHeight * WIDTH * 4; + let dirtyPixel1 = -1; // the pixel offset up to which all the data is equal to the prev frame + let dirtyPixel2 = -1; // the pixel offset after which all the data is equal to the prev frame + let copySourceStart = -1; let copySourceEnd = -1; let copyDestStart = -1; @@ -810,6 +818,12 @@ export class Minimap extends ViewPart { if (copySourceStart !== -1) { // flush existing copy request targetData.set(lastTargetData.subarray(copySourceStart, copySourceEnd), copyDestStart); + if (dirtyPixel1 === -1 && copySourceStart === 0 && copySourceStart === copyDestStart) { + dirtyPixel1 = copySourceEnd; + } + if (dirtyPixel2 === -1 && copySourceEnd === maxDestPixel && copySourceStart === copyDestStart) { + dirtyPixel2 = copySourceStart; + } } copySourceStart = sourceStart; copySourceEnd = sourceEnd; @@ -824,9 +838,18 @@ export class Minimap extends ViewPart { if (copySourceStart !== -1) { // flush existing copy request targetData.set(lastTargetData.subarray(copySourceStart, copySourceEnd), copyDestStart); + if (dirtyPixel1 === -1 && copySourceStart === 0 && copySourceStart === copyDestStart) { + dirtyPixel1 = copySourceEnd; + } + if (dirtyPixel2 === -1 && copySourceEnd === maxDestPixel && copySourceStart === copyDestStart) { + dirtyPixel2 = copySourceStart; + } } - return needed; + const dirtyY1 = (dirtyPixel1 === -1 ? -1 : dirtyPixel1 / (WIDTH * 4)); + const dirtyY2 = (dirtyPixel2 === -1 ? -1 : dirtyPixel2 / (WIDTH * 4)); + + return [dirtyY1, dirtyY2, needed]; } private static _renderLine( From 277126132d45144464202333444d612b7e4bc9df Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Thu, 21 Sep 2017 15:22:48 +0200 Subject: [PATCH 157/281] Defer folder setup computation --- .../electron-browser/task.contribution.ts | 80 ++++++++++++------- 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index 91753e9ff9c..106a280e398 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -564,9 +564,9 @@ class TaskService extends EventEmitter implements ITaskService { private quickOpenService: IQuickOpenService; private _configHasErrors: boolean; - private _schemaVersion: JsonSchemaVersion; - private _executionEngine: ExecutionEngine; - private _workspaceFolders: IWorkspaceFolder[]; + private __schemaVersion: JsonSchemaVersion; + private __executionEngine: ExecutionEngine; + private __workspaceFolders: IWorkspaceFolder[]; private _providers: Map; private _workspaceTasksPromise: TPromise>; @@ -621,8 +621,8 @@ class TaskService extends EventEmitter implements ITaskService { if (!this._taskSystem && !this._workspaceTasksPromise) { return; } - let folderSetup = this.computeWorkspaceFolders(); - if (this._executionEngine !== folderSetup[1] && this._taskSystem && this._taskSystem.getActiveTasks().length > 0) { + let folderSetup = this.computeWorkspaceFolderSetup(); + if (this.executionEngine !== folderSetup[1] && this._taskSystem && this._taskSystem.getActiveTasks().length > 0) { this.messageService.show( Severity.Info, { @@ -638,15 +638,9 @@ class TaskService extends EventEmitter implements ITaskService { ); return; } - this._workspaceFolders = folderSetup[0]; - this._executionEngine = folderSetup[1]; - this._schemaVersion = folderSetup[2]; + this.updateSetup(folderSetup); this.updateWorkspaceTasks(); }); - let folderSetup = this.computeWorkspaceFolders(); - this._workspaceFolders = folderSetup[0]; - this._executionEngine = folderSetup[1]; - this._schemaVersion = folderSetup[2]; lifecycleService.onWillShutdown(event => event.veto(this.beforeShutdown())); this.registerCommands(); } @@ -709,6 +703,36 @@ class TaskService extends EventEmitter implements ITaskService { }); } + private get workspaceFolders(): IWorkspaceFolder[] { + if (!this.__workspaceFolders) { + this.updateSetup(); + } + return this.__workspaceFolders; + } + + private get executionEngine(): ExecutionEngine { + if (this.__executionEngine === void 0) { + this.updateSetup(); + } + return this.__executionEngine; + } + + private get schemaVersion(): JsonSchemaVersion { + if (this.__schemaVersion === void 0) { + this.updateSetup(); + } + return this.__schemaVersion; + } + + private updateSetup(setup?: [IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion]): void { + if (!setup) { + setup = this.computeWorkspaceFolderSetup(); + } + this.__workspaceFolders = setup[0]; + this.__executionEngine = setup[1]; + this.__schemaVersion = setup[2]; + } + private showOutput(): void { this._outputChannel.show(true); } @@ -805,7 +829,7 @@ class TaskService extends EventEmitter implements ITaskService { return this.getGroupedTasks().then((tasks) => { let runnable = this.createRunnableTask(tasks, TaskGroup.Build); if (!runnable || !runnable.task) { - if (this._schemaVersion === JsonSchemaVersion.V0_1_0) { + if (this.schemaVersion === JsonSchemaVersion.V0_1_0) { throw new TaskError(Severity.Info, nls.localize('TaskService.noBuildTask1', 'No build task defined. Mark a task with \'isBuildCommand\' in the tasks.json file.'), TaskErrors.NoBuildTask); } else { throw new TaskError(Severity.Info, nls.localize('TaskService.noBuildTask2', 'No build task defined. Mark a task with as a \'build\' group in the tasks.json file.'), TaskErrors.NoBuildTask); @@ -830,7 +854,7 @@ class TaskService extends EventEmitter implements ITaskService { return this.getGroupedTasks().then((tasks) => { let runnable = this.createRunnableTask(tasks, TaskGroup.Test); if (!runnable || !runnable.task) { - if (this._schemaVersion === JsonSchemaVersion.V0_1_0) { + if (this.schemaVersion === JsonSchemaVersion.V0_1_0) { throw new TaskError(Severity.Info, nls.localize('TaskService.noTestTask1', 'No test task defined. Mark a task with \'isTestCommand\' in the tasks.json file.'), TaskErrors.NoTestTask); } else { throw new TaskError(Severity.Info, nls.localize('TaskService.noTestTask2', 'No test task defined. Mark a task with as a \'test\' group in the tasks.json file.'), TaskErrors.NoTestTask); @@ -963,7 +987,7 @@ class TaskService extends EventEmitter implements ITaskService { } public canCustomize(task: Task): boolean { - if (this._schemaVersion !== JsonSchemaVersion.V2_0_0) { + if (this.schemaVersion !== JsonSchemaVersion.V2_0_0) { return false; } if (CustomTask.is(task)) { @@ -1269,7 +1293,7 @@ class TaskService extends EventEmitter implements ITaskService { if (this._taskSystem) { return this._taskSystem; } - if (this._executionEngine === ExecutionEngine.Terminal) { + if (this.executionEngine === ExecutionEngine.Terminal) { this._taskSystem = new TerminalTaskSystem( this.terminalService, this.outputService, this.markerService, this.modelService, this.configurationResolverService, this.telemetryService, @@ -1309,7 +1333,7 @@ class TaskService extends EventEmitter implements ITaskService { resolve(result); } }; - if (this._schemaVersion === JsonSchemaVersion.V2_0_0 && this._providers.size > 0) { + if (this.schemaVersion === JsonSchemaVersion.V2_0_0 && this._providers.size > 0) { this._providers.forEach((provider) => { counter++; provider.provideTasks().done(done, error); @@ -1439,7 +1463,7 @@ class TaskService extends EventEmitter implements ITaskService { private updateWorkspaceTasks(): void { this._workspaceTasksPromise = this.computeWorkspaceTasks().then(value => { - if (this._executionEngine === ExecutionEngine.Process && this._taskSystem instanceof ProcessTaskSystem) { + if (this.executionEngine === ExecutionEngine.Process && this._taskSystem instanceof ProcessTaskSystem) { // We can only have a process engine if we have one folder. value.forEach((value) => { this._configHasErrors = value.hasErrors; @@ -1451,11 +1475,11 @@ class TaskService extends EventEmitter implements ITaskService { } private computeWorkspaceTasks(): TPromise> { - if (this._workspaceFolders.length === 0) { + if (this.workspaceFolders.length === 0) { return TPromise.as(new Map()); } else { let promises: TPromise[] = []; - for (let folder of this._workspaceFolders) { + for (let folder of this.workspaceFolders) { promises.push(this.computeWorkspaceFolderTasks(folder).then((value) => value, () => undefined)); } return TPromise.join(promises).then((values) => { @@ -1471,7 +1495,7 @@ class TaskService extends EventEmitter implements ITaskService { } private computeWorkspaceFolderTasks(workspaceFolder: IWorkspaceFolder): TPromise { - return (this._executionEngine === ExecutionEngine.Process + return (this.executionEngine === ExecutionEngine.Process ? this.computeLegacyConfiguration(workspaceFolder) : this.computeConfiguration(workspaceFolder)). then((workspaceFolderConfiguration) => { @@ -1549,7 +1573,7 @@ class TaskService extends EventEmitter implements ITaskService { } } - private computeWorkspaceFolders(): [IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion] { + private computeWorkspaceFolderSetup(): [IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion] { let workspaceFolders: IWorkspaceFolder[] = []; let executionEngine = ExecutionEngine.Terminal; let schemaVersion = JsonSchemaVersion.V2_0_0; @@ -1632,7 +1656,7 @@ class TaskService extends EventEmitter implements ITaskService { if (this._taskSystem) { return this._taskSystem instanceof TerminalTaskSystem; } - return this._executionEngine === ExecutionEngine.Terminal; + return this.executionEngine === ExecutionEngine.Terminal; } private hasDetectorSupport(config: TaskConfig.ExternalTaskRunnerConfiguration): boolean { @@ -1916,7 +1940,7 @@ class TaskService extends EventEmitter implements ITaskService { if (!this.canRunCommand()) { return; } - if (this._schemaVersion === JsonSchemaVersion.V0_1_0) { + if (this.schemaVersion === JsonSchemaVersion.V0_1_0) { this.build(); return; } @@ -1962,7 +1986,7 @@ class TaskService extends EventEmitter implements ITaskService { if (!this.canRunCommand()) { return; } - if (this._schemaVersion === JsonSchemaVersion.V0_1_0) { + if (this.schemaVersion === JsonSchemaVersion.V0_1_0) { this.runTest(); return; } @@ -2076,7 +2100,7 @@ class TaskService extends EventEmitter implements ITaskService { return undefined; } let taskPromise: TPromise; - if (this._schemaVersion === JsonSchemaVersion.V2_0_0) { + if (this.schemaVersion === JsonSchemaVersion.V2_0_0) { taskPromise = this.getGroupedTasks(); } else { taskPromise = TPromise.as(new TaskMap()); @@ -2196,7 +2220,7 @@ class TaskService extends EventEmitter implements ITaskService { if (!this.canRunCommand()) { return; } - if (this._schemaVersion === JsonSchemaVersion.V2_0_0) { + if (this.schemaVersion === JsonSchemaVersion.V2_0_0) { this.tasks().then((tasks => { if (tasks.length === 0) { this.runConfigureTasks(); @@ -2239,7 +2263,7 @@ class TaskService extends EventEmitter implements ITaskService { if (!this.canRunCommand()) { return; } - if (this._schemaVersion === JsonSchemaVersion.V2_0_0) { + if (this.schemaVersion === JsonSchemaVersion.V2_0_0) { this.tasks().then((tasks => { if (tasks.length === 0) { this.runConfigureTasks(); From ec5ad0ae30f620f1a34bf9739aa4ddc4522cc10f Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Thu, 21 Sep 2017 15:58:05 +0200 Subject: [PATCH 158/281] More code cleanup --- .../electron-browser/task.contribution.ts | 4 +- .../parts/tasks/node/processRunnerDetector.ts | 45 ++++++++++--------- .../parts/tasks/node/processTaskSystem.ts | 29 ++++++------ 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index 106a280e398..ad0a72066aa 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -1540,7 +1540,7 @@ class TaskService extends EventEmitter implements ITaskService { } if (config) { if (this.hasDetectorSupport(config)) { - return new ProcessRunnerDetector(this.fileService, this.contextService, this.configurationResolverService, config).detect(true).then((value): WorkspaceFolderConfigurationResult => { + return new ProcessRunnerDetector(workspaceFolder, this.fileService, this.contextService, this.configurationResolverService, config).detect(true).then((value): WorkspaceFolderConfigurationResult => { let hasErrors = this.printStderr(value.stderr); let detectedConfig = value.config; if (!detectedConfig) { @@ -1566,7 +1566,7 @@ class TaskService extends EventEmitter implements ITaskService { return TPromise.as({ workspaceFolder, config, hasErrors: false }); } } else { - return new ProcessRunnerDetector(this.fileService, this.contextService, this.configurationResolverService).detect(true).then((value) => { + return new ProcessRunnerDetector(workspaceFolder, this.fileService, this.contextService, this.configurationResolverService).detect(true).then((value) => { let hasErrors = this.printStderr(value.stderr); return { workspaceFolder, config: value.config, hasErrors }; }); diff --git a/src/vs/workbench/parts/tasks/node/processRunnerDetector.ts b/src/vs/workbench/parts/tasks/node/processRunnerDetector.ts index 03e29fb4ade..8d54a4baca4 100644 --- a/src/vs/workbench/parts/tasks/node/processRunnerDetector.ts +++ b/src/vs/workbench/parts/tasks/node/processRunnerDetector.ts @@ -18,7 +18,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import * as Tasks from '../common/tasks'; import * as TaskConfig from './taskConfiguration'; @@ -145,18 +145,20 @@ export class ProcessRunnerDetector { private contextService: IWorkspaceContextService; private configurationResolverService: IConfigurationResolverService; private taskConfiguration: TaskConfig.ExternalTaskRunnerConfiguration; + private _workspaceRoot: IWorkspaceFolder; private _stderr: string[]; private _stdout: string[]; private _cwd: string; - constructor(fileService: IFileService, contextService: IWorkspaceContextService, configurationResolverService: IConfigurationResolverService, config: TaskConfig.ExternalTaskRunnerConfiguration = null) { + constructor(workspaceFolder: IWorkspaceFolder, fileService: IFileService, contextService: IWorkspaceContextService, configurationResolverService: IConfigurationResolverService, config: TaskConfig.ExternalTaskRunnerConfiguration = null) { this.fileService = fileService; this.contextService = contextService; this.configurationResolverService = configurationResolverService; this.taskConfiguration = config; + this._workspaceRoot = workspaceFolder; this._stderr = []; this._stdout = []; - this._cwd = this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? Paths.normalize(this.contextService.getWorkspace().folders[0].uri.fsPath, true) : ''; + this._cwd = this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? Paths.normalize(this._workspaceRoot.uri.fsPath, true) : ''; } public get stderr(): string[] { @@ -171,21 +173,20 @@ export class ProcessRunnerDetector { if (this.taskConfiguration && this.taskConfiguration.command && ProcessRunnerDetector.supports(this.taskConfiguration.command)) { let config = ProcessRunnerDetector.detectorConfig(this.taskConfiguration.command); let args = (this.taskConfiguration.args || []).concat(config.arg); - let options: CommandOptions = this.taskConfiguration.options ? this.resolveCommandOptions(this.taskConfiguration.options) : { cwd: this._cwd }; + let options: CommandOptions = this.taskConfiguration.options ? this.resolveCommandOptions(this._workspaceRoot, this.taskConfiguration.options) : { cwd: this._cwd }; let isShellCommand = !!this.taskConfiguration.isShellCommand; - // TODO@Dirk adopt new configuration resolver service https://github.com/Microsoft/vscode/issues/31365 return this.runDetection( - new LineProcess(this.taskConfiguration.command, this.configurationResolverService.resolve(this.contextService.getWorkspace().folders[0], args), isShellCommand, options), + new LineProcess(this.taskConfiguration.command, this.configurationResolverService.resolve(this._workspaceRoot, args), isShellCommand, options), this.taskConfiguration.command, isShellCommand, config.matcher, ProcessRunnerDetector.DefaultProblemMatchers, list); } else { if (detectSpecific) { let detectorPromise: TPromise; if ('gulp' === detectSpecific) { - detectorPromise = this.tryDetectGulp(list); + detectorPromise = this.tryDetectGulp(this._workspaceRoot, list); } else if ('jake' === detectSpecific) { - detectorPromise = this.tryDetectJake(list); + detectorPromise = this.tryDetectJake(this._workspaceRoot, list); } else if ('grunt' === detectSpecific) { - detectorPromise = this.tryDetectGrunt(list); + detectorPromise = this.tryDetectGrunt(this._workspaceRoot, list); } return detectorPromise.then((value) => { if (value) { @@ -195,15 +196,15 @@ export class ProcessRunnerDetector { } }); } else { - return this.tryDetectGulp(list).then((value) => { + return this.tryDetectGulp(this._workspaceRoot, list).then((value) => { if (value) { return value; } - return this.tryDetectJake(list).then((value) => { + return this.tryDetectJake(this._workspaceRoot, list).then((value) => { if (value) { return value; } - return this.tryDetectGrunt(list).then((value) => { + return this.tryDetectGrunt(this._workspaceRoot, list).then((value) => { if (value) { return value; } @@ -215,20 +216,20 @@ export class ProcessRunnerDetector { } } - private resolveCommandOptions(options: CommandOptions): CommandOptions { + private resolveCommandOptions(workspaceFolder: IWorkspaceFolder, options: CommandOptions): CommandOptions { // TODO@Dirk adopt new configuration resolver service https://github.com/Microsoft/vscode/issues/31365 let result = Objects.clone(options); if (result.cwd) { - result.cwd = this.configurationResolverService.resolve(this.contextService.getWorkspace().folders[0], result.cwd); + result.cwd = this.configurationResolverService.resolve(workspaceFolder, result.cwd); } if (result.env) { - result.env = this.configurationResolverService.resolve(this.contextService.getWorkspace().folders[0], result.env); + result.env = this.configurationResolverService.resolve(workspaceFolder, result.env); } return result; } - private tryDetectGulp(list: boolean): TPromise { - return this.fileService.resolveFile(this.contextService.getWorkspace().folders[0].toResource('gulpfile.js')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) + private tryDetectGulp(workspaceFolder: IWorkspaceFolder, list: boolean): TPromise { + return this.fileService.resolveFile(workspaceFolder.toResource('gulpfile.js')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) let config = ProcessRunnerDetector.detectorConfig('gulp'); let process = new LineProcess('gulp', [config.arg, '--no-color'], true, { cwd: this._cwd }); return this.runDetection(process, 'gulp', true, config.matcher, ProcessRunnerDetector.DefaultProblemMatchers, list); @@ -237,8 +238,8 @@ export class ProcessRunnerDetector { }); } - private tryDetectGrunt(list: boolean): TPromise { - return this.fileService.resolveFile(this.contextService.getWorkspace().folders[0].toResource('Gruntfile.js')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) + private tryDetectGrunt(workspaceFolder: IWorkspaceFolder, list: boolean): TPromise { + return this.fileService.resolveFile(workspaceFolder.toResource('Gruntfile.js')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) let config = ProcessRunnerDetector.detectorConfig('grunt'); let process = new LineProcess('grunt', [config.arg, '--no-color'], true, { cwd: this._cwd }); return this.runDetection(process, 'grunt', true, config.matcher, ProcessRunnerDetector.DefaultProblemMatchers, list); @@ -247,16 +248,16 @@ export class ProcessRunnerDetector { }); } - private tryDetectJake(list: boolean): TPromise { + private tryDetectJake(workspaceFolder: IWorkspaceFolder, list: boolean): TPromise { let run = () => { let config = ProcessRunnerDetector.detectorConfig('jake'); let process = new LineProcess('jake', [config.arg], true, { cwd: this._cwd }); return this.runDetection(process, 'jake', true, config.matcher, ProcessRunnerDetector.DefaultProblemMatchers, list); }; - return this.fileService.resolveFile(this.contextService.getWorkspace().folders[0].toResource('Jakefile')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) + return this.fileService.resolveFile(workspaceFolder.toResource('Jakefile')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) return run(); }, (err: any) => { - return this.fileService.resolveFile(this.contextService.getWorkspace().folders[0].toResource('Jakefile.js')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) + return this.fileService.resolveFile(workspaceFolder.toResource('Jakefile.js')).then((stat) => { // TODO@Dirk (https://github.com/Microsoft/vscode/issues/29454) return run(); }, (err: any) => { return null; diff --git a/src/vs/workbench/parts/tasks/node/processTaskSystem.ts b/src/vs/workbench/parts/tasks/node/processTaskSystem.ts index e0006516a31..6074ce58b46 100644 --- a/src/vs/workbench/parts/tasks/node/processTaskSystem.ts +++ b/src/vs/workbench/parts/tasks/node/processTaskSystem.ts @@ -181,9 +181,9 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { } let args: string[] = commandConfig.args ? commandConfig.args.slice() : []; - args = this.resolveVariables(args); - let command: string = this.resolveVariable(commandConfig.name); - this.childProcess = new LineProcess(command, args, commandConfig.runtime === RuntimeType.Shell, this.resolveOptions(commandConfig.options)); + args = this.resolveVariables(task, args); + let command: string = this.resolveVariable(task, commandConfig.name); + this.childProcess = new LineProcess(command, args, commandConfig.runtime === RuntimeType.Shell, this.resolveOptions(task, commandConfig.options)); telemetryEvent.command = this.childProcess.getSanitizedCommand(); // we have no problem matchers defined. So show the output log let reveal = task.command.presentation.reveal; @@ -196,7 +196,7 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { this.log(`running command${prompt} ${command} ${args.join(' ')}`); } if (task.isBackground) { - let watchingProblemMatcher = new WatchingProblemCollector(this.resolveMatchers(task.problemMatchers), this.markerService, this.modelService); + let watchingProblemMatcher = new WatchingProblemCollector(this.resolveMatchers(task, task.problemMatchers), this.markerService, this.modelService); let toUnbind: IDisposable[] = []; let event: TaskEvent = { taskId: task._id, taskName: task.name, type: TaskType.Watching, group: task.group }; let eventCounter: number = 0; @@ -259,7 +259,7 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { } else { let event: TaskEvent = { taskId: task._id, taskName: task.name, type: TaskType.SingleRun, group: task.group }; this.emit(TaskSystemEvents.Active, event); - let startStopProblemMatcher = new StartStopProblemCollector(this.resolveMatchers(task.problemMatchers), this.markerService, this.modelService); + let startStopProblemMatcher = new StartStopProblemCollector(this.resolveMatchers(task, task.problemMatchers), this.markerService, this.modelService); this.activeTask = task; this.activeTaskPromise = this.childProcess.start().then((success): ITaskSummary => { this.childProcessEnded(); @@ -329,14 +329,14 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { return false; } - private resolveOptions(options: CommandOptions): CommandOptions { - let result: CommandOptions = { cwd: this.resolveVariable(options.cwd) }; + private resolveOptions(task: CustomTask, options: CommandOptions): CommandOptions { + let result: CommandOptions = { cwd: this.resolveVariable(task, options.cwd) }; if (options.env) { result.env = Object.create(null); Object.keys(options.env).forEach((key) => { let value: any = options.env[key]; if (Types.isString(value)) { - result.env[key] = this.resolveVariable(value); + result.env[key] = this.resolveVariable(task, value); } else { result.env[key] = value.toString(); } @@ -345,11 +345,11 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { return result; } - private resolveVariables(value: string[]): string[] { - return value.map(s => this.resolveVariable(s)); + private resolveVariables(task: CustomTask, value: string[]): string[] { + return value.map(s => this.resolveVariable(task, s)); } - private resolveMatchers(values: (string | ProblemMatcher)[]): ProblemMatcher[] { + private resolveMatchers(task: CustomTask, values: (string | ProblemMatcher)[]): ProblemMatcher[] { if (values === void 0 || values === null || values.length === 0) { return []; } @@ -373,16 +373,15 @@ export class ProcessTaskSystem extends EventEmitter implements ITaskSystem { result.push(matcher); } else { let copy = Objects.clone(matcher); - copy.filePrefix = this.resolveVariable(copy.filePrefix); + copy.filePrefix = this.resolveVariable(task, copy.filePrefix); result.push(copy); } }); return result; } - private resolveVariable(value: string): string { - // TODO@Dirk adopt new configuration resolver service https://github.com/Microsoft/vscode/issues/31365 - return this.configurationResolverService.resolve(this.contextService.getWorkspace().folders[0], value); + private resolveVariable(task: CustomTask, value: string): string { + return this.configurationResolverService.resolve(Task.getWorkspaceFolder(task), value); } public log(value: string): void { From 8751a1c2685b0dfcecd78ee331c9bd0e5ce9258a Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Thu, 21 Sep 2017 16:03:51 +0200 Subject: [PATCH 159/281] Removed () from folder name qualification --- .../parts/tasks/electron-browser/task.contribution.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index ad0a72066aa..47f0d1de4be 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -1791,7 +1791,7 @@ class TaskService extends EventEmitter implements ITaskService { if (this.needsFolderQualification()) { let workspaceFolder = Task.getWorkspaceFolder(task); if (workspaceFolder) { - description = `(${workspaceFolder.name})`; + description = workspaceFolder.name; } } return { label: task._label, description, task }; @@ -2185,7 +2185,7 @@ class TaskService extends EventEmitter implements ITaskService { if (tasks.length > 0) { tasks = tasks.slice().sort((a, b) => a._label.localeCompare(b._label)); for (let i = 0; i < tasks.length; i++) { - let entry: EntryType = { label: tasks[i]._label, task: tasks[i] }; + let entry: EntryType = { label: tasks[i]._label, task: tasks[i], description: folder.name }; if (i === 0) { entry.separator = { label: folder.name, border: index > 0 }; } From 0c29dc72ca2b5446ee67ef271a73ee1d5964c30a Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 21 Sep 2017 16:18:38 +0200 Subject: [PATCH 160/281] allow workspaces with 0 folders (#34622) --- .../electron-main/workspacesMainService.ts | 4 ++-- .../files/browser/fileActions.contribution.ts | 15 +++++++-------- .../services/configuration/node/configuration.ts | 7 ++----- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index 1764e625a5f..432850ff32d 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -103,13 +103,13 @@ export class WorkspacesMainService implements IWorkspacesMainService { throw new Error(`${path} cannot be parsed as JSON file (${error}).`); } - // Filter out folders which do not have a path set + // Filter out folders which do not have a path or uri set if (Array.isArray(storedWorkspace.folders)) { storedWorkspace.folders = storedWorkspace.folders.filter(folder => isStoredWorkspaceFolder(folder)); } // Validate - if (!Array.isArray(storedWorkspace.folders) || storedWorkspace.folders.length === 0) { + if (!Array.isArray(storedWorkspace.folders)) { throw new Error(`${path} looks like an invalid workspace file.`); } diff --git a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts index 150727ee766..c64ab4ad996 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts @@ -92,14 +92,13 @@ class FilesViewerActionContributor extends ActionBarContributor { } if (stat.isRoot && this.environmentService.appQuality !== 'stable') { - let action: Action = this.instantiationService.createInstance(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL); - action.order = 52; - actions.push(action); - if (this.contextService.getWorkspace().folders.length > 1) { - action = this.instantiationService.createInstance(RemoveRootFolderAction, stat.resource, RemoveRootFolderAction.ID, RemoveRootFolderAction.LABEL); - action.order = 53; - actions.push(action); - } + const addRootFolderAction: Action = this.instantiationService.createInstance(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL); + addRootFolderAction.order = 52; + actions.push(addRootFolderAction); + + const removeRootFolderAction = this.instantiationService.createInstance(RemoveRootFolderAction, stat.resource, RemoveRootFolderAction.ID, RemoveRootFolderAction.LABEL); + removeRootFolderAction.order = 53; + actions.push(removeRootFolderAction); actions.push(new Separator(null, 54)); } diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configuration.ts index f2f7f20657e..dc937676842 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configuration.ts @@ -211,9 +211,9 @@ contributionRegistry.registerSchema('vscode://schemas/workspaceConfig', { required: ['folders'], properties: { 'folders': { - minItems: 1, + minItems: 0, uniqueItems: true, - description: nls.localize('workspaceConfig.folders.description', "List of folders to be loaded in the workspace. Must be a file path. e.g. `/root/folderA` or `./folderA` for a relative path that will be resolved against the location of the workspace file."), + description: nls.localize('workspaceConfig.folders.description', "List of folders to be loaded in the workspace."), items: { type: 'object', default: { path: '' }, @@ -407,9 +407,6 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat .then(() => { const workspaceConfigurationModel = this.workspaceConfiguration.workspaceConfigurationModel; const workspaceFolders = toWorkspaceFolders(workspaceConfigurationModel.folders, URI.file(paths.dirname(workspaceConfigPath.fsPath))); - if (!workspaceFolders.length) { - return TPromise.wrapError(new Error('Invalid workspace configuraton file ' + workspaceConfigPath)); - } const workspaceId = workspaceIdentifier.id; const workspaceName = getWorkspaceLabel({ id: workspaceId, configPath: workspaceConfigPath.fsPath }, this.environmentService); return new Workspace(workspaceId, workspaceName, workspaceFolders, workspaceConfigPath); From 4855cf0643995de9eb75a1b4e112bafca4a98daf Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 21 Sep 2017 12:17:52 +0200 Subject: [PATCH 161/281] add id to FileStat and remove resource, make readdir return tuples, sketch up error codes, add todos on the API --- src/vs/platform/files/common/files.ts | 4 +- src/vs/vscode.proposed.d.ts | 85 ++++++++++++++++++- .../electron-browser/mainThreadFileSystem.ts | 2 +- src/vs/workbench/api/node/extHost.protocol.ts | 2 +- .../workbench/api/node/extHostFileSystem.ts | 2 +- .../electron-browser/remoteFileService.ts | 45 +++++----- 6 files changed, 110 insertions(+), 30 deletions(-) diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 469fe9552c6..efd44a680a5 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -166,7 +166,7 @@ export enum FileType { Symlink = 2 } export interface IStat { - resource: URI; + id: number | string; mtime: number; size: number; type: FileType; @@ -185,7 +185,7 @@ export interface IFileSystemProvider { unlink(resource: URI): TPromise; rename(resource: URI, target: URI): TPromise; mkdir(resource: URI): TPromise; - readdir(resource: URI): TPromise; + readdir(resource: URI): TPromise<[URI, IStat][]>; rmdir(resource: URI): TPromise; } diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 37f76762ed7..4b63d9f20dc 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -120,6 +120,58 @@ declare module 'vscode' { ignoreFocusOut?: boolean; } + + // export enum FileErrorCodes { + // /** + // * Not owner. + // */ + // EPERM = 1, + // /** + // * No such file or directory. + // */ + // ENOENT = 2, + // /** + // * I/O error. + // */ + // EIO = 5, + // /** + // * Permission denied. + // */ + // EACCES = 13, + // /** + // * File exists. + // */ + // EEXIST = 17, + // /** + // * Not a directory. + // */ + // ENOTDIR = 20, + // /** + // * Is a directory. + // */ + // EISDIR = 21, + // /** + // * File too large. + // */ + // EFBIG = 27, + // /** + // * No space left on device. + // */ + // ENOSPC = 28, + // /** + // * Directory is not empty. + // */ + // ENOTEMPTY = 66, + // /** + // * Invalid file handle. + // */ + // ESTALE = 70, + // /** + // * Illegal NFS file handle. + // */ + // EBADHANDLE = 10001, + // } + export enum FileChangeType { Updated = 0, Added = 1, @@ -138,7 +190,7 @@ declare module 'vscode' { } export interface FileStat { - resource: Uri; + id: number | string; mtime: number; size: number; type: FileType; @@ -155,13 +207,40 @@ declare module 'vscode' { // utimes(resource: Uri, mtime: number): Thenable; stat(resource: Uri): Thenable; + + // todo@remote + // offset - byte offset to start + // count - number of bytes to read + // Thenable - number of bytes actually red read(resource: Uri, progress: Progress): Thenable; + + // todo@remote + // offset - byte offset to start + // count - number of bytes to write + // Thenable - number of bytes actually written write(resource: Uri, content: Uint8Array): Thenable; - unlink(resource: Uri): Thenable; + + // todo@remote + // Thenable rename(resource: Uri, target: Uri): Thenable; + + // todo@remote + // Thenable mkdir(resource: Uri): Thenable; - readdir(resource: Uri): Thenable; + readdir(resource: Uri): Thenable<[Uri, FileStat][]>; + + // todo@remote + // ? merge both + // ? recursive del rmdir(resource: Uri): Thenable; + unlink(resource: Uri): Thenable; + + // todo@remote + // create(resource: Uri): Thenable; + + // todo@remote + // helps with performance bigly + // copy(from: Uri, to: Uri): Thenable; } export namespace workspace { diff --git a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts index 51decb5ec71..106e79e772c 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts @@ -109,7 +109,7 @@ class RemoteFileSystemProvider implements IFileSystemProvider { mkdir(resource: URI): TPromise { return this._proxy.$mkdir(this._handle, resource); } - readdir(resource: URI): TPromise { + readdir(resource: URI): TPromise<[URI, IStat][], any> { return this._proxy.$readdir(this._handle, resource); } rmdir(resource: URI): TPromise { diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 8c89933b9bb..89b49dd8292 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -486,7 +486,7 @@ export interface ExtHostFileSystemShape { $unlink(handle: number, resource: URI): TPromise; $rename(handle: number, resource: URI, target: URI): TPromise; $mkdir(handle: number, resource: URI): TPromise; - $readdir(handle: number, resource: URI): TPromise; + $readdir(handle: number, resource: URI): TPromise<[URI, IStat][]>; $rmdir(handle: number, resource: URI): TPromise; } diff --git a/src/vs/workbench/api/node/extHostFileSystem.ts b/src/vs/workbench/api/node/extHostFileSystem.ts index d46e8ac3f3a..55fb5012fef 100644 --- a/src/vs/workbench/api/node/extHostFileSystem.ts +++ b/src/vs/workbench/api/node/extHostFileSystem.ts @@ -66,7 +66,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { $mkdir(handle: number, resource: URI): TPromise { return TPromise.as(this._provider.get(handle).mkdir(resource)); } - $readdir(handle: number, resource: URI): TPromise { + $readdir(handle: number, resource: URI): TPromise<[URI, IStat][], any> { return TPromise.as(this._provider.get(handle).readdir(resource)); } $rmdir(handle: number, resource: URI): TPromise { diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index d34a4e9db69..7944090af4e 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -25,12 +25,13 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; -function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse?: (stat: IStat) => boolean): TPromise { - const ret: IFileStat = { +function toIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], recurse?: (tuple: [URI, IStat]) => boolean): TPromise { + const [resource, stat] = tuple; + const fileStat: IFileStat = { isDirectory: false, hasChildren: false, - resource: stat.resource, - name: basename(stat.resource.path), + resource: resource, + name: basename(resource.path), mtime: stat.mtime, size: stat.size, etag: stat.mtime.toString(29) + stat.size.toString(31), @@ -38,38 +39,38 @@ function toIFileStat(provider: IFileSystemProvider, stat: IStat, recurse?: (stat if (stat.type === FileType.File) { // done - return TPromise.as(ret); + return TPromise.as(fileStat); } else { // dir -> resolve - return provider.readdir(stat.resource).then(items => { - ret.isDirectory = true; - ret.hasChildren = items.length > 0; + return provider.readdir(resource).then(entries => { + fileStat.isDirectory = true; + fileStat.hasChildren = entries.length > 0; - if (recurse && recurse(stat)) { + if (recurse && recurse([resource, stat])) { // resolve children if requested - return TPromise.join(items.map(stat => toIFileStat(provider, stat, recurse))).then(children => { - ret.children = children; - return ret; + return TPromise.join(entries.map(stat => toIFileStat(provider, stat, recurse))).then(children => { + fileStat.children = children; + return fileStat; }); } else { - return ret; + return fileStat; } }); } } -export function toDeepIFileStat(provider: IFileSystemProvider, stat: IStat, to: URI[]): TPromise { +export function toDeepIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], to: URI[]): TPromise { const trie = new StringTrieMap(); - trie.insert(stat.resource.toString(), true); + trie.insert(tuple[0].toString(), true); if (!isFalsyOrEmpty(to)) { to.forEach(uri => trie.insert(uri.toString(), true)); } - return toIFileStat(provider, stat, candidate => { - const sub = trie.findSuperstr(candidate.resource.toString()); + return toIFileStat(provider, tuple, candidate => { + const sub = trie.findSuperstr(candidate[0].toString()); return !!sub; }); } @@ -193,7 +194,7 @@ export class RemoteFileService extends FileService { let promises: TPromise[] = []; for (const item of toResolve) { promises.push(provider.stat(item.resource) - .then(stat => toDeepIFileStat(provider, stat, item.options && item.options.resolveTo)) + .then(stat => toDeepIFileStat(provider, [item.resource, stat], item.options && item.options.resolveTo)) .then(stat => result.push({ stat, success: true }))); } return TPromise.join(promises).then(() => result); @@ -221,7 +222,7 @@ export class RemoteFileService extends FileService { private async _doResolveContent(provider: IFileSystemProvider, resource: URI): TPromise { - const stat = await toIFileStat(provider, await provider.stat(resource)); + const stat = await toIFileStat(provider, [resource, await provider.stat(resource)]); const encoding = this.getEncoding(resource); const stream = decodeStream(encoding); @@ -267,7 +268,7 @@ export class RemoteFileService extends FileService { const encoding = this.getEncoding(resource, options.encoding); await provider.write(resource, encode(content, encoding)); const stat = await provider.stat(resource); - const fileStat = await toIFileStat(provider, stat); + const fileStat = await toIFileStat(provider, [resource, stat]); return fileStat; } @@ -306,7 +307,7 @@ export class RemoteFileService extends FileService { } else { const provider = await this._withProvider(resource); await provider.mkdir(resource); - const stat = await toIFileStat(provider, await provider.stat(resource)); + const stat = await toIFileStat(provider, [resource, await provider.stat(resource)]); this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, stat)); return stat; } @@ -414,7 +415,7 @@ export class RemoteFileService extends FileService { await provider.write(resource, new Uint8Array(0)); stat = await provider.stat(resource); } - return toIFileStat(provider, stat); + return toIFileStat(provider, [resource, stat]); } // TODO@Joh - file watching on demand! From ea4ee63ed17f549d64fdf304e2663c5e473957c1 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 21 Sep 2017 12:30:54 +0200 Subject: [PATCH 162/281] operations that create a file/folder should return a stat-object because we want it anyways --- src/vs/platform/files/common/files.ts | 6 +++--- src/vs/vscode.proposed.d.ts | 12 ++++++------ .../api/electron-browser/mainThreadFileSystem.ts | 6 +++--- src/vs/workbench/api/node/extHost.protocol.ts | 4 ++-- src/vs/workbench/api/node/extHostFileSystem.ts | 6 +++--- .../files/electron-browser/remoteFileService.ts | 16 ++++++++-------- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index efd44a680a5..9c752093669 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -182,11 +182,11 @@ export interface IFileSystemProvider { stat(resource: URI): TPromise; read(resource: URI, progress: IProgress): TPromise; write(resource: URI, content: Uint8Array): TPromise; - unlink(resource: URI): TPromise; - rename(resource: URI, target: URI): TPromise; - mkdir(resource: URI): TPromise; + move(from: URI, to: URI): TPromise; + mkdir(resource: URI): TPromise; readdir(resource: URI): TPromise<[URI, IStat][]>; rmdir(resource: URI): TPromise; + unlink(resource: URI): TPromise; } diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 4b63d9f20dc..ee038ba05f5 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -222,11 +222,15 @@ declare module 'vscode' { // todo@remote // Thenable - rename(resource: Uri, target: Uri): Thenable; + move(resource: Uri, target: Uri): Thenable; + + // todo@remote + // helps with performance bigly + // copy?(from: Uri, to: Uri): Thenable; // todo@remote // Thenable - mkdir(resource: Uri): Thenable; + mkdir(resource: Uri): Thenable; readdir(resource: Uri): Thenable<[Uri, FileStat][]>; // todo@remote @@ -237,10 +241,6 @@ declare module 'vscode' { // todo@remote // create(resource: Uri): Thenable; - - // todo@remote - // helps with performance bigly - // copy(from: Uri, to: Uri): Thenable; } export namespace workspace { diff --git a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts index 106e79e772c..f5d967e6eb4 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts @@ -103,10 +103,10 @@ class RemoteFileSystemProvider implements IFileSystemProvider { unlink(resource: URI): TPromise { return this._proxy.$unlink(this._handle, resource); } - rename(resource: URI, target: URI): TPromise { - return this._proxy.$rename(this._handle, resource, target); + move(resource: URI, target: URI): TPromise { + return this._proxy.$move(this._handle, resource, target); } - mkdir(resource: URI): TPromise { + mkdir(resource: URI): TPromise { return this._proxy.$mkdir(this._handle, resource); } readdir(resource: URI): TPromise<[URI, IStat][], any> { diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 89b49dd8292..2c8be377b23 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -484,8 +484,8 @@ export interface ExtHostFileSystemShape { $read(handle: number, resource: URI): TPromise; $write(handle: number, resource: URI, content: number[]): TPromise; $unlink(handle: number, resource: URI): TPromise; - $rename(handle: number, resource: URI, target: URI): TPromise; - $mkdir(handle: number, resource: URI): TPromise; + $move(handle: number, resource: URI, target: URI): TPromise; + $mkdir(handle: number, resource: URI): TPromise; $readdir(handle: number, resource: URI): TPromise<[URI, IStat][]>; $rmdir(handle: number, resource: URI): TPromise; } diff --git a/src/vs/workbench/api/node/extHostFileSystem.ts b/src/vs/workbench/api/node/extHostFileSystem.ts index 55fb5012fef..9c54bdfcd38 100644 --- a/src/vs/workbench/api/node/extHostFileSystem.ts +++ b/src/vs/workbench/api/node/extHostFileSystem.ts @@ -60,10 +60,10 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { $unlink(handle: number, resource: URI): TPromise { return TPromise.as(this._provider.get(handle).unlink(resource)); } - $rename(handle: number, resource: URI, target: URI): TPromise { - return TPromise.as(this._provider.get(handle).rename(resource, target)); + $move(handle: number, resource: URI, target: URI): TPromise { + return TPromise.as(this._provider.get(handle).move(resource, target)); } - $mkdir(handle: number, resource: URI): TPromise { + $mkdir(handle: number, resource: URI): TPromise { return TPromise.as(this._provider.get(handle).mkdir(resource)); } $readdir(handle: number, resource: URI): TPromise<[URI, IStat][], any> { diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 7944090af4e..2c11eb22ec3 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -306,10 +306,10 @@ export class RemoteFileService extends FileService { return super.createFolder(resource); } else { const provider = await this._withProvider(resource); - await provider.mkdir(resource); - const stat = await toIFileStat(provider, [resource, await provider.stat(resource)]); - this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, stat)); - return stat; + const stat = await provider.mkdir(resource); + const fileStat = await toIFileStat(provider, [resource, stat]); + this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, fileStat)); + return fileStat; } } @@ -344,10 +344,10 @@ export class RemoteFileService extends FileService { // abort on other errors } } - await provider.rename(source, target); - const stat = await this.resolveFile(target); - this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.MOVE, stat)); - return stat; + const stat = await provider.move(source, target); + const fileStat = await toIFileStat(provider, [target, stat]); + this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.MOVE, fileStat)); + return fileStat; } private async _manualMove(source: URI, target: URI, overwrite?: boolean): TPromise { From 8cb7d0a71e1840097425f9837c7222d9979f1ccd Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 21 Sep 2017 16:22:50 +0200 Subject: [PATCH 163/281] better error handling when resolving non-existent files, stop using async/await --- .../workbench/api/node/extHostFileSystem.ts | 19 +- .../electron-browser/remoteFileService.ts | 299 ++++++++++-------- 2 files changed, 170 insertions(+), 148 deletions(-) diff --git a/src/vs/workbench/api/node/extHostFileSystem.ts b/src/vs/workbench/api/node/extHostFileSystem.ts index 9c54bdfcd38..02407f01c7c 100644 --- a/src/vs/workbench/api/node/extHostFileSystem.ts +++ b/src/vs/workbench/api/node/extHostFileSystem.ts @@ -10,6 +10,7 @@ import { MainContext, IMainContext, ExtHostFileSystemShape, MainThreadFileSystem import * as vscode from 'vscode'; import { IStat } from 'vs/platform/files/common/files'; import { IDisposable } from 'vs/base/common/lifecycle'; +import { asWinJsPromise } from 'vs/base/common/async'; export class ExtHostFileSystem implements ExtHostFileSystemShape { @@ -42,34 +43,34 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { } $utimes(handle: number, resource: URI, mtime: number): TPromise { - return TPromise.as(this._provider.get(handle).utimes(resource, mtime)); + return asWinJsPromise(token => this._provider.get(handle).utimes(resource, mtime)); } $stat(handle: number, resource: URI): TPromise { - return TPromise.as(this._provider.get(handle).stat(resource)); + return asWinJsPromise(token => this._provider.get(handle).stat(resource)); } $read(handle: number, resource: URI): TPromise { - return TPromise.as(this._provider.get(handle).read(resource, { + return asWinJsPromise(token => this._provider.get(handle).read(resource, { report: (chunk) => { this._proxy.$reportFileChunk(handle, resource, [].slice.call(chunk)); } })); } $write(handle: number, resource: URI, content: number[]): TPromise { - return TPromise.as(this._provider.get(handle).write(resource, Buffer.from(content))); + return asWinJsPromise(token => this._provider.get(handle).write(resource, Buffer.from(content))); } $unlink(handle: number, resource: URI): TPromise { - return TPromise.as(this._provider.get(handle).unlink(resource)); + return asWinJsPromise(token => this._provider.get(handle).unlink(resource)); } $move(handle: number, resource: URI, target: URI): TPromise { - return TPromise.as(this._provider.get(handle).move(resource, target)); + return asWinJsPromise(token => this._provider.get(handle).move(resource, target)); } $mkdir(handle: number, resource: URI): TPromise { - return TPromise.as(this._provider.get(handle).mkdir(resource)); + return asWinJsPromise(token => this._provider.get(handle).mkdir(resource)); } $readdir(handle: number, resource: URI): TPromise<[URI, IStat][], any> { - return TPromise.as(this._provider.get(handle).readdir(resource)); + return asWinJsPromise(token => this._provider.get(handle).readdir(resource)); } $rmdir(handle: number, resource: URI): TPromise { - return TPromise.as(this._provider.get(handle).rmdir(resource)); + return asWinJsPromise(token => this._provider.get(handle).rmdir(resource)); } } diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 2c11eb22ec3..8018711f857 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -137,51 +137,45 @@ export class RemoteFileService extends FileService { return this._extensionService.activateByEvent('onFileSystemAccess:' + resource.scheme).then(() => { const provider = this._provider.get(resource.scheme); if (!provider) { - throw new Error('ENOPRO - no provider known for ' + resource); + const err = new Error(); + err.name = 'ENOPRO'; + err.message = `no provider for ${resource.toString}`; + throw err; } return provider; }); } - async existsFile(resource: URI): TPromise { + existsFile(resource: URI): TPromise { if (resource.scheme === Schemas.file) { return super.existsFile(resource); } else { - const provider = await this._withProvider(resource); - return provider - ? this._doResolveFiles(provider, [{ resource }]).then(data => data.length > 0) - : true; + return this.resolveFile(resource).then(data => true, err => false); } } - async resolveFile(resource: URI, options?: IResolveFileOptions): TPromise { + resolveFile(resource: URI, options?: IResolveFileOptions): TPromise { if (resource.scheme === Schemas.file) { return super.resolveFile(resource, options); } else { - const provider = await this._withProvider(resource); - if (!provider) { - throw new Error('ENOENT'); - } - return this._doResolveFiles(provider, [{ resource, options }]).then(data => { - if (isFalsyOrEmpty(data)) { - throw new Error('NotFound'); + return this._doResolveFiles([{ resource, options }]).then(data => { + if (data.length !== 1 || !data[0].success) { + throw new Error(`ENOENT, ${resource}`); + } else { + return data[0].stat; } - return data[0].stat; }); } } - async resolveFiles(toResolve: { resource: URI; options?: IResolveFileOptions; }[]): TPromise { + resolveFiles(toResolve: { resource: URI; options?: IResolveFileOptions; }[]): TPromise { const groups = groupBy(toResolve, (a, b) => compare(a.resource.scheme, b.resource.scheme)); const promises: TPromise[] = []; for (const group of groups) { if (group[0].resource.scheme === Schemas.file) { promises.push(super.resolveFiles(group)); } else { - const provider = await this._withProvider(group[0].resource); - if (provider) { - promises.push(this._doResolveFiles(provider, group)); - } + promises.push(this._doResolveFiles(group)); } } return TPromise.join(promises).then(data => { @@ -189,87 +183,106 @@ export class RemoteFileService extends FileService { }); } - private _doResolveFiles(provider: IFileSystemProvider, toResolve: { resource: URI; options?: IResolveFileOptions; }[]): TPromise { - let result: IResolveFileResult[] = []; - let promises: TPromise[] = []; - for (const item of toResolve) { - promises.push(provider.stat(item.resource) - .then(stat => toDeepIFileStat(provider, [item.resource, stat], item.options && item.options.resolveTo)) - .then(stat => result.push({ stat, success: true }))); - } - return TPromise.join(promises).then(() => result); + private _doResolveFiles(toResolve: { resource: URI; options?: IResolveFileOptions; }[]): TPromise { + return this._withProvider(toResolve[0].resource).then(provider => { + let result: IResolveFileResult[] = []; + let promises = toResolve.map((item, idx) => { + return provider.stat(item.resource).then(stat => { + return toDeepIFileStat(provider, [item.resource, stat], item.options && item.options.resolveTo).then(fileStat => { + result[idx] = { stat: fileStat, success: true }; + }); + }, err => { + result[idx] = { stat: undefined, success: false }; + }); + }); + return TPromise.join(promises).then(() => result); + }); } // --- resolve - async resolveContent(resource: URI, options?: IResolveContentOptions): TPromise { + resolveContent(resource: URI, options?: IResolveContentOptions): TPromise { if (resource.scheme === Schemas.file) { return super.resolveContent(resource, options); } else { - const provider = await this._withProvider(resource); - return this._doResolveContent(provider, resource).then(RemoteFileService._asContent); + return this._doResolveContent(resource, options).then(RemoteFileService._asContent); } } - async resolveStreamContent(resource: URI, options?: IResolveContentOptions): TPromise { + resolveStreamContent(resource: URI, options?: IResolveContentOptions): TPromise { if (resource.scheme === Schemas.file) { return super.resolveStreamContent(resource, options); } else { - const provider = await this._withProvider(resource); - return this._doResolveContent(provider, resource); + return this._doResolveContent(resource, options); } } - private async _doResolveContent(provider: IFileSystemProvider, resource: URI): TPromise { + private _doResolveContent(resource: URI, options: IResolveContentOptions): TPromise { + return this._withProvider(resource).then(provider => { + return this.resolveFile(resource).then(fileStat => { - const stat = await toIFileStat(provider, [resource, await provider.stat(resource)]); + const encoding = this.getEncoding(resource); + const stream = decodeStream(encoding); - const encoding = this.getEncoding(resource); - const stream = decodeStream(encoding); - await provider.read(resource, new Progress(chunk => stream.write(chunk))); - stream.end(); + provider.read(resource, new Progress(chunk => stream.write(chunk))).then(() => { + stream.end(); + }, err => { + stream.emit('error', err); + stream.end(); + }); - return { - encoding, - value: stream, - resource: stat.resource, - name: stat.name, - etag: stat.etag, - mtime: stat.mtime, - }; + return { + encoding, + value: stream, + resource: fileStat.resource, + name: fileStat.name, + etag: fileStat.etag, + mtime: fileStat.mtime, + }; + }); + }); } // --- saving - async createFile(resource: URI, content?: string, options?: ICreateFileOptions): TPromise { + createFile(resource: URI, content?: string, options?: ICreateFileOptions): TPromise { if (resource.scheme === Schemas.file) { return super.createFile(resource, content, options); } else { - const provider = await this._withProvider(resource); - if (options && !options.overwrite && await this.existsFile(resource)) { - throw new FileOperationError('EEXIST', FileOperationResult.FILE_MODIFIED_SINCE); - } - const stat = await this._doUpdateContent(provider, resource, content || '', {}); - this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, stat)); - return stat; + return this._withProvider(resource).then(provider => { + let prepare = options && !options.overwrite + ? this.existsFile(resource) + : TPromise.as(false); + + + return prepare.then(exists => { + if (exists && options && !options.overwrite) { + return TPromise.wrapError(new FileOperationError('EEXIST', FileOperationResult.FILE_MODIFIED_SINCE)); + } + return this._doUpdateContent(provider, resource, content || '', {}); + }).then(fileStat => { + this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, fileStat)); + return fileStat; + }); + }); } } - async updateContent(resource: URI, value: string, options?: IUpdateContentOptions): TPromise { + updateContent(resource: URI, value: string, options?: IUpdateContentOptions): TPromise { if (resource.scheme === Schemas.file) { return super.updateContent(resource, value, options); } else { - const provider = await this._withProvider(resource); - return this._doUpdateContent(provider, resource, value, options || {}); + return this._withProvider(resource).then(provider => { + return this._doUpdateContent(provider, resource, value, options || {}); + }); } } - private async _doUpdateContent(provider: IFileSystemProvider, resource: URI, content: string, options: IUpdateContentOptions): TPromise { + private _doUpdateContent(provider: IFileSystemProvider, resource: URI, content: string, options: IUpdateContentOptions): TPromise { const encoding = this.getEncoding(resource, options.encoding); - await provider.write(resource, encode(content, encoding)); - const stat = await provider.stat(resource); - const fileStat = await toIFileStat(provider, [resource, stat]); - return fileStat; + return provider.write(resource, encode(content, encoding)).then(() => { + return this.resolveFile(resource); + }); } private static _asContent(content: IStreamContent): TPromise { @@ -290,72 +303,79 @@ export class RemoteFileService extends FileService { // --- delete - async del(resource: URI, useTrash?: boolean): TPromise { + del(resource: URI, useTrash?: boolean): TPromise { if (resource.scheme === Schemas.file) { return super.del(resource, useTrash); } else { - const provider = await this._withProvider(resource); - const stat = await provider.stat(resource); - await stat.type === FileType.Dir ? provider.rmdir(resource) : provider.unlink(resource); - this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.DELETE)); + return this._withProvider(resource).then(provider => { + return provider.stat(resource).then(stat => { + return stat.type === FileType.Dir ? provider.rmdir(resource) : provider.unlink(resource); + }).then(() => { + this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.DELETE)); + }); + }); } } - async createFolder(resource: URI): TPromise { + createFolder(resource: URI): TPromise { if (resource.scheme === Schemas.file) { return super.createFolder(resource); } else { - const provider = await this._withProvider(resource); - const stat = await provider.mkdir(resource); - const fileStat = await toIFileStat(provider, [resource, stat]); - this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, fileStat)); - return fileStat; + return this._withProvider(resource).then(provider => { + return provider.mkdir(resource).then(stat => { + return toIFileStat(provider, [resource, stat]); + }); + }).then(fileStat => { + this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, fileStat)); + return fileStat; + }); } } - async rename(resource: URI, newName: string): TPromise { + rename(resource: URI, newName: string): TPromise { if (resource.scheme === Schemas.file) { return super.rename(resource, newName); } else { - const provider = await this._withProvider(resource); const target = resource.with({ path: join(resource.path, '..', newName) }); - return this._doMove(provider, resource, target, false); + return this._doMoveWithInScheme(resource, target, false); } } - async moveFile(source: URI, target: URI, overwrite?: boolean): TPromise { + moveFile(source: URI, target: URI, overwrite?: boolean): TPromise { if (source.scheme !== target.scheme) { - return this._manualMove(source, target); + return this._doMoveAcrossScheme(source, target); } else if (source.scheme === Schemas.file) { return super.moveFile(source, target, overwrite); } else { - const provider = await this._withProvider(source); - return this._doMove(provider, source, target, overwrite); + return this._doMoveWithInScheme(source, target, overwrite); } } - private async _doMove(provider: IFileSystemProvider, source: URI, target: URI, overwrite?: boolean): TPromise { - if (overwrite) { - try { - await this.del(target); - } catch (e) { - // TODO@Joh Better errors - // ignore not_exists error - // abort on other errors - } - } - const stat = await provider.move(source, target); - const fileStat = await toIFileStat(provider, [target, stat]); - this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.MOVE, fileStat)); - return fileStat; + private _doMoveWithInScheme(source: URI, target: URI, overwrite?: boolean): TPromise { + + const prepare = overwrite + ? this.del(target).then(undefined, err => { /*ignore*/ }) + : TPromise.as(null); + + return prepare.then(() => this._withProvider(source)).then(provider => { + return provider.move(source, target).then(stat => { + return toIFileStat(provider, [target, stat]); + }).then(fileStat => { + this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.MOVE, fileStat)); + return fileStat; + }); + }); } - private async _manualMove(source: URI, target: URI, overwrite?: boolean): TPromise { - await this.copyFile(source, target, overwrite); - await this.del(source); - const stat = await this.resolveFile(target); - this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.MOVE, stat)); - return stat; + private _doMoveAcrossScheme(source: URI, target: URI, overwrite?: boolean): TPromise { + return this.copyFile(source, target, overwrite).then(() => { + return this.del(source); + }).then(() => { + return this.resolveFile(target); + }).then(fileStat => { + this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.MOVE, fileStat)); + return fileStat; + }); } importFile(source: URI, targetFolder: URI): TPromise { @@ -367,55 +387,56 @@ export class RemoteFileService extends FileService { } } - async copyFile(source: URI, target: URI, overwrite?: boolean): TPromise { + copyFile(source: URI, target: URI, overwrite?: boolean): TPromise { if (source.scheme === target.scheme && source.scheme === Schemas.file) { return super.copyFile(source, target, overwrite); } - if (overwrite) { - try { - await this.del(target); - } catch (e) { - // TODO@Joh Better errors - // ignore not_exists error - // abort on other errors - } - } - // TODO@Joh This does only work for textfiles - // because the content turns things into a string - // and all binary data will be broken - const content = await this.resolveContent(source); - const targetProvider = await this._withProvider(target); + const prepare = overwrite + ? this.del(target).then(undefined, err => { /*ignore*/ }) + : TPromise.as(null); + + return prepare.then(() => { + // TODO@Joh This does only work for textfiles + // because the content turns things into a string + // and all binary data will be broken + return this.resolveContent(source).then(content => { + return this._withProvider(target).then(provider => { + return this._doUpdateContent(provider, target, content.value, { encoding: content.encoding }).then(fileStat => { + this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.COPY, fileStat)); + return fileStat; + }); + }, err => { + if (err instanceof Error && err.name === 'ENOPRO') { + // file scheme + return super.updateContent(target, content.value, { encoding: content.encoding }); + } else { + return TPromise.wrapError(err); + } + }); + }); + }); - if (targetProvider) { - const stat = await this._doUpdateContent(targetProvider, target, content.value, { encoding: content.encoding }); - this._onAfterOperation.fire(new FileOperationEvent(source, FileOperation.COPY, stat)); - return stat; - } else { - return super.updateContent(target, content.value, { encoding: content.encoding }); - } } - async touchFile(resource: URI): TPromise { + touchFile(resource: URI): TPromise { if (resource.scheme === Schemas.file) { return super.touchFile(resource); } else { - const provider = await this._withProvider(resource); - return this._doTouchFile(provider, resource); + return this._doTouchFile(resource); } } - private async _doTouchFile(provider: IFileSystemProvider, resource: URI): TPromise { - let stat: IStat; - try { - await provider.stat(resource); - stat = await provider.utimes(resource, Date.now()); - } catch (e) { - // TODO@Joh, if ENOENT - await provider.write(resource, new Uint8Array(0)); - stat = await provider.stat(resource); - } - return toIFileStat(provider, [resource, stat]); + private _doTouchFile(resource: URI): TPromise { + return this._withProvider(resource).then(provider => { + return provider.stat(resource).then(() => { + return provider.utimes(resource, Date.now()); + }, err => { + return provider.write(resource, new Uint8Array(0)); + }).then(() => { + return this.resolveFile(resource); + }); + }); } // TODO@Joh - file watching on demand! From ba4f4db59844b3fd61cf7c2d9d44438e8bc74742 Mon Sep 17 00:00:00 2001 From: isidor Date: Thu, 21 Sep 2017 16:37:21 +0200 Subject: [PATCH 164/281] fix tests --- src/vs/workbench/parts/debug/common/debugModel.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index 9d9f29b99d1..cc30dc0f072 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -959,8 +959,7 @@ export class Model implements IModel { if (previousOutput && previousOutput.value === '') { // remove potential empty lines between different output types this.replElements.pop(); - } - if (previousOutput instanceof OutputElement && severity === previousOutput.severity && toAdd.length && toAdd[0].sourceData === previousOutput.sourceData) { + } else if (previousOutput instanceof OutputElement && severity === previousOutput.severity && toAdd.length && toAdd[0].sourceData === previousOutput.sourceData) { previousOutput.value += toAdd.shift().value; } this.addReplElements(toAdd); From b09f1c4358e1cbb8789d908420436df5db65dbe4 Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Thu, 21 Sep 2017 16:38:11 +0200 Subject: [PATCH 165/281] Fixes #31133: Task output - show the folder in which a task is running #31133 --- .../tasks/electron-browser/terminalTaskSystem.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts b/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts index 1176ca1c7af..39b6e37ba07 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts @@ -22,7 +22,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import * as TPath from 'vs/base/common/paths'; import { IMarkerService } from 'vs/platform/markers/common/markers'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ProblemMatcher, ProblemMatcherRegistry /*, ProblemPattern, getResource */ } from 'vs/platform/markers/common/problemMatcher'; @@ -440,6 +440,8 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { }; let shellLaunchConfig: IShellLaunchConfig = undefined; let isShellCommand = task.command.runtime === RuntimeType.Shell; + let workspaceFolder = Task.getWorkspaceFolder(task); + let needsFolderQualification = workspaceFolder && this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; if (isShellCommand) { if (Platform.isWindows && ((options.cwd && TPath.isUNC(options.cwd)) || (!options.cwd && TPath.isUNC(process.cwd())))) { throw new TaskError(Severity.Error, nls.localize('TerminalTaskSystem', 'Can\'t execute a shell command on an UNC drive.'), TaskErrors.UnknownError); @@ -492,7 +494,11 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { shellArgs.push(commandLine); shellLaunchConfig.args = windowsShellArgs ? shellArgs.join(' ') : shellArgs; if (task.command.presentation.echo) { - shellLaunchConfig.initialText = `\x1b[1m> Executing task: ${commandLine} <\x1b[0m\n`; + if (needsFolderQualification) { + shellLaunchConfig.initialText = `\x1b[1m> Executing task in folder ${workspaceFolder.name}: ${commandLine} <\x1b[0m\n`; + } else { + shellLaunchConfig.initialText = `\x1b[1m> Executing task: ${commandLine} <\x1b[0m\n`; + } } } else { let cwd = options && options.cwd ? options.cwd : process.cwd(); @@ -515,7 +521,11 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem { } return args.join(' '); }; - shellLaunchConfig.initialText = `\x1b[1m> Executing task: ${shellLaunchConfig.executable} ${getArgsToEcho(shellLaunchConfig.args)} <\x1b[0m\n`; + if (needsFolderQualification) { + shellLaunchConfig.initialText = `\x1b[1m> Executing task in folder ${workspaceFolder.name}: ${shellLaunchConfig.executable} ${getArgsToEcho(shellLaunchConfig.args)} <\x1b[0m\n`; + } else { + shellLaunchConfig.initialText = `\x1b[1m> Executing task: ${shellLaunchConfig.executable} ${getArgsToEcho(shellLaunchConfig.args)} <\x1b[0m\n`; + } } } if (options.cwd) { From 4900f157f3a31f72c699e3ace1df41dfc9452e8d Mon Sep 17 00:00:00 2001 From: isidor Date: Thu, 21 Sep 2017 16:57:01 +0200 Subject: [PATCH 166/281] debug: polish quick open entry label --- .../parts/debug/browser/debugQuickOpen.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/debug/browser/debugQuickOpen.ts b/src/vs/workbench/parts/debug/browser/debugQuickOpen.ts index 10e86cda486..943f64d823a 100644 --- a/src/vs/workbench/parts/debug/browser/debugQuickOpen.ts +++ b/src/vs/workbench/parts/debug/browser/debugQuickOpen.ts @@ -11,16 +11,21 @@ import QuickOpen = require('vs/base/parts/quickopen/common/quickOpen'); import Model = require('vs/base/parts/quickopen/browser/quickOpenModel'); import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IDebugService, ILaunch } from 'vs/workbench/parts/debug/common/debug'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import * as errors from 'vs/base/common/errors'; class DebugEntry extends Model.QuickOpenEntry { - constructor(private debugService: IDebugService, private launch: ILaunch, private configurationName: string, highlights: Model.IHighlight[] = []) { + constructor(private debugService: IDebugService, private contextService: IWorkspaceContextService, private launch: ILaunch, private configurationName: string, highlights: Model.IHighlight[] = []) { super(highlights); } public getLabel(): string { - return this.debugService.getConfigurationManager().getLaunches().length <= 1 ? this.configurationName : `${this.configurationName} (${this.launch.workspace.name})`; + return this.configurationName; + } + + public getDescription(): string { + return this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? this.launch.workspace.name : ''; } public getAriaLabel(): string { @@ -43,7 +48,8 @@ export class DebugQuickOpenHandler extends Quickopen.QuickOpenHandler { constructor( @IQuickOpenService private quickOpenService: IQuickOpenService, - @IDebugService private debugService: IDebugService + @IDebugService private debugService: IDebugService, + @IWorkspaceContextService private contextService: IWorkspaceContextService ) { super(); } @@ -58,7 +64,7 @@ export class DebugQuickOpenHandler extends Quickopen.QuickOpenHandler { for (let launch of this.debugService.getConfigurationManager().getLaunches()) { launch.getConfigurationNames().map(config => ({ config: config, highlights: Filters.matchesContiguousSubString(input, config) })) .filter(({ highlights }) => !!highlights) - .forEach(({ config, highlights }) => configurations.push(new DebugEntry(this.debugService, launch, config, highlights))); + .forEach(({ config, highlights }) => configurations.push(new DebugEntry(this.debugService, this.contextService, launch, config, highlights))); } return TPromise.as(new Model.QuickOpenModel(configurations)); From 28c7b2ee01df29e042ea2da7663632e3729404db Mon Sep 17 00:00:00 2001 From: isidor Date: Thu, 21 Sep 2017 17:00:31 +0200 Subject: [PATCH 167/281] null check fixes #34746 --- src/vs/workbench/browser/parts/compositePart.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/compositePart.ts b/src/vs/workbench/browser/parts/compositePart.ts index 31d7e3c1ee8..4c9a6580090 100644 --- a/src/vs/workbench/browser/parts/compositePart.ts +++ b/src/vs/workbench/browser/parts/compositePart.ts @@ -351,7 +351,7 @@ export abstract class CompositePart extends Part { private updateTitle(compositeId: string, compositeTitle?: string): void { let compositeDescriptor = this.registry.getComposite(compositeId); - if (!compositeDescriptor) { + if (!compositeDescriptor || !this.titleLabel) { return; } From 845c25cae944c0ee4561e0929de5696fb91248f0 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 21 Sep 2017 17:04:58 +0200 Subject: [PATCH 168/281] Fixes #11007: improve text that lands in the clipboard in the multicursor case --- .../editor/common/viewModel/viewModelImpl.ts | 46 +++--- .../common/viewModel/viewModelImpl.test.ts | 144 ++++++++++++++++++ 2 files changed, 171 insertions(+), 19 deletions(-) diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index 13331cdc5ba..f1a7fcbf961 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -463,29 +463,37 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel } public getPlainTextToCopy(ranges: Range[], emptySelectionClipboard: boolean): string { - let newLineCharacter = this.model.getEOL(); + const newLineCharacter = this.model.getEOL(); - if (ranges.length === 1) { - let range: Range = ranges[0]; - if (range.isEmpty()) { - if (emptySelectionClipboard) { - let modelLineNumber = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(range.startLineNumber, 1)).lineNumber; - return this.model.getLineContent(modelLineNumber) + newLineCharacter; - } else { - return ''; + ranges = ranges.slice(0); + ranges.sort(Range.compareRangesUsingStarts); + const nonEmptyRanges = ranges.filter((r) => !r.isEmpty()); + + if (nonEmptyRanges.length === 0) { + if (!emptySelectionClipboard) { + return ''; + } + + const modelLineNumbers = ranges.map((r) => { + const viewLineStart = new Position(r.startLineNumber, 1); + return this.coordinatesConverter.convertViewPositionToModelPosition(viewLineStart).lineNumber; + }); + + let result = ''; + for (let i = 0; i < modelLineNumbers.length; i++) { + if (i > 0 && modelLineNumbers[i - 1] === modelLineNumbers[i]) { + continue; } + result += this.model.getLineContent(modelLineNumbers[i]) + newLineCharacter; } - - return this.getValueInRange(range, editorCommon.EndOfLinePreference.TextDefined); - } else { - ranges = ranges.slice(0).sort(Range.compareRangesUsingStarts); - let result: string[] = []; - for (let i = 0; i < ranges.length; i++) { - result.push(this.getValueInRange(ranges[i], editorCommon.EndOfLinePreference.TextDefined)); - } - - return result.join(newLineCharacter); + return result; } + + let result: string[] = []; + for (let i = 0; i < nonEmptyRanges.length; i++) { + result.push(this.getValueInRange(nonEmptyRanges[i], editorCommon.EndOfLinePreference.TextDefined)); + } + return result.join(newLineCharacter); } public getHTMLToCopy(viewRanges: Range[], emptySelectionClipboard: boolean): string { diff --git a/src/vs/editor/test/common/viewModel/viewModelImpl.test.ts b/src/vs/editor/test/common/viewModel/viewModelImpl.test.ts index 40c071085cd..665f07f72ef 100644 --- a/src/vs/editor/test/common/viewModel/viewModelImpl.test.ts +++ b/src/vs/editor/test/common/viewModel/viewModelImpl.test.ts @@ -41,4 +41,148 @@ suite('ViewModel', () => { assert.equal(viewModel.getLineCount(), 10); }); }); + + function assertGetPlainTextToCopy(text: string[], ranges: Range[], emptySelectionClipboard: boolean, expected: string): void { + testViewModel(text, {}, (viewModel, model) => { + let actual = viewModel.getPlainTextToCopy(ranges, emptySelectionClipboard); + assert.equal(actual, expected); + }); + } + + const USUAL_TEXT = [ + '', + 'line2', + 'line3', + 'line4', + '' + ]; + + test('getPlainTextToCopy 0/1', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 2) + ], + false, + '' + ); + }); + + test('getPlainTextToCopy 0/1 - emptySelectionClipboard', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 2) + ], + true, + 'line2\n' + ); + }); + + test('getPlainTextToCopy 1/1', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 6) + ], + false, + 'ine2' + ); + }); + + test('getPlainTextToCopy 1/1 - emptySelectionClipboard', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 6) + ], + true, + 'ine2' + ); + }); + + test('getPlainTextToCopy 0/2', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 2), + new Range(3, 2, 3, 2), + ], + false, + '' + ); + }); + + test('getPlainTextToCopy 0/2 - emptySelectionClipboard', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 2), + new Range(3, 2, 3, 2), + ], + true, + 'line2\nline3\n' + ); + }); + + test('getPlainTextToCopy 1/2', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 6), + new Range(3, 2, 3, 2), + ], + false, + 'ine2' + ); + }); + + test('getPlainTextToCopy 1/2 - emptySelectionClipboard', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 6), + new Range(3, 2, 3, 2), + ], + true, + 'ine2' + ); + }); + + test('getPlainTextToCopy 2/2', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 6), + new Range(3, 2, 3, 6), + ], + false, + 'ine2\nine3' + ); + }); + + test('getPlainTextToCopy 2/2 reversed', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(3, 2, 3, 6), + new Range(2, 2, 2, 6), + ], + false, + 'ine2\nine3' + ); + }); + + test('getPlainTextToCopy 0/3 - emptySelectionClipboard', () => { + assertGetPlainTextToCopy( + USUAL_TEXT, + [ + new Range(2, 2, 2, 2), + new Range(2, 3, 2, 3), + new Range(3, 2, 3, 2), + ], + true, + 'line2\nline3\n' + ); + }); }); From 424e1ebc28edbee570ffcee769410f00bd287500 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 21 Sep 2017 17:22:00 +0200 Subject: [PATCH 169/281] save workspace is always enabled (#34622) --- src/vs/code/electron-main/menus.ts | 6 ++---- .../workbench/browser/actions/workspaceActions.ts | 13 +++---------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 032972aafc9..b796c7e82cd 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -80,7 +80,6 @@ export class CodeMenu { private closeFolder: Electron.MenuItem; private closeWorkspace: Electron.MenuItem; - private saveWorkspaceAs: Electron.MenuItem; private nativeTabMenuItems: Electron.MenuItem[]; @@ -255,7 +254,6 @@ export class CodeMenu { this.closeWorkspace.visible = isInWorkspaceContext; this.closeFolder.visible = !isInWorkspaceContext; this.closeFolder.enabled = isInFolderContext; - this.saveWorkspaceAs.enabled = isInFolderContext || isInWorkspaceContext; } private install(): void { @@ -407,7 +405,7 @@ export class CodeMenu { const isMultiRootEnabled = (product.quality !== 'stable'); // TODO@Ben multi root - this.saveWorkspaceAs = this.createMenuItem(nls.localize({ key: 'miSaveWorkspaceAs', comment: ['&& denotes a mnemonic'] }, "&&Save Workspace As..."), 'workbench.action.saveWorkspaceAs'); + const saveWorkspaceAs = this.createMenuItem(nls.localize({ key: 'miSaveWorkspaceAs', comment: ['&& denotes a mnemonic'] }, "&&Save Workspace As..."), 'workbench.action.saveWorkspaceAs'); const addFolder = this.createMenuItem(nls.localize({ key: 'miAddFolderToWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Add Folder to Workspace..."), 'workbench.action.addRootFolder'); const saveFile = this.createMenuItem(nls.localize({ key: 'miSave', comment: ['&& denotes a mnemonic'] }, "&&Save"), 'workbench.action.files.save'); @@ -443,7 +441,7 @@ export class CodeMenu { openRecent, isMultiRootEnabled ? __separator__() : null, isMultiRootEnabled ? addFolder : null, - isMultiRootEnabled ? this.saveWorkspaceAs : null, + isMultiRootEnabled ? saveWorkspaceAs : null, __separator__(), saveFile, saveFileAs, diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index 58f09abc65b..0989bcd5418 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -17,7 +17,7 @@ import URI from 'vs/base/common/uri'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { WORKSPACE_FILTER } from 'vs/platform/workspaces/common/workspaces'; -import { IMessageService, Severity } from 'vs/platform/message/common/message'; +import { IMessageService } from 'vs/platform/message/common/message'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { isLinux } from 'vs/base/common/platform'; import { dirname } from 'vs/base/common/paths'; @@ -203,17 +203,10 @@ export class SaveWorkspaceAsAction extends BaseWorkspacesAction { } public run(): TPromise { - const workspaceState = this.contextService.getWorkbenchState(); - if (workspaceState === WorkbenchState.EMPTY) { - this.messageService.show(Severity.Info, nls.localize('saveEmptyWorkspaceNotSupported', "Please open a workspace first to save.")); - - return TPromise.as(null); - } - const configPath = this.getNewWorkspaceConfigPath(); if (configPath) { - switch (workspaceState) { - + switch (this.contextService.getWorkbenchState()) { + case WorkbenchState.EMPTY: case WorkbenchState.FOLDER: const workspaceFolders = this.contextService.getWorkspace().folders.map(root => root.uri.fsPath); return this.workspaceEditingService.createAndEnterWorkspace(workspaceFolders, configPath); From 40dd269a7263a2c120536262c2ddb58ef283b852 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 21 Sep 2017 17:38:02 +0200 Subject: [PATCH 170/281] allow to define byte-offset and byte-count when reading from a provider --- src/vs/platform/files/common/files.ts | 2 +- src/vs/vscode.proposed.d.ts | 8 +++----- .../api/electron-browser/mainThreadFileSystem.ts | 4 ++-- src/vs/workbench/api/node/extHost.protocol.ts | 2 +- src/vs/workbench/api/node/extHostFileSystem.ts | 9 +++++---- .../services/files/electron-browser/remoteFileService.ts | 2 +- 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 9c752093669..a7bd37587d3 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -180,7 +180,7 @@ export interface IFileSystemProvider { // utimes(resource: URI, mtime: number): TPromise; stat(resource: URI): TPromise; - read(resource: URI, progress: IProgress): TPromise; + read(resource: URI, offset: number, count: number, progress: IProgress): TPromise; write(resource: URI, content: Uint8Array): TPromise; move(from: URI, to: URI): TPromise; mkdir(resource: URI): TPromise; diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index ee038ba05f5..91d6d321fb1 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -206,13 +206,10 @@ declare module 'vscode' { // more... // utimes(resource: Uri, mtime: number): Thenable; + stat(resource: Uri): Thenable; - // todo@remote - // offset - byte offset to start - // count - number of bytes to read - // Thenable - number of bytes actually red - read(resource: Uri, progress: Progress): Thenable; + read(resource: Uri, offset: number, length: number, progress: Progress): Thenable; // todo@remote // offset - byte offset to start @@ -231,6 +228,7 @@ declare module 'vscode' { // todo@remote // Thenable mkdir(resource: Uri): Thenable; + readdir(resource: Uri): Thenable<[Uri, FileStat][]>; // todo@remote diff --git a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts index f5d967e6eb4..7667c708e84 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts @@ -90,9 +90,9 @@ class RemoteFileSystemProvider implements IFileSystemProvider { stat(resource: URI): TPromise { return this._proxy.$stat(this._handle, resource); } - read(resource: URI, progress: IProgress): TPromise { + read(resource: URI, offset: number, count: number, progress: IProgress): TPromise { this._reads.set(resource.toString(), progress); - return this._proxy.$read(this._handle, resource); + return this._proxy.$read(this._handle, offset, count, resource); } reportFileChunk(resource: URI, chunk: number[]): void { this._reads.get(resource.toString()).report(Buffer.from(chunk)); diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 2c8be377b23..92ed6c653db 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -481,7 +481,7 @@ export interface ExtHostWorkspaceShape { export interface ExtHostFileSystemShape { $utimes(handle: number, resource: URI, mtime: number): TPromise; $stat(handle: number, resource: URI): TPromise; - $read(handle: number, resource: URI): TPromise; + $read(handle: number, offset: number, count: number, resource: URI): TPromise; $write(handle: number, resource: URI, content: number[]): TPromise; $unlink(handle: number, resource: URI): TPromise; $move(handle: number, resource: URI, target: URI): TPromise; diff --git a/src/vs/workbench/api/node/extHostFileSystem.ts b/src/vs/workbench/api/node/extHostFileSystem.ts index 02407f01c7c..3488b9570f9 100644 --- a/src/vs/workbench/api/node/extHostFileSystem.ts +++ b/src/vs/workbench/api/node/extHostFileSystem.ts @@ -48,12 +48,13 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { $stat(handle: number, resource: URI): TPromise { return asWinJsPromise(token => this._provider.get(handle).stat(resource)); } - $read(handle: number, resource: URI): TPromise { - return asWinJsPromise(token => this._provider.get(handle).read(resource, { - report: (chunk) => { + $read(handle: number, offset: number, count: number, resource: URI): TPromise { + const progress = { + report: chunk => { this._proxy.$reportFileChunk(handle, resource, [].slice.call(chunk)); } - })); + }; + return asWinJsPromise(token => this._provider.get(handle).read(resource, offset, count, progress)); } $write(handle: number, resource: URI, content: number[]): TPromise { return asWinJsPromise(token => this._provider.get(handle).write(resource, Buffer.from(content))); diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 8018711f857..cffef7f3846 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -224,7 +224,7 @@ export class RemoteFileService extends FileService { const encoding = this.getEncoding(resource); const stream = decodeStream(encoding); - provider.read(resource, new Progress(chunk => stream.write(chunk))).then(() => { + provider.read(resource, 0, Number.MAX_VALUE, new Progress(chunk => stream.write(chunk))).then(() => { stream.end(); }, err => { stream.emit('error', err); From 088bbdbe9daed387bf6339c0dbd3de1dce83fd52 Mon Sep 17 00:00:00 2001 From: isidor Date: Thu, 21 Sep 2017 17:38:34 +0200 Subject: [PATCH 171/281] #34714 --- .../parts/debug/electron-browser/statusbarColorProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.ts b/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.ts index 979919f795a..a49f5ec93e9 100644 --- a/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.ts +++ b/src/vs/workbench/parts/debug/electron-browser/statusbarColorProvider.ts @@ -87,7 +87,7 @@ export class StatusBarColorProvider extends Themable implements IWorkbenchContri } private isDebugging(): boolean { - if (this.debugService.state === State.Inactive) { + if (this.debugService.state === State.Inactive || this.debugService.state === State.Initializing) { return false; } From 3a031832745434c8c85a689bb76d11b8dd95ac9f Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 21 Sep 2017 17:38:44 +0200 Subject: [PATCH 172/281] Fixes #34031: Remove workaround for Backslash and IntlBackslash "swapped" on ISO keyboards - #24153 --- src/vs/code/electron-main/app.ts | 4 +- src/vs/code/electron-main/keyboard.ts | 44 ++---------- src/vs/code/electron-main/window.ts | 4 -- src/vs/platform/windows/common/windows.ts | 1 - src/vs/workbench/electron-browser/main.ts | 2 +- src/vs/workbench/electron-browser/window.ts | 4 +- .../common/macLinuxKeyboardMapper.ts | 22 +----- .../electron-browser/keybindingService.ts | 26 +++---- .../test/macLinuxKeyboardMapper.test.ts | 68 ++----------------- 9 files changed, 24 insertions(+), 151 deletions(-) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index db62b2c15e1..df39afe3f61 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -228,9 +228,9 @@ export class CodeApplication { }); // Keyboard layout changes - KeyboardLayoutMonitor.INSTANCE.onDidChangeKeyboardLayout(isISOKeyboard => { + KeyboardLayoutMonitor.INSTANCE.onDidChangeKeyboardLayout(() => { if (this.windowsMainService) { - this.windowsMainService.sendToAll('vscode:keyboardLayoutChanged', isISOKeyboard); + this.windowsMainService.sendToAll('vscode:keyboardLayoutChanged', false); } }); } diff --git a/src/vs/code/electron-main/keyboard.ts b/src/vs/code/electron-main/keyboard.ts index 3b19f2fea15..d7d10e70d7b 100644 --- a/src/vs/code/electron-main/keyboard.ts +++ b/src/vs/code/electron-main/keyboard.ts @@ -7,7 +7,6 @@ import * as nativeKeymap from 'native-keymap'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { isMacintosh } from 'vs/base/common/platform'; import { IStorageService } from 'vs/platform/storage/node/storage'; import Event, { Emitter, once } from 'vs/base/common/event'; import { ConfigWatcher } from 'vs/base/node/config'; @@ -21,59 +20,24 @@ export class KeyboardLayoutMonitor { public static readonly INSTANCE = new KeyboardLayoutMonitor(); - private _emitter: Emitter; + private _emitter: Emitter; private _registered: boolean; - private _isISOKeyboard: boolean; private constructor() { - this._emitter = new Emitter(); + this._emitter = new Emitter(); this._registered = false; - this._isISOKeyboard = this._readIsISOKeyboard(); } - public onDidChangeKeyboardLayout(callback: (isISOKeyboard: boolean) => void): IDisposable { + public onDidChangeKeyboardLayout(callback: () => void): IDisposable { if (!this._registered) { this._registered = true; nativeKeymap.onDidChangeKeyboardLayout(() => { - this._emitter.fire(this._isISOKeyboard); + this._emitter.fire(); }); - - if (isMacintosh) { - // See https://github.com/Microsoft/vscode/issues/24153 - // On OSX, on ISO keyboards, Chromium swaps the scan codes - // of IntlBackslash and Backquote. - // - // The C++ methods can give the current keyboard type (ISO or not) - // only after a NSEvent was handled. - // - // We therefore poll. - setInterval(() => { - let newValue = this._readIsISOKeyboard(); - if (this._isISOKeyboard === newValue) { - // no change - return; - } - - this._isISOKeyboard = newValue; - this._emitter.fire(this._isISOKeyboard); - - }, 3000); - } } return this._emitter.event(callback); } - - private _readIsISOKeyboard(): boolean { - // if (isMacintosh) { - // return nativeKeymap.isISOKeyboard(); - // } - return false; - } - - public isISOKeyboard(): boolean { - return this._isISOKeyboard; - } } export interface IKeybinding { diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index ce4af4dbc88..b4cd79ee7ed 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -21,7 +21,6 @@ import product from 'vs/platform/node/product'; import pkg from 'vs/platform/node/package'; import { IWindowSettings, MenuBarVisibility, IWindowConfiguration, ReadyState, IRunActionInWindowRequest } from 'vs/platform/windows/common/windows'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { KeyboardLayoutMonitor } from 'vs/code/electron-main/keyboard'; import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; import { ICodeWindow } from 'vs/platform/windows/electron-main/windows'; import { IWorkspaceIdentifier, IWorkspacesMainService } from 'vs/platform/workspaces/common/workspaces'; @@ -550,9 +549,6 @@ export class CodeWindow implements ICodeWindow { windowConfiguration.highContrast = isWindows && systemPreferences.isInvertedColorScheme() && (!windowConfig || windowConfig.autoDetectHighContrast); windowConfiguration.accessibilitySupport = app.isAccessibilitySupportEnabled(); - // Set Keyboard Config - windowConfiguration.isISOKeyboard = KeyboardLayoutMonitor.INSTANCE.isISOKeyboard(); - // Theme windowConfiguration.baseTheme = this.getBaseTheme(); windowConfiguration.backgroundColor = this.getBackgroundColor(); diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index 95846dfb1e0..6be7162905c 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -242,7 +242,6 @@ export interface IWindowConfiguration extends ParsedArgs, IOpenFileRequest { workspace?: IWorkspaceIdentifier; folderPath?: string; - isISOKeyboard?: boolean; zoomLevel?: number; fullscreen?: boolean; highContrast?: boolean; diff --git a/src/vs/workbench/electron-browser/main.ts b/src/vs/workbench/electron-browser/main.ts index 0e08a60442a..f461e27e464 100644 --- a/src/vs/workbench/electron-browser/main.ts +++ b/src/vs/workbench/electron-browser/main.ts @@ -58,7 +58,7 @@ export function startup(configuration: IWindowConfiguration): TPromise { browser.setFullscreen(!!configuration.fullscreen); - KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged(configuration.isISOKeyboard); + KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged(); browser.setAccessibilitySupport(configuration.accessibilitySupport ? platform.AccessibilitySupport.Enabled : platform.AccessibilitySupport.Disabled); diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 79872402bda..622cf14e8d3 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -225,8 +225,8 @@ export class ElectronWindow extends Themable { }); // keyboard layout changed event - ipc.on('vscode:keyboardLayoutChanged', (event, isISOKeyboard: boolean) => { - KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged(isISOKeyboard); + ipc.on('vscode:keyboardLayoutChanged', event => { + KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged(); }); // keyboard layout changed event diff --git a/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts b/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts index 29dcb5a716d..2bb8da1d890 100644 --- a/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts +++ b/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts @@ -429,10 +429,6 @@ class ScanCodeKeyCodeMapper { export class MacLinuxKeyboardMapper implements IKeyboardMapper { - /** - * Is the keyboard type ISO (on Mac) - */ - private readonly _isISOKeyboard: boolean; /** * Is this the standard US keyboard layout? */ @@ -458,8 +454,7 @@ export class MacLinuxKeyboardMapper implements IKeyboardMapper { */ private readonly _scanCodeToDispatch: string[] = []; - constructor(isISOKeyboard: boolean, isUSStandard: boolean, rawMappings: IMacLinuxKeyboardMapping, OS: OperatingSystem) { - this._isISOKeyboard = isISOKeyboard; + constructor(isUSStandard: boolean, rawMappings: IMacLinuxKeyboardMapping, OS: OperatingSystem) { this._isUSStandard = isUSStandard; this._OS = OS; this._codeInfo = []; @@ -1055,21 +1050,6 @@ export class MacLinuxKeyboardMapper implements IKeyboardMapper { code = ScanCode.Enter; } - if (this._OS === OperatingSystem.Macintosh && this._isISOKeyboard) { - // See https://github.com/Microsoft/vscode/issues/24153 - // On OSX, on ISO keyboards, Chromium swaps the scan codes - // of IntlBackslash and Backquote. - - switch (code) { - case ScanCode.IntlBackslash: - code = ScanCode.Backquote; - break; - case ScanCode.Backquote: - code = ScanCode.IntlBackslash; - break; - } - } - const keyCode = keyboardEvent.keyCode; if ( diff --git a/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts b/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts index 4d7dfa3e616..0e599328bf5 100644 --- a/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts @@ -40,7 +40,6 @@ import { onUnexpectedError } from 'vs/base/common/errors'; export class KeyboardMapperFactory { public static INSTANCE = new KeyboardMapperFactory(); - private _isISOKeyboard: boolean; private _layoutInfo: nativeKeymap.IKeyboardLayoutInfo; private _rawMapping: nativeKeymap.IKeyboardMapping; private _keyboardMapper: IKeyboardMapper; @@ -50,25 +49,21 @@ export class KeyboardMapperFactory { public onDidChangeKeyboardMapper: Event = this._onDidChangeKeyboardMapper.event; private constructor() { - this._isISOKeyboard = false; this._layoutInfo = null; this._rawMapping = null; this._keyboardMapper = null; this._initialized = false; } - public _onKeyboardLayoutChanged(isISOKeyboard: boolean): void { - isISOKeyboard = !!isISOKeyboard; + public _onKeyboardLayoutChanged(): void { if (this._initialized) { - this._setKeyboardData(isISOKeyboard, nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); - } else { - this._isISOKeyboard = isISOKeyboard; + this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); } } public getKeyboardMapper(dispatchConfig: DispatchConfig): IKeyboardMapper { if (!this._initialized) { - this._setKeyboardData(this._isISOKeyboard, nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); + this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); } if (dispatchConfig === DispatchConfig.KeyCode) { // Forcefully set to use keyCode @@ -79,7 +74,7 @@ export class KeyboardMapperFactory { public getCurrentKeyboardLayout(): nativeKeymap.IKeyboardLayoutInfo { if (!this._initialized) { - this._setKeyboardData(this._isISOKeyboard, nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); + this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); } return this._layoutInfo; } @@ -105,27 +100,26 @@ export class KeyboardMapperFactory { public getRawKeyboardMapping(): nativeKeymap.IKeyboardMapping { if (!this._initialized) { - this._setKeyboardData(this._isISOKeyboard, nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); + this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); } return this._rawMapping; } - private _setKeyboardData(isISOKeyboard: boolean, layoutInfo: nativeKeymap.IKeyboardLayoutInfo, rawMapping: nativeKeymap.IKeyboardMapping): void { + private _setKeyboardData(layoutInfo: nativeKeymap.IKeyboardLayoutInfo, rawMapping: nativeKeymap.IKeyboardMapping): void { this._layoutInfo = layoutInfo; - if (this._initialized && this._isISOKeyboard === isISOKeyboard && KeyboardMapperFactory._equals(this._rawMapping, rawMapping)) { + if (this._initialized && KeyboardMapperFactory._equals(this._rawMapping, rawMapping)) { // nothing to do... return; } this._initialized = true; - this._isISOKeyboard = isISOKeyboard; this._rawMapping = rawMapping; - this._keyboardMapper = KeyboardMapperFactory._createKeyboardMapper(this._isISOKeyboard, this._layoutInfo, this._rawMapping); + this._keyboardMapper = KeyboardMapperFactory._createKeyboardMapper(this._layoutInfo, this._rawMapping); this._onDidChangeKeyboardMapper.fire(); } - private static _createKeyboardMapper(isISOKeyboard: boolean, layoutInfo: nativeKeymap.IKeyboardLayoutInfo, rawMapping: nativeKeymap.IKeyboardMapping): IKeyboardMapper { + private static _createKeyboardMapper(layoutInfo: nativeKeymap.IKeyboardLayoutInfo, rawMapping: nativeKeymap.IKeyboardMapping): IKeyboardMapper { const isUSStandard = KeyboardMapperFactory._isUSStandard(layoutInfo); if (OS === OperatingSystem.Windows) { return new WindowsKeyboardMapper(isUSStandard, rawMapping); @@ -144,7 +138,7 @@ export class KeyboardMapperFactory { } } - return new MacLinuxKeyboardMapper(isISOKeyboard, isUSStandard, rawMapping, OS); + return new MacLinuxKeyboardMapper(isUSStandard, rawMapping, OS); } private static _equals(a: nativeKeymap.IKeyboardMapping, b: nativeKeymap.IKeyboardMapping): boolean { diff --git a/src/vs/workbench/services/keybinding/test/macLinuxKeyboardMapper.test.ts b/src/vs/workbench/services/keybinding/test/macLinuxKeyboardMapper.test.ts index aa5d104d8b7..bd0f29a1abe 100644 --- a/src/vs/workbench/services/keybinding/test/macLinuxKeyboardMapper.test.ts +++ b/src/vs/workbench/services/keybinding/test/macLinuxKeyboardMapper.test.ts @@ -19,7 +19,7 @@ const WRITE_FILE_IF_DIFFERENT = false; function createKeyboardMapper(isUSStandard: boolean, file: string, OS: OperatingSystem): TPromise { return readRawMapping(file).then((rawMappings) => { - return new MacLinuxKeyboardMapper(false, isUSStandard, rawMappings, OS); + return new MacLinuxKeyboardMapper(isUSStandard, rawMappings, OS); }); } @@ -1202,7 +1202,7 @@ suite('keyboardMapper - LINUX en_us', () => { suite('keyboardMapper', () => { test('issue #23706: Linux UK layout: Ctrl + Apostrophe also toggles terminal', () => { - let mapper = new MacLinuxKeyboardMapper(false, false, { + let mapper = new MacLinuxKeyboardMapper(false, { 'Backquote': { 'value': '`', 'withShift': '¬', @@ -1234,7 +1234,7 @@ suite('keyboardMapper', () => { }); test('issue #24064: NumLock/NumPad keys stopped working in 1.11 on Linux', () => { - let mapper = new MacLinuxKeyboardMapper(false, false, {}, OperatingSystem.Linux); + let mapper = new MacLinuxKeyboardMapper(false, {}, OperatingSystem.Linux); function assertNumpadKeyboardEvent(keyCode: KeyCode, code: string, label: string, electronAccelerator: string, userSettingsLabel: string, dispatch: string): void { assertResolveKeyboardEvent( @@ -1273,7 +1273,7 @@ suite('keyboardMapper', () => { }); test('issue #24107: Delete, Insert, Home, End, PgUp, PgDn, and arrow keys no longer work editor in 1.11', () => { - let mapper = new MacLinuxKeyboardMapper(false, false, {}, OperatingSystem.Linux); + let mapper = new MacLinuxKeyboardMapper(false, {}, OperatingSystem.Linux); function assertKeyboardEvent(keyCode: KeyCode, code: string, label: string, electronAccelerator: string, userSettingsLabel: string, dispatch: string): void { assertResolveKeyboardEvent( @@ -1322,66 +1322,6 @@ suite('keyboardMapper', () => { assertKeyboardEvent(KeyCode.DownArrow, 'NumpadEnter', 'DownArrow', 'Down', 'down', '[ArrowDown]'); assertKeyboardEvent(KeyCode.UpArrow, 'Lang3', 'UpArrow', 'Up', 'up', '[ArrowUp]'); }); - - test('issue #24153: ISO Keyboards: Backslash and IntlBackslash "swapped"', () => { - let mapper = new MacLinuxKeyboardMapper(true, false, { - 'Backquote': { - 'value': '`', - 'withShift': '~', - 'withAltGr': '`', - 'withShiftAltGr': '`' - }, - 'IntlBackslash': { - 'value': '§', - 'withShift': '°', - 'withAltGr': '§', - 'withShiftAltGr': '°' - } - }, OperatingSystem.Macintosh); - - assertResolveKeyboardEvent( - mapper, - { - ctrlKey: true, - shiftKey: false, - altKey: false, - metaKey: false, - keyCode: -1, - code: 'Backquote' - }, - { - label: '⌃§', - ariaLabel: 'Control+§', - electronAccelerator: null, - userSettingsLabel: 'ctrl+[IntlBackslash]', - isWYSIWYG: false, - isChord: false, - dispatchParts: ['ctrl+[IntlBackslash]', null], - } - ); - - assertResolveKeyboardEvent( - mapper, - { - ctrlKey: true, - shiftKey: false, - altKey: false, - metaKey: false, - keyCode: -1, - code: 'IntlBackslash' - }, - { - label: '⌃`', - ariaLabel: 'Control+`', - electronAccelerator: null, - userSettingsLabel: 'ctrl+`', - isWYSIWYG: true, - isChord: false, - dispatchParts: ['ctrl+[Backquote]', null], - } - ); - }); - }); suite('keyboardMapper - LINUX ru', () => { From ec572b1df55ae9af26f5a508a1cd1bd314dc4f53 Mon Sep 17 00:00:00 2001 From: Ramya Achutha Rao Date: Wed, 20 Sep 2017 21:07:51 -0700 Subject: [PATCH 173/281] Sort extension based recommendations based on recommended date #34233 --- .../electron-browser/extensionTipsService.ts | 5 +++- .../electron-browser/extensionsViews.ts | 25 +++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts index 869c71175a9..91a304a62e8 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts @@ -107,7 +107,10 @@ export class ExtensionTipsService implements IExtensionTipsService { getRecommendations(): string[] { const allRecomendations = this._getAllRecommendationsInProduct(); const fileBased = Object.keys(this._fileBasedRecommendations) - .filter(recommendation => allRecomendations.indexOf(recommendation) !== -1); + .filter(recommendation => allRecomendations.indexOf(recommendation) !== -1) + .sort((a, b) => { + return this._fileBasedRecommendations[a] > this._fileBasedRecommendations[b] ? -1 : 1; + }); const exeBased = distinct(this._exeBasedRecommendations); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts index 2938cc9b3f1..eacb5df736e 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts @@ -299,7 +299,10 @@ export class ExtensionsListView extends CollapsibleView { } options.source = 'recommendations-all'; return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length })) - .then(pager => new PagedModel(pager || [])); + .then(pager => { + this.sortFirstPage(pager, names); + return new PagedModel(pager || []); + }); }); }); } @@ -321,7 +324,10 @@ export class ExtensionsListView extends CollapsibleView { } options.source = 'recommendations'; return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length })) - .then(pager => new PagedModel(pager || [])); + .then(pager => { + this.sortFirstPage(pager, names); + return new PagedModel(pager || []); + }); }); } @@ -355,6 +361,21 @@ export class ExtensionsListView extends CollapsibleView { .then(result => new PagedModel(result)); } + // Sorts the firsPage of the pager in the same order as given array of extension ids + private sortFirstPage(pager: IPager, ids: string[]) { + if (ids.length === pager.pageSize) { + let newArray = new Array(pager.pageSize); + for (let i = 0; i < pager.pageSize; i++) { + let index = ids.indexOf(pager.firstPage[i].id); + if (index === -1) { + return; + } + newArray[index] = pager.firstPage[i]; + } + pager.firstPage = newArray; + } + } + private setModel(model: IPagedModel) { this.list.model = model; this.list.scrollTop = 0; From 2930aeb146333edc2dfafa66195e036502d24891 Mon Sep 17 00:00:00 2001 From: Ramya Achutha Rao Date: Thu, 21 Sep 2017 11:43:23 -0700 Subject: [PATCH 174/281] Recommend only if files exists --- .../parts/extensions/electron-browser/extensionTipsService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts index 91a304a62e8..11abcc7372c 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts @@ -345,7 +345,7 @@ export class ExtensionTipsService implements IExtensionTipsService { let findExecutable = (exeName, path) => { return pfs.fileExists(path).then(exists => { - if (!foundExecutables.has(exeName)) { + if (exists && !foundExecutables.has(exeName)) { foundExecutables.add(exeName); recommendations.push(...product.exeBasedExtensionTips[exeName]['recommendations']); } From e2725c4da0fb185e7fa3d57b45fe50e9b5db8f86 Mon Sep 17 00:00:00 2001 From: Ramya Achutha Rao Date: Thu, 21 Sep 2017 14:40:25 -0700 Subject: [PATCH 175/281] Lowercase extension ids before check --- .../electron-browser/extensionsViews.ts | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts index eacb5df736e..1317316f3ee 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts @@ -363,17 +363,19 @@ export class ExtensionsListView extends CollapsibleView { // Sorts the firsPage of the pager in the same order as given array of extension ids private sortFirstPage(pager: IPager, ids: string[]) { - if (ids.length === pager.pageSize) { - let newArray = new Array(pager.pageSize); - for (let i = 0; i < pager.pageSize; i++) { - let index = ids.indexOf(pager.firstPage[i].id); - if (index === -1) { - return; - } - newArray[index] = pager.firstPage[i]; - } - pager.firstPage = newArray; + if (ids.length !== pager.pageSize) { + return; } + ids = ids.map(x => x.toLowerCase()); + let newFirstPage = new Array(pager.pageSize); + for (let i = 0; i < pager.pageSize; i++) { + let index = ids.indexOf(pager.firstPage[i].id.toLowerCase()); + if (index === -1) { + return; // Something went wrong, Abort! Abort! + } + newFirstPage[index] = pager.firstPage[i]; + } + pager.firstPage = newFirstPage; } private setModel(model: IPagedModel) { From 0f611dbe05be55a46afa507e0a37ec99343a50b3 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 21 Sep 2017 12:51:50 -0700 Subject: [PATCH 176/281] Cleaning up formatting provider to use async --- .../src/features/formattingProvider.ts | 139 ++++++++++-------- 1 file changed, 77 insertions(+), 62 deletions(-) diff --git a/extensions/typescript/src/features/formattingProvider.ts b/extensions/typescript/src/features/formattingProvider.ts index b4f26fdcd0a..53f2c5fd9dc 100644 --- a/extensions/typescript/src/features/formattingProvider.ts +++ b/extensions/typescript/src/features/formattingProvider.ts @@ -110,47 +110,57 @@ export class TypeScriptFormattingProvider implements DocumentRangeFormattingEdit return this.config.enable; } - private ensureFormatOptions(document: TextDocument, options: FormattingOptions, token: CancellationToken): Promise { + private async ensureFormatOptions( + document: TextDocument, + options: FormattingOptions, + token: CancellationToken + ): Promise { const key = document.uri.toString(); const currentOptions = this.formatOptions[key]; if (currentOptions && currentOptions.tabSize === options.tabSize && currentOptions.indentSize === options.tabSize && currentOptions.convertTabsToSpaces === options.insertSpaces) { - return Promise.resolve(currentOptions); - } else { - const absPath = this.client.normalizePath(document.uri); - if (!absPath) { - return Promise.resolve(Object.create(null)); - } - - const formatOptions = this.getFormatOptions(options); - const args: Proto.ConfigureRequestArguments = { - file: absPath, - formatOptions: formatOptions - }; - return this.client.execute('configure', args, token).then(_ => { - this.formatOptions[key] = formatOptions; - return formatOptions; - }); + return currentOptions; } - } - - private doFormat(document: TextDocument, options: FormattingOptions, args: Proto.FormatRequestArgs, token: CancellationToken): Promise { - return this.ensureFormatOptions(document, options, token).then(() => { - return this.client.execute('format', args, token).then((response): TextEdit[] => { - if (response.body) { - return response.body.map(this.codeEdit2SingleEditOperation); - } else { - return []; - } - }, () => { - return []; - }); - }); - } - - public provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): Promise { const absPath = this.client.normalizePath(document.uri); if (!absPath) { - return Promise.resolve([]); + return Object.create(null); + } + const formatOptions = this.getFormatOptions(options); + const args: Proto.ConfigureRequestArguments = { + file: absPath, + formatOptions: formatOptions + }; + await this.client.execute('configure', args, token); + this.formatOptions[key] = formatOptions; + return formatOptions; + } + + private async doFormat( + document: TextDocument, + options: FormattingOptions, + args: Proto.FormatRequestArgs, + token: CancellationToken + ): Promise { + await this.ensureFormatOptions(document, options, token); + try { + const response = await this.client.execute('format', args, token); + if (response.body) { + return response.body.map(this.codeEdit2SingleEditOperation); + } + } catch { + // noop + } + return []; + } + + public async provideDocumentRangeFormattingEdits( + document: TextDocument, + range: Range, + options: FormattingOptions, + token: CancellationToken + ): Promise { + const absPath = this.client.normalizePath(document.uri); + if (!absPath) { + return []; } const args: Proto.FormatRequestArgs = { file: absPath, @@ -162,10 +172,16 @@ export class TypeScriptFormattingProvider implements DocumentRangeFormattingEdit return this.doFormat(document, options, args, token); } - public provideOnTypeFormattingEdits(document: TextDocument, position: Position, ch: string, options: FormattingOptions, token: CancellationToken): Promise { + public async provideOnTypeFormattingEdits( + document: TextDocument, + position: Position, + ch: string, + options: FormattingOptions, + token: CancellationToken + ): Promise { const filepath = this.client.normalizePath(document.uri); if (!filepath) { - return Promise.resolve([]); + return []; } let args: Proto.FormatOnKeyRequestArgs = { file: filepath, @@ -174,34 +190,33 @@ export class TypeScriptFormattingProvider implements DocumentRangeFormattingEdit key: ch }; - return this.ensureFormatOptions(document, options, token).then(() => { - return this.client.execute('formatonkey', args, token).then((response): TextEdit[] => { - let edits = response.body; - let result: TextEdit[] = []; - if (!edits) { - return result; - } - for (let edit of edits) { - let textEdit = this.codeEdit2SingleEditOperation(edit); - let range = textEdit.range; - // Work around for https://github.com/Microsoft/TypeScript/issues/6700. - // Check if we have an edit at the beginning of the line which only removes white spaces and leaves - // an empty line. Drop those edits - if (range.start.character === 0 && range.start.line === range.end.line && textEdit.newText === '') { - let lText = document.lineAt(range.start.line).text; - // If the edit leaves something on the line keep the edit (note that the end character is exclusive). - // Keep it also if it removes something else than whitespace - if (lText.trim().length > 0 || lText.length > range.end.character) { - result.push(textEdit); - } - } else { + await this.ensureFormatOptions(document, options, token); + return this.client.execute('formatonkey', args, token).then((response): TextEdit[] => { + let edits = response.body; + let result: TextEdit[] = []; + if (!edits) { + return result; + } + for (let edit of edits) { + let textEdit = this.codeEdit2SingleEditOperation(edit); + let range = textEdit.range; + // Work around for https://github.com/Microsoft/TypeScript/issues/6700. + // Check if we have an edit at the beginning of the line which only removes white spaces and leaves + // an empty line. Drop those edits + if (range.start.character === 0 && range.start.line === range.end.line && textEdit.newText === '') { + let lText = document.lineAt(range.start.line).text; + // If the edit leaves something on the line keep the edit (note that the end character is exclusive). + // Keep it also if it removes something else than whitespace + if (lText.trim().length > 0 || lText.length > range.end.character) { result.push(textEdit); } + } else { + result.push(textEdit); } - return result; - }, () => { - return []; - }); + } + return result; + }, () => { + return []; }); } From 5bb143137c964d84eac3221137ae3c25c2eb9d6f Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 21 Sep 2017 13:01:45 -0700 Subject: [PATCH 177/281] Move formatting options manager to own class --- .../src/features/formattingProvider.ts | 108 ++++++++++-------- 1 file changed, 63 insertions(+), 45 deletions(-) diff --git a/extensions/typescript/src/features/formattingProvider.ts b/extensions/typescript/src/features/formattingProvider.ts index 53f2c5fd9dc..7d7be05df1c 100644 --- a/extensions/typescript/src/features/formattingProvider.ts +++ b/extensions/typescript/src/features/formattingProvider.ts @@ -78,15 +78,15 @@ namespace Configuration { } } -export class TypeScriptFormattingProvider implements DocumentRangeFormattingEditProvider, OnTypeFormattingEditProvider { +export class FormattingOptionsManager { private config: Configuration; - private formatOptions: { [key: string]: Proto.FormatCodeSettings | undefined; }; + + private formatOptions: { [key: string]: Proto.FormatCodeSettings | undefined; } = Object.create(null); public constructor( private client: ITypescriptServiceClient ) { this.config = Configuration.def(); - this.formatOptions = Object.create(null); Workspace.onDidCloseTextDocument((textDocument) => { let key = textDocument.uri.toString(); // When a document gets closed delete the cached formatting options. @@ -97,20 +97,7 @@ export class TypeScriptFormattingProvider implements DocumentRangeFormattingEdit }); } - public updateConfiguration(config: WorkspaceConfiguration): void { - let newConfig = config.get('format', Configuration.def()); - - if (!Configuration.equals(this.config, newConfig)) { - this.config = newConfig; - this.formatOptions = Object.create(null); - } - } - - public isEnabled(): boolean { - return this.config.enable; - } - - private async ensureFormatOptions( + public async ensureFormatOptions( document: TextDocument, options: FormattingOptions, token: CancellationToken @@ -134,13 +121,70 @@ export class TypeScriptFormattingProvider implements DocumentRangeFormattingEdit return formatOptions; } + public updateConfiguration(config: WorkspaceConfiguration): void { + let newConfig = config.get('format', Configuration.def()); + + if (!Configuration.equals(this.config, newConfig)) { + this.config = newConfig; + this.formatOptions = Object.create(null); + } + } + + + private getFormatOptions(options: FormattingOptions): Proto.FormatCodeSettings { + return { + tabSize: options.tabSize, + indentSize: options.tabSize, + convertTabsToSpaces: options.insertSpaces, + // We can use \n here since the editor normalizes later on to its line endings. + newLineCharacter: '\n', + insertSpaceAfterCommaDelimiter: this.config.insertSpaceAfterCommaDelimiter, + insertSpaceAfterConstructor: this.config.insertSpaceAfterConstructor, + insertSpaceAfterSemicolonInForStatements: this.config.insertSpaceAfterSemicolonInForStatements, + insertSpaceBeforeAndAfterBinaryOperators: this.config.insertSpaceBeforeAndAfterBinaryOperators, + insertSpaceAfterKeywordsInControlFlowStatements: this.config.insertSpaceAfterKeywordsInControlFlowStatements, + insertSpaceAfterFunctionKeywordForAnonymousFunctions: this.config.insertSpaceAfterFunctionKeywordForAnonymousFunctions, + insertSpaceBeforeFunctionParenthesis: this.config.insertSpaceBeforeFunctionParenthesis, + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces, + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces, + insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces, + insertSpaceAfterTypeAssertion: this.config.insertSpaceAfterTypeAssertion, + placeOpenBraceOnNewLineForFunctions: this.config.placeOpenBraceOnNewLineForFunctions, + placeOpenBraceOnNewLineForControlBlocks: this.config.placeOpenBraceOnNewLineForControlBlocks, + + }; + } +} + +export class TypeScriptFormattingProvider implements DocumentRangeFormattingEditProvider, OnTypeFormattingEditProvider { + private config: Configuration; + private formattingOptionsManager: FormattingOptionsManager; + + public constructor( + private client: ITypescriptServiceClient + ) { + this.config = Configuration.def(); + this.formattingOptionsManager = new FormattingOptionsManager(client); + } + + public updateConfiguration(config: WorkspaceConfiguration): void { + this.config = config.get('format', Configuration.def()); + this.formattingOptionsManager.updateConfiguration(config); + } + + public isEnabled(): boolean { + return this.config.enable; + } + private async doFormat( document: TextDocument, options: FormattingOptions, args: Proto.FormatRequestArgs, token: CancellationToken ): Promise { - await this.ensureFormatOptions(document, options, token); + await this.formattingOptionsManager.ensureFormatOptions(document, options, token); try { const response = await this.client.execute('format', args, token); if (response.body) { @@ -190,7 +234,7 @@ export class TypeScriptFormattingProvider implements DocumentRangeFormattingEdit key: ch }; - await this.ensureFormatOptions(document, options, token); + await this.formattingOptionsManager.ensureFormatOptions(document, options, token); return this.client.execute('formatonkey', args, token).then((response): TextEdit[] => { let edits = response.body; let result: TextEdit[] = []; @@ -223,32 +267,6 @@ export class TypeScriptFormattingProvider implements DocumentRangeFormattingEdit private codeEdit2SingleEditOperation(edit: Proto.CodeEdit): TextEdit { return new TextEdit(tsTextSpanToVsRange(edit), edit.newText); } - - private getFormatOptions(options: FormattingOptions): Proto.FormatCodeSettings { - return { - tabSize: options.tabSize, - indentSize: options.tabSize, - convertTabsToSpaces: options.insertSpaces, - // We can use \n here since the editor normalizes later on to its line endings. - newLineCharacter: '\n', - insertSpaceAfterCommaDelimiter: this.config.insertSpaceAfterCommaDelimiter, - insertSpaceAfterConstructor: this.config.insertSpaceAfterConstructor, - insertSpaceAfterSemicolonInForStatements: this.config.insertSpaceAfterSemicolonInForStatements, - insertSpaceBeforeAndAfterBinaryOperators: this.config.insertSpaceBeforeAndAfterBinaryOperators, - insertSpaceAfterKeywordsInControlFlowStatements: this.config.insertSpaceAfterKeywordsInControlFlowStatements, - insertSpaceAfterFunctionKeywordForAnonymousFunctions: this.config.insertSpaceAfterFunctionKeywordForAnonymousFunctions, - insertSpaceBeforeFunctionParenthesis: this.config.insertSpaceBeforeFunctionParenthesis, - insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces, - insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces, - insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces, - insertSpaceAfterTypeAssertion: this.config.insertSpaceAfterTypeAssertion, - placeOpenBraceOnNewLineForFunctions: this.config.placeOpenBraceOnNewLineForFunctions, - placeOpenBraceOnNewLineForControlBlocks: this.config.placeOpenBraceOnNewLineForControlBlocks, - - }; - } } export class FormattingProviderManager { From 1646463dd223eae1b22d5f176d58a0bcf7d04b2b Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 21 Sep 2017 14:25:58 -0700 Subject: [PATCH 178/281] Split formatting config manager to own file --- .../src/features/formattingProvider.ts | 152 +----------------- 1 file changed, 2 insertions(+), 150 deletions(-) diff --git a/extensions/typescript/src/features/formattingProvider.ts b/extensions/typescript/src/features/formattingProvider.ts index 7d7be05df1c..706ec6578b5 100644 --- a/extensions/typescript/src/features/formattingProvider.ts +++ b/extensions/typescript/src/features/formattingProvider.ts @@ -3,160 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { workspace as Workspace, DocumentRangeFormattingEditProvider, OnTypeFormattingEditProvider, FormattingOptions, TextDocument, Position, Range, CancellationToken, TextEdit, WorkspaceConfiguration, Disposable, languages, workspace } from 'vscode'; +import { DocumentRangeFormattingEditProvider, OnTypeFormattingEditProvider, FormattingOptions, TextDocument, Position, Range, CancellationToken, TextEdit, WorkspaceConfiguration, Disposable, languages, workspace } from 'vscode'; import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; import { tsTextSpanToVsRange } from '../utils/convert'; - -interface Configuration { - enable: boolean; - insertSpaceAfterCommaDelimiter: boolean; - insertSpaceAfterConstructor: boolean; - insertSpaceAfterSemicolonInForStatements: boolean; - insertSpaceBeforeAndAfterBinaryOperators: boolean; - insertSpaceAfterKeywordsInControlFlowStatements: boolean; - insertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean; - insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean; - insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: boolean; - insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: boolean; - insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: boolean; - insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: boolean; - insertSpaceAfterTypeAssertion: boolean; - insertSpaceBeforeFunctionParenthesis: boolean; - placeOpenBraceOnNewLineForFunctions: boolean; - placeOpenBraceOnNewLineForControlBlocks: boolean; -} - -namespace Configuration { - export const insertSpaceAfterCommaDelimiter = 'insertSpaceAfterCommaDelimiter'; - export const insertSpaceAfterConstructor = 'insertSpaceAfterConstructor'; - export const insertSpaceAfterSemicolonInForStatements = 'insertSpaceAfterSemicolonInForStatements'; - export const insertSpaceBeforeAndAfterBinaryOperators = 'insertSpaceBeforeAndAfterBinaryOperators'; - export const insertSpaceAfterKeywordsInControlFlowStatements = 'insertSpaceAfterKeywordsInControlFlowStatements'; - export const insertSpaceAfterFunctionKeywordForAnonymousFunctions = 'insertSpaceAfterFunctionKeywordForAnonymousFunctions'; - export const insertSpaceBeforeFunctionParenthesis = 'insertSpaceBeforeFunctionParenthesis'; - export const insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = 'insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis'; - export const insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets = 'insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets'; - export const insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces = 'insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces'; - export const insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces = 'insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces'; - export const insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces = 'insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces'; - export const insertSpaceAfterTypeAssertion = 'insertSpaceAfterTypeAssertion'; - export const placeOpenBraceOnNewLineForFunctions = 'placeOpenBraceOnNewLineForFunctions'; - export const placeOpenBraceOnNewLineForControlBlocks = 'placeOpenBraceOnNewLineForControlBlocks'; - - export function equals(a: Configuration, b: Configuration): boolean { - let keys = Object.keys(a); - for (let i = 0; i < keys.length; i++) { - let key = keys[i]; - if ((a as any)[key] !== (b as any)[key]) { - return false; - } - } - return true; - } - - export function def(): Configuration { - let result: Configuration = Object.create(null); - result.enable = true; - result.insertSpaceAfterCommaDelimiter = true; - result.insertSpaceAfterConstructor = false; - result.insertSpaceAfterSemicolonInForStatements = true; - result.insertSpaceBeforeAndAfterBinaryOperators = true; - result.insertSpaceAfterKeywordsInControlFlowStatements = true; - result.insertSpaceAfterFunctionKeywordForAnonymousFunctions = false; - result.insertSpaceBeforeFunctionParenthesis = false; - result.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = false; - result.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets = false; - result.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces = true; - result.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces = false; - result.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces = false; - result.insertSpaceAfterTypeAssertion = false; - result.placeOpenBraceOnNewLineForFunctions = false; - result.placeOpenBraceOnNewLineForControlBlocks = false; - return result; - } -} - -export class FormattingOptionsManager { - private config: Configuration; - - private formatOptions: { [key: string]: Proto.FormatCodeSettings | undefined; } = Object.create(null); - - public constructor( - private client: ITypescriptServiceClient - ) { - this.config = Configuration.def(); - Workspace.onDidCloseTextDocument((textDocument) => { - let key = textDocument.uri.toString(); - // When a document gets closed delete the cached formatting options. - // This is necessary sine the tsserver now closed a project when its - // last file in it closes which drops the stored formatting options - // as well. - delete this.formatOptions[key]; - }); - } - - public async ensureFormatOptions( - document: TextDocument, - options: FormattingOptions, - token: CancellationToken - ): Promise { - const key = document.uri.toString(); - const currentOptions = this.formatOptions[key]; - if (currentOptions && currentOptions.tabSize === options.tabSize && currentOptions.indentSize === options.tabSize && currentOptions.convertTabsToSpaces === options.insertSpaces) { - return currentOptions; - } - const absPath = this.client.normalizePath(document.uri); - if (!absPath) { - return Object.create(null); - } - const formatOptions = this.getFormatOptions(options); - const args: Proto.ConfigureRequestArguments = { - file: absPath, - formatOptions: formatOptions - }; - await this.client.execute('configure', args, token); - this.formatOptions[key] = formatOptions; - return formatOptions; - } - - public updateConfiguration(config: WorkspaceConfiguration): void { - let newConfig = config.get('format', Configuration.def()); - - if (!Configuration.equals(this.config, newConfig)) { - this.config = newConfig; - this.formatOptions = Object.create(null); - } - } - - - private getFormatOptions(options: FormattingOptions): Proto.FormatCodeSettings { - return { - tabSize: options.tabSize, - indentSize: options.tabSize, - convertTabsToSpaces: options.insertSpaces, - // We can use \n here since the editor normalizes later on to its line endings. - newLineCharacter: '\n', - insertSpaceAfterCommaDelimiter: this.config.insertSpaceAfterCommaDelimiter, - insertSpaceAfterConstructor: this.config.insertSpaceAfterConstructor, - insertSpaceAfterSemicolonInForStatements: this.config.insertSpaceAfterSemicolonInForStatements, - insertSpaceBeforeAndAfterBinaryOperators: this.config.insertSpaceBeforeAndAfterBinaryOperators, - insertSpaceAfterKeywordsInControlFlowStatements: this.config.insertSpaceAfterKeywordsInControlFlowStatements, - insertSpaceAfterFunctionKeywordForAnonymousFunctions: this.config.insertSpaceAfterFunctionKeywordForAnonymousFunctions, - insertSpaceBeforeFunctionParenthesis: this.config.insertSpaceBeforeFunctionParenthesis, - insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces, - insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces, - insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces, - insertSpaceAfterTypeAssertion: this.config.insertSpaceAfterTypeAssertion, - placeOpenBraceOnNewLineForFunctions: this.config.placeOpenBraceOnNewLineForFunctions, - placeOpenBraceOnNewLineForControlBlocks: this.config.placeOpenBraceOnNewLineForControlBlocks, - - }; - } -} +import { FormattingOptionsManager, Configuration } from './FormattingConfigurationManager'; export class TypeScriptFormattingProvider implements DocumentRangeFormattingEditProvider, OnTypeFormattingEditProvider { private config: Configuration; From 163f51db8dae6285f98cddeda1054ba3c8dbf301 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 21 Sep 2017 14:33:39 -0700 Subject: [PATCH 179/281] Don't export config from formatting config manager --- .../formattingConfigurationManager.ts | 154 ++++++++++++++++++ .../src/features/formattingProvider.ts | 9 +- 2 files changed, 158 insertions(+), 5 deletions(-) create mode 100644 extensions/typescript/src/features/formattingConfigurationManager.ts diff --git a/extensions/typescript/src/features/formattingConfigurationManager.ts b/extensions/typescript/src/features/formattingConfigurationManager.ts new file mode 100644 index 00000000000..510dda1c428 --- /dev/null +++ b/extensions/typescript/src/features/formattingConfigurationManager.ts @@ -0,0 +1,154 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { workspace as Workspace, FormattingOptions, TextDocument, CancellationToken, WorkspaceConfiguration } from 'vscode'; + +import * as Proto from '../protocol'; +import { ITypescriptServiceClient } from '../typescriptService'; + +interface Configuration { + insertSpaceAfterCommaDelimiter: boolean; + insertSpaceAfterConstructor: boolean; + insertSpaceAfterSemicolonInForStatements: boolean; + insertSpaceBeforeAndAfterBinaryOperators: boolean; + insertSpaceAfterKeywordsInControlFlowStatements: boolean; + insertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean; + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean; + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: boolean; + insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: boolean; + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: boolean; + insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: boolean; + insertSpaceAfterTypeAssertion: boolean; + insertSpaceBeforeFunctionParenthesis: boolean; + placeOpenBraceOnNewLineForFunctions: boolean; + placeOpenBraceOnNewLineForControlBlocks: boolean; +} +namespace Configuration { + export const insertSpaceAfterCommaDelimiter = 'insertSpaceAfterCommaDelimiter'; + export const insertSpaceAfterConstructor = 'insertSpaceAfterConstructor'; + export const insertSpaceAfterSemicolonInForStatements = 'insertSpaceAfterSemicolonInForStatements'; + export const insertSpaceBeforeAndAfterBinaryOperators = 'insertSpaceBeforeAndAfterBinaryOperators'; + export const insertSpaceAfterKeywordsInControlFlowStatements = 'insertSpaceAfterKeywordsInControlFlowStatements'; + export const insertSpaceAfterFunctionKeywordForAnonymousFunctions = 'insertSpaceAfterFunctionKeywordForAnonymousFunctions'; + export const insertSpaceBeforeFunctionParenthesis = 'insertSpaceBeforeFunctionParenthesis'; + export const insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = 'insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis'; + export const insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets = 'insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets'; + export const insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces = 'insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces'; + export const insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces = 'insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces'; + export const insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces = 'insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces'; + export const insertSpaceAfterTypeAssertion = 'insertSpaceAfterTypeAssertion'; + export const placeOpenBraceOnNewLineForFunctions = 'placeOpenBraceOnNewLineForFunctions'; + export const placeOpenBraceOnNewLineForControlBlocks = 'placeOpenBraceOnNewLineForControlBlocks'; + + export function equals(a: Configuration, b: Configuration): boolean { + let keys = Object.keys(a); + for (let i = 0; i < keys.length; i++) { + let key = keys[i]; + if ((a as any)[key] !== (b as any)[key]) { + return false; + } + } + return true; + } + + export function def(): Configuration { + let result: Configuration = Object.create(null); + result.insertSpaceAfterCommaDelimiter = true; + result.insertSpaceAfterConstructor = false; + result.insertSpaceAfterSemicolonInForStatements = true; + result.insertSpaceBeforeAndAfterBinaryOperators = true; + result.insertSpaceAfterKeywordsInControlFlowStatements = true; + result.insertSpaceAfterFunctionKeywordForAnonymousFunctions = false; + result.insertSpaceBeforeFunctionParenthesis = false; + result.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = false; + result.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets = false; + result.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces = true; + result.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces = false; + result.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces = false; + result.insertSpaceAfterTypeAssertion = false; + result.placeOpenBraceOnNewLineForFunctions = false; + result.placeOpenBraceOnNewLineForControlBlocks = false; + return result; + } +} + +export default class FormattingOptionsManager { + private config: Configuration; + + private formatOptions: { [key: string]: Proto.FormatCodeSettings | undefined; } = Object.create(null); + + public constructor( + private client: ITypescriptServiceClient + ) { + this.config = Configuration.def(); + Workspace.onDidCloseTextDocument((textDocument) => { + let key = textDocument.uri.toString(); + // When a document gets closed delete the cached formatting options. + // This is necessary sine the tsserver now closed a project when its + // last file in it closes which drops the stored formatting options + // as well. + delete this.formatOptions[key]; + }); + } + + public async ensureFormatOptions( + document: TextDocument, + options: FormattingOptions, + token: CancellationToken + ): Promise { + const key = document.uri.toString(); + const currentOptions = this.formatOptions[key]; + if (currentOptions && currentOptions.tabSize === options.tabSize && currentOptions.indentSize === options.tabSize && currentOptions.convertTabsToSpaces === options.insertSpaces) { + return currentOptions; + } + const absPath = this.client.normalizePath(document.uri); + if (!absPath) { + return Object.create(null); + } + const formatOptions = this.getFormatOptions(options); + const args: Proto.ConfigureRequestArguments = { + file: absPath, + formatOptions: formatOptions + }; + await this.client.execute('configure', args, token); + this.formatOptions[key] = formatOptions; + return formatOptions; + } + + public updateConfiguration(config: WorkspaceConfiguration): void { + let newConfig = config.get('format', Configuration.def()); + + if (!Configuration.equals(this.config, newConfig)) { + this.config = newConfig; + this.formatOptions = Object.create(null); + } + } + + private getFormatOptions(options: FormattingOptions): Proto.FormatCodeSettings { + return { + tabSize: options.tabSize, + indentSize: options.tabSize, + convertTabsToSpaces: options.insertSpaces, + // We can use \n here since the editor normalizes later on to its line endings. + newLineCharacter: '\n', + insertSpaceAfterCommaDelimiter: this.config.insertSpaceAfterCommaDelimiter, + insertSpaceAfterConstructor: this.config.insertSpaceAfterConstructor, + insertSpaceAfterSemicolonInForStatements: this.config.insertSpaceAfterSemicolonInForStatements, + insertSpaceBeforeAndAfterBinaryOperators: this.config.insertSpaceBeforeAndAfterBinaryOperators, + insertSpaceAfterKeywordsInControlFlowStatements: this.config.insertSpaceAfterKeywordsInControlFlowStatements, + insertSpaceAfterFunctionKeywordForAnonymousFunctions: this.config.insertSpaceAfterFunctionKeywordForAnonymousFunctions, + insertSpaceBeforeFunctionParenthesis: this.config.insertSpaceBeforeFunctionParenthesis, + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces, + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces, + insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces, + insertSpaceAfterTypeAssertion: this.config.insertSpaceAfterTypeAssertion, + placeOpenBraceOnNewLineForFunctions: this.config.placeOpenBraceOnNewLineForFunctions, + placeOpenBraceOnNewLineForControlBlocks: this.config.placeOpenBraceOnNewLineForControlBlocks, + + }; + } +} diff --git a/extensions/typescript/src/features/formattingProvider.ts b/extensions/typescript/src/features/formattingProvider.ts index 706ec6578b5..f10fd2b269a 100644 --- a/extensions/typescript/src/features/formattingProvider.ts +++ b/extensions/typescript/src/features/formattingProvider.ts @@ -8,26 +8,25 @@ import { DocumentRangeFormattingEditProvider, OnTypeFormattingEditProvider, Form import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; import { tsTextSpanToVsRange } from '../utils/convert'; -import { FormattingOptionsManager, Configuration } from './FormattingConfigurationManager'; +import FormattingOptionsManager from './FormattingConfigurationManager'; export class TypeScriptFormattingProvider implements DocumentRangeFormattingEditProvider, OnTypeFormattingEditProvider { - private config: Configuration; + private enabled: boolean = true; private formattingOptionsManager: FormattingOptionsManager; public constructor( private client: ITypescriptServiceClient ) { - this.config = Configuration.def(); this.formattingOptionsManager = new FormattingOptionsManager(client); } public updateConfiguration(config: WorkspaceConfiguration): void { - this.config = config.get('format', Configuration.def()); + this.enabled = config.get('format.enabled', true); this.formattingOptionsManager.updateConfiguration(config); } public isEnabled(): boolean { - return this.config.enable; + return this.enabled; } private async doFormat( From e94a569f7cfa0b0096f18d12bb18fc44b6dbb0fe Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 21 Sep 2017 14:51:21 -0700 Subject: [PATCH 180/281] Move ts and js config manager into same object --- .../formattingConfigurationManager.ts | 108 ++++++++---------- .../src/features/formattingProvider.ts | 11 +- extensions/typescript/src/typescriptMain.ts | 6 +- 3 files changed, 57 insertions(+), 68 deletions(-) diff --git a/extensions/typescript/src/features/formattingConfigurationManager.ts b/extensions/typescript/src/features/formattingConfigurationManager.ts index 510dda1c428..b053aea7d92 100644 --- a/extensions/typescript/src/features/formattingConfigurationManager.ts +++ b/extensions/typescript/src/features/formattingConfigurationManager.ts @@ -8,7 +8,7 @@ import { workspace as Workspace, FormattingOptions, TextDocument, CancellationTo import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; -interface Configuration { +interface FormattingConfiguration { insertSpaceAfterCommaDelimiter: boolean; insertSpaceAfterConstructor: boolean; insertSpaceAfterSemicolonInForStatements: boolean; @@ -25,24 +25,9 @@ interface Configuration { placeOpenBraceOnNewLineForFunctions: boolean; placeOpenBraceOnNewLineForControlBlocks: boolean; } -namespace Configuration { - export const insertSpaceAfterCommaDelimiter = 'insertSpaceAfterCommaDelimiter'; - export const insertSpaceAfterConstructor = 'insertSpaceAfterConstructor'; - export const insertSpaceAfterSemicolonInForStatements = 'insertSpaceAfterSemicolonInForStatements'; - export const insertSpaceBeforeAndAfterBinaryOperators = 'insertSpaceBeforeAndAfterBinaryOperators'; - export const insertSpaceAfterKeywordsInControlFlowStatements = 'insertSpaceAfterKeywordsInControlFlowStatements'; - export const insertSpaceAfterFunctionKeywordForAnonymousFunctions = 'insertSpaceAfterFunctionKeywordForAnonymousFunctions'; - export const insertSpaceBeforeFunctionParenthesis = 'insertSpaceBeforeFunctionParenthesis'; - export const insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = 'insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis'; - export const insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets = 'insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets'; - export const insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces = 'insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces'; - export const insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces = 'insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces'; - export const insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces = 'insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces'; - export const insertSpaceAfterTypeAssertion = 'insertSpaceAfterTypeAssertion'; - export const placeOpenBraceOnNewLineForFunctions = 'placeOpenBraceOnNewLineForFunctions'; - export const placeOpenBraceOnNewLineForControlBlocks = 'placeOpenBraceOnNewLineForControlBlocks'; - export function equals(a: Configuration, b: Configuration): boolean { +namespace FormattingConfiguration { + export function equals(a: FormattingConfiguration, b: FormattingConfiguration): boolean { let keys = Object.keys(a); for (let i = 0; i < keys.length; i++) { let key = keys[i]; @@ -53,36 +38,34 @@ namespace Configuration { return true; } - export function def(): Configuration { - let result: Configuration = Object.create(null); - result.insertSpaceAfterCommaDelimiter = true; - result.insertSpaceAfterConstructor = false; - result.insertSpaceAfterSemicolonInForStatements = true; - result.insertSpaceBeforeAndAfterBinaryOperators = true; - result.insertSpaceAfterKeywordsInControlFlowStatements = true; - result.insertSpaceAfterFunctionKeywordForAnonymousFunctions = false; - result.insertSpaceBeforeFunctionParenthesis = false; - result.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = false; - result.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets = false; - result.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces = true; - result.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces = false; - result.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces = false; - result.insertSpaceAfterTypeAssertion = false; - result.placeOpenBraceOnNewLineForFunctions = false; - result.placeOpenBraceOnNewLineForControlBlocks = false; - return result; - } + export const def: FormattingConfiguration = { + insertSpaceAfterCommaDelimiter: true, + insertSpaceAfterConstructor: false, + insertSpaceAfterSemicolonInForStatements: true, + insertSpaceBeforeAndAfterBinaryOperators: true, + insertSpaceAfterKeywordsInControlFlowStatements: true, + insertSpaceAfterFunctionKeywordForAnonymousFunctions: false, + insertSpaceBeforeFunctionParenthesis: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true, + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false, + insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false, + insertSpaceAfterTypeAssertion: false, + placeOpenBraceOnNewLineForFunctions: false, + placeOpenBraceOnNewLineForControlBlocks: false + }; } export default class FormattingOptionsManager { - private config: Configuration; + private jsConfig: FormattingConfiguration = FormattingConfiguration.def; + private tsConfig: FormattingConfiguration = FormattingConfiguration.def; private formatOptions: { [key: string]: Proto.FormatCodeSettings | undefined; } = Object.create(null); public constructor( private client: ITypescriptServiceClient ) { - this.config = Configuration.def(); Workspace.onDidCloseTextDocument((textDocument) => { let key = textDocument.uri.toString(); // When a document gets closed delete the cached formatting options. @@ -107,7 +90,7 @@ export default class FormattingOptionsManager { if (!absPath) { return Object.create(null); } - const formatOptions = this.getFormatOptions(options); + const formatOptions = this.getFormatOptions(document, options); const args: Proto.ConfigureRequestArguments = { file: absPath, formatOptions: formatOptions @@ -118,37 +101,42 @@ export default class FormattingOptionsManager { } public updateConfiguration(config: WorkspaceConfiguration): void { - let newConfig = config.get('format', Configuration.def()); + const newJsConfig = config.get('javascript.format', FormattingConfiguration.def); + const newTsConfig = config.get('typeScript.format', FormattingConfiguration.def); - if (!Configuration.equals(this.config, newConfig)) { - this.config = newConfig; + if (!FormattingConfiguration.equals(this.jsConfig, newJsConfig) || !FormattingConfiguration.equals(this.tsConfig, newTsConfig)) { this.formatOptions = Object.create(null); } + this.jsConfig = newJsConfig; + this.tsConfig = newTsConfig; } - private getFormatOptions(options: FormattingOptions): Proto.FormatCodeSettings { + private getFormatOptions( + document: TextDocument, + options: FormattingOptions + ): Proto.FormatCodeSettings { + const config = document.languageId === 'typescript' || document.languageId === 'typescriptreact' ? this.tsConfig : this.jsConfig; return { tabSize: options.tabSize, indentSize: options.tabSize, convertTabsToSpaces: options.insertSpaces, // We can use \n here since the editor normalizes later on to its line endings. newLineCharacter: '\n', - insertSpaceAfterCommaDelimiter: this.config.insertSpaceAfterCommaDelimiter, - insertSpaceAfterConstructor: this.config.insertSpaceAfterConstructor, - insertSpaceAfterSemicolonInForStatements: this.config.insertSpaceAfterSemicolonInForStatements, - insertSpaceBeforeAndAfterBinaryOperators: this.config.insertSpaceBeforeAndAfterBinaryOperators, - insertSpaceAfterKeywordsInControlFlowStatements: this.config.insertSpaceAfterKeywordsInControlFlowStatements, - insertSpaceAfterFunctionKeywordForAnonymousFunctions: this.config.insertSpaceAfterFunctionKeywordForAnonymousFunctions, - insertSpaceBeforeFunctionParenthesis: this.config.insertSpaceBeforeFunctionParenthesis, - insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces, - insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces, - insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces, - insertSpaceAfterTypeAssertion: this.config.insertSpaceAfterTypeAssertion, - placeOpenBraceOnNewLineForFunctions: this.config.placeOpenBraceOnNewLineForFunctions, - placeOpenBraceOnNewLineForControlBlocks: this.config.placeOpenBraceOnNewLineForControlBlocks, - + insertSpaceAfterCommaDelimiter: config.insertSpaceAfterCommaDelimiter, + insertSpaceAfterConstructor: config.insertSpaceAfterConstructor, + insertSpaceAfterSemicolonInForStatements: config.insertSpaceAfterSemicolonInForStatements, + insertSpaceBeforeAndAfterBinaryOperators: config.insertSpaceBeforeAndAfterBinaryOperators, + insertSpaceAfterKeywordsInControlFlowStatements: config.insertSpaceAfterKeywordsInControlFlowStatements, + insertSpaceAfterFunctionKeywordForAnonymousFunctions: config.insertSpaceAfterFunctionKeywordForAnonymousFunctions, + insertSpaceBeforeFunctionParenthesis: config.insertSpaceBeforeFunctionParenthesis, + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: config.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces, + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: config.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces, + insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: config.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces, + insertSpaceAfterTypeAssertion: config.insertSpaceAfterTypeAssertion, + placeOpenBraceOnNewLineForFunctions: config.placeOpenBraceOnNewLineForFunctions, + placeOpenBraceOnNewLineForControlBlocks: config.placeOpenBraceOnNewLineForControlBlocks, }; } } diff --git a/extensions/typescript/src/features/formattingProvider.ts b/extensions/typescript/src/features/formattingProvider.ts index f10fd2b269a..3ec937913c2 100644 --- a/extensions/typescript/src/features/formattingProvider.ts +++ b/extensions/typescript/src/features/formattingProvider.ts @@ -8,21 +8,18 @@ import { DocumentRangeFormattingEditProvider, OnTypeFormattingEditProvider, Form import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; import { tsTextSpanToVsRange } from '../utils/convert'; -import FormattingOptionsManager from './FormattingConfigurationManager'; +import FormattingOptionsManager from './formattingConfigurationManager'; export class TypeScriptFormattingProvider implements DocumentRangeFormattingEditProvider, OnTypeFormattingEditProvider { private enabled: boolean = true; - private formattingOptionsManager: FormattingOptionsManager; public constructor( - private client: ITypescriptServiceClient - ) { - this.formattingOptionsManager = new FormattingOptionsManager(client); - } + private readonly client: ITypescriptServiceClient, + private readonly formattingOptionsManager: FormattingOptionsManager + ) { } public updateConfiguration(config: WorkspaceConfiguration): void { this.enabled = config.get('format.enabled', true); - this.formattingOptionsManager.updateConfiguration(config); } public isEnabled(): boolean { diff --git a/extensions/typescript/src/typescriptMain.ts b/extensions/typescript/src/typescriptMain.ts index 87c312eb268..de05aa08ed8 100644 --- a/extensions/typescript/src/typescriptMain.ts +++ b/extensions/typescript/src/typescriptMain.ts @@ -34,6 +34,7 @@ import VersionStatus from './utils/versionStatus'; import { getContributedTypeScriptServerPlugins, TypeScriptServerPlugin } from './utils/plugins'; import { openOrCreateConfigFile, isImplicitProjectConfigFile } from './utils/tsconfig'; import { tsLocationToVsPosition } from './utils/convert'; +import FormattingOptionsManager from './features/formattingConfigurationManager'; interface LanguageDescription { id: string; @@ -174,6 +175,7 @@ class LanguageProvider { private syntaxDiagnostics: ObjectMap; private readonly currentDiagnostics: DiagnosticCollection; private readonly bufferSyncSupport: BufferSyncSupport; + private readonly formattingOptionsManager: FormattingOptionsManager; private readonly typingsStatus: TypingsStatus; private readonly ataProgressReporter: AtaProgressReporter; @@ -189,6 +191,7 @@ class LanguageProvider { private readonly client: TypeScriptServiceClient, private readonly description: LanguageDescription ) { + this.formattingOptionsManager = new FormattingOptionsManager(client); this.bufferSyncSupport = new BufferSyncSupport(client, description.modeIds, { delete: (file: string) => { this.currentDiagnostics.delete(client.asUrl(file)); @@ -244,7 +247,7 @@ class LanguageProvider { this.disposables.push(languages.registerCompletionItemProvider(selector, new (await import('./features/directiveCommentCompletionProvider')).default(client), '@')); const { TypeScriptFormattingProvider, FormattingProviderManager } = await import('./features/formattingProvider'); - const formattingProvider = new TypeScriptFormattingProvider(client); + const formattingProvider = new TypeScriptFormattingProvider(client, this.formattingOptionsManager); formattingProvider.updateConfiguration(config); this.disposables.push(languages.registerOnTypeFormattingEditProvider(selector, formattingProvider, ';', '}', '\n')); @@ -323,6 +326,7 @@ class LanguageProvider { private configurationChanged(): void { const config = workspace.getConfiguration(this.id); this.updateValidate(config.get(validateSetting, true)); + this.formattingOptionsManager.updateConfiguration(config); for (const toUpdate of this.toUpdateOnConfigurationChanged) { toUpdate.updateConfiguration(); From 84605ab7a9a5eaaba32e4c03d836d5de11821f0f Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 21 Sep 2017 14:52:05 -0700 Subject: [PATCH 181/281] Rename to FormattingConfigurationManager --- .../src/features/formattingConfigurationManager.ts | 2 +- extensions/typescript/src/features/formattingProvider.ts | 4 ++-- extensions/typescript/src/typescriptMain.ts | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/typescript/src/features/formattingConfigurationManager.ts b/extensions/typescript/src/features/formattingConfigurationManager.ts index b053aea7d92..ab9e7d85211 100644 --- a/extensions/typescript/src/features/formattingConfigurationManager.ts +++ b/extensions/typescript/src/features/formattingConfigurationManager.ts @@ -57,7 +57,7 @@ namespace FormattingConfiguration { }; } -export default class FormattingOptionsManager { +export default class FormattingConfigurationManager { private jsConfig: FormattingConfiguration = FormattingConfiguration.def; private tsConfig: FormattingConfiguration = FormattingConfiguration.def; diff --git a/extensions/typescript/src/features/formattingProvider.ts b/extensions/typescript/src/features/formattingProvider.ts index 3ec937913c2..2a125ce1145 100644 --- a/extensions/typescript/src/features/formattingProvider.ts +++ b/extensions/typescript/src/features/formattingProvider.ts @@ -8,14 +8,14 @@ import { DocumentRangeFormattingEditProvider, OnTypeFormattingEditProvider, Form import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; import { tsTextSpanToVsRange } from '../utils/convert'; -import FormattingOptionsManager from './formattingConfigurationManager'; +import FormattingConfigurationManager from './formattingConfigurationManager'; export class TypeScriptFormattingProvider implements DocumentRangeFormattingEditProvider, OnTypeFormattingEditProvider { private enabled: boolean = true; public constructor( private readonly client: ITypescriptServiceClient, - private readonly formattingOptionsManager: FormattingOptionsManager + private readonly formattingOptionsManager: FormattingConfigurationManager ) { } public updateConfiguration(config: WorkspaceConfiguration): void { diff --git a/extensions/typescript/src/typescriptMain.ts b/extensions/typescript/src/typescriptMain.ts index de05aa08ed8..92521b94813 100644 --- a/extensions/typescript/src/typescriptMain.ts +++ b/extensions/typescript/src/typescriptMain.ts @@ -34,7 +34,7 @@ import VersionStatus from './utils/versionStatus'; import { getContributedTypeScriptServerPlugins, TypeScriptServerPlugin } from './utils/plugins'; import { openOrCreateConfigFile, isImplicitProjectConfigFile } from './utils/tsconfig'; import { tsLocationToVsPosition } from './utils/convert'; -import FormattingOptionsManager from './features/formattingConfigurationManager'; +import FormattingConfigurationManager from './features/formattingConfigurationManager'; interface LanguageDescription { id: string; @@ -175,7 +175,7 @@ class LanguageProvider { private syntaxDiagnostics: ObjectMap; private readonly currentDiagnostics: DiagnosticCollection; private readonly bufferSyncSupport: BufferSyncSupport; - private readonly formattingOptionsManager: FormattingOptionsManager; + private readonly formattingOptionsManager: FormattingConfigurationManager; private readonly typingsStatus: TypingsStatus; private readonly ataProgressReporter: AtaProgressReporter; @@ -191,7 +191,7 @@ class LanguageProvider { private readonly client: TypeScriptServiceClient, private readonly description: LanguageDescription ) { - this.formattingOptionsManager = new FormattingOptionsManager(client); + this.formattingOptionsManager = new FormattingConfigurationManager(client); this.bufferSyncSupport = new BufferSyncSupport(client, description.modeIds, { delete: (file: string) => { this.currentDiagnostics.delete(client.asUrl(file)); From 0e4e0d8f8108ff346000fb68f5215d10920d5768 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 21 Sep 2017 15:30:57 -0700 Subject: [PATCH 182/281] Make sure we send format requests before code actions / refactor --- .../src/features/codeActionProvider.ts | 64 +++-------------- .../formattingConfigurationManager.ts | 70 ++++++++++--------- .../src/features/formattingProvider.ts | 2 +- .../src/features/refactorProvider.ts | 15 ++-- extensions/typescript/src/typescriptMain.ts | 4 +- 5 files changed, 58 insertions(+), 97 deletions(-) diff --git a/extensions/typescript/src/features/codeActionProvider.ts b/extensions/typescript/src/features/codeActionProvider.ts index 037a1039dc7..32f50fef59f 100644 --- a/extensions/typescript/src/features/codeActionProvider.ts +++ b/extensions/typescript/src/features/codeActionProvider.ts @@ -3,23 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands, Uri, workspace, WorkspaceEdit, TextEdit, FormattingOptions, window } from 'vscode'; +import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands, workspace, WorkspaceEdit } from 'vscode'; import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; import { tsTextSpanToVsRange, vsRangeToTsFileRange } from '../utils/convert'; +import FormattingConfigurationManager from './formattingConfigurationManager'; interface NumberSet { [key: number]: boolean; } -interface Source { - uri: Uri; - version: number; - range: Range; - formattingOptions: FormattingOptions | undefined; -} - export default class TypeScriptCodeActionProvider implements CodeActionProvider { private commandId: string; @@ -27,6 +21,7 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider constructor( private readonly client: ITypescriptServiceClient, + private readonly formattingConfigurationManager: FormattingConfigurationManager, mode: string ) { this.commandId = `_typescript.applyCodeAction.${mode}`; @@ -53,26 +48,14 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider return []; } - let formattingOptions: FormattingOptions | undefined = undefined; - for (const editor of window.visibleTextEditors) { - if (editor.document.fileName === document.fileName) { - formattingOptions = { tabSize: editor.options.tabSize, insertSpaces: editor.options.insertSpaces } as FormattingOptions; - break; - } - } + await this.formattingConfigurationManager.ensureFormatOptionsForDocument(document, token); - const source: Source = { - uri: document.uri, - version: document.version, - range: range, - formattingOptions: formattingOptions - }; const args: Proto.CodeFixRequestArgs = { ...vsRangeToTsFileRange(file, range), errorCodes: Array.from(supportedActions) }; const response = await this.client.execute('getCodeFixes', args, token); - return (response.body || []).map(action => this.getCommandForAction(source, action)); + return (response.body || []).map(action => this.getCommandForAction(action)); } private get supportedCodeActions(): Thenable { @@ -96,15 +79,15 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider .filter(code => supportedActions[code]))); } - private getCommandForAction(source: Source, action: Proto.CodeAction): Command { + private getCommandForAction(action: Proto.CodeAction): Command { return { title: action.description, command: this.commandId, - arguments: [source, action] + arguments: [action] }; } - private async onCodeAction(source: Source, action: Proto.CodeAction): Promise { + private async onCodeAction(action: Proto.CodeAction): Promise { const workspaceEdit = new WorkspaceEdit(); for (const change of action.changes) { for (const textChange of change.textChanges) { @@ -114,35 +97,6 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider } } - const success = workspace.applyEdit(workspaceEdit); - if (!success) { - return false; - } - - let firstEdit: TextEdit | undefined = undefined; - for (const [uri, edits] of workspaceEdit.entries()) { - if (uri.toString() === source.uri.toString()) { - firstEdit = edits[0]; - break; - } - } - - if (!firstEdit) { - return true; - } - - const newLines = firstEdit.newText.match(/\n/g); - const editedRange = new Range( - firstEdit.range.start.line, 0, - firstEdit.range.end.line + 1 + (newLines ? newLines.length : 0), 0); - // TODO: Workaround for https://github.com/Microsoft/TypeScript/issues/12249 - // apply formatting to the source range until TS returns formatted results - const edits = (await commands.executeCommand('vscode.executeFormatRangeProvider', source.uri, editedRange, source.formattingOptions || {})) as TextEdit[]; - if (!edits || !edits.length) { - return false; - } - const formattingEdit = new WorkspaceEdit(); - formattingEdit.set(source.uri, edits); - return workspace.applyEdit(formattingEdit); + return workspace.applyEdit(workspaceEdit); } } \ No newline at end of file diff --git a/extensions/typescript/src/features/formattingConfigurationManager.ts b/extensions/typescript/src/features/formattingConfigurationManager.ts index ab9e7d85211..923c3d43a65 100644 --- a/extensions/typescript/src/features/formattingConfigurationManager.ts +++ b/extensions/typescript/src/features/formattingConfigurationManager.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { workspace as Workspace, FormattingOptions, TextDocument, CancellationToken, WorkspaceConfiguration } from 'vscode'; +import { workspace as Workspace, FormattingOptions, TextDocument, CancellationToken, WorkspaceConfiguration, window } from 'vscode'; import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; @@ -58,8 +58,7 @@ namespace FormattingConfiguration { } export default class FormattingConfigurationManager { - private jsConfig: FormattingConfiguration = FormattingConfiguration.def; - private tsConfig: FormattingConfiguration = FormattingConfiguration.def; + private config: FormattingConfiguration = FormattingConfiguration.def; private formatOptions: { [key: string]: Proto.FormatCodeSettings | undefined; } = Object.create(null); @@ -76,67 +75,72 @@ export default class FormattingConfigurationManager { }); } + public async ensureFormatOptionsForDocument( + document: TextDocument, + token: CancellationToken | undefined + ): Promise { + for (const editor of window.visibleTextEditors) { + if (editor.document.fileName === document.fileName) { + const formattingOptions = { tabSize: editor.options.tabSize, insertSpaces: editor.options.insertSpaces } as FormattingOptions; + return this.ensureFormatOptions(document, formattingOptions, token); + } + } + } + public async ensureFormatOptions( document: TextDocument, options: FormattingOptions, - token: CancellationToken - ): Promise { + token: CancellationToken | undefined + ): Promise { const key = document.uri.toString(); const currentOptions = this.formatOptions[key]; if (currentOptions && currentOptions.tabSize === options.tabSize && currentOptions.indentSize === options.tabSize && currentOptions.convertTabsToSpaces === options.insertSpaces) { - return currentOptions; + return; } const absPath = this.client.normalizePath(document.uri); if (!absPath) { return Object.create(null); } - const formatOptions = this.getFormatOptions(document, options); + const formatOptions = this.getFormatOptions(options); const args: Proto.ConfigureRequestArguments = { file: absPath, formatOptions: formatOptions }; await this.client.execute('configure', args, token); this.formatOptions[key] = formatOptions; - return formatOptions; } public updateConfiguration(config: WorkspaceConfiguration): void { - const newJsConfig = config.get('javascript.format', FormattingConfiguration.def); - const newTsConfig = config.get('typeScript.format', FormattingConfiguration.def); + const newConfig = config.get('format', FormattingConfiguration.def); - if (!FormattingConfiguration.equals(this.jsConfig, newJsConfig) || !FormattingConfiguration.equals(this.tsConfig, newTsConfig)) { + if (!FormattingConfiguration.equals(this.config, newConfig)) { this.formatOptions = Object.create(null); } - this.jsConfig = newJsConfig; - this.tsConfig = newTsConfig; + this.config = newConfig; } - private getFormatOptions( - document: TextDocument, - options: FormattingOptions - ): Proto.FormatCodeSettings { - const config = document.languageId === 'typescript' || document.languageId === 'typescriptreact' ? this.tsConfig : this.jsConfig; + private getFormatOptions(options: FormattingOptions): Proto.FormatCodeSettings { return { tabSize: options.tabSize, indentSize: options.tabSize, convertTabsToSpaces: options.insertSpaces, // We can use \n here since the editor normalizes later on to its line endings. newLineCharacter: '\n', - insertSpaceAfterCommaDelimiter: config.insertSpaceAfterCommaDelimiter, - insertSpaceAfterConstructor: config.insertSpaceAfterConstructor, - insertSpaceAfterSemicolonInForStatements: config.insertSpaceAfterSemicolonInForStatements, - insertSpaceBeforeAndAfterBinaryOperators: config.insertSpaceBeforeAndAfterBinaryOperators, - insertSpaceAfterKeywordsInControlFlowStatements: config.insertSpaceAfterKeywordsInControlFlowStatements, - insertSpaceAfterFunctionKeywordForAnonymousFunctions: config.insertSpaceAfterFunctionKeywordForAnonymousFunctions, - insertSpaceBeforeFunctionParenthesis: config.insertSpaceBeforeFunctionParenthesis, - insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: config.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces, - insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: config.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces, - insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: config.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces, - insertSpaceAfterTypeAssertion: config.insertSpaceAfterTypeAssertion, - placeOpenBraceOnNewLineForFunctions: config.placeOpenBraceOnNewLineForFunctions, - placeOpenBraceOnNewLineForControlBlocks: config.placeOpenBraceOnNewLineForControlBlocks, + insertSpaceAfterCommaDelimiter: this.config.insertSpaceAfterCommaDelimiter, + insertSpaceAfterConstructor: this.config.insertSpaceAfterConstructor, + insertSpaceAfterSemicolonInForStatements: this.config.insertSpaceAfterSemicolonInForStatements, + insertSpaceBeforeAndAfterBinaryOperators: this.config.insertSpaceBeforeAndAfterBinaryOperators, + insertSpaceAfterKeywordsInControlFlowStatements: this.config.insertSpaceAfterKeywordsInControlFlowStatements, + insertSpaceAfterFunctionKeywordForAnonymousFunctions: this.config.insertSpaceAfterFunctionKeywordForAnonymousFunctions, + insertSpaceBeforeFunctionParenthesis: this.config.insertSpaceBeforeFunctionParenthesis, + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces, + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces, + insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: this.config.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces, + insertSpaceAfterTypeAssertion: this.config.insertSpaceAfterTypeAssertion, + placeOpenBraceOnNewLineForFunctions: this.config.placeOpenBraceOnNewLineForFunctions, + placeOpenBraceOnNewLineForControlBlocks: this.config.placeOpenBraceOnNewLineForControlBlocks, }; } } diff --git a/extensions/typescript/src/features/formattingProvider.ts b/extensions/typescript/src/features/formattingProvider.ts index 2a125ce1145..04fa0ff4675 100644 --- a/extensions/typescript/src/features/formattingProvider.ts +++ b/extensions/typescript/src/features/formattingProvider.ts @@ -19,7 +19,7 @@ export class TypeScriptFormattingProvider implements DocumentRangeFormattingEdit ) { } public updateConfiguration(config: WorkspaceConfiguration): void { - this.enabled = config.get('format.enabled', true); + this.enabled = config.get('format.enable', true); } public isEnabled(): boolean { diff --git a/extensions/typescript/src/features/refactorProvider.ts b/extensions/typescript/src/features/refactorProvider.ts index d87d6c01076..2a461598c42 100644 --- a/extensions/typescript/src/features/refactorProvider.ts +++ b/extensions/typescript/src/features/refactorProvider.ts @@ -10,7 +10,7 @@ import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionC import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; import { tsTextSpanToVsRange, vsRangeToTsFileRange, tsLocationToVsPosition } from '../utils/convert'; - +import FormattingOptionsManager from './formattingConfigurationManager'; export default class TypeScriptRefactorProvider implements CodeActionProvider { private doRefactorCommandId: string; @@ -18,6 +18,7 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { constructor( private readonly client: ITypescriptServiceClient, + private formattingOptionsManager: FormattingOptionsManager, mode: string ) { this.doRefactorCommandId = `_typescript.applyRefactoring.${mode}`; @@ -55,14 +56,14 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { actions.push({ title: info.description, command: this.selectRefactorCommandId, - arguments: [file, info, range] + arguments: [document, file, info, range] }); } else { for (const action of info.actions) { actions.push({ title: action.description, command: this.doRefactorCommandId, - arguments: [file, info.name, action.name, range] + arguments: [document, file, info.name, action.name, range] }); } } @@ -85,7 +86,7 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { return workspaceEdit; } - private async selectRefactoring(file: string, info: Proto.ApplicableRefactorInfo, range: Range): Promise { + private async selectRefactoring(document: TextDocument, file: string, info: Proto.ApplicableRefactorInfo, range: Range): Promise { return window.showQuickPick(info.actions.map((action): QuickPickItem => ({ label: action.name, description: action.description @@ -93,11 +94,13 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { if (!selected) { return false; } - return this.doRefactoring(file, info.name, selected.label, range); + return this.doRefactoring(document, file, info.name, selected.label, range); }); } - private async doRefactoring(file: string, refactor: string, action: string, range: Range): Promise { + private async doRefactoring(document: TextDocument, file: string, refactor: string, action: string, range: Range): Promise { + await this.formattingOptionsManager.ensureFormatOptionsForDocument(document, undefined); + const args: Proto.GetEditsForRefactorRequestArgs = { ...vsRangeToTsFileRange(file, range), refactor, diff --git a/extensions/typescript/src/typescriptMain.ts b/extensions/typescript/src/typescriptMain.ts index 92521b94813..a559595c8d9 100644 --- a/extensions/typescript/src/typescriptMain.ts +++ b/extensions/typescript/src/typescriptMain.ts @@ -267,8 +267,8 @@ class LanguageProvider { this.disposables.push(languages.registerDocumentSymbolProvider(selector, new (await import('./features/documentSymbolProvider')).default(client))); this.disposables.push(languages.registerSignatureHelpProvider(selector, new (await import('./features/signatureHelpProvider')).default(client), '(', ',')); this.disposables.push(languages.registerRenameProvider(selector, new (await import('./features/renameProvider')).default(client))); - this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/codeActionProvider')).default(client, this.description.id))); - this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/refactorProvider')).default(client, this.description.id))); + this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/codeActionProvider')).default(client, this.formattingOptionsManager, this.description.id))); + this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/refactorProvider')).default(client, this.formattingOptionsManager, this.description.id))); this.registerVersionDependentProviders(); for (const modeId of this.description.modeIds) { From c28c278171c0855026064237464e86aec699e8a6 Mon Sep 17 00:00:00 2001 From: Ramya Achutha Rao Date: Thu, 21 Sep 2017 16:35:22 -0700 Subject: [PATCH 183/281] Include extensionId in telemetry event for recommendation popup --- .../extensions/electron-browser/extensionTipsService.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts index 11abcc7372c..d49a036b406 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts @@ -247,7 +247,7 @@ export class ExtensionTipsService implements IExtensionTipsService { this.choiceService.choose(Severity.Info, message, options, 2).done(choice => { switch (choice) { case 0: - this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'show' }); + this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'show', extensionId: name }); return recommendationsAction.run(); case 1: this.importantRecommendationsIgnoreList.push(id); this.storageService.store( @@ -255,13 +255,13 @@ export class ExtensionTipsService implements IExtensionTipsService { JSON.stringify(this.importantRecommendationsIgnoreList), StorageScope.GLOBAL ); - this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'neverShowAgain' }); + this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'neverShowAgain', extensionId: name }); return this.ignoreExtensionRecommendations(); case 2: - this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'close' }); + this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'close', extensionId: name }); } }, () => { - this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'cancelled' }); + this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'cancelled', extensionId: name }); }); }); }); From 606ab06533d0686c29b4fc280b9eb194a8eadca8 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 21 Sep 2017 17:03:24 -0700 Subject: [PATCH 184/281] Auto show path intellisense when typing ' or " in import statement Fixes #23962 --- .../src/features/completionItemProvider.ts | 19 +++++++++++++++++-- extensions/typescript/src/typescriptMain.ts | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/extensions/typescript/src/features/completionItemProvider.ts b/extensions/typescript/src/features/completionItemProvider.ts index e91e71ac9fd..1a88075c91b 100644 --- a/extensions/typescript/src/features/completionItemProvider.ts +++ b/extensions/typescript/src/features/completionItemProvider.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CompletionItem, TextDocument, Position, CompletionItemKind, CompletionItemProvider, CancellationToken, TextEdit, Range, SnippetString, workspace, ProviderResult } from 'vscode'; +import { CompletionItem, TextDocument, Position, CompletionItemKind, CompletionItemProvider, CancellationToken, TextEdit, Range, SnippetString, workspace, ProviderResult, CompletionContext } from 'vscode'; import { ITypescriptServiceClient } from '../typescriptService'; import TypingsStatus from '../utils/typingsStatus'; @@ -159,7 +159,12 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP this.config.nameSuggestions = jsConfig.get(Configuration.nameSuggestions, true); } - public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): Promise { + public provideCompletionItems( + document: TextDocument, + position: Position, + token: CancellationToken, + context: CompletionContext + ): Promise { if (this.typingsStatus.isAcquiringTypings) { return Promise.reject({ label: localize( @@ -175,6 +180,16 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP if (!file) { return Promise.resolve([]); } + + + if (context.triggerCharacter === '"' || context.triggerCharacter === '\'') { + // make sure we are in something that looks like an import + const line = document.lineAt(position.line).text.slice(0, position.character); + if (!line.match(/^import .+? from\s*["']$/)) { + return Promise.resolve([]); + } + } + const args: CompletionsRequestArgs = vsPositionToTsFileLocation(file, position); return this.client.execute('completions', args, token).then((msg) => { // This info has to come from the tsserver. See https://github.com/Microsoft/TypeScript/issues/2831 diff --git a/extensions/typescript/src/typescriptMain.ts b/extensions/typescript/src/typescriptMain.ts index a559595c8d9..98d4c267c25 100644 --- a/extensions/typescript/src/typescriptMain.ts +++ b/extensions/typescript/src/typescriptMain.ts @@ -242,7 +242,7 @@ class LanguageProvider { const completionItemProvider = new (await import('./features/completionItemProvider')).default(client, this.typingsStatus); completionItemProvider.updateConfiguration(); this.toUpdateOnConfigurationChanged.push(completionItemProvider); - this.disposables.push(languages.registerCompletionItemProvider(selector, completionItemProvider, '.')); + this.disposables.push(languages.registerCompletionItemProvider(selector, completionItemProvider, '.', '"', '\'')); this.disposables.push(languages.registerCompletionItemProvider(selector, new (await import('./features/directiveCommentCompletionProvider')).default(client), '@')); From 5ec101edadf162169b5cbd79a3a3b1d5aacc777a Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 21 Sep 2017 17:10:57 -0700 Subject: [PATCH 185/281] Trigger intellisense on / in ts paths --- .../typescript/src/features/completionItemProvider.ts | 11 +++++++++-- extensions/typescript/src/typescriptMain.ts | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/extensions/typescript/src/features/completionItemProvider.ts b/extensions/typescript/src/features/completionItemProvider.ts index 1a88075c91b..349d03c9bbd 100644 --- a/extensions/typescript/src/features/completionItemProvider.ts +++ b/extensions/typescript/src/features/completionItemProvider.ts @@ -181,15 +181,22 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP return Promise.resolve([]); } - if (context.triggerCharacter === '"' || context.triggerCharacter === '\'') { - // make sure we are in something that looks like an import + // make sure we are in something that looks like the start of an import const line = document.lineAt(position.line).text.slice(0, position.character); if (!line.match(/^import .+? from\s*["']$/)) { return Promise.resolve([]); } } + if (context.triggerCharacter === '/') { + // make sure we are in something that looks line an import path + const line = document.lineAt(position.line).text.slice(0, position.character); + if (!line.match(/^import .+? from\s*["'][^'"]*$/)) { + return Promise.resolve([]); + } + } + const args: CompletionsRequestArgs = vsPositionToTsFileLocation(file, position); return this.client.execute('completions', args, token).then((msg) => { // This info has to come from the tsserver. See https://github.com/Microsoft/TypeScript/issues/2831 diff --git a/extensions/typescript/src/typescriptMain.ts b/extensions/typescript/src/typescriptMain.ts index 98d4c267c25..6cf20c87391 100644 --- a/extensions/typescript/src/typescriptMain.ts +++ b/extensions/typescript/src/typescriptMain.ts @@ -242,7 +242,7 @@ class LanguageProvider { const completionItemProvider = new (await import('./features/completionItemProvider')).default(client, this.typingsStatus); completionItemProvider.updateConfiguration(); this.toUpdateOnConfigurationChanged.push(completionItemProvider); - this.disposables.push(languages.registerCompletionItemProvider(selector, completionItemProvider, '.', '"', '\'')); + this.disposables.push(languages.registerCompletionItemProvider(selector, completionItemProvider, '.', '"', '\'', '/')); this.disposables.push(languages.registerCompletionItemProvider(selector, new (await import('./features/directiveCommentCompletionProvider')).default(client), '@')); From b60623c968c20fdb60c3549d413e412b622c4503 Mon Sep 17 00:00:00 2001 From: Ramya Achutha Rao Date: Thu, 21 Sep 2017 17:28:05 -0700 Subject: [PATCH 186/281] Add source when installing extension via uri --- .../parts/extensions/node/extensionsWorkbenchService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts index d05db9e48fe..39795d8e8a3 100644 --- a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts @@ -825,7 +825,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return TPromise.as(null); } - return this.queryGallery({ names: [extensionId] }).then(result => { + return this.queryGallery({ names: [extensionId], source: 'uri' }).then(result => { if (result.total < 1) { return TPromise.as(null); } From b9765381408ba186b67971a41ac9b9a0b0b800ef Mon Sep 17 00:00:00 2001 From: Faustino Aguilar Date: Thu, 21 Sep 2017 21:19:49 -0500 Subject: [PATCH 187/281] Fix #33939 - Add protected and private visibility keywords to increaseIndentPattern - Remove `when` keyword from decreaseIndentPattern --- extensions/ruby/language-configuration.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/ruby/language-configuration.json b/extensions/ruby/language-configuration.json index fe8a5e9e2ac..fc4125f0691 100644 --- a/extensions/ruby/language-configuration.json +++ b/extensions/ruby/language-configuration.json @@ -23,7 +23,7 @@ ["'", "'"] ], "indentationRules": { - "increaseIndentPattern": "^\\s*((begin|class|def|else|elsif|ensure|for|if|module|rescue|unless|until|when|while)|(.*\\sdo\\b))\\b[^\\{;]*$", - "decreaseIndentPattern": "^\\s*([}\\]]([,)]?\\s*(#|$)|\\.[a-zA-Z_]\\w*\\b)|(end|rescue|ensure|else|elsif|when)\\b)" + "increaseIndentPattern": "^\\s*((begin|class|(private|protected)\\s+def|def|else|elsif|ensure|for|if|module|rescue|unless|until|when|while)|(.*\\sdo\\b))\\b[^\\{;]*$", + "decreaseIndentPattern": "^\\s*([}\\]]([,)]?\\s*(#|$)|\\.[a-zA-Z_]\\w*\\b)|(end|rescue|ensure|else|elsif)\\b)" } -} \ No newline at end of file +} From 16dcd4dd2c9ac27431b54c387386ba4c6ad3e99c Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 21 Sep 2017 21:08:29 -0700 Subject: [PATCH 188/281] Also trigger completion items for require and import expressions --- extensions/typescript/src/features/completionItemProvider.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/typescript/src/features/completionItemProvider.ts b/extensions/typescript/src/features/completionItemProvider.ts index 349d03c9bbd..4c5d88ede58 100644 --- a/extensions/typescript/src/features/completionItemProvider.ts +++ b/extensions/typescript/src/features/completionItemProvider.ts @@ -184,7 +184,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP if (context.triggerCharacter === '"' || context.triggerCharacter === '\'') { // make sure we are in something that looks like the start of an import const line = document.lineAt(position.line).text.slice(0, position.character); - if (!line.match(/^import .+? from\s*["']$/)) { + if (!line.match(/^import .+? from\s*["']$/) && !line.match(/\b(import|require)\(['"]$/)) { return Promise.resolve([]); } } @@ -192,7 +192,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP if (context.triggerCharacter === '/') { // make sure we are in something that looks line an import path const line = document.lineAt(position.line).text.slice(0, position.character); - if (!line.match(/^import .+? from\s*["'][^'"]*$/)) { + if (!line.match(/^import .+? from\s*["'][^'"]*$/) && !line.match(/\b(import|require)\(['"][^'"]*$/)) { return Promise.resolve([]); } } From ee681677d0eb58854cb9303f66864d3f113fe7e7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 22 Sep 2017 08:21:54 +0200 Subject: [PATCH 189/281] Non standard Delimiter Used in title/Caption bar (fixes #34742) --- src/vs/workbench/browser/parts/titlebar/titlebarPart.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 2d63ae042a1..f3484f3f7d0 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -32,6 +32,7 @@ import { Verbosity } from 'vs/platform/editor/common/editor'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { TITLE_BAR_ACTIVE_BACKGROUND, TITLE_BAR_ACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_BACKGROUND, TITLE_BAR_BORDER } from 'vs/workbench/common/theme'; import { IPartService } from 'vs/workbench/services/part/common/partService'; +import { isMacintosh } from 'vs/base/common/platform'; export class TitlebarPart extends Part implements ITitleService { @@ -40,7 +41,7 @@ export class TitlebarPart extends Part implements ITitleService { private static NLS_UNSUPPORTED = nls.localize('patchedWindowTitle', "[Unsupported]"); private static NLS_EXTENSION_HOST = nls.localize('devExtensionWindowTitlePrefix', "[Extension Development Host]"); private static TITLE_DIRTY = '\u25cf '; - private static TITLE_SEPARATOR = ' — '; + private static TITLE_SEPARATOR = isMacintosh ? ' - ' : ' - '; // macOS uses special - separator private titleContainer: Builder; private title: Builder; From d1eeb0445bdcceeced5860b60c2c5b8dae28fd71 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 22 Sep 2017 08:43:55 +0200 Subject: [PATCH 190/281] clarify WorkspaceFolder#uri --- src/vs/vscode.d.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 044110c7891..2bc56f24ad1 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -4835,13 +4835,16 @@ declare module 'vscode' { export interface WorkspaceFolder { /** - * The associated URI for this workspace folder. + * The associated uri for this workspace folder. + * + * *Note:* The [Uri](#Uri)-type was intentionally chosen such that future releases of the editor can support + * workspace folders that are not stored on the local disk, e.g. `ftp://server/workspaces/foo`. */ readonly uri: Uri; /** * The name of this workspace folder. Defaults to - * the basename its [uri-path](#Uri.path) + * the basename of its [uri-path](#Uri.path) */ readonly name: string; From 9977d3280c12f26abc153c43113d72867e1c59cc Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 22 Sep 2017 09:30:43 +0200 Subject: [PATCH 191/281] Fixes #34408: Have the mode picker change the mode for both models in the diff editor case --- .../browser/parts/editor/editorStatus.ts | 52 +++++++++++-------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index 7f8fe09b18d..544307a16d4 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -43,7 +43,7 @@ import { TabFocus } from 'vs/editor/common/config/commonEditorConfig'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { getCodeEditor as getEditorWidget } from 'vs/editor/common/services/codeEditorService'; +import { getCodeEditor as getEditorWidget, getCodeOrDiffEditor } from 'vs/editor/common/services/codeEditorService'; import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; @@ -873,28 +873,38 @@ export class ChangeModeAction extends Action { // Change mode for active editor activeEditor = this.editorService.getActiveEditor(); - const editorWidget = getEditorWidget(activeEditor); - if (editorWidget) { - const models: IModel[] = []; - - const textModel = editorWidget.getModel(); - if (textModel) { - models.push(textModel); + const codeOrDiffEditor = getCodeOrDiffEditor(activeEditor); + const models: IModel[] = []; + if (codeOrDiffEditor.codeEditor) { + const codeEditorModel = codeOrDiffEditor.codeEditor.getModel(); + if (codeEditorModel) { + models.push(codeEditorModel); } - - // Find mode - let mode: TPromise; - if (pick === autoDetectMode) { - mode = this.modeService.getOrCreateModeByFilenameOrFirstLine(toResource(activeEditor.input, { supportSideBySide: true, filter: ['file', 'untitled'] }).fsPath, textModel.getLineContent(1)); - } else { - mode = this.modeService.getOrCreateModeByLanguageName(pick.label); - } - - // Change mode - models.forEach(textModel => { - this.modelService.setMode(textModel, mode); - }); } + if (codeOrDiffEditor.diffEditor) { + const diffEditorModel = codeOrDiffEditor.diffEditor.getModel(); + if (diffEditorModel) { + if (diffEditorModel.original) { + models.push(diffEditorModel.original); + } + if (diffEditorModel.modified) { + models.push(diffEditorModel.modified); + } + } + } + + // Find mode + let mode: TPromise; + if (pick === autoDetectMode) { + mode = this.modeService.getOrCreateModeByFilenameOrFirstLine(toResource(activeEditor.input, { supportSideBySide: true, filter: ['file', 'untitled'] }).fsPath, textModel.getLineContent(1)); + } else { + mode = this.modeService.getOrCreateModeByLanguageName(pick.label); + } + + // Change mode + models.forEach(textModel => { + this.modelService.setMode(textModel, mode); + }); }); } From 38000de236d9ac5b082e86f010d9dabb2b00dcf7 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 22 Sep 2017 09:37:27 +0200 Subject: [PATCH 192/281] [html] fix build error (shrinkwrap not uptodate) --- extensions/html/npm-shrinkwrap.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/html/npm-shrinkwrap.json b/extensions/html/npm-shrinkwrap.json index f2c127f085f..97c20854f46 100644 --- a/extensions/html/npm-shrinkwrap.json +++ b/extensions/html/npm-shrinkwrap.json @@ -33,9 +33,9 @@ "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.4.2.tgz" }, "vscode-languageserver-types": { - "version": "3.3.0", - "from": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.3.0.tgz" + "version": "3.4.0", + "from": "vscode-languageserver-types@3.4.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.4.0.tgz" }, "vscode-nls": { "version": "2.0.2", From b6677bccae3d0e62650f4d6c5e59898e47e36d02 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 22 Sep 2017 09:40:08 +0200 Subject: [PATCH 193/281] [html] update vscode-languageserver-types to 3.4.0 --- extensions/html/server/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/html/server/package.json b/extensions/html/server/package.json index 169a0320972..56c6df7218e 100644 --- a/extensions/html/server/package.json +++ b/extensions/html/server/package.json @@ -12,7 +12,7 @@ "vscode-html-languageservice": "^2.0.8", "vscode-languageserver": "^3.4.2", "vscode-languageserver-protocol": "^3.4.2", - "vscode-languageserver-types": "^3.3.0", + "vscode-languageserver-types": "^3.4.0", "vscode-nls": "^2.0.2", "vscode-uri": "^1.0.1" }, From 54877bdbbfc23ac51debebc8ff3a480179624416 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 22 Sep 2017 09:42:23 +0200 Subject: [PATCH 194/281] fix #34751 --- .../electron-browser/nodeCachedDataManager.ts | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/electron-browser/nodeCachedDataManager.ts b/src/vs/workbench/electron-browser/nodeCachedDataManager.ts index 52d57348df6..76a4a17982a 100644 --- a/src/vs/workbench/electron-browser/nodeCachedDataManager.ts +++ b/src/vs/workbench/electron-browser/nodeCachedDataManager.ts @@ -7,7 +7,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { onUnexpectedError } from 'vs/base/common/errors'; import { TPromise } from 'vs/base/common/winjs.base'; -import { join, basename } from 'path'; +import { join, basename, dirname } from 'path'; import { readdir, rimraf, stat } from 'vs/base/node/pfs'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -73,28 +73,45 @@ export class NodeCachedDataManager { private _manageCachedDataSoon(): void { // Cached data is stored as user data and we run a cleanup task everytime // the editor starts. The strategy is to delete all files that are older than - // 3 months + // 3 months (1 week respectively) - const { nodeCachedDataDir } = this._environmentService; - if (!nodeCachedDataDir) { + if (!this._environmentService.nodeCachedDataDir) { return; } + // The folder which contains folders of cached data. Each of these folder is per + // version + const nodeCachedDataRootDir = dirname(this._environmentService.nodeCachedDataDir); + const nodeCachedDataCurrent = basename(this._environmentService.nodeCachedDataDir); + let handle = setTimeout(() => { handle = undefined; - readdir(nodeCachedDataDir).then(entries => { + readdir(nodeCachedDataRootDir).then(entries => { const now = Date.now(); - const deletes = entries.map(entry => { - const path = join(nodeCachedDataDir, entry); - return stat(path).then(stats => { - const diff = now - stats.mtime.getTime(); - if (diff > NodeCachedDataManager._DataMaxAge) { - return rimraf(path); - } - return undefined; - }); + const deletes: TPromise[] = []; + + entries.forEach(entry => { + // name check + // * name is a git commit id (40 hex characters) + // * not the current cached data folder + if (entry.match(/^[a-f0-9]{40}$/i) && entry !== nodeCachedDataCurrent) { + + const path = join(nodeCachedDataRootDir, entry); + deletes.push(stat(path).then(stats => { + // stat check + // * only directories + // * only when old enough + if (stats.isDirectory()) { + const diff = now - stats.mtime.getTime(); + if (diff > NodeCachedDataManager._DataMaxAge) { + return rimraf(path); + } + } + return undefined; + })); + } }); return TPromise.join(deletes); From 0489f7ba3f707caef831ee27b1a0454972c19635 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 22 Sep 2017 10:08:40 +0200 Subject: [PATCH 195/281] tweak deprecation comment --- src/vs/vscode.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 2bc56f24ad1..883b86e3699 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -3932,9 +3932,9 @@ declare module 'vscode' { export class Task { /** - * Creates a new task. + * ~~Creates a new task.~~ * - * @deprecated: Use the new constructors that allow specifying a target for the task. + * @deprecated Use the new constructors that allow specifying a target for the task. * * @param definition The task definition as defined in the taskDefinitions extension point. * @param scope The task's name. Is presented in the user interface. From 4370c5adb10da51472606868a62beee6386acf0d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 22 Sep 2017 10:15:13 +0200 Subject: [PATCH 196/281] add perf-ticks for extensions handling --- .../extensions/electron-browser/extensionService.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index cb3e2266cf6..e600bf32f97 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -32,6 +32,7 @@ import { ExtHostCustomersRegistry } from 'vs/workbench/api/electron-browser/extH import { IWindowService } from 'vs/platform/windows/common/windows'; import { Action } from 'vs/base/common/actions'; import { IDisposable } from 'vs/base/common/lifecycle'; +import { startTimer } from 'vs/base/node/startupTimers'; const SystemExtensionsRoot = path.normalize(path.join(URI.parse(require.toUrl('')).fsPath, '..', 'extensions')); @@ -318,7 +319,12 @@ export class ExtensionService implements IExtensionService { let messageHandler = (msg: IMessage) => this._handleExtensionPointMessage(msg); for (let i = 0, len = extensionPoints.length; i < len; i++) { - ExtensionService._handleExtensionPoint(extensionPoints[i], availableExtensions, messageHandler); + const clock = startTimer(`handleExtensionPoint:${extensionPoints[i].name}`); + try { + ExtensionService._handleExtensionPoint(extensionPoints[i], availableExtensions, messageHandler); + } finally { + clock.stop(); + } } this._barrier.open(); From effc0215a043a4ceed91c4c10063367bae47bc89 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 22 Sep 2017 10:32:03 +0200 Subject: [PATCH 197/281] breakpoint event 'update' for backward compatibility --- src/vs/workbench/parts/debug/electron-browser/debugService.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index f88b0136dd8..956c5559259 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -381,7 +381,8 @@ export class DebugService implements debug.IDebugService { } // For compatibilty reasons check if wrong reason and source not present - if (event.body.reason === 'changed' || (event.body.reason === 'new' && !event.body.breakpoint.source)) { + // TODO@Isidor clean up these checks in October + if (event.body.reason === 'changed' || (event.body.reason === 'new' && !event.body.breakpoint.source) || event.body.reason === 'update') { if (breakpoint) { if (!breakpoint.column) { event.body.breakpoint.column = undefined; @@ -1096,6 +1097,7 @@ export class DebugService implements debug.IDebugService { const source = process.sources.get(modelUri.toString()); const rawSource = source ? source.raw : { path: paths.normalize(modelUri.fsPath, true), name: paths.basename(modelUri.fsPath) }; + return session.setBreakpoints({ source: rawSource, lines: breakpointsToSend.map(bp => bp.lineNumber), From 516054d1be0f2a06b6578f9d1ad05b1ad11830d2 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 22 Sep 2017 10:34:33 +0200 Subject: [PATCH 198/281] debug: fix adapterData being passed around fixes #34511 --- src/vs/workbench/parts/debug/common/debugModel.ts | 6 ++++-- .../parts/debug/electron-browser/debugService.ts | 8 +++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index cc30dc0f072..5c661077e7b 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -682,6 +682,7 @@ export class Breakpoint implements IBreakpoint { public enabled: boolean, public condition: string, public hitCondition: string, + public adapterData: any ) { if (enabled === undefined) { this.enabled = true; @@ -862,9 +863,9 @@ export class Model implements IModel { this._onDidChangeBreakpoints.fire(); } - public addBreakpoints(uri: uri, rawData: IRawBreakpoint[]): void { + public addBreakpoints(uri: uri, rawData: IRawBreakpoint[], adapterData: any = undefined): void { this.breakpoints = this.breakpoints.concat(rawData.map(rawBp => - new Breakpoint(uri, rawBp.lineNumber, rawBp.column, rawBp.enabled, rawBp.condition, rawBp.hitCondition))); + new Breakpoint(uri, rawBp.lineNumber, rawBp.column, rawBp.enabled, rawBp.condition, rawBp.hitCondition, adapterData))); this.breakpointsActivated = true; this.breakpoints = distinct(this.breakpoints, bp => `${bp.uri.toString()}:${bp.lineNumber}:${bp.column}`); this._onDidChangeBreakpoints.fire(); @@ -886,6 +887,7 @@ export class Model implements IModel { bp.verified = bpData.verified; bp.idFromAdapter = bpData.id; bp.message = bpData.message; + bp.adapterData = bpData.source ? bpData.source.adapterData : bp.adapterData; } }); this.breakpoints = distinct(this.breakpoints, bp => `${bp.uri.toString()}:${bp.lineNumber}:${bp.column}`); diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 956c5559259..37f43720911 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -366,7 +366,7 @@ export class DebugService implements debug.IDebugService { column: event.body.breakpoint.column, enabled: true, lineNumber: event.body.breakpoint.line - }]); + }], source.raw.adapterData); const newBreakpoint = this.model.getBreakpoints().filter(bp => bp.idFromAdapter === event.body.breakpoint.id).pop(); this.model.updateBreakpoints({ [newBreakpoint.getId()]: event.body.breakpoint }); } @@ -433,7 +433,7 @@ export class DebugService implements debug.IDebugService { let result: Breakpoint[]; try { result = JSON.parse(this.storageService.get(DEBUG_BREAKPOINTS_KEY, StorageScope.WORKSPACE, '[]')).map((breakpoint: any) => { - return new Breakpoint(uri.parse(breakpoint.uri.external || breakpoint.source.uri.external), breakpoint.lineNumber, breakpoint.column, breakpoint.enabled, breakpoint.condition, breakpoint.hitCondition); + return new Breakpoint(uri.parse(breakpoint.uri.external || breakpoint.source.uri.external), breakpoint.lineNumber, breakpoint.column, breakpoint.enabled, breakpoint.condition, breakpoint.hitCondition, breakpoint.adapterData); }); } catch (e) { } @@ -1096,7 +1096,9 @@ export class DebugService implements debug.IDebugService { const source = process.sources.get(modelUri.toString()); const rawSource = source ? source.raw : { path: paths.normalize(modelUri.fsPath, true), name: paths.basename(modelUri.fsPath) }; - + if (breakpointsToSend.length) { + rawSource.adapterData = breakpointsToSend[0].adapterData; + } return session.setBreakpoints({ source: rawSource, From 2428b6270178bfa624bf60d4cf1acadbc7b61782 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 22 Sep 2017 10:30:00 +0200 Subject: [PATCH 199/281] Given URI impl a more special name... --- src/vs/base/common/uri.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index e5e97ac6342..cd87a26a9d3 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -185,7 +185,7 @@ export default class URI { return this; } - return new UriWithCache(scheme, authority, path, query, fragment); + return new _URI(scheme, authority, path, query, fragment); } // ---- parse & validate ------------------------ @@ -193,9 +193,9 @@ export default class URI { public static parse(value: string): URI { const match = _regexp.exec(value); if (!match) { - return new UriWithCache(_empty, _empty, _empty, _empty, _empty); + return new _URI(_empty, _empty, _empty, _empty, _empty); } - return new UriWithCache( + return new _URI( match[2] || _empty, decodeURIComponent(match[4] || _empty), decodeURIComponent(match[5] || _empty), @@ -234,11 +234,11 @@ export default class URI { path = _slash + path; } - return new UriWithCache('file', authority, path, _empty, _empty); + return new _URI('file', authority, path, _empty, _empty); } public static from(components: { scheme?: string; authority?: string; path?: string; query?: string; fragment?: string }): URI { - return new UriWithCache( + return new _URI( components.scheme, components.authority, components.path, @@ -288,7 +288,7 @@ export default class URI { } static revive(data: any): URI { - let result = new UriWithCache( + let result = new _URI( (data).scheme, (data).authority, (data).path, @@ -302,7 +302,8 @@ export default class URI { } -class UriWithCache extends URI { +// tslint:disable-next-line:class-name +class _URI extends URI { _formatted: string = null; _fsPath: string = null; @@ -331,12 +332,12 @@ class UriWithCache extends URI { public toString(skipEncoding: boolean = false): string { if (!skipEncoding) { if (!this._formatted) { - this._formatted = UriWithCache._asFormatted(this, false); + this._formatted = _URI._asFormatted(this, false); } return this._formatted; } else { // we don't cache that - return UriWithCache._asFormatted(this, true); + return _URI._asFormatted(this, true); } } From 9cfb745faae8d4207cbf41f25edfe002a5886789 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 22 Sep 2017 10:37:58 +0200 Subject: [PATCH 200/281] log api usage for getWorkspaceFolder --- src/vs/workbench/api/node/extHost.api.impl.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 1325ce46809..40f44cbc4ee 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -403,6 +403,7 @@ export function createApiFactory( throw errors.readonly(); }, getWorkspaceFolder(resource) { + apiUsage.publicLog('workspace#getWorkspaceFolder'); return extHostWorkspace.getWorkspaceFolder(resource); }, get workspaceFolders() { From 4970b660bc53f8be0342edb25843325123be5844 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 22 Sep 2017 10:41:23 +0200 Subject: [PATCH 201/281] tweaks for #34449 --- src/vs/base/common/uri.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index cd87a26a9d3..b5e8a739f4d 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -55,6 +55,7 @@ const _slash = '/'; const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; const _driveLetterPath = /^\/[a-zA-Z]:/; const _upperCaseDrive = /^(\/)?([A-Z]:)/; +const _driveLetter = /^[a-zA-Z]:/; /** * Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986. @@ -217,20 +218,26 @@ export default class URI { // check for authority as used in UNC shares // or use the path as given - if (path[0] === _slash && path[0] === path[1]) { + if (path[0] === _slash && path[1] === _slash) { let idx = path.indexOf(_slash, 2); if (idx === -1) { authority = path.substring(2); - path = _empty; + path = _slash; } else { authority = path.substring(2, idx); - path = path.substring(idx); + path = path.substring(idx) || _slash; } } // Ensure that path starts with a slash // or that it is at least a slash - if (path[0] !== _slash) { + if (_driveLetter.test(path)) { + path = _slash + path; + + } else if (path[0] !== _slash) { + // tricky -> makes invalid paths + // but otherwise we have to stop + // allowing relative paths... path = _slash + path; } From 45bc150e6d4e2ae675cae53958a1e232016e17b0 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 22 Sep 2017 11:04:28 +0200 Subject: [PATCH 202/281] debug: custom telemetry service should be per session fixes Microsoft/vscode-internalbacklog#100 --- .../parts/debug/electron-browser/debugService.ts | 11 +++++------ .../parts/debug/electron-browser/rawDebugSession.ts | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 37f43720911..0b4c58c66a3 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -74,7 +74,6 @@ export class DebugService implements debug.IDebugService { private viewModel: ViewModel; private allProcesses: Map; private configurationManager: ConfigurationManager; - private customTelemetryService: ITelemetryService; private toDispose: lifecycle.IDisposable[]; private toDisposeOnSessionEnd: Map; private inDebugMode: IContextKey; @@ -328,8 +327,8 @@ export class DebugService implements debug.IDebugService { if (event.body.category === 'telemetry') { // only log telemetry events from debug adapter if the adapter provided the telemetry key // and the user opted in telemetry - if (this.customTelemetryService && this.telemetryService.isOptedIn) { - this.customTelemetryService.publicLog(event.body.output, event.body.data); + if (session.customTelemetryService && this.telemetryService.isOptedIn) { + session.customTelemetryService.publicLog(event.body.output, event.body.data); } return; @@ -821,9 +820,9 @@ export class DebugService implements debug.IDebugService { const adapter = this.configurationManager.getAdapter(configuration.type); const { aiKey, type } = adapter; const publisher = adapter.extensionDescription.publisher; - this.customTelemetryService = null; let client: TelemetryClient; + let customTelemetryService: TelemetryService; if (aiKey) { client = new TelemetryClient( uri.parse(require.toUrl('bootstrap')).fsPath, @@ -842,10 +841,10 @@ export class DebugService implements debug.IDebugService { const channel = client.getChannel('telemetryAppender'); const appender = new TelemetryAppenderClient(channel); - this.customTelemetryService = new TelemetryService({ appender }, this.configurationService); + customTelemetryService = new TelemetryService({ appender }, this.configurationService); } - const session = this.instantiationService.createInstance(RawDebugSession, sessionId, configuration.debugServer, adapter, this.customTelemetryService, root); + const session = this.instantiationService.createInstance(RawDebugSession, sessionId, configuration.debugServer, adapter, customTelemetryService, root); const process = this.model.addProcess(configuration, session); this.allProcesses.set(process.getId(), process); diff --git a/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts b/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts index 3a5f8153adc..992f4a6d673 100644 --- a/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts +++ b/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts @@ -70,7 +70,7 @@ export class RawDebugSession extends V8Protocol implements debug.ISession { id: string, private debugServerPort: number, private adapter: Adapter, - private customTelemetryService: ITelemetryService, + public customTelemetryService: ITelemetryService, public root: IWorkspaceFolder, @IMessageService private messageService: IMessageService, @ITelemetryService private telemetryService: ITelemetryService, From 9dce4655b131538acf905896669e0c9dcf3c0d38 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 22 Sep 2017 11:20:45 +0200 Subject: [PATCH 203/281] move open/save api into stable api, #13807 --- src/vs/vscode.d.ts | 85 +++++++++++++++++++ src/vs/vscode.proposed.d.ts | 85 ------------------- src/vs/workbench/api/node/extHost.api.impl.ts | 12 +-- 3 files changed, 91 insertions(+), 91 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 883b86e3699..3ec9e869fd4 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1503,6 +1503,75 @@ declare module 'vscode' { onDidSelectItem?(item: QuickPickItem | string): any; } + /** + * Options to configure the behaviour of a file open dialog. + */ + export interface OpenDialogOptions { + /** + * The resource the dialog shows when opened. + */ + defaultUri?: Uri; + + /** + * A human-readable string for the open button. + */ + openLabel?: string; + + /** + * Only allow to select files. *Note* that not all operating systems support + * to select files and folders in one dialog instance. + */ + openFiles?: boolean; + + /** + * Only allow to select folders. *Note* that not all operating systems support + * to select files and folders in one dialog instance. + */ + openFolders?: boolean; + + /** + * Allow to select many files or folders. + */ + openMany?: boolean; + + /** + * A set of file filters that are shown in the dialog, e.g. + * ```ts + * { + * ['Images']: ['*.png', '*.jpg'] + * ['TypeScript']: ['*.ts', '*.tsx'] + * } + * ``` + */ + filters: { [name: string]: string[] }; + } + + /** + * Options to configure the behaviour of a file save dialog. + */ + export interface SaveDialogOptions { + /** + * The resource the dialog shows when opened. + */ + defaultUri?: Uri; + + /** + * A human-readable string for the save button. + */ + saveLabel?: string; + + /** + * A set of file filters that are shown in the dialog, e.g. + * ```ts + * { + * ['Images']: ['*.png', '*.jpg'] + * ['TypeScript']: ['*.ts', '*.tsx'] + * } + * ``` + */ + filters: { [name: string]: string[] }; + } + /** * Represents an action that is shown with an information, warning, or * error message. @@ -4446,6 +4515,22 @@ declare module 'vscode' { */ export function showQuickPick(items: T[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable; + /** + * Shows a file open dialog to the user. + * + * @param options Options that control the dialog. + * @returns A promise that resolves to the selected resources or `undefined`. + */ + export function showOpenDialog(options: OpenDialogOptions): Thenable; + + /** + * Shows a file save dialog to the user. + * + * @param options Options that control the dialog. + * @returns A promise that resolves to the selected resource or `undefined`. + */ + export function showSaveDialog(options: SaveDialogOptions): Thenable; + /** * Opens an input box to ask the user for input. * diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 91d6d321fb1..c6914589faf 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -7,93 +7,8 @@ declare module 'vscode' { - /** - * Options to configure the behaviour of a file open dialog. - */ - export interface OpenDialogOptions { - /** - * The resource the dialog shows when opened. - */ - defaultUri?: Uri; - - /** - * A human-readable string for the open button. - */ - openLabel?: string; - - /** - * Only allow to select files. *Note* that not all operating systems support - * to select files and folders in one dialog instance. - */ - openFiles?: boolean; - - /** - * Only allow to select folders. *Note* that not all operating systems support - * to select files and folders in one dialog instance. - */ - openFolders?: boolean; - - /** - * Allow to select many files or folders. - */ - openMany?: boolean; - - /** - * A set of file filters that are shown in the dialog, e.g. - * ```ts - * { - * ['Images']: ['*.png', '*.jpg'] - * ['TypeScript']: ['*.ts', '*.tsx'] - * } - * ``` - */ - filters: { [name: string]: string[] }; - } - - /** - * Options to configure the behaviour of a file save dialog. - */ - export interface SaveDialogOptions { - /** - * The resource the dialog shows when opened. - */ - defaultUri?: Uri; - - /** - * A human-readable string for the save button. - */ - saveLabel?: string; - - /** - * A set of file filters that are shown in the dialog, e.g. - * ```ts - * { - * ['Images']: ['*.png', '*.jpg'] - * ['TypeScript']: ['*.ts', '*.tsx'] - * } - * ``` - */ - filters: { [name: string]: string[] }; - } - export namespace window { - /** - * Shows a file open dialog to the user. - * - * @param options Options that control the dialog. - * @returns A promise that resolves to the selected resources or `undefined`. - */ - export function showOpenDialog(options: OpenDialogOptions): Thenable; - - /** - * Shows a file save dialog to the user. - * - * @param options Options that control the dialog. - * @returns A promise that resolves to the selected resource or `undefined`. - */ - export function showSaveDialog(options: SaveDialogOptions): Thenable; - /** * Shows a selection list of [workspace folders](#workspace.workspaceFolders) to pick from. * Returns `undefined` if no folder is open. diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 40f44cbc4ee..11d0d16889f 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -356,6 +356,12 @@ export function createApiFactory( showInputBox(options?: vscode.InputBoxOptions, token?: vscode.CancellationToken) { return extHostQuickOpen.showInput(options, token); }, + showOpenDialog(options) { + return extHostDialogs.showOpenDialog(options); + }, + showSaveDialog(options) { + return extHostDialogs.showSaveDialog(options); + }, createStatusBarItem(position?: vscode.StatusBarAlignment, priority?: number): vscode.StatusBarItem { return extHostStatusBar.createStatusBarEntry(extension.id, position, priority); }, @@ -385,12 +391,6 @@ export function createApiFactory( sampleFunction: proposedApiFunction(extension, () => { return extHostMessageService.showMessage(extension, Severity.Info, 'Hello Proposed Api!', {}, []); }), - showOpenDialog: proposedApiFunction(extension, options => { - return extHostDialogs.showOpenDialog(options); - }), - showSaveDialog: proposedApiFunction(extension, options => { - return extHostDialogs.showSaveDialog(options); - }) }; // namespace: workspace From 07eaf2ac5335505fa44abca4abef00f512d09346 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 22 Sep 2017 11:29:53 +0200 Subject: [PATCH 204/281] workspace.openTextDocument works incorectly when passing { content?: string; } as argument (fix #34796) --- src/vs/workbench/api/node/extHost.api.impl.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 11d0d16889f..4eb4d090db3 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -439,7 +439,7 @@ export function createApiFactory( let uriPromise: TPromise; let options = uriOrFileNameOrOptions as { language?: string; content?: string; }; - if (!options || typeof options.language === 'string') { + if (!options || typeof options === 'object') { uriPromise = extHostDocuments.createDocumentData(options); } else if (typeof uriOrFileNameOrOptions === 'string') { uriPromise = TPromise.as(URI.file(uriOrFileNameOrOptions)); From 44c17d19501284edf21959e61074fabd8d0c7aba Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 22 Sep 2017 11:30:39 +0200 Subject: [PATCH 205/281] actually invoke a function... #34704 --- .../services/files/electron-browser/remoteFileService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index cffef7f3846..f4be4acd9ea 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -139,7 +139,7 @@ export class RemoteFileService extends FileService { if (!provider) { const err = new Error(); err.name = 'ENOPRO'; - err.message = `no provider for ${resource.toString}`; + err.message = `no provider for ${resource.toString()}`; throw err; } return provider; From bdefc09eb0e20de032e777fd25ff251792bc7889 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 22 Sep 2017 11:33:36 +0200 Subject: [PATCH 206/281] showWorkspaceFolderPick not enforced as proposed api (fixes #34819) --- src/vs/workbench/api/node/extHost.api.impl.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 4eb4d090db3..b6434280765 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -350,9 +350,9 @@ export function createApiFactory( showQuickPick(items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken) { return extHostQuickOpen.showQuickPick(items, options, token); }, - showWorkspaceFolderPick(options: vscode.WorkspaceFolderPickOptions) { + showWorkspaceFolderPick: proposedApiFunction(extension, (options: vscode.WorkspaceFolderPickOptions) => { return extHostQuickOpen.showWorkspaceFolderPick(options); - }, + }), showInputBox(options?: vscode.InputBoxOptions, token?: vscode.CancellationToken) { return extHostQuickOpen.showInput(options, token); }, From de99997ab5715de51a1a9903acf46e487e73f7fa Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Fri, 22 Sep 2017 11:26:56 +0200 Subject: [PATCH 207/281] Fixes #31970: When computing the task definition key we should falsify undefined properties --- .../parts/tasks/node/taskConfiguration.ts | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/tasks/node/taskConfiguration.ts b/src/vs/workbench/parts/tasks/node/taskConfiguration.ts index fe0429bd85e..b6cd314e6e8 100644 --- a/src/vs/workbench/parts/tasks/node/taskConfiguration.ts +++ b/src/vs/workbench/parts/tasks/node/taskConfiguration.ts @@ -1154,12 +1154,42 @@ namespace ConfiguringTask { identifier = { type }; - Object.keys(typeDeclaration.properties).forEach((property) => { + let properties = typeDeclaration.properties; + let required: Set = new Set(); + if (Array.isArray(typeDeclaration.required)) { + typeDeclaration.required.forEach(element => Types.isString(element) ? required.add(element) : required); + } + for (let property of Object.keys(properties)) { let value = external[property]; if (value !== void 0 && value !== null) { identifier[property] = value; + } else if (required.has(property)) { + let schema = properties[property]; + if (schema.default !== void 0) { + identifier[property] = Objects.deepClone(schema.default); + } else { + switch (schema.type) { + case 'boolean': + identifier[property] = false; + break; + case 'number': + case 'integer': + identifier[property] = 0; + break; + case 'string': + identifier[property] = ''; + break; + default: + let message = nls.localize( + 'ConfigurationParser.missingRequiredProperty', + 'Error: the task configuration \'{0}\' missed the required property \'{1}\'. The task configuration will be ignored.', JSON.stringify(external, undefined, 0), property + ); + context.problemReporter.error(message); + return undefined; + } + } } - }); + } } let taskIdentifier = TaskIdentifier.from(identifier); let configElement: Tasks.TaskSourceConfigElement = { From 0aba690f842b9e2c0a77459b3a3dcca1bd49e96e Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Fri, 22 Sep 2017 12:26:51 +0200 Subject: [PATCH 208/281] Fixes #34412: problemMatcher $tsc-watch ignores error second time around --- src/vs/workbench/parts/tasks/common/problemCollectors.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/vs/workbench/parts/tasks/common/problemCollectors.ts b/src/vs/workbench/parts/tasks/common/problemCollectors.ts index e886d8ef1a9..c40e58579b1 100644 --- a/src/vs/workbench/parts/tasks/common/problemCollectors.ts +++ b/src/vs/workbench/parts/tasks/common/problemCollectors.ts @@ -284,6 +284,11 @@ export class AbstractProblemCollector extends EventEmitter implements IDisposabl } return result; } + + protected cleanMarkerCaches(): void { + this.markers.clear(); + this.deliveredMarkers.clear(); + } } export enum ProblemHandlingStrategy { @@ -410,6 +415,7 @@ export class WatchingProblemCollector extends AbstractProblemCollector implement if (matches) { result = true; this.emit(ProblemCollectorEvents.WatchingBeginDetected, {}); + this.cleanMarkerCaches(); this.resetCurrentResource(); let owner = beginMatcher.problemMatcher.owner; let file = matches[beginMatcher.pattern.file]; @@ -435,6 +441,7 @@ export class WatchingProblemCollector extends AbstractProblemCollector implement let owner = endMatcher.problemMatcher.owner; this.resetCurrentResource(); this.cleanMarkers(owner); + this.cleanMarkerCaches(); } } return result; From 19c1db883ea17be2acffccd960a37852eaa8f870 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 22 Sep 2017 12:35:52 +0200 Subject: [PATCH 209/281] debug: remove fsPath usage --- src/vs/workbench/parts/debug/common/debugModel.ts | 4 ++-- src/vs/workbench/parts/debug/common/debugSource.ts | 7 ++++++- .../debug/electron-browser/debugConfigurationManager.ts | 2 +- .../workbench/parts/debug/electron-browser/debugService.ts | 3 ++- .../workbench/parts/debug/electron-browser/debugViewer.ts | 7 ++++--- .../workbench/parts/debug/electron-browser/debugViews.ts | 4 ++-- 6 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index 5c661077e7b..f831c74c5e6 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import uri from 'vs/base/common/uri'; -import * as paths from 'vs/base/common/paths'; +import * as resources from 'vs/base/common/resources'; import { TPromise } from 'vs/base/common/winjs.base'; import * as lifecycle from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; @@ -544,7 +544,7 @@ export class Process implements IProcess { } public getName(includeRoot: boolean): string { - return includeRoot ? `${this.configuration.name} (${paths.basename(this.session.root.uri.fsPath)})` : this.configuration.name; + return includeRoot ? `${this.configuration.name} (${resources.basenameOrAuthority(this.session.root.uri)})` : this.configuration.name; } public get state(): ProcessState { diff --git a/src/vs/workbench/parts/debug/common/debugSource.ts b/src/vs/workbench/parts/debug/common/debugSource.ts index 2fab8508e1b..73be541a020 100644 --- a/src/vs/workbench/parts/debug/common/debugSource.ts +++ b/src/vs/workbench/parts/debug/common/debugSource.ts @@ -6,6 +6,7 @@ import * as nls from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import uri from 'vs/base/common/uri'; +import * as paths from 'vs/base/common/paths'; import { DEBUG_SCHEME } from 'vs/workbench/parts/debug/common/debug'; import { IRange } from 'vs/editor/common/core/range'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -26,7 +27,11 @@ export class Source { if (this.raw.sourceReference > 0) { this.uri = uri.parse(`${DEBUG_SCHEME}:${encodeURIComponent(path)}?session=${encodeURIComponent(sessionId)}&ref=${this.raw.sourceReference}`); } else { - this.uri = uri.file(path); // path should better be absolute! + if (paths.isAbsolute(path)) { + this.uri = uri.file(path); // path should better be absolute! + } else { + this.uri = uri.parse(path); + } } } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts index cb3a63ce624..98589ef4c44 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts @@ -542,7 +542,7 @@ class Launch implements ILaunch { } public get uri(): uri { - return uri.file(paths.join(this.workspace.uri.fsPath, '/.vscode/launch.json')); + return this.workspace.uri.with({ path: paths.join(this.workspace.uri.path, '/.vscode/launch.json') }); } public openConfigFile(sideBySide: boolean, type?: string): TPromise { diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 0b4c58c66a3..e90bba74fb2 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -7,6 +7,7 @@ import * as nls from 'vs/nls'; import * as lifecycle from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; import * as paths from 'vs/base/common/paths'; +import * as resources from 'vs/base/common/resources'; import * as strings from 'vs/base/common/strings'; import { generateUuid } from 'vs/base/common/uuid'; import uri from 'vs/base/common/uri'; @@ -1094,7 +1095,7 @@ export class DebugService implements debug.IDebugService { const breakpointsToSend = this.model.getBreakpoints().filter(bp => this.model.areBreakpointsActivated() && bp.enabled && bp.uri.toString() === modelUri.toString()); const source = process.sources.get(modelUri.toString()); - const rawSource = source ? source.raw : { path: paths.normalize(modelUri.fsPath, true), name: paths.basename(modelUri.fsPath) }; + const rawSource = source ? source.raw : { path: paths.normalize(modelUri.fsPath, true), name: resources.basenameOrAuthority(modelUri) }; if (breakpointsToSend.length) { rawSource.adapterData = breakpointsToSend[0].adapterData; } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts index 5690c49421c..e5be9a9f8c0 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts @@ -8,6 +8,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as lifecycle from 'vs/base/common/lifecycle'; import { KeyCode } from 'vs/base/common/keyCodes'; import * as paths from 'vs/base/common/paths'; +import * as resources from 'vs/base/common/resources'; import * as errors from 'vs/base/common/errors'; import { equalsIgnoreCase } from 'vs/base/common/strings'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; @@ -194,7 +195,7 @@ function getSourceName(source: Source, contextService: IWorkspaceContextService, return source.name; } - return paths.basename(source.uri.fsPath); + return resources.basenameOrAuthority(source.uri); } export class BaseDebugController extends DefaultController { @@ -1233,7 +1234,7 @@ export class BreakpointsRenderer implements IRenderer { if (breakpoint.column) { data.lineNumber.textContent += `:${breakpoint.column}`; } - data.filePath.textContent = getPathLabel(paths.dirname(breakpoint.uri.fsPath), this.contextService, this.environmentService); + data.filePath.textContent = getPathLabel(resources.dirname(breakpoint.uri), this.contextService, this.environmentService); data.checkbox.checked = breakpoint.enabled; const debugActive = this.debugService.state === debug.State.Running || this.debugService.state === debug.State.Stopped || this.debugService.state === debug.State.Initializing; @@ -1260,7 +1261,7 @@ export class BreakpointsAccessibilityProvider implements IAccessibilityProvider public getAriaLabel(tree: ITree, element: any): string { if (element instanceof Breakpoint) { - return nls.localize('breakpointAriaLabel', "Breakpoint line {0} {1}, breakpoints, debug", (element).lineNumber, getPathLabel(paths.basename((element).uri.fsPath), this.contextService), this.contextService); + return nls.localize('breakpointAriaLabel', "Breakpoint line {0} {1}, breakpoints, debug", (element).lineNumber, getPathLabel(resources.basenameOrAuthority((element).uri), this.contextService), this.contextService); } if (element instanceof FunctionBreakpoint) { return nls.localize('functionBreakpointAriaLabel', "Function breakpoint {0}, breakpoints, debug", (element).name); diff --git a/src/vs/workbench/parts/debug/electron-browser/debugViews.ts b/src/vs/workbench/parts/debug/electron-browser/debugViews.ts index 6cdcb8d7338..a87b57536b8 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugViews.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugViews.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import * as paths from 'vs/base/common/paths'; +import * as resources from 'vs/base/common/resources'; import { RunOnceScheduler } from 'vs/base/common/async'; import * as dom from 'vs/base/browser/dom'; import * as builder from 'vs/base/browser/builder'; @@ -457,7 +457,7 @@ export class BreakpointsView extends CollapsibleView { } if (first.uri.toString() !== second.uri.toString()) { - return paths.basename(first.uri.fsPath).localeCompare(paths.basename(second.uri.fsPath)); + return resources.basenameOrAuthority(first.uri).localeCompare(resources.basenameOrAuthority(second.uri)); } if (first.lineNumber === second.lineNumber) { return first.column - second.column; From 3c511821a615847bc41bd0fe7498b818ce01adfa Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 22 Sep 2017 12:55:16 +0200 Subject: [PATCH 210/281] debug: do not allow breakpoints in settings files always #30996 --- .../debug/electron-browser/debugConfigurationManager.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts index 98589ef4c44..3c704fe5a54 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts @@ -12,7 +12,6 @@ import { first } from 'vs/base/common/arrays'; import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; import * as objects from 'vs/base/common/objects'; import uri from 'vs/base/common/uri'; -import { Schemas } from 'vs/base/common/network'; import * as paths from 'vs/base/common/paths'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { IModel, isCommonCodeEditor } from 'vs/editor/common/editorCommon'; @@ -29,7 +28,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IDebugConfigurationProvider, IRawAdapter, ICompound, IDebugConfiguration, DEBUG_SCHEME, IConfig, IEnvConfig, IGlobalConfig, IConfigurationManager, ILaunch } from 'vs/workbench/parts/debug/common/debug'; +import { IDebugConfigurationProvider, IRawAdapter, ICompound, IDebugConfiguration, IConfig, IEnvConfig, IGlobalConfig, IConfigurationManager, ILaunch } from 'vs/workbench/parts/debug/common/debug'; import { Adapter } from 'vs/workbench/parts/debug/node/debugAdapter'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; @@ -398,15 +397,15 @@ export class ConfigurationManager implements IConfigurationManager { } public canSetBreakpointsIn(model: IModel): boolean { - if (model.uri.scheme !== Schemas.file && model.uri.scheme !== DEBUG_SCHEME) { + const modeId = model ? model.getLanguageIdentifier().language : null; + if (!modeId || modeId === 'json') { + // do not allow breakpoints in our settings files return false; } if (this.configurationService.getConfiguration('debug').allowBreakpointsEverywhere) { return true; } - const modeId = model ? model.getLanguageIdentifier().language : null; - return this.breakpointModeIdsSet.has(modeId); } From a678f60100ef20ae3ed3ffe4ca2b29ae1798979d Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 22 Sep 2017 12:59:44 +0200 Subject: [PATCH 211/281] FoldingRules language configuration simplification --- extensions/clojure/language-configuration.json | 4 +--- .../coffeescript/language-configuration.json | 4 +--- extensions/fsharp/language-configuration.json | 4 +--- extensions/markdown/language-configuration.json | 4 +--- extensions/pug/language-configuration.json | 4 +--- extensions/python/language-configuration.json | 4 +--- extensions/yaml/language-configuration.json | 4 +--- .../editor/common/model/textModelWithTokens.ts | 3 +-- .../common/modes/languageConfiguration.ts | 17 +++++++---------- src/vs/monaco.d.ts | 16 +++++++--------- .../languageConfigurationExtensionPoint.ts | 12 +++--------- 11 files changed, 25 insertions(+), 51 deletions(-) diff --git a/extensions/clojure/language-configuration.json b/extensions/clojure/language-configuration.json index b68c24d92e3..24f52480015 100644 --- a/extensions/clojure/language-configuration.json +++ b/extensions/clojure/language-configuration.json @@ -20,8 +20,6 @@ ["\"", "\""] ], "folding": { - "indendationBasedFolding": { - "offSide": true - } + "offSide": true } } \ No newline at end of file diff --git a/extensions/coffeescript/language-configuration.json b/extensions/coffeescript/language-configuration.json index be41b444061..8c7fbd458df 100644 --- a/extensions/coffeescript/language-configuration.json +++ b/extensions/coffeescript/language-configuration.json @@ -23,8 +23,6 @@ ["'", "'"] ], "folding": { - "indendationBasedFolding": { - "offSide": true - } + "offSide": true } } \ No newline at end of file diff --git a/extensions/fsharp/language-configuration.json b/extensions/fsharp/language-configuration.json index 8a88df12433..effac7e3835 100644 --- a/extensions/fsharp/language-configuration.json +++ b/extensions/fsharp/language-configuration.json @@ -22,8 +22,6 @@ ["'", "'"] ], "folding": { - "indendationBasedFolding": { - "offSide": true - } + "offSide": true } } diff --git a/extensions/markdown/language-configuration.json b/extensions/markdown/language-configuration.json index c328f05d0e0..6fa9139b76f 100644 --- a/extensions/markdown/language-configuration.json +++ b/extensions/markdown/language-configuration.json @@ -39,8 +39,6 @@ ["`", "`"] ], "folding": { - "indendationBasedFolding": { - "offSide": true - } + "offSide": true } } \ No newline at end of file diff --git a/extensions/pug/language-configuration.json b/extensions/pug/language-configuration.json index 96f950546e6..00f4885d46e 100644 --- a/extensions/pug/language-configuration.json +++ b/extensions/pug/language-configuration.json @@ -22,8 +22,6 @@ ["\"", "\""] ], "folding": { - "indendationBasedFolding": { - "offSide": true - } + "offSide": true } } \ No newline at end of file diff --git a/extensions/python/language-configuration.json b/extensions/python/language-configuration.json index 7d9f13e6ce5..97feb4d8aca 100644 --- a/extensions/python/language-configuration.json +++ b/extensions/python/language-configuration.json @@ -23,8 +23,6 @@ ["'", "'"] ], "folding": { - "indendationBasedFolding": { - "offSide": true - } + "offSide": true } } \ No newline at end of file diff --git a/extensions/yaml/language-configuration.json b/extensions/yaml/language-configuration.json index 3d122eed6e0..cc1aa26cde6 100644 --- a/extensions/yaml/language-configuration.json +++ b/extensions/yaml/language-configuration.json @@ -22,8 +22,6 @@ ["'", "'"] ], "folding": { - "indendationBasedFolding": { - "offSide": true - } + "offSide": true } } \ No newline at end of file diff --git a/src/vs/editor/common/model/textModelWithTokens.ts b/src/vs/editor/common/model/textModelWithTokens.ts index 14c19d4a080..58a4414920e 100644 --- a/src/vs/editor/common/model/textModelWithTokens.ts +++ b/src/vs/editor/common/model/textModelWithTokens.ts @@ -844,8 +844,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke private _getIndentRanges(): IndentRange[] { if (!this._indentRanges) { let foldingRules = LanguageConfigurationRegistry.getFoldingRules(this._languageIdentifier.id); - let offSide = foldingRules && foldingRules.indendationBasedFolding && foldingRules.indendationBasedFolding.offSide; - this._indentRanges = computeRanges(this, offSide); + let offSide = foldingRules && foldingRules.offSide; } return this._indentRanges; } diff --git a/src/vs/editor/common/modes/languageConfiguration.ts b/src/vs/editor/common/modes/languageConfiguration.ts index ad764283935..093db6b102a 100644 --- a/src/vs/editor/common/modes/languageConfiguration.ts +++ b/src/vs/editor/common/modes/languageConfiguration.ts @@ -102,18 +102,15 @@ export interface IndentationRule { * Describes folding rules for a language. */ export interface FoldingRules { - indendationBasedFolding?: { - /** - * Used by the indentation based strategy to decide wheter empty lines belong to the previous or the next block. - * A language adheres to the off-side rule if blocks in that language are expressed by their indentation. - * See [wikipedia](https://en.wikipedia.org/wiki/Off-side_rule) for more information. - * If not set, `false` is used and empty lines belong to the previous block. - */ - offSide: boolean; - }; + /** + * Used by the indentation based strategy to decide wheter empty lines belong to the previous or the next block. + * A language adheres to the off-side rule if blocks in that language are expressed by their indentation. + * See [wikipedia](https://en.wikipedia.org/wiki/Off-side_rule) for more information. + * If not set, `false` is used and empty lines belong to the previous block. + */ + offSide?: boolean; } - /** * Describes a rule to be evaluated when pressing Enter. */ diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index d490e9c987e..bff19722704 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4365,15 +4365,13 @@ declare module monaco.languages { * Describes folding rules for a language. */ export interface FoldingRules { - indendationBasedFolding?: { - /** - * Used by the indentation based strategy to decide wheter empty lines belong to the previous or the next block. - * A language adheres to the off-side rule if blocks in that language are expressed by their indentation. - * See [wikipedia](https://en.wikipedia.org/wiki/Off-side_rule) for more information. - * If not set, `false` is used and empty lines belong to the previous block. - */ - offSide: boolean; - }; + /** + * Used by the indentation based strategy to decide wheter empty lines belong to the previous or the next block. + * A language adheres to the off-side rule if blocks in that language are expressed by their indentation. + * See [wikipedia](https://en.wikipedia.org/wiki/Off-side_rule) for more information. + * If not set, `false` is used and empty lines belong to the previous block. + */ + offSide?: boolean; } /** diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts b/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts index b97d7b652e3..d6532f578bd 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts @@ -387,15 +387,9 @@ const schema: IJSONSchema = { type: 'object', description: nls.localize('schema.folding', 'The language\'s folding settings.'), properties: { - indendationBasedFolding: { - type: 'object', - description: nls.localize('schema.folding.indendationBasedFolding', 'Settings for indentation based folding.'), - properties: { - offSide: { - type: 'boolean', - description: nls.localize('schema.folding.indendationBasedFolding.offSide', 'A language adheres to the off-side rule if blocks in that language are expressed by their indentation. If set, empty lines belong to the subsequent block.'), - } - } + offSide: { + type: 'boolean', + description: nls.localize('schema.folding.offSide', 'A language adheres to the off-side rule if blocks in that language are expressed by their indentation. If set, empty lines belong to the subsequent block.'), } } } From 9e05d4b635b403cdb94bb5fe6600e1d9710ab320 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 22 Sep 2017 13:49:41 +0200 Subject: [PATCH 212/281] [folding] fold regions, initial, preconfigured support. For #12146 --- extensions/cpp/package.json | 6 + extensions/csharp/language-configuration.json | 8 +- .../javascript-language-configuration.json | 8 +- .../powershell/language-configuration.json | 8 +- .../typescript/language-configuration.json | 8 +- extensions/vb/language-configuration.json | 8 +- src/vs/editor/common/model/indentRanges.ts | 83 +++-- .../common/model/textModelWithTokens.ts | 2 + .../test/common/model/indentRanges.test.ts | 345 ++++++++++++------ 9 files changed, 341 insertions(+), 135 deletions(-) diff --git a/extensions/cpp/package.json b/extensions/cpp/package.json index ce8f3d711a6..5e24898671f 100644 --- a/extensions/cpp/package.json +++ b/extensions/cpp/package.json @@ -33,5 +33,11 @@ "scopeName": "source.c.platform", "path": "./syntaxes/Platform.tmLanguage" }] + }, + "folding": { + "markers": { + "start": "^\\s*#pragma\\s+region", + "end": "^\\s*#pragma\\s+endregion" + } } } \ No newline at end of file diff --git a/extensions/csharp/language-configuration.json b/extensions/csharp/language-configuration.json index 5502deac4da..17f3fb0caf6 100644 --- a/extensions/csharp/language-configuration.json +++ b/extensions/csharp/language-configuration.json @@ -23,5 +23,11 @@ ["<", ">"], ["'", "'"], ["\"", "\""] - ] + ], + "folding": { + "markers": { + "start": "^\\s*#region", + "end": "^\\s*#endregion" + } + } } \ No newline at end of file diff --git a/extensions/javascript/javascript-language-configuration.json b/extensions/javascript/javascript-language-configuration.json index f25940db455..4080becc987 100644 --- a/extensions/javascript/javascript-language-configuration.json +++ b/extensions/javascript/javascript-language-configuration.json @@ -24,5 +24,11 @@ ["'", "'"], ["\"", "\""], ["`", "`"] - ] + ], + "folding": { + "markers": { + "start": "^\\s*//\\s*#region", + "end": "^\\s*//\\s*#endregion" + } + } } \ No newline at end of file diff --git a/extensions/powershell/language-configuration.json b/extensions/powershell/language-configuration.json index b409b3ce4c0..1227fef697d 100644 --- a/extensions/powershell/language-configuration.json +++ b/extensions/powershell/language-configuration.json @@ -22,5 +22,11 @@ ["(", ")"], ["\"", "\""], ["'", "'"] - ] + ], + "folding": { + "markers": { + "start": "^\\s*#region", + "end": "^\\s*#endregion" + } + } } \ No newline at end of file diff --git a/extensions/typescript/language-configuration.json b/extensions/typescript/language-configuration.json index f25940db455..4080becc987 100644 --- a/extensions/typescript/language-configuration.json +++ b/extensions/typescript/language-configuration.json @@ -24,5 +24,11 @@ ["'", "'"], ["\"", "\""], ["`", "`"] - ] + ], + "folding": { + "markers": { + "start": "^\\s*//\\s*#region", + "end": "^\\s*//\\s*#endregion" + } + } } \ No newline at end of file diff --git a/extensions/vb/language-configuration.json b/extensions/vb/language-configuration.json index f1fabbd4f22..6ef9c3c4d48 100644 --- a/extensions/vb/language-configuration.json +++ b/extensions/vb/language-configuration.json @@ -20,5 +20,11 @@ ["(", ")"], ["\"", "\""], ["<", ">"] - ] + ], + "folding": { + "markers": { + "start": "^\\s*#Region", + "end": "^\\s*#End Region" + } + } } \ No newline at end of file diff --git a/src/vs/editor/common/model/indentRanges.ts b/src/vs/editor/common/model/indentRanges.ts index a26176a5817..272b011460d 100644 --- a/src/vs/editor/common/model/indentRanges.ts +++ b/src/vs/editor/common/model/indentRanges.ts @@ -12,11 +12,13 @@ export class IndentRange { startLineNumber: number; endLineNumber: number; indent: number; + marker: boolean; - constructor(startLineNumber: number, endLineNumber: number, indent: number) { + constructor(startLineNumber: number, endLineNumber: number, indent: number, marker?: boolean) { this.startLineNumber = startLineNumber; this.endLineNumber = endLineNumber; this.indent = indent; + this.marker = marker; } public static deepCloneArr(indentRanges: IndentRange[]): IndentRange[] { @@ -29,12 +31,27 @@ export class IndentRange { } } -export function computeRanges(model: ITextModel, offSide: boolean, minimumRangeSize: number = 1): IndentRange[] { +export interface FoldMarkers { + start: string; + end: string; + indent?: number; +} + +interface PreviousRegion { indent: number; line: number; marker: RegExp; }; + +export function computeRanges(model: ITextModel, offSide: boolean, markers?: FoldMarkers, minimumRangeSize: number = 1): IndentRange[] { let result: IndentRange[] = []; - let previousRegions: { indent: number, line: number }[] = []; - previousRegions.push({ indent: -1, line: model.getLineCount() + 1 }); // sentinel, to make sure there's at least one entry + let pattern = void 0; + let patternIndent = -1; + if (markers) { + pattern = new RegExp(`(${markers.start})|(?:${markers.end})`); + patternIndent = typeof markers.indent === 'number' ? markers.indent : -1; + } + + let previousRegions: PreviousRegion[] = []; + previousRegions.push({ indent: -1, line: model.getLineCount() + 1, marker: null }); // sentinel, to make sure there's at least one entry for (let line = model.getLineCount(); line > 0; line--) { let indent = model.getIndentLevel(line); @@ -46,26 +63,48 @@ export function computeRanges(model: ITextModel, offSide: boolean, minimumRangeS } continue; // only whitespace } + let m; + if (pattern && (patternIndent === -1 || patternIndent === indent) && (m = model.getLineContent(line).match(pattern))) { + // folding pattern match + if (m[1]) { // start pattern match + if (previous.indent >= 0 && !previous.marker) { - - if (previous.indent > indent) { - // discard all regions with larger indent - do { - previousRegions.pop(); - previous = previousRegions[previousRegions.length - 1]; - } while (previous.indent > indent); - - // new folding range - let endLineNumber = previous.line - 1; - if (endLineNumber - line >= minimumRangeSize) { - result.push(new IndentRange(line, endLineNumber, indent)); + // discard all regions until the folding pattern + do { + previousRegions.pop(); + previous = previousRegions[previousRegions.length - 1]; + } while (previous.indent >= 0 && !previous.marker); + } + if (previous.marker) { + // new folding range from pattern, includes the end line + result.push(new IndentRange(line, previous.line, indent, true)); + previous.marker = null; + previous.indent = indent; + previous.line = line; + } + } else { // end pattern match + previousRegions.push({ indent: -2, line, marker: pattern }); + } + } else { + if (previous.indent > indent) { + // discard all regions with larger indent + do { + previousRegions.pop(); + previous = previousRegions[previousRegions.length - 1]; + } while (previous.indent > indent); + + // new folding range + let endLineNumber = previous.line - 1; + if (endLineNumber - line >= minimumRangeSize) { + result.push(new IndentRange(line, endLineNumber, indent)); + } + } + if (previous.indent === indent) { + previous.line = line; + } else { // previous.indent < indent + // new region with a bigger indent + previousRegions.push({ indent, line, marker: null }); } - } - if (previous.indent === indent) { - previous.line = line; - } else { // previous.indent < indent - // new region with a bigger indent - previousRegions.push({ indent, line }); } } diff --git a/src/vs/editor/common/model/textModelWithTokens.ts b/src/vs/editor/common/model/textModelWithTokens.ts index 58a4414920e..0006a7da417 100644 --- a/src/vs/editor/common/model/textModelWithTokens.ts +++ b/src/vs/editor/common/model/textModelWithTokens.ts @@ -845,6 +845,8 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke if (!this._indentRanges) { let foldingRules = LanguageConfigurationRegistry.getFoldingRules(this._languageIdentifier.id); let offSide = foldingRules && foldingRules.offSide; + let markers = foldingRules && foldingRules['markers']; + this._indentRanges = computeRanges(this, offSide, markers); } return this._indentRanges; } diff --git a/src/vs/editor/test/common/model/indentRanges.test.ts b/src/vs/editor/test/common/model/indentRanges.test.ts index 6f13fd9c8f0..0a022e43d02 100644 --- a/src/vs/editor/test/common/model/indentRanges.test.ts +++ b/src/vs/editor/test/common/model/indentRanges.test.ts @@ -7,137 +7,266 @@ import * as assert from 'assert'; import { Model } from 'vs/editor/common/model/model'; -import { computeRanges } from 'vs/editor/common/model/indentRanges'; +import { computeRanges, FoldMarkers } from 'vs/editor/common/model/indentRanges'; export interface IndentRange { startLineNumber: number; endLineNumber: number; indent: number; + marker: boolean; } -suite('Indentation Folding', () => { - function assertRanges(lines: string[], expected: IndentRange[], offside): void { - let model = Model.createFromString(lines.join('\n')); - let actual = computeRanges(model, offside); - actual.sort((r1, r2) => r1.startLineNumber - r2.startLineNumber); - assert.deepEqual(actual, expected); - model.dispose(); - } +function assertRanges(lines: string[], expected: IndentRange[], offside: boolean, markers?: FoldMarkers): void { + let model = Model.createFromString(lines.join('\n')); + let actual = computeRanges(model, offside, markers); + actual.sort((r1, r2) => r1.startLineNumber - r2.startLineNumber); + assert.deepEqual(actual, expected); + model.dispose(); +} - function r(startLineNumber: number, endLineNumber: number, indent: number): IndentRange { - return { startLineNumber, endLineNumber, indent }; - } +function r(startLineNumber: number, endLineNumber: number, indent: number, marker?: boolean): IndentRange { + return { startLineNumber, endLineNumber, indent, marker }; +} - test('Fold one level', () => { - let range = [ - 'A', - ' A', - ' A', - ' A' - ]; - assertRanges(range, [r(1, 4, 0)], true); - assertRanges(range, [r(1, 4, 0)], false); - }); +// suite('Indentation Folding', () => { - test('Fold two levels', () => { - let range = [ - 'A', - ' A', - ' A', - ' A', - ' A' - ]; - assertRanges(range, [r(1, 5, 0), r(3, 5, 2)], true); - assertRanges(range, [r(1, 5, 0), r(3, 5, 2)], false); - }); +// test('Fold one level', () => { +// let range = [ +// 'A', +// ' A', +// ' A', +// ' A' +// ]; +// assertRanges(range, [r(1, 4, 0)], true); +// assertRanges(range, [r(1, 4, 0)], false); +// }); - test('Fold three levels', () => { - let range = [ - 'A', - ' A', - ' A', - ' A', - 'A' - ]; - assertRanges(range, [r(1, 4, 0), r(2, 4, 2), r(3, 4, 4)], true); - assertRanges(range, [r(1, 4, 0), r(2, 4, 2), r(3, 4, 4)], false); - }); +// test('Fold two levels', () => { +// let range = [ +// 'A', +// ' A', +// ' A', +// ' A', +// ' A' +// ]; +// assertRanges(range, [r(1, 5, 0), r(3, 5, 2)], true); +// assertRanges(range, [r(1, 5, 0), r(3, 5, 2)], false); +// }); - test('Fold decreasing indent', () => { - let range = [ - ' A', - ' A', - 'A' - ]; - assertRanges(range, [], true); - assertRanges(range, [], false); - }); +// test('Fold three levels', () => { +// let range = [ +// 'A', +// ' A', +// ' A', +// ' A', +// 'A' +// ]; +// assertRanges(range, [r(1, 4, 0), r(2, 4, 2), r(3, 4, 4)], true); +// assertRanges(range, [r(1, 4, 0), r(2, 4, 2), r(3, 4, 4)], false); +// }); - test('Fold Java', () => { +// test('Fold decreasing indent', () => { +// let range = [ +// ' A', +// ' A', +// 'A' +// ]; +// assertRanges(range, [], true); +// assertRanges(range, [], false); +// }); + +// test('Fold Java', () => { +// assertRanges([ +// /* 1*/ 'class A {', +// /* 2*/ ' void foo() {', +// /* 3*/ ' console.log();', +// /* 4*/ ' console.log();', +// /* 5*/ ' }', +// /* 6*/ '', +// /* 7*/ ' void bar() {', +// /* 8*/ ' console.log();', +// /* 9*/ ' }', +// /*10*/ '}', +// /*11*/ 'interface B {', +// /*12*/ ' void bar();', +// /*13*/ '}', +// ], [r(1, 9, 0), r(2, 4, 2), r(7, 8, 2), r(11, 12, 0)], false); +// }); + +// test('Fold Javadoc', () => { +// assertRanges([ +// /* 1*/ '/**', +// /* 2*/ ' * Comment', +// /* 3*/ ' */', +// /* 4*/ 'class A {', +// /* 5*/ ' void foo() {', +// /* 6*/ ' }', +// /* 7*/ '}', +// ], [r(1, 3, 0), r(4, 6, 0)], false); +// }); +// test('Fold Whitespace Java', () => { +// assertRanges([ +// /* 1*/ 'class A {', +// /* 2*/ '', +// /* 3*/ ' void foo() {', +// /* 4*/ ' ', +// /* 5*/ ' return 0;', +// /* 6*/ ' }', +// /* 7*/ ' ', +// /* 8*/ '}', +// ], [r(1, 7, 0), r(3, 5, 2)], false); +// }); + +// test('Fold Whitespace Python', () => { +// assertRanges([ +// /* 1*/ 'def a:', +// /* 2*/ ' pass', +// /* 3*/ ' ', +// /* 4*/ ' def b:', +// /* 5*/ ' pass', +// /* 6*/ ' ', +// /* 7*/ ' ', +// /* 8*/ 'def c: # since there was a deintent here' +// ], [r(1, 5, 0), r(4, 5, 2)], true); +// }); + +// test('Fold Tabs', () => { +// assertRanges([ +// /* 1*/ 'class A {', +// /* 2*/ '\t\t', +// /* 3*/ '\tvoid foo() {', +// /* 4*/ '\t \t//hello', +// /* 5*/ '\t return 0;', +// /* 6*/ ' \t}', +// /* 7*/ ' ', +// /* 8*/ '}', +// ], [r(1, 7, 0), r(3, 5, 4)], false); +// }); +// }); + +let foldPattern: FoldMarkers = { + start: '^\\s*#region', + end: '^\\s*#endregion' +}; + +suite('Folding with regions', () => { + test('Inside region, indented', () => { assertRanges([ /* 1*/ 'class A {', - /* 2*/ ' void foo() {', - /* 3*/ ' console.log();', - /* 4*/ ' console.log();', - /* 5*/ ' }', - /* 6*/ '', - /* 7*/ ' void bar() {', - /* 8*/ ' console.log();', - /* 9*/ ' }', - /*10*/ '}', - /*11*/ 'interface B {', - /*12*/ ' void bar();', - /*13*/ '}', - ], [r(1, 9, 0), r(2, 4, 2), r(7, 8, 2), r(11, 12, 0)], false); - }); - - test('Fold Javadoc', () => { - assertRanges([ - /* 1*/ '/**', - /* 2*/ ' * Comment', - /* 3*/ ' */', - /* 4*/ 'class A {', - /* 5*/ ' void foo() {', - /* 6*/ ' }', - /* 7*/ '}', - ], [r(1, 3, 0), r(4, 6, 0)], false); - }); - test('Fold Whitespace Java', () => { - assertRanges([ - /* 1*/ 'class A {', - /* 2*/ '', + /* 2*/ ' #region', /* 3*/ ' void foo() {', /* 4*/ ' ', /* 5*/ ' return 0;', /* 6*/ ' }', - /* 7*/ ' ', + /* 7*/ ' #endregion', /* 8*/ '}', - ], [r(1, 7, 0), r(3, 5, 2)], false); + ], [r(1, 7, 0), r(2, 7, 2, true), r(3, 5, 2)], false, foldPattern); }); - - test('Fold Whitespace Python', () => { + test('Inside region, not indented', () => { assertRanges([ - /* 1*/ 'def a:', - /* 2*/ ' pass', - /* 3*/ ' ', - /* 4*/ ' def b:', - /* 5*/ ' pass', - /* 6*/ ' ', - /* 7*/ ' ', - /* 8*/ 'def c: # since there was a deintent here' - ], [r(1, 5, 0), r(4, 5, 2)], true); + /* 1*/ 'var x;', + /* 2*/ '#region', + /* 3*/ 'void foo() {', + /* 4*/ ' ', + /* 5*/ ' return 0;', + /* 6*/ ' }', + /* 7*/ '#endregion', + /* 8*/ '', + ], [r(2, 7, 0, true), r(3, 6, 0)], false, foldPattern); }); - - test('Fold Tabs', () => { + test('Empty Regions', () => { + assertRanges([ + /* 1*/ 'var x;', + /* 2*/ '#region', + /* 3*/ '#endregion', + /* 4*/ '#region', + /* 5*/ '', + /* 6*/ '#endregion', + /* 7*/ 'var y;', + ], [r(2, 3, 0, true), r(4, 6, 0, true)], false, foldPattern); + }); + test('Nested Regions', () => { + assertRanges([ + /* 1*/ 'var x;', + /* 2*/ '#region', + /* 3*/ '#region', + /* 4*/ '', + /* 5*/ '#endregion', + /* 6*/ '#endregion', + /* 7*/ 'var y;', + ], [r(2, 6, 0, true), r(3, 5, 0, true)], false, foldPattern); + }); + test('Nested Regions 2', () => { assertRanges([ /* 1*/ 'class A {', - /* 2*/ '\t\t', - /* 3*/ '\tvoid foo() {', - /* 4*/ '\t \t//hello', - /* 5*/ '\t return 0;', - /* 6*/ ' \t}', - /* 7*/ ' ', - /* 8*/ '}', - ], [r(1, 7, 0), r(3, 5, 4)], false); + /* 2*/ ' #region', + /* 3*/ '', + /* 4*/ ' #region', + /* 5*/ '', + /* 6*/ ' #endregion', + /* 7*/ ' // comment', + /* 8*/ ' #endregion', + /* 9*/ '}', + ], [r(1, 8, 0), r(2, 8, 2, true), r(4, 6, 2, true)], false, foldPattern); }); -}); + test('Incomplete Regions', () => { + assertRanges([ + /* 1*/ 'class A {', + /* 2*/ '#region', + /* 3*/ ' // comment', + /* 4*/ '}', + ], [], false, foldPattern); + }); + test('Incomplete Regions', () => { + assertRanges([ + /* 1*/ '', + /* 2*/ '#region', + /* 3*/ '#region', + /* 4*/ '#region', + /* 5*/ ' // comment', + /* 6*/ '#endregion', + /* 7*/ '#endregion', + /* 8*/ ' // hello', + ], [r(3, 7, 0, true), r(4, 6, 0, true)], false, foldPattern); + }); + test('Indented region before', () => { + assertRanges([ + /* 1*/ 'if (x)', + /* 2*/ ' return;', + /* 3*/ '', + /* 4*/ '#region', + /* 5*/ ' // comment', + /* 6*/ '#endregion', + ], [r(1, 3, 0), r(4, 6, 0, true)], false, foldPattern); + }); + test('Indented region before 2', () => { + assertRanges([ + /* 1*/ 'if (x)', + /* 2*/ ' log();', + /* 3*/ '', + /* 4*/ ' #region', + /* 5*/ ' // comment', + /* 6*/ ' #endregion', + ], [r(1, 6, 0), r(2, 6, 2), r(4, 6, 4, true)], false, foldPattern); + }); + test('Indented region in-between', () => { + assertRanges([ + /* 1*/ '#region', + /* 2*/ ' // comment', + /* 3*/ ' if (x)', + /* 4*/ ' return;', + /* 5*/ '', + /* 6*/ '#endregion', + ], [r(1, 6, 0, true), r(3, 5, 2)], false, foldPattern); + }); + test('Indented region after', () => { + assertRanges([ + /* 1*/ '#region', + /* 2*/ ' // comment', + /* 3*/ '', + /* 4*/ '#endregion', + /* 5*/ ' if (x)', + /* 6*/ ' return;', + ], [r(1, 4, 0, true), r(5, 6, 2)], false, foldPattern); + }); +}); \ No newline at end of file From 3e9fa5961632003ef9cbf31225a95b9cf13413df Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 22 Sep 2017 13:52:23 +0200 Subject: [PATCH 213/281] Introduce GlobPattern and adopt in DocumentFilter/FileWatcher/FileSearch (#34695) * introduce IRelativePattern and use in extension API * :lipstick: * docs * introduce RelativePattern * support RelativePattern also for file watcher * also make findFiles support RelativePattern * less type conversion * add GlobPattern type and remove readonly * make base a string * fix setter access to RelativePattern * fix npe when exclude is undefined * fix findFiles: pattern seems to be matched against workspace always * :lipstick: * clarify glob pattern matching --- src/vs/base/common/glob.ts | 77 +++++++++++++++---- src/vs/base/test/node/glob.test.ts | 31 ++++++++ .../editor/common/modes/languageSelector.ts | 4 +- src/vs/vscode.d.ts | 50 +++++++++--- .../electron-browser/mainThreadWorkspace.ts | 19 +++-- src/vs/workbench/api/node/extHost.api.impl.ts | 1 + src/vs/workbench/api/node/extHost.protocol.ts | 3 +- .../api/node/extHostFileSystemEventService.ts | 6 +- .../api/node/extHostTypeConverters.ts | 2 +- src/vs/workbench/api/node/extHostTypes.ts | 11 +++ src/vs/workbench/api/node/extHostWorkspace.ts | 3 +- 11 files changed, 169 insertions(+), 38 deletions(-) diff --git a/src/vs/base/common/glob.ts b/src/vs/base/common/glob.ts index cc14eea9d51..fb9ce79e05d 100644 --- a/src/vs/base/common/glob.ts +++ b/src/vs/base/common/glob.ts @@ -16,6 +16,11 @@ export interface IExpression { [pattern: string]: boolean | SiblingClause | any; } +export interface IRelativePattern { + base: string; + pattern: string; +} + export function getEmptyExpression(): IExpression { return Object.create(null); } @@ -28,6 +33,8 @@ export interface SiblingClause { when: string; } +const GLOBSTAR = '**'; +const GLOB_SPLIT = '/'; const PATH_REGEX = '[/\\\\]'; // any slash or backslash const NO_PATH_REGEX = '[^/\\\\]'; // any non-slash and non-backslash const ALL_FORWARD_SLASHES = /\//g; @@ -103,10 +110,10 @@ function parseRegExp(pattern: string): string { let regEx = ''; // Split up into segments for each slash found - let segments = splitGlobAware(pattern, '/'); + let segments = splitGlobAware(pattern, GLOB_SPLIT); // Special case where we only have globstars - if (segments.every(s => s === '**')) { + if (segments.every(s => s === GLOBSTAR)) { regEx = '.*'; } @@ -116,7 +123,7 @@ function parseRegExp(pattern: string): string { segments.forEach((segment, index) => { // Globstar is special - if (segment === '**') { + if (segment === GLOBSTAR) { // if we have more than one globstar after another, just ignore it if (!previousSegmentWasGlobStar) { @@ -207,7 +214,7 @@ function parseRegExp(pattern: string): string { } // Tail: Add the slash we had split on if there is more to come and the next one is not a globstar - if (index < segments.length - 1 && segments[index + 1] !== '**') { + if (index < segments.length - 1 && segments[index + 1] !== GLOBSTAR) { regEx += PATH_REGEX; } @@ -264,11 +271,39 @@ const NULL = function (): string { return null; }; -function parsePattern(pattern: string, options: IGlobOptions): ParsedStringPattern { - if (!pattern) { +function toAbsolutePattern(relativePattern: IRelativePattern | string): string { + + // Without a base URI, best we can do is add '**' to the pattern + if (typeof relativePattern === 'string') { + if (relativePattern.indexOf(GLOBSTAR) !== 0) { + relativePattern = GLOBSTAR + GLOB_SPLIT + strings.ltrim(relativePattern, GLOB_SPLIT); + } + + return relativePattern; + } + + // Guard against null/undefined + if (!relativePattern) { + return undefined; + } + + // With a base URI, we can append the path to the relative glob as prefix + return relativePattern.base + GLOB_SPLIT + strings.ltrim(relativePattern.pattern, GLOB_SPLIT); +} + +function parsePattern(arg1: string | IRelativePattern, options: IGlobOptions): ParsedStringPattern { + if (!arg1) { return NULL; } + // Handle IRelativePattern + let pattern: string; + if (typeof arg1 !== 'string') { + pattern = toAbsolutePattern(arg1.pattern); + } else { + pattern = arg1; + } + // Whitespace trimming pattern = pattern.trim(); @@ -276,7 +311,7 @@ function parsePattern(pattern: string, options: IGlobOptions): ParsedStringPatte const patternKey = `${pattern}_${!!options.trimForExclusions}`; let parsedPattern = CACHE.get(patternKey); if (parsedPattern) { - return parsedPattern; + return wrapRelativePattern(parsedPattern, pattern); } // Check for Trivias @@ -304,7 +339,21 @@ function parsePattern(pattern: string, options: IGlobOptions): ParsedStringPatte // Cache CACHE.set(patternKey, parsedPattern); - return parsedPattern; + return wrapRelativePattern(parsedPattern, pattern); +} + +function wrapRelativePattern(parsedPattern: ParsedStringPattern, arg2: string | IRelativePattern): ParsedStringPattern { + if (typeof arg2 === 'string') { + return parsedPattern; + } + + return function (path, basename) { + if (!paths.isEqualOrParent(path, arg2.base)) { + return null; + } + + return parsedPattern(path, basename); + }; } function trimForExclusions(pattern: string, options: IGlobOptions): string { @@ -395,9 +444,9 @@ function toRegExp(pattern: string): ParsedStringPattern { * - simple brace expansion ({js,ts} => js or ts) * - character ranges (using [...]) */ -export function match(pattern: string, path: string): boolean; +export function match(pattern: string | IRelativePattern, path: string): boolean; export function match(expression: IExpression, path: string, siblingsFn?: () => string[]): string /* the matching pattern */; -export function match(arg1: string | IExpression, path: string, siblingsFn?: () => string[]): any { +export function match(arg1: string | IExpression | IRelativePattern, path: string, siblingsFn?: () => string[]): any { if (!arg1 || !path) { return false; } @@ -413,16 +462,16 @@ export function match(arg1: string | IExpression, path: string, siblingsFn?: () * - simple brace expansion ({js,ts} => js or ts) * - character ranges (using [...]) */ -export function parse(pattern: string, options?: IGlobOptions): ParsedPattern; +export function parse(pattern: string | IRelativePattern, options?: IGlobOptions): ParsedPattern; export function parse(expression: IExpression, options?: IGlobOptions): ParsedExpression; -export function parse(arg1: string | IExpression, options: IGlobOptions = {}): any { +export function parse(arg1: string | IExpression | IRelativePattern, options: IGlobOptions = {}): any { if (!arg1) { return FALSE; } // Glob with String - if (typeof arg1 === 'string') { - const parsedPattern = parsePattern(arg1, options); + if (typeof arg1 === 'string' || (arg1 as IRelativePattern).base) { + const parsedPattern = parsePattern(arg1 as string | IRelativePattern, options); if (parsedPattern === NULL) { return FALSE; } diff --git a/src/vs/base/test/node/glob.test.ts b/src/vs/base/test/node/glob.test.ts index 1e3183171bd..1c87c114c4a 100644 --- a/src/vs/base/test/node/glob.test.ts +++ b/src/vs/base/test/node/glob.test.ts @@ -884,4 +884,35 @@ suite('Glob', () => { // Later expressions take precedence assert.deepEqual(glob.mergeExpressions({ 'a': true, 'b': false, 'c': true }, { 'a': false, 'b': true }), { 'a': false, 'b': true, 'c': true }); }); + + test('relative pattern', function () { + let p: glob.IRelativePattern = { base: '/DNXConsoleApp', pattern: '**/*.cs' }; + + assert(glob.match(p, '/DNXConsoleApp/Program.cs')); + assert(glob.match(p, '/DNXConsoleApp/foo/Program.cs')); + assert(!glob.match(p, '/DNXConsoleApp/foo/Program.ts')); + assert(!glob.match(p, '/other/DNXConsoleApp/foo/Program.ts')); + + p = { base: 'C:\\DNXConsoleApp', pattern: '**/*.cs' }; + assert(glob.match(p, 'C:\\DNXConsoleApp\\Program.cs')); + assert(glob.match(p, 'C:\\DNXConsoleApp\\foo\\Program.cs')); + assert(!glob.match(p, 'C:\\DNXConsoleApp\\foo\\Program.ts')); + assert(!glob.match(p, 'C:\\other\\DNXConsoleApp\\foo\\Program.ts')); + + assert(glob.match(p, 'C:/DNXConsoleApp/Program.cs')); + assert(glob.match(p, 'C:/DNXConsoleApp/foo/Program.cs')); + assert(!glob.match(p, 'C:/DNXConsoleApp/foo/Program.ts')); + assert(!glob.match(p, 'C:/other/DNXConsoleApp/foo/Program.ts')); + + p = { base: 'C:/DNXConsoleApp', pattern: '**/*.cs' }; + assert(glob.match(p, 'C:\\DNXConsoleApp\\Program.cs')); + assert(glob.match(p, 'C:\\DNXConsoleApp\\foo\\Program.cs')); + assert(!glob.match(p, 'C:\\DNXConsoleApp\\foo\\Program.ts')); + assert(!glob.match(p, 'C:\\other\\DNXConsoleApp\\foo\\Program.ts')); + + assert(glob.match(p, 'C:/DNXConsoleApp/Program.cs')); + assert(glob.match(p, 'C:/DNXConsoleApp/foo/Program.cs')); + assert(!glob.match(p, 'C:/DNXConsoleApp/foo/Program.ts')); + assert(!glob.match(p, 'C:/other/DNXConsoleApp/foo/Program.ts')); + }); }); \ No newline at end of file diff --git a/src/vs/editor/common/modes/languageSelector.ts b/src/vs/editor/common/modes/languageSelector.ts index 335e08e8b2e..356f454ecf4 100644 --- a/src/vs/editor/common/modes/languageSelector.ts +++ b/src/vs/editor/common/modes/languageSelector.ts @@ -6,12 +6,12 @@ 'use strict'; import URI from 'vs/base/common/uri'; -import { match as matchGlobPattern } from 'vs/base/common/glob'; // TODO@Alex +import { match as matchGlobPattern, IRelativePattern } from 'vs/base/common/glob'; // TODO@Alex export interface LanguageFilter { language?: string; scheme?: string; - pattern?: string; + pattern?: string | IRelativePattern; } export type LanguageSelector = string | LanguageFilter | (string | LanguageFilter)[]; diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 3ec9e869fd4..4b01c762c7e 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1658,6 +1658,31 @@ declare module 'vscode' { validateInput?(value: string): string | undefined | null; } + class RelativePattern { + + /** + * A base file path to which the pattern will be matched against relatively. + */ + base: string; + + /** + * A file glob pattern like `*.{ts,js}` that will be matched on file paths + * relative to the base path. + * + * Example: Given a base of `/home/work/folder` and a file path of `/home/work/folder/index.js`, + * the file glob pattern will match on `index.js`. + */ + pattern: string; + + constructor(pattern: string, base: WorkspaceFolder | string) + } + + /** + * A file glob pattern to match file paths against. This can either be a glob pattern string + * (like `**∕*.{ts,js}` or `*.{ts,js}`) or a [relative pattern](#RelativePattern). + */ + export type GlobPattern = string | RelativePattern; + /** * A document filter denotes a document by different properties like * the [language](#TextDocument.languageId), the [scheme](#Uri.scheme) of @@ -1679,9 +1704,9 @@ declare module 'vscode' { scheme?: string; /** - * A glob pattern, like `*.{ts,js}`. + * A [glob pattern](#GlobPattern) that is matched on the absolute path of the document. */ - pattern?: string; + pattern?: GlobPattern; } /** @@ -1693,7 +1718,6 @@ declare module 'vscode' { */ export type DocumentSelector = string | DocumentFilter | (string | DocumentFilter)[]; - /** * A provider result represents the values a provider, like the [`HoverProvider`](#HoverProvider), * may return. For once this is the actual result type `T`, like `Hover`, or a thenable that resolves @@ -4999,30 +5023,34 @@ declare module 'vscode' { /** * Creates a file system watcher. * - * A glob pattern that filters the file events must be provided. Optionally, flags to ignore certain - * kinds of events can be provided. To stop listening to events the watcher must be disposed. + * A glob pattern that filters the file events on their absolute path must be provided. Optionally, + * flags to ignore certain kinds of events can be provided. To stop listening to events the watcher must be disposed. * * *Note* that only files within the current [workspace folders](#workspace.workspaceFolders) can be watched. * - * @param globPattern A glob pattern that is applied to the names of created, changed, and deleted files. + * @param globPattern A [glob pattern](#GlobPattern) that is applied to the absolute paths of created, changed, + * and deleted files. * @param ignoreCreateEvents Ignore when files have been created. * @param ignoreChangeEvents Ignore when files have been changed. * @param ignoreDeleteEvents Ignore when files have been deleted. * @return A new file system watcher instance. */ - export function createFileSystemWatcher(globPattern: string, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): FileSystemWatcher; + export function createFileSystemWatcher(globPattern: GlobPattern, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): FileSystemWatcher; /** - * Find files in the workspace. + * Find files in the workspace. Will return no results if no [workspace folders](#workspace.workspaceFolders) + * are opened. * * @sample `findFiles('**∕*.js', '**∕node_modules∕**', 10)` - * @param include A glob pattern that defines the files to search for. - * @param exclude A glob pattern that defines files and folders to exclude. + * @param include A [glob pattern](#GlobPattern) that defines the files to search for. The glob pattern + * will be matched against the file paths of resulting matches relative to their workspace. + * @param exclude A [glob pattern](#GlobPattern) that defines files and folders to exclude. The glob pattern + * will be matched against the file paths of resulting matches relative to their workspace. * @param maxResults An upper-bound for the result. * @param token A token that can be used to signal cancellation to the underlying search engine. * @return A thenable that resolves to an array of resource identifiers. */ - export function findFiles(include: string, exclude?: string, maxResults?: number, token?: CancellationToken): Thenable; + export function findFiles(include: GlobPattern, exclude?: GlobPattern, maxResults?: number, token?: CancellationToken): Thenable; /** * Save all dirty files. diff --git a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts index b53bba5f047..12777a683c8 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts @@ -6,7 +6,7 @@ import { isPromiseCanceledError } from 'vs/base/common/errors'; import URI from 'vs/base/common/uri'; -import { ISearchService, QueryType, ISearchQuery } from 'vs/platform/search/common/search'; +import { ISearchService, QueryType, ISearchQuery, IFolderQuery } from 'vs/platform/search/common/search'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -15,6 +15,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import { IExperimentService } from 'vs/platform/telemetry/common/experiments'; +import { IRelativePattern } from 'vs/base/common/glob'; @extHostNamedCustomer(MainContext.MainThreadWorkspace) export class MainThreadWorkspace implements MainThreadWorkspaceShape { @@ -53,17 +54,25 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { // --- search --- - $startSearch(include: string, exclude: string, maxResults: number, requestId: number): Thenable { + $startSearch(include: string | IRelativePattern, exclude: string | IRelativePattern, maxResults: number, requestId: number): Thenable { const workspace = this._contextService.getWorkspace(); if (!workspace.folders.length) { return undefined; } + + let folderQueries: IFolderQuery[]; + if (typeof include === 'string' || !include) { + folderQueries = workspace.folders.map(folder => ({ folder: folder.uri })); // absolute pattern: search across all folders + } else { + folderQueries = [{ folder: URI.file(include.base) }]; // relative pattern: search only in base folder + } + const query: ISearchQuery = { - folderQueries: workspace.folders.map(folder => ({ folder: folder.uri })), + folderQueries, type: QueryType.File, maxResults, - includePattern: { [include]: true }, - excludePattern: { [exclude]: true }, + includePattern: { [typeof include === 'string' ? include : !!include ? include.pattern : undefined]: true }, + excludePattern: { [typeof exclude === 'string' ? exclude : !!exclude ? exclude.pattern : undefined]: true }, useRipgrep: this._experimentService.getExperiments().ripgrepQuickSearch }; this._searchService.extendQuery(query); diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index b6434280765..845f114f678 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -610,6 +610,7 @@ export function createApiFactory( TaskScope: extHostTypes.TaskScope, Task: extHostTypes.Task, ConfigurationTarget: extHostTypes.ConfigurationTarget, + RelativePattern: extHostTypes.RelativePattern, // TODO@JOH,remote FileChangeType: FileChangeType, diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 92ed6c653db..1c193f868ba 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -47,6 +47,7 @@ import { ITreeItem } from 'vs/workbench/common/views'; import { ThemeColor } from 'vs/platform/theme/common/themeService'; import { IDisposable } from 'vs/base/common/lifecycle'; import { SerializedError } from 'vs/base/common/errors'; +import { IRelativePattern } from 'vs/base/common/glob'; import { IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace'; import { IStat, IFileChange } from 'vs/platform/files/common/files'; @@ -311,7 +312,7 @@ export interface MainThreadTelemetryShape extends IDisposable { } export interface MainThreadWorkspaceShape extends IDisposable { - $startSearch(include: string, exclude: string, maxResults: number, requestId: number): Thenable; + $startSearch(include: string | IRelativePattern, exclude: string | IRelativePattern, maxResults: number, requestId: number): Thenable; $cancelSearch(requestId: number): Thenable; $saveAll(includeUntitled?: boolean): Thenable; } diff --git a/src/vs/workbench/api/node/extHostFileSystemEventService.ts b/src/vs/workbench/api/node/extHostFileSystemEventService.ts index 6038446ffc4..1c5aa2b1e28 100644 --- a/src/vs/workbench/api/node/extHostFileSystemEventService.ts +++ b/src/vs/workbench/api/node/extHostFileSystemEventService.ts @@ -6,7 +6,7 @@ import Event, { Emitter } from 'vs/base/common/event'; import { Disposable } from './extHostTypes'; -import { parse } from 'vs/base/common/glob'; +import { parse, IRelativePattern } from 'vs/base/common/glob'; import { Uri, FileSystemWatcher as _FileSystemWatcher } from 'vscode'; import { FileSystemEvents, ExtHostFileSystemEventServiceShape } from './extHost.protocol'; @@ -30,7 +30,7 @@ class FileSystemWatcher implements _FileSystemWatcher { return Boolean(this._config & 0b100); } - constructor(dispatcher: Event, globPattern: string, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean) { + constructor(dispatcher: Event, globPattern: string | IRelativePattern, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean) { this._config = 0; if (ignoreCreateEvents) { @@ -96,7 +96,7 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ constructor() { } - public createFileSystemWatcher(globPattern: string, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): _FileSystemWatcher { + public createFileSystemWatcher(globPattern: string | IRelativePattern, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): _FileSystemWatcher { return new FileSystemWatcher(this._emitter.event, globPattern, ignoreCreateEvents, ignoreChangeEvents, ignoreDeleteEvents); } diff --git a/src/vs/workbench/api/node/extHostTypeConverters.ts b/src/vs/workbench/api/node/extHostTypeConverters.ts index 22d9b4cacf5..81addd2688b 100644 --- a/src/vs/workbench/api/node/extHostTypeConverters.ts +++ b/src/vs/workbench/api/node/extHostTypeConverters.ts @@ -535,4 +535,4 @@ export namespace ProgressLocation { } return undefined; } -} +} \ No newline at end of file diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index 1db1c7986a9..e6678bfaab4 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -10,6 +10,7 @@ import URI from 'vs/base/common/uri'; import { illegalArgument } from 'vs/base/common/errors'; import * as vscode from 'vscode'; import { isMarkdownString } from 'vs/base/common/htmlContent'; +import { IRelativePattern } from 'vs/base/common/glob'; export class Disposable { @@ -1445,3 +1446,13 @@ export enum ConfigurationTarget { WorkspaceFolder = 3 } + +export class RelativePattern implements IRelativePattern { + base: string; + pattern: string; + + constructor(pattern: string, base: vscode.WorkspaceFolder | string) { + this.pattern = pattern; + this.base = typeof base === 'string' ? base : base.uri.fsPath; + } +} \ No newline at end of file diff --git a/src/vs/workbench/api/node/extHostWorkspace.ts b/src/vs/workbench/api/node/extHostWorkspace.ts index 7018fd88c07..1d7fd1b940f 100644 --- a/src/vs/workbench/api/node/extHostWorkspace.ts +++ b/src/vs/workbench/api/node/extHostWorkspace.ts @@ -14,6 +14,7 @@ import { IWorkspaceData, ExtHostWorkspaceShape, MainContext, MainThreadWorkspace import * as vscode from 'vscode'; import { compare } from 'vs/base/common/strings'; import { TrieMap } from 'vs/base/common/map'; +import { IRelativePattern } from 'vs/base/common/glob'; class Workspace2 extends Workspace { @@ -156,7 +157,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { // --- search --- - findFiles(include: string, exclude: string, maxResults?: number, token?: vscode.CancellationToken): Thenable { + findFiles(include: string | IRelativePattern, exclude: string | IRelativePattern, maxResults?: number, token?: vscode.CancellationToken): Thenable { const requestId = ExtHostWorkspace._requestIdPool++; const result = this._proxy.$startSearch(include, exclude, maxResults, requestId); if (token) { From 03933dcb7e9f87c24fde359ad9160740f03f6021 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 22 Sep 2017 14:00:02 +0200 Subject: [PATCH 214/281] :lipstick: --- src/vs/vscode.d.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 4b01c762c7e..805e53ff525 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -5038,17 +5038,18 @@ declare module 'vscode' { export function createFileSystemWatcher(globPattern: GlobPattern, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): FileSystemWatcher; /** - * Find files in the workspace. Will return no results if no [workspace folders](#workspace.workspaceFolders) - * are opened. + * Find files across all [workspace folders](#workspace.workspaceFolders) in the workspace. * * @sample `findFiles('**∕*.js', '**∕node_modules∕**', 10)` * @param include A [glob pattern](#GlobPattern) that defines the files to search for. The glob pattern - * will be matched against the file paths of resulting matches relative to their workspace. + * will be matched against the file paths of resulting matches relative to their workspace. Use [RelativePattern](#RelativePattern) + * to restrict the search to a specific folder of the workspace. * @param exclude A [glob pattern](#GlobPattern) that defines files and folders to exclude. The glob pattern * will be matched against the file paths of resulting matches relative to their workspace. * @param maxResults An upper-bound for the result. * @param token A token that can be used to signal cancellation to the underlying search engine. - * @return A thenable that resolves to an array of resource identifiers. + * @return A thenable that resolves to an array of resource identifiers. Will return no results if no + * [workspace folders](#workspace.workspaceFolders) are opened. */ export function findFiles(include: GlobPattern, exclude?: GlobPattern, maxResults?: number, token?: CancellationToken): Thenable; From 1b9ea3342505b00d0491e46e532a57a5ae0a420e Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 22 Sep 2017 14:04:32 +0200 Subject: [PATCH 215/281] [folding] fix cpp regions --- extensions/cpp/language-configuration.json | 6 ++++++ extensions/cpp/package.json | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/cpp/language-configuration.json b/extensions/cpp/language-configuration.json index a8782a61e3c..2888f3edea9 100644 --- a/extensions/cpp/language-configuration.json +++ b/extensions/cpp/language-configuration.json @@ -25,5 +25,11 @@ "indentationRules": { "increaseIndentPattern": "^.*\\{[^}\"\\']*$|^.*\\([^\\)\"\\']*$|^\\s*(public|private|protected):\\s*$|^\\s*@(public|private|protected)\\s*$|^\\s*\\{\\}$", "decreaseIndentPattern": "^\\s*(\\s*/[*].*[*]/\\s*)*\\}|^\\s*(\\s*/[*].*[*]/\\s*)*\\)|^\\s*(public|private|protected):\\s*$|^\\s*@(public|private|protected)\\s*$" + }, + "folding": { + "markers": { + "start": "^\\s*#pragma\\s+region", + "end": "^\\s*#pragma\\s+endregion" + } } } \ No newline at end of file diff --git a/extensions/cpp/package.json b/extensions/cpp/package.json index 5e24898671f..ce8f3d711a6 100644 --- a/extensions/cpp/package.json +++ b/extensions/cpp/package.json @@ -33,11 +33,5 @@ "scopeName": "source.c.platform", "path": "./syntaxes/Platform.tmLanguage" }] - }, - "folding": { - "markers": { - "start": "^\\s*#pragma\\s+region", - "end": "^\\s*#pragma\\s+endregion" - } } } \ No newline at end of file From 9cc82e780973a96856ec49f6d00407c534e373da Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 22 Sep 2017 14:50:36 +0200 Subject: [PATCH 216/281] :lipstick: --- src/vs/vscode.d.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 805e53ff525..1b3ebaedbfc 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1704,7 +1704,8 @@ declare module 'vscode' { scheme?: string; /** - * A [glob pattern](#GlobPattern) that is matched on the absolute path of the document. + * A [glob pattern](#GlobPattern) that is matched on the absolute path of the document. Use a [relative pattern](#RelativePattern) + * to filter documents to a [workspace folder](#WorkspaceFolder). */ pattern?: GlobPattern; } @@ -5029,7 +5030,7 @@ declare module 'vscode' { * *Note* that only files within the current [workspace folders](#workspace.workspaceFolders) can be watched. * * @param globPattern A [glob pattern](#GlobPattern) that is applied to the absolute paths of created, changed, - * and deleted files. + * and deleted files. Use a [relative pattern](#RelativePattern) to limit events to a certain [workspace folder](#WorkspaceFolder). * @param ignoreCreateEvents Ignore when files have been created. * @param ignoreChangeEvents Ignore when files have been changed. * @param ignoreDeleteEvents Ignore when files have been deleted. @@ -5042,8 +5043,8 @@ declare module 'vscode' { * * @sample `findFiles('**∕*.js', '**∕node_modules∕**', 10)` * @param include A [glob pattern](#GlobPattern) that defines the files to search for. The glob pattern - * will be matched against the file paths of resulting matches relative to their workspace. Use [RelativePattern](#RelativePattern) - * to restrict the search to a specific folder of the workspace. + * will be matched against the file paths of resulting matches relative to their workspace. Use a [relative pattern](#RelativePattern) + * to restrict the search results to a [workspace folder](#WorkspaceFolder). * @param exclude A [glob pattern](#GlobPattern) that defines files and folders to exclude. The glob pattern * will be matched against the file paths of resulting matches relative to their workspace. * @param maxResults An upper-bound for the result. From ddda90314e75806295720d9e6fd15fe90c095764 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 22 Sep 2017 14:57:48 +0200 Subject: [PATCH 217/281] smoke: fix quick open focus issue --- test/smoke/src/areas/quickopen/quickopen.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/smoke/src/areas/quickopen/quickopen.ts b/test/smoke/src/areas/quickopen/quickopen.ts index 9f91b96f1ae..a4e6ac85288 100644 --- a/test/smoke/src/areas/quickopen/quickopen.ts +++ b/test/smoke/src/areas/quickopen/quickopen.ts @@ -25,6 +25,9 @@ export class QuickOpen { public async openCommandPallette(): Promise { await this.spectron.command('workbench.action.showCommands'); await this.waitForQuickOpenOpened(); + + // we gotta wait 50 milliseconds due to https://github.com/Microsoft/vscode/blob/master/src/vs/platform/list/browser/listService.ts#L59 + await new Promise(c => setTimeout(c, 50)); } public async closeQuickOpen(): Promise { From 6dc90eace42ae18437850354970af6fa4c4f5db5 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 22 Sep 2017 15:00:51 +0200 Subject: [PATCH 218/281] explorerView: do not use filter: File #34768 --- src/vs/workbench/parts/files/browser/views/explorerView.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index 755418e131e..05a68b4275f 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -369,7 +369,7 @@ export class ExplorerView extends CollapsibleView { } // check for files - return toResource(input, { supportSideBySide: true, filter: 'file' }); + return toResource(input, { supportSideBySide: true }); } private get isCreated(): boolean { From 0962b2410d377807d13120b34256186a02415403 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 22 Sep 2017 14:30:40 +0200 Subject: [PATCH 219/281] read most of the encoding from stream --- src/vs/base/node/mime.ts | 2 +- .../electron-browser/remoteFileService.ts | 83 +++++++++++++++---- 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/src/vs/base/node/mime.ts b/src/vs/base/node/mime.ts index ee5ce368a7a..1e71046cce6 100644 --- a/src/vs/base/node/mime.ts +++ b/src/vs/base/node/mime.ts @@ -56,7 +56,7 @@ const ZERO_BYTE_DETECTION_BUFFER_MAX_LEN = 512; // number of bytes to look at to const NO_GUESS_BUFFER_MAX_LEN = 512; // when not auto guessing the encoding, small number of bytes are enough const AUTO_GUESS_BUFFER_MAX_LEN = 512 * 8; // with auto guessing we want a lot more content to be read for guessing -function maxBufferLen(arg1?: DetectMimesOption | boolean): number { +export function maxBufferLen(arg1?: DetectMimesOption | boolean): number { let autoGuessEncoding: boolean; if (typeof arg1 === 'boolean') { autoGuessEncoding = arg1; diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index f4be4acd9ea..d5625b24a05 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -14,7 +14,7 @@ import { groupBy, isFalsyOrEmpty, distinct } from 'vs/base/common/arrays'; import { compare } from 'vs/base/common/strings'; import { Schemas } from 'vs/base/common/network'; import { Progress } from 'vs/platform/progress/common/progress'; -import { decodeStream, encode } from 'vs/base/node/encoding'; +import { decodeStream, encode, UTF8, UTF8_with_bom } from 'vs/base/node/encoding'; import { StringTrieMap } from 'vs/base/common/map'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -24,6 +24,8 @@ import { IMessageService } from 'vs/platform/message/common/message'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; +import { maxBufferLen, detectMimeAndEncodingFromBuffer } from 'vs/base/node/mime'; +import { MIME_BINARY } from 'vs/base/common/mime'; function toIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], recurse?: (tuple: [URI, IStat]) => boolean): TPromise { const [resource, stat] = tuple; @@ -217,28 +219,73 @@ export class RemoteFileService extends FileService { } } - private _doResolveContent(resource: URI, options: IResolveContentOptions): TPromise { + private _doResolveContent(resource: URI, options: IResolveContentOptions = Object.create(null)): TPromise { return this._withProvider(resource).then(provider => { + return this.resolveFile(resource).then(fileStat => { + const guessEncoding = options.autoGuessEncoding; + const count = maxBufferLen(options); + const chunks: Buffer[] = []; - const encoding = this.getEncoding(resource); - const stream = decodeStream(encoding); + return provider.read( + resource, + 0, count, + new Progress(chunk => chunks.push(chunk)) + ).then(bytesRead => { + // send to bla + return detectMimeAndEncodingFromBuffer({ bytesRead, buffer: Buffer.concat(chunks) }, guessEncoding); - provider.read(resource, 0, Number.MAX_VALUE, new Progress(chunk => stream.write(chunk))).then(() => { - stream.end(); - }, err => { - stream.emit('error', err); - stream.end(); + }).then(detected => { + if (options.acceptTextOnly && detected.mimes.indexOf(MIME_BINARY) >= 0) { + throw new Error('binary'); + } + + let preferredEncoding: string; + if (options && options.encoding) { + if (detected.encoding === UTF8 && options.encoding === UTF8) { + preferredEncoding = UTF8_with_bom; // indicate the file has BOM if we are to resolve with UTF 8 + } else { + preferredEncoding = options.encoding; // give passed in encoding highest priority + } + } else if (detected.encoding) { + if (detected.encoding === UTF8) { + preferredEncoding = UTF8_with_bom; // if we detected UTF-8, it can only be because of a BOM + } else { + preferredEncoding = detected.encoding; + } + // todo@remote - encoding logic should not be kept + // hostage inside the node file service + // } else if (super.configuredEncoding(resource) === UTF8_with_bom) { + } else { + preferredEncoding = UTF8; // if we did not detect UTF 8 BOM before, this can only be UTF 8 then + } + + // const encoding = this.getEncoding(resource); + const stream = decodeStream(preferredEncoding); + + // start with what we have already read + // and have a new stream to read the rest + let offset = 0; + for (const chunk of chunks) { + stream.write(chunk); + offset += chunk.length; + } + provider.read(resource, offset, Number.MAX_VALUE, new Progress(chunk => stream.write(chunk))).then(() => { + stream.end(); + }, err => { + stream.emit('error', err); + stream.end(); + }); + + return { + encoding: preferredEncoding, + value: stream, + resource: fileStat.resource, + name: fileStat.name, + etag: fileStat.etag, + mtime: fileStat.mtime, + }; }); - - return { - encoding, - value: stream, - resource: fileStat.resource, - name: fileStat.name, - etag: fileStat.etag, - mtime: fileStat.mtime, - }; }); }); } From 22d78300480806a2812b0c1eef7e9049c60f4ea1 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 22 Sep 2017 15:24:49 +0200 Subject: [PATCH 220/281] debug: when constructiing source path take scheme into account --- src/vs/workbench/parts/debug/electron-browser/debugService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index e90bba74fb2..250d862a371 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -1095,7 +1095,7 @@ export class DebugService implements debug.IDebugService { const breakpointsToSend = this.model.getBreakpoints().filter(bp => this.model.areBreakpointsActivated() && bp.enabled && bp.uri.toString() === modelUri.toString()); const source = process.sources.get(modelUri.toString()); - const rawSource = source ? source.raw : { path: paths.normalize(modelUri.fsPath, true), name: resources.basenameOrAuthority(modelUri) }; + const rawSource = source ? source.raw : { path: modelUri.scheme === 'file' || modelUri.scheme === debug.DEBUG_SCHEME ? paths.normalize(modelUri.fsPath, true) : modelUri.toString(), name: resources.basenameOrAuthority(modelUri) }; if (breakpointsToSend.length) { rawSource.adapterData = breakpointsToSend[0].adapterData; } From cd571e7f517bcfd6236c1c17d6c3e61e928116eb Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 22 Sep 2017 15:29:31 +0200 Subject: [PATCH 221/281] better (the same we already have) binary file error --- .../services/files/electron-browser/remoteFileService.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index d5625b24a05..cae0f64a73c 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -26,6 +26,7 @@ import { ITextResourceConfigurationService } from 'vs/editor/common/services/res import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { maxBufferLen, detectMimeAndEncodingFromBuffer } from 'vs/base/node/mime'; import { MIME_BINARY } from 'vs/base/common/mime'; +import { localize } from 'vs/nls'; function toIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], recurse?: (tuple: [URI, IStat]) => boolean): TPromise { const [resource, stat] = tuple; @@ -237,7 +238,10 @@ export class RemoteFileService extends FileService { }).then(detected => { if (options.acceptTextOnly && detected.mimes.indexOf(MIME_BINARY) >= 0) { - throw new Error('binary'); + return TPromise.wrapError(new FileOperationError( + localize('fileBinaryError', "File seems to be binary and cannot be opened as text"), + FileOperationResult.FILE_IS_BINARY + )); } let preferredEncoding: string; From 7fd92e048fcc2e1b81db316643a58aa4b98fb481 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 22 Sep 2017 15:33:50 +0200 Subject: [PATCH 222/281] workspace: remove fsPath --- src/vs/platform/workspace/common/workspace.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index 46d4d312bf9..3c05b4dd124 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -6,6 +6,7 @@ import URI from 'vs/base/common/uri'; import * as paths from 'vs/base/common/paths'; +import * as resources from 'vs/base/common/resources'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { StringTrieMap } from 'vs/base/common/map'; import Event from 'vs/base/common/event'; @@ -216,7 +217,7 @@ export class WorkspaceFolder implements IWorkspaceFolder { } toResource(relativePath: string): URI { - return URI.file(paths.join(this.uri.fsPath, relativePath)); + return this.uri.with({ path: paths.join(this.uri.path, relativePath) }); } toJSON(): IWorkspaceFolderData { @@ -227,7 +228,7 @@ export class WorkspaceFolder implements IWorkspaceFolder { export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo?: URI): WorkspaceFolder[] { let workspaceFolders = parseWorkspaceFolders(configuredFolders, relativeTo); return ensureUnique(coalesce(workspaceFolders)) - .map(({ uri, raw, name }, index) => new WorkspaceFolder({ uri, name: name || paths.basename(uri.fsPath), index }, raw)); + .map(({ uri, raw, name }, index) => new WorkspaceFolder({ uri, name: name || resources.basenameOrAuthority(uri), index }, raw)); } function parseWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo: URI): WorkspaceFolder[] { @@ -256,12 +257,12 @@ function toUri(path: string, relativeTo: URI): URI { return URI.file(path); } if (relativeTo) { - return URI.file(paths.join(relativeTo.fsPath, path)); + return relativeTo.with({ path: paths.join(relativeTo.path, path) }); } } return null; } function ensureUnique(folders: WorkspaceFolder[]): WorkspaceFolder[] { - return distinct(folders, folder => isLinux ? folder.uri.fsPath : folder.uri.fsPath.toLowerCase()); + return distinct(folders, folder => isLinux ? folder.uri.toString() : folder.uri.toString().toLowerCase()); } From 0cba333056ddccbfe7132aecb19dd7626135e5d4 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 22 Sep 2017 15:34:25 +0200 Subject: [PATCH 223/281] :lipstick: --- src/vs/platform/files/common/files.ts | 9 ++++++--- .../workbench/services/editor/browser/editorService.ts | 2 +- .../services/files/electron-browser/remoteFileService.ts | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index a7bd37587d3..f70e2b3005b 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -33,11 +33,14 @@ export interface IFileService { onAfterOperation: Event; /** - * + * Registeres a file system provider for a certain scheme. */ - registerProvider?(authority: string, provider: IFileSystemProvider): IDisposable; + registerProvider?(scheme: string, provider: IFileSystemProvider): IDisposable; - supportResource?(resource: URI): boolean; + /** + * Checks if this file service can handle the given resource. + */ + canHandleResource?(resource: URI): boolean; /** * Resolve the properties of a file identified by the resource. diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index 52fa698bfd4..9a2f95831b5 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -275,7 +275,7 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { } let input: ICachedEditorInput; - if (resource.scheme === network.Schemas.file || this.fileService.supportResource && this.fileService.supportResource(resource)) { + if (resource.scheme === network.Schemas.file || this.fileService.canHandleResource && this.fileService.canHandleResource(resource)) { input = this.fileInputFactory.createFileInput(resource, encoding, instantiationService); } else { input = instantiationService.createInstance(ResourceEditorInput, label, description, resource); diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index cae0f64a73c..4d9366fdaa5 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -127,7 +127,7 @@ export class RemoteFileService extends FileService { }; } - supportResource(resource: URI): boolean { + canHandleResource(resource: URI): boolean { return resource.scheme === Schemas.file || this._provider.has(resource.scheme) // TODO@remote From a7ad71be3bf9c1db4ad247d9a1ac39738540c13a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 22 Sep 2017 16:02:51 +0200 Subject: [PATCH 224/281] remote - refine utimes --- src/vs/platform/files/common/files.ts | 2 +- src/vs/vscode.proposed.d.ts | 3 ++- src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts | 4 ++-- src/vs/workbench/api/node/extHost.protocol.ts | 2 +- src/vs/workbench/api/node/extHostFileSystem.ts | 4 ++-- .../services/files/electron-browser/remoteFileService.ts | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index f70e2b3005b..4456aae8707 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -181,7 +181,7 @@ export interface IFileSystemProvider { // more... // - utimes(resource: URI, mtime: number): TPromise; + utimes(resource: URI, mtime: number, atime: number): TPromise; stat(resource: URI): TPromise; read(resource: URI, offset: number, count: number, progress: IProgress): TPromise; write(resource: URI, content: Uint8Array): TPromise; diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index c6914589faf..85ca4a72cd1 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -107,6 +107,7 @@ declare module 'vscode' { export interface FileStat { id: number | string; mtime: number; + // atime: number; size: number; type: FileType; } @@ -120,7 +121,7 @@ declare module 'vscode' { // more... // - utimes(resource: Uri, mtime: number): Thenable; + utimes(resource: Uri, mtime: number, atime: number): Thenable; stat(resource: Uri): Thenable; diff --git a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts index 7667c708e84..76aac923806 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadFileSystem.ts @@ -84,8 +84,8 @@ class RemoteFileSystemProvider implements IFileSystemProvider { // --- forwarding calls - utimes(resource: URI, mtime: number): TPromise { - return this._proxy.$utimes(this._handle, resource, mtime); + utimes(resource: URI, mtime: number, atime: number): TPromise { + return this._proxy.$utimes(this._handle, resource, mtime, atime); } stat(resource: URI): TPromise { return this._proxy.$stat(this._handle, resource); diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 1c193f868ba..1a04c2f8dd0 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -480,7 +480,7 @@ export interface ExtHostWorkspaceShape { } export interface ExtHostFileSystemShape { - $utimes(handle: number, resource: URI, mtime: number): TPromise; + $utimes(handle: number, resource: URI, mtime: number, atime: number): TPromise; $stat(handle: number, resource: URI): TPromise; $read(handle: number, offset: number, count: number, resource: URI): TPromise; $write(handle: number, resource: URI, content: number[]): TPromise; diff --git a/src/vs/workbench/api/node/extHostFileSystem.ts b/src/vs/workbench/api/node/extHostFileSystem.ts index 3488b9570f9..6b7466381f5 100644 --- a/src/vs/workbench/api/node/extHostFileSystem.ts +++ b/src/vs/workbench/api/node/extHostFileSystem.ts @@ -42,8 +42,8 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { }; } - $utimes(handle: number, resource: URI, mtime: number): TPromise { - return asWinJsPromise(token => this._provider.get(handle).utimes(resource, mtime)); + $utimes(handle: number, resource: URI, mtime: number, atime: number): TPromise { + return asWinJsPromise(token => this._provider.get(handle).utimes(resource, mtime, atime)); } $stat(handle: number, resource: URI): TPromise { return asWinJsPromise(token => this._provider.get(handle).stat(resource)); diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 4d9366fdaa5..cfcfe0e3913 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -481,7 +481,7 @@ export class RemoteFileService extends FileService { private _doTouchFile(resource: URI): TPromise { return this._withProvider(resource).then(provider => { return provider.stat(resource).then(() => { - return provider.utimes(resource, Date.now()); + return provider.utimes(resource, Date.now(), Date.now()); }, err => { return provider.write(resource, new Uint8Array(0)); }).then(() => { From dc7519257e50e10729714d1ce96f0f1466c49101 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 22 Sep 2017 16:31:42 +0200 Subject: [PATCH 225/281] linkDetector: remove elative paths supported fixes #29190 --- src/vs/workbench/parts/debug/browser/linkDetector.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/vs/workbench/parts/debug/browser/linkDetector.ts b/src/vs/workbench/parts/debug/browser/linkDetector.ts index 420c424b840..ac31e70c14a 100644 --- a/src/vs/workbench/parts/debug/browser/linkDetector.ts +++ b/src/vs/workbench/parts/debug/browser/linkDetector.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import strings = require('vs/base/common/strings'); import uri from 'vs/base/common/uri'; import { isMacintosh } from 'vs/base/common/platform'; import * as errors from 'vs/base/common/errors'; @@ -37,7 +36,6 @@ export class LinkDetector { * If no links were detected, returns the original string. */ public handleLinks(text: string): HTMLElement | string { - const workspaceFolder = this.contextService.getWorkspace().folders[0]; let linkContainer: HTMLElement; for (let pattern of LinkDetector.FILE_LOCATION_PATTERNS) { @@ -47,13 +45,6 @@ export class LinkDetector { let match = pattern.exec(text); while (match !== null) { let resource: uri = null; - if (workspaceFolder) { - try { - resource = (match && !strings.startsWith(match[0], 'http')) - && (match[2] || strings.startsWith(match[1], '/') ? uri.file(match[1]) : workspaceFolder.toResource(match[1])); // TODO@Michel TODO@Isidor (https://github.com/Microsoft/vscode/issues/29190) - } catch (e) { } - } - if (!resource) { match = pattern.exec(text); continue; From 0088fba3c6ef78b8a5b13c6d1748b873f9a8bf84 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 22 Sep 2017 16:58:20 +0200 Subject: [PATCH 226/281] move node cached data clean up into shared process --- .../electron-browser/contrib/contributions.ts | 13 +++ .../contrib/nodeCachedDataCleaner.ts | 89 +++++++++++++++++++ .../electron-browser/sharedProcessMain.ts | 3 + .../electron-browser/nodeCachedDataManager.ts | 79 +--------------- 4 files changed, 107 insertions(+), 77 deletions(-) create mode 100644 src/vs/code/electron-browser/contrib/contributions.ts create mode 100644 src/vs/code/electron-browser/contrib/nodeCachedDataCleaner.ts diff --git a/src/vs/code/electron-browser/contrib/contributions.ts b/src/vs/code/electron-browser/contrib/contributions.ts new file mode 100644 index 00000000000..acb31a18450 --- /dev/null +++ b/src/vs/code/electron-browser/contrib/contributions.ts @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + + +import { NodeCachedDataCleaner } from 'vs/code/electron-browser/contrib/nodeCachedDataCleaner'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; + +export function createSharedProcessContributions(service: IInstantiationService): void { + service.createInstance(NodeCachedDataCleaner); +} diff --git a/src/vs/code/electron-browser/contrib/nodeCachedDataCleaner.ts b/src/vs/code/electron-browser/contrib/nodeCachedDataCleaner.ts new file mode 100644 index 00000000000..d4d74b8971c --- /dev/null +++ b/src/vs/code/electron-browser/contrib/nodeCachedDataCleaner.ts @@ -0,0 +1,89 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { join, basename, dirname } from 'path'; +import { readdir, rimraf, stat } from 'vs/base/node/pfs'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import product from 'vs/platform/node/product'; + +declare type OnNodeCachedDataArgs = [{ errorCode: string, path: string, detail?: string }, { path: string, length: number }]; +declare const MonacoEnvironment: { onNodeCachedData: OnNodeCachedDataArgs[] }; + +export class NodeCachedDataCleaner { + + private static _DataMaxAge = product.nameLong.indexOf('Insiders') >= 0 + ? 1000 * 60 * 60 * 24 * 7 // roughly 1 week + : 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months + + private _disposables: IDisposable[] = []; + + constructor( + @IEnvironmentService private readonly _environmentService: IEnvironmentService + ) { + this._manageCachedDataSoon(); + } + + dispose(): void { + this._disposables = dispose(this._disposables); + } + + private _manageCachedDataSoon(): void { + // Cached data is stored as user data and we run a cleanup task everytime + // the editor starts. The strategy is to delete all files that are older than + // 3 months (1 week respectively) + if (!this._environmentService.nodeCachedDataDir) { + return; + } + + // The folder which contains folders of cached data. Each of these folder is per + // version + const nodeCachedDataRootDir = dirname(this._environmentService.nodeCachedDataDir); + const nodeCachedDataCurrent = basename(this._environmentService.nodeCachedDataDir); + + let handle = setTimeout(() => { + handle = undefined; + + readdir(nodeCachedDataRootDir).then(entries => { + + const now = Date.now(); + const deletes: TPromise[] = []; + + entries.forEach(entry => { + // name check + // * name is a git commit id (40 hex characters) + // * not the current cached data folder + if (entry.match(/^[a-f0-9]{40}$/i) && entry !== nodeCachedDataCurrent) { + + const path = join(nodeCachedDataRootDir, entry); + deletes.push(stat(path).then(stats => { + // stat check + // * only directories + // * only when old enough + if (stats.isDirectory()) { + const diff = now - stats.mtime.getTime(); + if (diff > NodeCachedDataCleaner._DataMaxAge) { + return rimraf(path); + } + } + return undefined; + })); + } + }); + + return TPromise.join(deletes); + + }).done(undefined, onUnexpectedError); + + }, 30 * 1000); + + this._disposables.push({ + dispose() { clearTimeout(handle); } + }); + } +} diff --git a/src/vs/code/electron-browser/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcessMain.ts index 3e7149a8103..f83a1b2669e 100644 --- a/src/vs/code/electron-browser/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcessMain.ts @@ -35,6 +35,7 @@ import { WindowsChannelClient } from 'vs/platform/windows/common/windowsIpc'; import { ipcRenderer } from 'electron'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { StorageService, inMemoryLocalStorageInstance } from 'vs/platform/storage/common/storageService'; +import { createSharedProcessContributions } from 'vs/code/electron-browser/contrib/contributions'; interface ISharedProcessInitData { sharedIPCHandle: string; @@ -132,6 +133,8 @@ function main(server: Server, initData: ISharedProcessInitData): void { // clean up deprecated extensions (extensionManagementService as ExtensionManagementService).removeDeprecatedExtensions(); + + createSharedProcessContributions(instantiationService2); }); }); } diff --git a/src/vs/workbench/electron-browser/nodeCachedDataManager.ts b/src/vs/workbench/electron-browser/nodeCachedDataManager.ts index 76a4a17982a..c21787e2e28 100644 --- a/src/vs/workbench/electron-browser/nodeCachedDataManager.ts +++ b/src/vs/workbench/electron-browser/nodeCachedDataManager.ts @@ -4,41 +4,21 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { onUnexpectedError } from 'vs/base/common/errors'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { join, basename, dirname } from 'path'; -import { readdir, rimraf, stat } from 'vs/base/node/pfs'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { basename } from 'path'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import product from 'vs/platform/node/product'; declare type OnNodeCachedDataArgs = [{ errorCode: string, path: string, detail?: string }, { path: string, length: number }]; declare const MonacoEnvironment: { onNodeCachedData: OnNodeCachedDataArgs[] }; export class NodeCachedDataManager { - private static _DataMaxAge = product.nameLong.indexOf('Insiders') >= 0 - ? 1000 * 60 * 60 * 24 * 7 // roughly 1 week - : 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months - - private _telemetryService: ITelemetryService; - private _environmentService: IEnvironmentService; - private _disposables: IDisposable[] = []; + private readonly _telemetryService: ITelemetryService; constructor( @ITelemetryService telemetryService: ITelemetryService, - @IEnvironmentService environmentService: IEnvironmentService ) { this._telemetryService = telemetryService; - this._environmentService = environmentService; - this._handleCachedDataInfo(); - this._manageCachedDataSoon(); - } - - dispose(): void { - this._disposables = dispose(this._disposables); } private _handleCachedDataInfo(): void { @@ -69,59 +49,4 @@ export class NodeCachedDataManager { global.require.config({ onNodeCachedData: undefined }); delete MonacoEnvironment.onNodeCachedData; } - - private _manageCachedDataSoon(): void { - // Cached data is stored as user data and we run a cleanup task everytime - // the editor starts. The strategy is to delete all files that are older than - // 3 months (1 week respectively) - - if (!this._environmentService.nodeCachedDataDir) { - return; - } - - // The folder which contains folders of cached data. Each of these folder is per - // version - const nodeCachedDataRootDir = dirname(this._environmentService.nodeCachedDataDir); - const nodeCachedDataCurrent = basename(this._environmentService.nodeCachedDataDir); - - let handle = setTimeout(() => { - handle = undefined; - - readdir(nodeCachedDataRootDir).then(entries => { - - const now = Date.now(); - const deletes: TPromise[] = []; - - entries.forEach(entry => { - // name check - // * name is a git commit id (40 hex characters) - // * not the current cached data folder - if (entry.match(/^[a-f0-9]{40}$/i) && entry !== nodeCachedDataCurrent) { - - const path = join(nodeCachedDataRootDir, entry); - deletes.push(stat(path).then(stats => { - // stat check - // * only directories - // * only when old enough - if (stats.isDirectory()) { - const diff = now - stats.mtime.getTime(); - if (diff > NodeCachedDataManager._DataMaxAge) { - return rimraf(path); - } - } - return undefined; - })); - } - }); - - return TPromise.join(deletes); - - }).done(undefined, onUnexpectedError); - - }, 30 * 1000); - - this._disposables.push({ - dispose() { clearTimeout(handle); } - }); - } } From e59d629e7dee18b30e6fd25e2001e842983db601 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 22 Sep 2017 17:29:34 +0200 Subject: [PATCH 227/281] Add a word or two about the query-argument, #34605 --- src/vs/vscode.d.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 1b3ebaedbfc..eb7385fd93f 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2186,6 +2186,11 @@ declare module 'vscode' { * skip the [location](#SymbolInformation.location) of symbols and implement `resolveWorkspaceSymbol` to do that * later. * + * The `query`-parameter should be interpreted in a *relaxed way* as the editor will apply its own highlighting + * and scoring on the results. A good rule of thumb is to match case-insensitive and to simply check that the + * characters of *query* appear in their order in a candidate symbol. Don't use prefix, substring, or similar + * strict matching. + * * @param query A non-empty query string. * @param token A cancellation token. * @return An array of document highlights or a thenable that resolves to such. The lack of a result can be From 44df02a3e2d0e1d56d9cd8d6670b650f295f43f0 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 22 Sep 2017 17:31:05 +0200 Subject: [PATCH 228/281] fix bogus compare of resource --- .../workbench/parts/files/common/editors/fileEditorTracker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts index 419a6b49c96..d748379eac4 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts @@ -241,8 +241,8 @@ export class FileEditorTracker implements IWorkbenchContribution { for (let i = 0; i < editors.length; i++) { const editor = editors[i]; if (editor && editor.position === stacks.positionOfGroup(group)) { - const resource = toResource(editor.input, { filter: 'file' }); - if (resource && paths.isEqual(resource.fsPath, resource.fsPath)) { + const editorResource = toResource(editor.input, { filter: 'file' }); + if (editorResource && paths.isEqual(resource.fsPath, editorResource.fsPath)) { const control = editor.getControl(); if (isCommonCodeEditor(control)) { return control.saveViewState(); From d5275987a14e9eba634d101dcbc5ef901f186a11 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 22 Sep 2017 17:37:15 +0200 Subject: [PATCH 229/281] :lipstick: --- .../workbench/parts/files/common/editors/fileEditorTracker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts index d748379eac4..42afd62358c 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts @@ -241,8 +241,8 @@ export class FileEditorTracker implements IWorkbenchContribution { for (let i = 0; i < editors.length; i++) { const editor = editors[i]; if (editor && editor.position === stacks.positionOfGroup(group)) { - const editorResource = toResource(editor.input, { filter: 'file' }); - if (editorResource && paths.isEqual(resource.fsPath, editorResource.fsPath)) { + const editorResource = toResource(editor.input); + if (editorResource && resource.toString() === editorResource.toString()) { const control = editor.getControl(); if (isCommonCodeEditor(control)) { return control.saveViewState(); From 3b06706a32758c3b13fc59294c7b5871cd57002e Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 22 Sep 2017 16:45:00 +0200 Subject: [PATCH 230/281] smoke: dont use monaco-editor.focused --- test/smoke/package.json | 5 +-- test/smoke/src/areas/css/css.test.ts | 1 - test/smoke/src/areas/debug/debug.ts | 4 +- test/smoke/src/areas/editor/editor.ts | 43 ++++++++++++++----- .../src/areas/workbench/data-loss.test.ts | 8 ++-- .../areas/workbench/data-migration.test.ts | 7 +-- test/smoke/src/areas/workbench/workbench.ts | 7 +-- test/smoke/src/spectron/client.ts | 8 +++- 8 files changed, 52 insertions(+), 31 deletions(-) diff --git a/test/smoke/package.json b/test/smoke/package.json index 99c529813c7..95b3ba9dc95 100644 --- a/test/smoke/package.json +++ b/test/smoke/package.json @@ -24,7 +24,6 @@ "spectron": "~3.6.4", "strip-json-comments": "^2.0.1", "tmp": "0.0.33", - "typescript": "^2.2.2", - "vscode-uri": "^1.0.1" + "typescript": "^2.2.2" } -} +} \ No newline at end of file diff --git a/test/smoke/src/areas/css/css.test.ts b/test/smoke/src/areas/css/css.test.ts index 3d249c5adc1..c13b2afdd83 100644 --- a/test/smoke/src/areas/css/css.test.ts +++ b/test/smoke/src/areas/css/css.test.ts @@ -23,7 +23,6 @@ describe('CSS', () => { it('verifies warnings for the empty rule', async () => { await app.workbench.quickopen.openFile('style.css'); - await app.client.waitForElement(`.monaco-editor.focused`); await app.client.type('.foo{}'); let warning = await app.client.waitForElement(Problems.getSelectorInEditor(ProblemSeverity.WARNING)); diff --git a/test/smoke/src/areas/debug/debug.ts b/test/smoke/src/areas/debug/debug.ts index e16e3a51bc5..e500d129446 100644 --- a/test/smoke/src/areas/debug/debug.ts +++ b/test/smoke/src/areas/debug/debug.ts @@ -26,7 +26,7 @@ const VARIABLE = `${VIEWLET} .debug-variables .monaco-tree-row .expression`; const CONSOLE_OUTPUT = `.repl .output.expression`; const CONSOLE_INPUT_OUTPUT = `.repl .input-output-pair .output.expression .value`; -const REPL_FOCUSED = '.repl-input-wrapper .monaco-editor.focused'; +const REPL_FOCUSED = '.repl-input-wrapper .monaco-editor textarea'; export interface IStackFrame { id: string; @@ -113,7 +113,7 @@ export class Debug extends Viewlet { async waitForReplCommand(text: string, accept: (result: string) => boolean): Promise { await this.spectron.workbench.quickopen.runCommand('Debug: Focus Debug Console'); - await this.spectron.client.waitForElement(REPL_FOCUSED); + await this.spectron.client.waitForActiveElement(REPL_FOCUSED); await this.spectron.client.type(text); await this.spectron.client.waitForElement(CONSOLE_INPUT_OUTPUT); await this.spectron.client.waitFor(async () => { diff --git a/test/smoke/src/areas/editor/editor.ts b/test/smoke/src/areas/editor/editor.ts index e37d916cedf..1ff35896a1d 100644 --- a/test/smoke/src/areas/editor/editor.ts +++ b/test/smoke/src/areas/editor/editor.ts @@ -18,11 +18,6 @@ export class Editor { constructor(private spectron: SpectronApplication) { } - public async getEditorFirstLineText(): Promise { - const result = await this.spectron.client.waitForText('.monaco-editor.focused .view-lines span span:nth-child(1)'); - return Array.isArray(result) ? result.join() : result; - } - public async getEditorVisibleText(): Promise { return await this.spectron.client.getText('.view-lines'); } @@ -102,11 +97,39 @@ export class Editor { await this.spectron.client.waitAndClick(selector); } - public async getFocusedEditorUri(): Promise { - return this.spectron.webclient.selectorExecute(`.editor-container .monaco-editor.focused`, (elements: HTMLElement[]) => { - elements = Array.isArray(elements) ? elements : [elements]; - return elements[0].getAttribute('data-uri'); - }); + public async waitForActiveEditor(filename: string): Promise { + const selector = `.editor-container .monaco-editor[data-uri$="${filename}"] textarea`; + return this.spectron.client.waitForActiveElement(selector); + } + + public async waitForActiveEditorFirstLineText(filename: string): Promise { + const selector = `.editor-container .monaco-editor[data-uri$="${filename}"] textarea`; + const result = await this.spectron.client.waitFor( + () => this.spectron.client.spectron.client.execute(s => { + if (!document.activeElement.matches(s)) { + return undefined; + } + + let element: Element | null = document.activeElement; + while (element && !/monaco-editor/.test(element.className) && element !== document.body) { + element = element.parentElement; + } + + if (element && /monaco-editor/.test(element.className)) { + const firstLine = element.querySelector('.view-lines span span:nth-child(1)'); + + if (firstLine) { + return (firstLine.textContent || '').replace(/\u00a0/g, ' '); // DAMN + } + } + + return undefined; + }, selector), + r => typeof r.value === 'string', + `wait for active editor first line: ${selector}` + ); + + return result.value; } private async getClassSelectors(term: string, viewline: number): Promise { diff --git a/test/smoke/src/areas/workbench/data-loss.test.ts b/test/smoke/src/areas/workbench/data-loss.test.ts index 62c4fde7667..aa33283753e 100644 --- a/test/smoke/src/areas/workbench/data-loss.test.ts +++ b/test/smoke/src/areas/workbench/data-loss.test.ts @@ -27,13 +27,13 @@ describe('Dataloss', () => { await app.workbench.waitForActiveTab(fileName, true); await app.screenCapturer.capture(`${fileName} after reload`); - let actual = await app.workbench.editor.getEditorFirstLineText(); - assert.ok(actual.startsWith(textToType), `${actual} did not start with ${textToType}`); + let actual = await app.workbench.editor.waitForActiveEditorFirstLineText(fileName); + assert.ok(actual.startsWith(textToType), `'${actual}' did not start with '${textToType}'`); await app.workbench.waitForTab(untitled, true); await app.workbench.selectTab('Untitled-1', true); await app.screenCapturer.capture('Untitled file after reload'); - actual = await app.workbench.editor.getEditorFirstLineText(); - assert.ok(actual.startsWith(textToTypeInUntitled), `${actual} did not start with ${textToTypeInUntitled}`); + actual = await app.workbench.editor.waitForActiveEditorFirstLineText('Untitled-1'); + assert.ok(actual.startsWith(textToTypeInUntitled), `'${actual}' did not start with '${textToTypeInUntitled}'`); }); }); \ No newline at end of file diff --git a/test/smoke/src/areas/workbench/data-migration.test.ts b/test/smoke/src/areas/workbench/data-migration.test.ts index 4156ad0501a..3e2c44674f7 100644 --- a/test/smoke/src/areas/workbench/data-migration.test.ts +++ b/test/smoke/src/areas/workbench/data-migration.test.ts @@ -37,7 +37,7 @@ describe('Data Migration', () => { app.screenCapturer.testName = 'Untitled is restorted'; assert.ok(await app.workbench.waitForActiveTab('Untitled-1', true), `Untitled-1 tab is not present after migration.`); - const actual = await app.workbench.editor.getEditorFirstLineText(); + const actual = await app.workbench.editor.waitForActiveEditorFirstLineText('Untitled-1'); await app.screenCapturer.capture('Untitled file text'); assert.ok(actual.startsWith(textToType), `${actual} did not start with ${textToType}`); }); @@ -65,8 +65,9 @@ describe('Data Migration', () => { await app.start('Data Migration'); app.screenCapturer.testName = 'Newly created dirty file is restorted'; - assert.ok(await app.workbench.waitForActiveTab(fileName.split('/')[1]), `Untitled-1 tab is not present after migration.`); - const actual = await app.workbench.editor.getEditorFirstLineText(); + const filename = fileName.split('/')[1]; + assert.ok(await app.workbench.waitForActiveTab(filename), `Untitled-1 tab is not present after migration.`); + const actual = await app.workbench.editor.waitForActiveEditorFirstLineText(filename); await app.screenCapturer.capture(fileName + ' text'); assert.ok(actual.startsWith(firstTextPart.concat(secondTextPart)), `${actual} did not start with ${firstTextPart.concat(secondTextPart)}`); diff --git a/test/smoke/src/areas/workbench/workbench.ts b/test/smoke/src/areas/workbench/workbench.ts index 1d04da84db5..7bbe09c719f 100644 --- a/test/smoke/src/areas/workbench/workbench.ts +++ b/test/smoke/src/areas/workbench/workbench.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as path from 'path'; -import URI from 'vscode-uri'; import { SpectronApplication } from '../../spectron/application'; import { Explorer } from '../explorer/explorer'; import { ActivityBar } from '../activitybar/activityBar'; @@ -70,10 +68,7 @@ export class Workbench { public async waitForEditorFocus(fileName: string, untitled: boolean = false): Promise { await this.waitForActiveTab(fileName); - await this.spectron.client.waitFor(async () => { - const uri = await this.editor.getFocusedEditorUri(); - return uri && path.basename(URI.parse(uri).path) === fileName; - }, void 0, `Wait for editor with ${fileName} is focussed`); + await this.editor.waitForActiveEditor(fileName); } public async waitForActiveTab(fileName: string, isDirty: boolean = false): Promise { diff --git a/test/smoke/src/spectron/client.ts b/test/smoke/src/spectron/client.ts index 72697d5d903..7868d48c5ef 100644 --- a/test/smoke/src/spectron/client.ts +++ b/test/smoke/src/spectron/client.ts @@ -101,8 +101,12 @@ export class SpectronClient { .then(result => result.value); } - public async waitForActiveElement(accept: (result: Element | undefined) => boolean = result => !!result): Promise { - return this.waitFor>(() => this.spectron.client.elementActive(), result => accept(result ? result.value : void 0), `elementActive`); + public async waitForActiveElement(selector: string): Promise { + return this.waitFor( + () => this.spectron.client.execute(s => document.activeElement.matches(s), selector), + r => r.value, + `wait for active element: ${selector}` + ); } public async waitForAttribute(selector: string, attribute: string, accept: (result: string) => boolean = result => !!result): Promise { From d1ebe12440540d1867f46b0ed241e1916d4770c0 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 22 Sep 2017 16:47:02 +0200 Subject: [PATCH 231/281] smoke: dont use monaco-editor.focused --- test/smoke/src/areas/preferences/settings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/smoke/src/areas/preferences/settings.ts b/test/smoke/src/areas/preferences/settings.ts index 8e62c210e12..6d0cc980a75 100644 --- a/test/smoke/src/areas/preferences/settings.ts +++ b/test/smoke/src/areas/preferences/settings.ts @@ -24,7 +24,7 @@ export class SettingsEditor { public async focusEditableSettings(): Promise { await this.spectron.client.keys(['ArrowDown', 'NULL'], false); - await this.spectron.client.waitForElement(`.editable-preferences-editor-container .monaco-editor.focused`); + await this.spectron.client.waitForActiveElement('.editable-preferences-editor-container .monaco-editor textarea'); await this.spectron.client.keys(['ArrowRight', 'NULL'], false); } From f89f492a5e937ed04b3d387de440e6a8b9d60176 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 22 Sep 2017 17:15:07 +0200 Subject: [PATCH 232/281] smoke: dont use :focus selector --- .../src/areas/multiroot/multiroot.test.ts | 3 +- test/smoke/src/areas/preferences/settings.ts | 9 ++--- test/smoke/src/areas/quickopen/quickopen.ts | 38 +++++++++---------- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/test/smoke/src/areas/multiroot/multiroot.test.ts b/test/smoke/src/areas/multiroot/multiroot.test.ts index 0d4225c9e48..56a1c9d483b 100644 --- a/test/smoke/src/areas/multiroot/multiroot.test.ts +++ b/test/smoke/src/areas/multiroot/multiroot.test.ts @@ -19,10 +19,9 @@ describe('Multi Root', () => { it('shows results from all folders', async function () { await app.workbench.quickopen.openQuickOpen(); - await app.workbench.quickopen.type('*.*'); - await app.workbench.quickopen.waitForQuickOpenElements(6); + await app.workbench.quickopen.closeQuickOpen(); }); it('shows workspace name in title', async function () { diff --git a/test/smoke/src/areas/preferences/settings.ts b/test/smoke/src/areas/preferences/settings.ts index 6d0cc980a75..094fda6a9a0 100644 --- a/test/smoke/src/areas/preferences/settings.ts +++ b/test/smoke/src/areas/preferences/settings.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { SpectronApplication } from '../../spectron/application'; -import { Element } from 'webdriverio'; export enum ActivityBarPosition { LEFT = 0, @@ -17,18 +16,18 @@ export class SettingsEditor { // noop } - public async openUserSettings(): Promise { + async openUserSettings(): Promise { await this.spectron.command('workbench.action.openGlobalSettings'); - return this.spectron.client.waitForElement('.settings-search-input input:focus'); + await this.spectron.client.waitForActiveElement('.settings-search-input input'); } - public async focusEditableSettings(): Promise { + async focusEditableSettings(): Promise { await this.spectron.client.keys(['ArrowDown', 'NULL'], false); await this.spectron.client.waitForActiveElement('.editable-preferences-editor-container .monaco-editor textarea'); await this.spectron.client.keys(['ArrowRight', 'NULL'], false); } - public async addUserSetting(setting: string, value: string): Promise { + async addUserSetting(setting: string, value: string): Promise { await this.openUserSettings(); // await this.spectron.wait(1); diff --git a/test/smoke/src/areas/quickopen/quickopen.ts b/test/smoke/src/areas/quickopen/quickopen.ts index a4e6ac85288..3958af57349 100644 --- a/test/smoke/src/areas/quickopen/quickopen.ts +++ b/test/smoke/src/areas/quickopen/quickopen.ts @@ -10,46 +10,41 @@ export class QuickOpen { static QUICK_OPEN_HIDDEN = 'div.quick-open-widget[aria-hidden="true"]'; static QUICK_OPEN = 'div.quick-open-widget[aria-hidden="false"]'; - static QUICK_OPEN_FOCUSSED_INPUT = `${QuickOpen.QUICK_OPEN} .quick-open-input input:focus`; + static QUICK_OPEN_INPUT = `${QuickOpen.QUICK_OPEN} .quick-open-input input`; static QUICK_OPEN_FOCUSED_ELEMENT = `${QuickOpen.QUICK_OPEN} .quick-open-tree .monaco-tree-row.focused .monaco-highlighted-label`; static QUICK_OPEN_ENTRY_SELECTOR = 'div[aria-label="Quick Picker"] .monaco-tree-rows.show-twisties .monaco-tree-row .quick-open-entry'; constructor(readonly spectron: SpectronApplication) { } - public async openQuickOpen(): Promise { + async openQuickOpen(): Promise { await this.spectron.command('workbench.action.quickOpen'); await this.waitForQuickOpenOpened(); } - public async openCommandPallette(): Promise { + async openCommandPallette(): Promise { await this.spectron.command('workbench.action.showCommands'); await this.waitForQuickOpenOpened(); - - // we gotta wait 50 milliseconds due to https://github.com/Microsoft/vscode/blob/master/src/vs/platform/list/browser/listService.ts#L59 - await new Promise(c => setTimeout(c, 50)); } - public async closeQuickOpen(): Promise { + async closeQuickOpen(): Promise { await this.spectron.command('workbench.action.closeQuickOpen'); await this.waitForQuickOpenClosed(); } - public async type(text: string): Promise { - let prefix = await this.spectron.client.getValue(QuickOpen.QUICK_OPEN_FOCUSSED_INPUT); + async type(text: string): Promise { await this.spectron.client.type(text); - await this.spectron.client.waitForValue(QuickOpen.QUICK_OPEN_FOCUSSED_INPUT, prefix + text); } - public async getQuickOpenElements(): Promise { + async getQuickOpenElements(): Promise { return this.spectron.client.waitForElements(QuickOpen.QUICK_OPEN_ENTRY_SELECTOR); } - public async waitForQuickOpenElements(count: number): Promise { + async waitForQuickOpenElements(count: number): Promise { return this.spectron.client.waitForElements(QuickOpen.QUICK_OPEN_ENTRY_SELECTOR, elements => elements && elements.length === count); } - public async openFile(fileName: string): Promise { + async openFile(fileName: string): Promise { await this.openQuickOpen(); await this.type(fileName); @@ -59,7 +54,7 @@ export class QuickOpen { await this.spectron.workbench.waitForEditorFocus(fileName); } - public async runCommand(commandText: string): Promise { + async runCommand(commandText: string): Promise { await this.openCommandPallette(); // type the text @@ -72,21 +67,24 @@ export class QuickOpen { await this.spectron.client.waitAndClick(QuickOpen.QUICK_OPEN_FOCUSED_ELEMENT); } - public waitForQuickOpenOpened(): Promise { - return this.spectron.client.waitForElement(QuickOpen.QUICK_OPEN_FOCUSSED_INPUT); + async waitForQuickOpenOpened(): Promise { + await this.spectron.client.waitForActiveElement(QuickOpen.QUICK_OPEN_INPUT); + + // we gotta wait 50 milliseconds due to https://github.com/Microsoft/vscode/blob/master/src/vs/platform/list/browser/listService.ts#L59 + await new Promise(c => setTimeout(c, 50)); } - public waitForQuickOpenClosed(): Promise { - return this.spectron.client.waitForElement(QuickOpen.QUICK_OPEN_HIDDEN); + private async waitForQuickOpenClosed(): Promise { + await this.spectron.client.waitForElement(QuickOpen.QUICK_OPEN_HIDDEN); } - public async submit(text: string): Promise { + async submit(text: string): Promise { await this.spectron.client.type(text); await this.spectron.client.keys(['Enter', 'NULL']); await this.waitForQuickOpenClosed(); } - public async selectQuickOpenElement(index: number): Promise { + async selectQuickOpenElement(index: number): Promise { await this.waitForQuickOpenOpened(); for (let from = 0; from < index; from++) { await this.spectron.client.keys(['ArrowDown', 'NULL']); From 89f671a4db3e1f553fbc14c0962553894fecf4a7 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 22 Sep 2017 17:29:25 +0200 Subject: [PATCH 233/281] smoke: add tracing message --- test/smoke/src/areas/debug/debug.test.ts | 16 ++++++++-------- test/smoke/src/areas/debug/debug.ts | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/test/smoke/src/areas/debug/debug.test.ts b/test/smoke/src/areas/debug/debug.test.ts index a6fcf6c9bb2..05f5c3c983c 100644 --- a/test/smoke/src/areas/debug/debug.test.ts +++ b/test/smoke/src/areas/debug/debug.test.ts @@ -74,7 +74,7 @@ describe('Debug', () => { await new Promise((c, e) => { const request = http.get(`http://localhost:${port}`); request.on('error', e); - app.workbench.debug.waitForStackFrame(sf => sf.name === 'index.js' && sf.lineNumber === 6).then(c, e); + app.workbench.debug.waitForStackFrame(sf => sf.name === 'index.js' && sf.lineNumber === 6, 'looking for index.js and line 6').then(c, e); }); await app.screenCapturer.capture('debugging is paused'); @@ -83,13 +83,13 @@ describe('Debug', () => { it('focus stack frames and variables', async function () { await app.client.waitFor(() => app.workbench.debug.getLocalVariableCount(), c => c === 4, 'there should be 4 local variables'); - await app.workbench.debug.focusStackFrame('layer.js'); + await app.workbench.debug.focusStackFrame('layer.js', 'looking for layer.js'); await app.client.waitFor(() => app.workbench.debug.getLocalVariableCount(), c => c === 5, 'there should be 5 local variables'); - await app.workbench.debug.focusStackFrame('route.js'); + await app.workbench.debug.focusStackFrame('route.js', 'looking for route.js'); await app.client.waitFor(() => app.workbench.debug.getLocalVariableCount(), c => c === 3, 'there should be 3 local variables'); - await app.workbench.debug.focusStackFrame('index.js'); + await app.workbench.debug.focusStackFrame('index.js', 'looking for index.js'); await app.client.waitFor(() => app.workbench.debug.getLocalVariableCount(), c => c === 4, 'there should be 4 local variables'); }); @@ -97,15 +97,15 @@ describe('Debug', () => { await app.workbench.debug.stepIn(); await app.screenCapturer.capture('debugging has stepped in'); - const first = await app.workbench.debug.waitForStackFrame(sf => sf.name === 'response.js'); + const first = await app.workbench.debug.waitForStackFrame(sf => sf.name === 'response.js', 'looking for response.js'); await app.workbench.debug.stepOver(); await app.screenCapturer.capture('debugging has stepped over'); - await app.workbench.debug.waitForStackFrame(sf => sf.name === 'response.js' && sf.lineNumber === first.lineNumber + 1); + await app.workbench.debug.waitForStackFrame(sf => sf.name === 'response.js' && sf.lineNumber === first.lineNumber + 1, `looking for response.js and line ${first.lineNumber + 1}`); await app.workbench.debug.stepOut(); await app.screenCapturer.capture('debugging has stepped out'); - await app.workbench.debug.waitForStackFrame(sf => sf.name === 'index.js' && sf.lineNumber === 7); + await app.workbench.debug.waitForStackFrame(sf => sf.name === 'index.js' && sf.lineNumber === 7, `looking for index.js and line 7`); }); it('continue', async function () { @@ -115,7 +115,7 @@ describe('Debug', () => { await new Promise((c, e) => { const request = http.get(`http://localhost:${port}`); request.on('error', e); - app.workbench.debug.waitForStackFrame(sf => sf.name === 'index.js' && sf.lineNumber === 6).then(c, e); + app.workbench.debug.waitForStackFrame(sf => sf.name === 'index.js' && sf.lineNumber === 6, `looking for index.js and line 6`).then(c, e); }); await app.screenCapturer.capture('debugging is paused'); diff --git a/test/smoke/src/areas/debug/debug.ts b/test/smoke/src/areas/debug/debug.ts index e500d129446..ae2770f5260 100644 --- a/test/smoke/src/areas/debug/debug.ts +++ b/test/smoke/src/areas/debug/debug.ts @@ -94,19 +94,19 @@ export class Debug extends Viewlet { await this.spectron.client.waitForElement(NOT_DEBUG_STATUS_BAR); } - async waitForStackFrame(func: (stackFrame: IStackFrame) => boolean): Promise { + async waitForStackFrame(func: (stackFrame: IStackFrame) => boolean, message: string): Promise { return await this.spectron.client.waitFor(async () => { const stackFrames = await this.getStackFrames(); return stackFrames.filter(func)[0]; - }, void 0, 'Waiting for Stack Frame'); + }, void 0, `Waiting for Stack Frame: ${message}`); } async waitForStackFrameLength(length: number): Promise { return await this.spectron.client.waitFor(() => this.getStackFrames(), stackFrames => stackFrames.length === length); } - async focusStackFrame(name: string): Promise { - const stackFrame = await this.waitForStackFrame(sf => sf.name === name); + async focusStackFrame(name: string, message: string): Promise { + const stackFrame = await this.waitForStackFrame(sf => sf.name === name, message); await this.spectron.client.spectron.client.elementIdClick(stackFrame.id); await this.spectron.workbench.waitForTab(name); } From 77288dfe00d06e1f9d649fcdc17b1c681b610730 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 22 Sep 2017 17:45:08 +0200 Subject: [PATCH 234/281] smoke: use debug inspector protocol --- test/smoke/src/areas/debug/debug.test.ts | 22 ++++++++++++++-------- test/smoke/src/areas/editor/editor.ts | 9 +++++---- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/test/smoke/src/areas/debug/debug.test.ts b/test/smoke/src/areas/debug/debug.test.ts index 05f5c3c983c..fcd2648fe98 100644 --- a/test/smoke/src/areas/debug/debug.test.ts +++ b/test/smoke/src/areas/debug/debug.test.ts @@ -9,7 +9,7 @@ import * as os from 'os'; import * as path from 'path'; import * as fs from 'fs'; import * as stripJsonComments from 'strip-json-comments'; -import { SpectronApplication, VSCODE_BUILD, EXTENSIONS_DIR, findFreePort } from '../../spectron/application'; +import { SpectronApplication, VSCODE_BUILD, EXTENSIONS_DIR, findFreePort, WORKSPACE_PATH } from '../../spectron/application'; describe('Debug', () => { let app: SpectronApplication = new SpectronApplication(); @@ -48,16 +48,22 @@ describe('Debug', () => { await app.workbench.debug.openDebugViewlet(); await app.workbench.openFile('app.js'); await app.workbench.debug.configure(); - await app.screenCapturer.capture('launch.json file'); - const content = await app.workbench.editor.getEditorVisibleText(); - const json = JSON.parse(stripJsonComments(content)); - assert.equal(json.configurations[0].request, 'launch'); - assert.equal(json.configurations[0].type, 'node'); + const launchJsonPath = path.join(WORKSPACE_PATH, '.vscode', 'launch.json'); + const content = fs.readFileSync(launchJsonPath, 'utf8'); + const config = JSON.parse(stripJsonComments(content)); + config.configurations[0].protocol = 'inspector'; + fs.writeFileSync(launchJsonPath, JSON.stringify(config, undefined, 4), 'utf8'); + + await app.workbench.editor.waitForEditorContents('launch.json', contents => /"protocol": "inspector"/.test(contents)); + await app.screenCapturer.capture('launch.json file'); + + assert.equal(config.configurations[0].request, 'launch'); + assert.equal(config.configurations[0].type, 'node'); if (process.platform === 'win32') { - assert.equal(json.configurations[0].program, '${workspaceFolder}\\bin\\www'); + assert.equal(config.configurations[0].program, '${workspaceFolder}\\bin\\www'); } else { - assert.equal(json.configurations[0].program, '${workspaceFolder}/bin/www'); + assert.equal(config.configurations[0].program, '${workspaceFolder}/bin/www'); } }); diff --git a/test/smoke/src/areas/editor/editor.ts b/test/smoke/src/areas/editor/editor.ts index 1ff35896a1d..ab80a87f55d 100644 --- a/test/smoke/src/areas/editor/editor.ts +++ b/test/smoke/src/areas/editor/editor.ts @@ -18,10 +18,6 @@ export class Editor { constructor(private spectron: SpectronApplication) { } - public async getEditorVisibleText(): Promise { - return await this.spectron.client.getText('.view-lines'); - } - public async openOutline(): Promise { const outline = new QuickOutline(this.spectron); await outline.open(); @@ -97,6 +93,11 @@ export class Editor { await this.spectron.client.waitAndClick(selector); } + public async waitForEditorContents(filename: string, accept: (contents: string) => boolean): Promise { + const selector = `.editor-container .monaco-editor[data-uri$="${filename}"] .view-lines`; + return this.spectron.client.waitForTextContent(selector, undefined, c => accept(c.replace(/\u00a0/g, ' '))); + } + public async waitForActiveEditor(filename: string): Promise { const selector = `.editor-container .monaco-editor[data-uri$="${filename}"] textarea`; return this.spectron.client.waitForActiveElement(selector); From 932b5c2463a7eba11d1e87f51104ec144d437c8b Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 22 Sep 2017 18:16:04 +0200 Subject: [PATCH 235/281] node debug version bumps --- build/gulpfile.vscode.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 890a186c4ea..79136915b76 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -45,8 +45,8 @@ const nodeModules = ['electron', 'original-fs'] // Build const builtInExtensions = [ - { name: 'ms-vscode.node-debug', version: '1.17.8' }, - { name: 'ms-vscode.node-debug2', version: '1.17.2' } + { name: 'ms-vscode.node-debug', version: '1.17.10' }, + { name: 'ms-vscode.node-debug2', version: '1.17.3' } ]; const excludedExtensions = [ From 2cae7c9da05b47c1b8c26b87d14ebb1d25554967 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 22 Sep 2017 11:12:05 -0700 Subject: [PATCH 236/281] Use async in refactor provider --- .../typescript/src/features/refactorProvider.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/extensions/typescript/src/features/refactorProvider.ts b/extensions/typescript/src/features/refactorProvider.ts index 2a461598c42..a17533f4b4b 100644 --- a/extensions/typescript/src/features/refactorProvider.ts +++ b/extensions/typescript/src/features/refactorProvider.ts @@ -87,15 +87,14 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { } private async selectRefactoring(document: TextDocument, file: string, info: Proto.ApplicableRefactorInfo, range: Range): Promise { - return window.showQuickPick(info.actions.map((action): QuickPickItem => ({ + const selected = await window.showQuickPick(info.actions.map((action): QuickPickItem => ({ label: action.name, description: action.description - }))).then(selected => { - if (!selected) { - return false; - } - return this.doRefactoring(document, file, info.name, selected.label, range); - }); + }))); + if (!selected) { + return false; + } + return this.doRefactoring(document, file, info.name, selected.label, range); } private async doRefactoring(document: TextDocument, file: string, refactor: string, action: string, range: Range): Promise { From a7e3513a7bef876eded19459f070406ccb61759c Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 22 Sep 2017 11:14:36 -0700 Subject: [PATCH 237/281] Localize markdown preview title Fixes #34830 --- extensions/markdown/src/extension.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/markdown/src/extension.ts b/extensions/markdown/src/extension.ts index 2d6bf4d1877..b684f8ad743 100644 --- a/extensions/markdown/src/extension.ts +++ b/extensions/markdown/src/extension.ts @@ -253,7 +253,7 @@ function showPreview(cspArbiter: ExtensionContentSecurityPolicyArbiter, uri?: vs const thenable = vscode.commands.executeCommand('vscode.previewHtml', getMarkdownUri(resource), getViewColumn(sideBySide), - `Preview '${path.basename(resource.fsPath)}'`, + localize('previewTitle', 'Preview {0}', path.basename(resource.fsPath)), { allowScripts: true, allowSvgs: cspArbiter.shouldAllowSvgsForResource(resource) From 5ff6747e4d976c7c378f190dbce4ddd2114c5fbc Mon Sep 17 00:00:00 2001 From: Daniel Ye Date: Fri, 22 Sep 2017 12:11:59 -0700 Subject: [PATCH 238/281] 2017-09-22. Merged in translations from Transifex. --- i18n/chs/extensions/css/package.i18n.json | 3 ++ .../src/vs/code/electron-main/menus.i18n.json | 2 -- .../config/commonEditorConfig.i18n.json | 1 + .../platform/environment/node/argv.i18n.json | 1 + .../node/extensionManagementService.i18n.json | 5 +--- .../common/extensionsRegistry.i18n.json | 1 + .../common/colorExtensionPoint.i18n.json | 2 ++ .../actions/workspaceActions.i18n.json | 1 - .../parts/views/panelViewlet.i18n.json | 8 +++++ .../electron-browser/debugService.i18n.json | 1 + .../browser/extensionsActions.i18n.json | 3 +- .../browser/preferencesActions.i18n.json | 1 - .../relauncher.contribution.i18n.json | 4 +-- .../task.contribution.i18n.json | 14 +-------- .../node/configuration.i18n.json | 3 +- .../remoteFileService.i18n.json | 8 +++++ i18n/cht/extensions/css/package.i18n.json | 3 ++ .../src/vs/code/electron-main/menus.i18n.json | 2 -- .../config/commonEditorConfig.i18n.json | 1 + .../node/extensionManagementService.i18n.json | 6 ++-- .../common/extensionsRegistry.i18n.json | 1 + .../common/colorExtensionPoint.i18n.json | 2 ++ .../actions/workspaceActions.i18n.json | 1 - .../parts/views/panelViewlet.i18n.json | 8 +++++ .../browser/extensionsActions.i18n.json | 3 +- .../browser/preferencesActions.i18n.json | 1 - .../relauncher.contribution.i18n.json | 4 +-- .../task.contribution.i18n.json | 14 +-------- .../node/configuration.i18n.json | 3 +- .../remoteFileService.i18n.json | 8 +++++ .../azure-account/out/azure-account.i18n.json | 1 + .../src/vs/code/electron-main/menus.i18n.json | 2 -- .../config/commonEditorConfig.i18n.json | 1 + .../node/extensionManagementService.i18n.json | 5 +--- .../actions/workspaceActions.i18n.json | 1 - .../parts/views/panelViewlet.i18n.json | 8 +++++ .../browser/extensionsActions.i18n.json | 3 +- .../browser/preferencesActions.i18n.json | 1 - .../relauncher.contribution.i18n.json | 4 +-- .../task.contribution.i18n.json | 14 +-------- .../node/configuration.i18n.json | 3 +- .../remoteFileService.i18n.json | 8 +++++ .../src/vs/code/electron-main/menus.i18n.json | 4 +-- .../vs/code/electron-main/windows.i18n.json | 1 + .../menusExtensionPoint.i18n.json | 1 + .../node/extensionManagementService.i18n.json | 6 ++-- .../actions/workspaceActions.i18n.json | 4 +-- .../parts/editor/editorActions.i18n.json | 1 + .../parts/views/panelViewlet.i18n.json | 8 +++++ .../main.contribution.i18n.json | 3 ++ ...guageConfigurationExtensionPoint.i18n.json | 4 ++- .../browser/extensionsActions.i18n.json | 4 +-- .../browser/files.contribution.i18n.json | 2 ++ .../browser/preferencesActions.i18n.json | 1 - .../relauncher.contribution.i18n.json | 4 +-- .../scm/electron-browser/scmViewlet.i18n.json | 1 + .../task.contribution.i18n.json | 29 ++++++++++--------- .../terminalTaskSystem.i18n.json | 1 + .../node/configuration.i18n.json | 9 ++++-- .../remoteFileService.i18n.json | 8 +++++ .../services/files/node/fileService.i18n.json | 1 + i18n/fra/extensions/css/package.i18n.json | 3 ++ .../src/vs/code/electron-main/menus.i18n.json | 6 +++- .../vs/code/electron-main/windows.i18n.json | 2 ++ .../config/commonEditorConfig.i18n.json | 1 + .../menusExtensionPoint.i18n.json | 1 + .../platform/environment/node/argv.i18n.json | 1 + .../node/extensionManagementService.i18n.json | 6 ++-- .../common/extensionsRegistry.i18n.json | 1 + .../common/colorExtensionPoint.i18n.json | 2 ++ .../actions/workspaceActions.i18n.json | 4 +-- .../activitybar/activitybarActions.i18n.json | 1 + .../parts/editor/editorActions.i18n.json | 1 + .../parts/views/panelViewlet.i18n.json | 8 +++++ .../electron-browser/actions.i18n.json | 7 ++++- .../main.contribution.i18n.json | 5 ++++ ...guageConfigurationExtensionPoint.i18n.json | 4 ++- .../electron-browser/debugService.i18n.json | 2 ++ .../browser/extensionEditor.i18n.json | 7 +++++ .../browser/extensionsActions.i18n.json | 4 +-- .../browser/files.contribution.i18n.json | 2 ++ .../files/common/dirtyFilesTracker.i18n.json | 1 + .../browser/preferencesActions.i18n.json | 1 - .../relauncher.contribution.i18n.json | 4 +-- .../scm/electron-browser/scmViewlet.i18n.json | 2 ++ .../electron-browser/insertSnippet.i18n.json | 4 ++- .../snippetsService.i18n.json | 1 + .../task.contribution.i18n.json | 29 ++++++++++--------- .../terminalTaskSystem.i18n.json | 1 + .../terminalActions.i18n.json | 3 +- .../terminalColorRegistry.i18n.json | 1 + .../vs_code_welcome_page.i18n.json | 1 + .../node/configuration.i18n.json | 10 +++++-- .../remoteFileService.i18n.json | 8 +++++ .../services/files/node/fileService.i18n.json | 2 ++ .../src/vs/code/electron-main/menus.i18n.json | 4 +-- .../vs/code/electron-main/windows.i18n.json | 1 + .../menusExtensionPoint.i18n.json | 1 + .../node/extensionManagementService.i18n.json | 6 ++-- .../actions/workspaceActions.i18n.json | 4 +-- .../parts/views/panelViewlet.i18n.json | 8 +++++ ...guageConfigurationExtensionPoint.i18n.json | 3 +- .../browser/extensionsActions.i18n.json | 4 +-- .../browser/preferencesActions.i18n.json | 1 - .../relauncher.contribution.i18n.json | 4 +-- .../scm/electron-browser/scmViewlet.i18n.json | 1 + .../task.contribution.i18n.json | 15 ++-------- .../terminalTaskSystem.i18n.json | 1 + .../node/configuration.i18n.json | 8 +++-- .../remoteFileService.i18n.json | 8 +++++ .../services/files/node/fileService.i18n.json | 1 + .../src/vs/code/electron-main/menus.i18n.json | 2 -- .../node/extensionManagementService.i18n.json | 5 +--- .../actions/workspaceActions.i18n.json | 1 - .../parts/views/panelViewlet.i18n.json | 8 +++++ .../browser/extensionsActions.i18n.json | 3 +- .../browser/preferencesActions.i18n.json | 1 - .../relauncher.contribution.i18n.json | 4 +-- .../task.contribution.i18n.json | 14 +-------- .../node/configuration.i18n.json | 3 +- .../remoteFileService.i18n.json | 8 +++++ i18n/jpn/extensions/css/package.i18n.json | 3 ++ .../jpn/extensions/git/out/commands.i18n.json | 2 +- .../src/vs/code/electron-main/menus.i18n.json | 6 ++-- .../vs/code/electron-main/windows.i18n.json | 2 ++ .../config/commonEditorConfig.i18n.json | 1 + .../platform/environment/node/argv.i18n.json | 2 +- .../node/extensionManagementService.i18n.json | 5 +--- .../actions/workspaceActions.i18n.json | 1 - .../activitybar/activitybarActions.i18n.json | 1 + .../parts/editor/editorActions.i18n.json | 1 + .../parts/views/panelViewlet.i18n.json | 8 +++++ .../electron-browser/actions.i18n.json | 7 ++++- .../main.contribution.i18n.json | 5 ++++ .../electron-browser/debugService.i18n.json | 2 ++ .../browser/extensionEditor.i18n.json | 6 ++++ .../browser/extensionsActions.i18n.json | 3 +- .../browser/files.contribution.i18n.json | 2 ++ .../files/common/dirtyFilesTracker.i18n.json | 1 + .../browser/preferencesActions.i18n.json | 1 - .../relauncher.contribution.i18n.json | 4 +-- .../electron-browser/insertSnippet.i18n.json | 4 ++- .../snippetsService.i18n.json | 1 + .../task.contribution.i18n.json | 15 ++-------- .../terminalActions.i18n.json | 3 +- .../terminalColorRegistry.i18n.json | 1 + .../vs_code_welcome_page.i18n.json | 1 + .../node/configuration.i18n.json | 4 +-- .../remoteFileService.i18n.json | 8 +++++ .../services/files/node/fileService.i18n.json | 2 ++ .../src/vs/code/electron-main/menus.i18n.json | 2 -- .../node/extensionManagementService.i18n.json | 5 +--- .../actions/workspaceActions.i18n.json | 1 - .../parts/views/panelViewlet.i18n.json | 8 +++++ .../browser/extensionsActions.i18n.json | 3 +- .../browser/preferencesActions.i18n.json | 1 - .../relauncher.contribution.i18n.json | 4 +-- .../task.contribution.i18n.json | 14 +-------- .../node/configuration.i18n.json | 3 +- .../remoteFileService.i18n.json | 8 +++++ .../src/vs/code/electron-main/menus.i18n.json | 2 -- .../vs/code/electron-main/windows.i18n.json | 1 + .../menusExtensionPoint.i18n.json | 1 + .../node/extensionManagementService.i18n.json | 6 ++-- .../actions/workspaceActions.i18n.json | 1 - .../parts/views/panelViewlet.i18n.json | 8 +++++ .../browser/extensionsActions.i18n.json | 3 +- .../browser/preferencesActions.i18n.json | 1 - .../relauncher.contribution.i18n.json | 4 +-- .../scm/electron-browser/scmViewlet.i18n.json | 1 - .../task.contribution.i18n.json | 15 ++-------- .../node/configuration.i18n.json | 3 +- .../remoteFileService.i18n.json | 8 +++++ .../services/files/node/fileService.i18n.json | 1 + .../src/vs/code/electron-main/menus.i18n.json | 2 -- .../node/extensionManagementService.i18n.json | 5 +--- .../actions/workspaceActions.i18n.json | 1 - .../parts/views/panelViewlet.i18n.json | 8 +++++ .../browser/extensionsActions.i18n.json | 3 +- .../browser/preferencesActions.i18n.json | 1 - .../relauncher.contribution.i18n.json | 4 +-- .../task.contribution.i18n.json | 14 +-------- .../node/configuration.i18n.json | 3 +- .../remoteFileService.i18n.json | 8 +++++ i18n/trk/extensions/css/package.i18n.json | 3 ++ .../src/vs/code/electron-main/menus.i18n.json | 8 +++-- .../vs/code/electron-main/windows.i18n.json | 2 ++ .../config/commonEditorConfig.i18n.json | 1 + .../menusExtensionPoint.i18n.json | 1 + .../platform/environment/node/argv.i18n.json | 1 + .../node/extensionManagementService.i18n.json | 6 ++-- .../common/extensionsRegistry.i18n.json | 1 + .../common/colorExtensionPoint.i18n.json | 2 ++ .../actions/workspaceActions.i18n.json | 4 +-- .../activitybar/activitybarActions.i18n.json | 1 + .../parts/editor/editorActions.i18n.json | 1 + .../parts/views/panelViewlet.i18n.json | 8 +++++ .../electron-browser/actions.i18n.json | 7 ++++- .../main.contribution.i18n.json | 5 ++++ ...guageConfigurationExtensionPoint.i18n.json | 4 ++- .../electron-browser/debugService.i18n.json | 2 ++ .../browser/extensionEditor.i18n.json | 7 +++++ .../browser/extensionsActions.i18n.json | 4 +-- .../browser/files.contribution.i18n.json | 2 ++ .../files/common/dirtyFilesTracker.i18n.json | 1 + .../browser/preferencesActions.i18n.json | 1 - .../relauncher.contribution.i18n.json | 4 +-- .../scm/electron-browser/scmViewlet.i18n.json | 2 ++ .../electron-browser/insertSnippet.i18n.json | 4 ++- .../snippetsService.i18n.json | 1 + .../task.contribution.i18n.json | 29 ++++++++++--------- .../terminalTaskSystem.i18n.json | 1 + .../terminalActions.i18n.json | 3 +- .../terminalColorRegistry.i18n.json | 1 + .../vs_code_welcome_page.i18n.json | 1 + .../node/configuration.i18n.json | 10 +++++-- .../remoteFileService.i18n.json | 8 +++++ .../services/files/node/fileService.i18n.json | 2 ++ 218 files changed, 547 insertions(+), 359 deletions(-) create mode 100644 i18n/chs/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json create mode 100644 i18n/chs/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json create mode 100644 i18n/cht/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json create mode 100644 i18n/cht/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json create mode 100644 i18n/deu/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json create mode 100644 i18n/deu/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json create mode 100644 i18n/esn/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json create mode 100644 i18n/esn/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json create mode 100644 i18n/fra/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json create mode 100644 i18n/fra/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json create mode 100644 i18n/hun/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json create mode 100644 i18n/hun/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json create mode 100644 i18n/ita/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json create mode 100644 i18n/ita/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json create mode 100644 i18n/jpn/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json create mode 100644 i18n/jpn/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json create mode 100644 i18n/kor/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json create mode 100644 i18n/kor/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json create mode 100644 i18n/ptb/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json create mode 100644 i18n/ptb/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json create mode 100644 i18n/rus/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json create mode 100644 i18n/rus/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json create mode 100644 i18n/trk/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json create mode 100644 i18n/trk/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json diff --git a/i18n/chs/extensions/css/package.i18n.json b/i18n/chs/extensions/css/package.i18n.json index 8f8d582630b..6b34f395c3d 100644 --- a/i18n/chs/extensions/css/package.i18n.json +++ b/i18n/chs/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "参数数量无效", "css.lint.boxModel.desc": "使用边距或边框时,不要使用宽度或高度", "css.lint.compatibleVendorPrefixes.desc": "使用供应商特定前缀时,确保同时包括所有其他供应商特定属性", @@ -25,6 +26,7 @@ "css.trace.server.desc": "跟踪 VS Code 与 CSS 语言服务器之间的通信。", "css.validate.title": "控制 CSS 验证和问题严重性。", "css.validate.desc": "启用或禁用所有验证", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "参数数量无效", "less.lint.boxModel.desc": "使用边距或边框时,不要使用宽度或高度", "less.lint.compatibleVendorPrefixes.desc": "使用供应商特定前缀时,确保同时包括所有其他供应商特定属性", @@ -45,6 +47,7 @@ "less.lint.zeroUnits.desc": "零不需要单位", "less.validate.title": "控制 LESS 验证和问题严重性。", "less.validate.desc": "启用或禁用所有验证", + "scss.title": "SCSS (Sass)", "scss.lint.argumentsInColorFunction.desc": "参数数量无效", "scss.lint.boxModel.desc": "使用边距或边框时,不要使用宽度或高度", "scss.lint.compatibleVendorPrefixes.desc": "使用供应商特定前缀时,确保同时包括所有其他供应商特定属性", diff --git a/i18n/chs/src/vs/code/electron-main/menus.i18n.json b/i18n/chs/src/vs/code/electron-main/menus.i18n.json index 40b03cafea8..34e3c359aa2 100644 --- a/i18n/chs/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/chs/src/vs/code/electron-main/menus.i18n.json @@ -171,8 +171,6 @@ "miRunningTask": "显示正在运行的任务(&&G)...", "miRestartTask": "重启正在运行的任务(&&E)...", "miTerminateTask": "终止任务(&&T)...", - "miConfigureTask": "配置任务(&&C)", - "miConfigureBuildTask": "配置默认生成任务(&&F)", "accessibilityOptionsWindowTitle": "辅助功能选项", "miRestartToUpdate": "重启以更新...", "miCheckingForUpdates": "正在检查更新...", diff --git a/i18n/chs/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/chs/src/vs/editor/common/config/commonEditorConfig.i18n.json index f7681a600e9..3abd825501a 100644 --- a/i18n/chs/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/chs/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -88,6 +88,7 @@ "accessibilitySupport": "控制编辑器是否应运行在对屏幕阅读器进行优化的模式。", "links": "控制编辑器是否应检测链接并使它们可被点击", "colorDecorators": "控制编辑器是否显示内联颜色修饰器和颜色选取器。", + "codeActions": "启用代码操作小灯泡提示", "sideBySide": "控制 Diff 编辑器以并排或内联形式显示差异", "ignoreTrimWhitespace": "控制差异编辑器是否将对前导空格或尾随空格的更改显示为差异", "renderIndicators": "控制差异编辑器是否为已添加/删除的更改显示 +/- 指示符号", diff --git a/i18n/chs/src/vs/platform/environment/node/argv.i18n.json b/i18n/chs/src/vs/platform/environment/node/argv.i18n.json index 37a32ad9d69..9fc0d95c7bd 100644 --- a/i18n/chs/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/chs/src/vs/platform/environment/node/argv.i18n.json @@ -15,6 +15,7 @@ "reuseWindow": "在上一活动窗口中强制打开文件或文件夹。", "userDataDir": "指定存放用户数据的目录,此目录在作为根运行时十分有用。", "verbose": "打印详细输出(表示 - 等待)。", + "wait": "等文件关闭后再返回。", "extensionHomePath": "设置扩展的根路径。", "listExtensions": "列出已安装的扩展。", "showVersions": "使用 --list-extension 时,显示已安装扩展的版本。", diff --git a/i18n/chs/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/chs/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index c550c5e4e59..9a0ff2ab7db 100644 --- a/i18n/chs/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/chs/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,7 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "扩展无效: package.json 不是 JSON 文件。", - "restartCode": "请先重启 Code 再重新安装 {0}。", - "installDependeciesConfirmation": "安装”{0}“还会安装其依赖项。是否要继续?", - "install": "是", - "doNotInstall": "否", + "restartCodeLocal": "请先重启 Code 再重新安装 {0}。", "uninstallDependeciesConfirmation": "要仅卸载“{0}”或者其依赖项也一起卸载?", "uninstallOnly": "仅", "uninstallAll": "全部", diff --git a/i18n/chs/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/chs/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index 177ad607767..4ae3c02e3c1 100644 --- a/i18n/chs/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/chs/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -16,6 +16,7 @@ "vscode.extension.activationEvents": "VS Code 扩展的激活事件。", "vscode.extension.activationEvents.onLanguage": "在打开被解析为指定语言的文件时发出的激活事件。", "vscode.extension.activationEvents.onCommand": "在调用指定命令时发出的激活事件。", + "vscode.extension.activationEvents.onDebug": "在用户准备调试或准备设置调试配置时发出的激活事件。", "vscode.extension.activationEvents.workspaceContains": "在打开至少包含一个匹配指定 glob 模式的文件的文件夹时发出的激活事件。", "vscode.extension.activationEvents.onView": "在指定视图被展开时发出的激活事件。", "vscode.extension.activationEvents.star": "在 VS Code 启动时发出的激活事件。为确保良好的最终用户体验,请仅在其他激活事件组合不适用于你的情况时,才在扩展中使用此事件。", diff --git a/i18n/chs/src/vs/platform/theme/common/colorExtensionPoint.i18n.json b/i18n/chs/src/vs/platform/theme/common/colorExtensionPoint.i18n.json index 8cd1865980d..72e224481c5 100644 --- a/i18n/chs/src/vs/platform/theme/common/colorExtensionPoint.i18n.json +++ b/i18n/chs/src/vs/platform/theme/common/colorExtensionPoint.i18n.json @@ -13,6 +13,8 @@ "contributes.defaults.highContrast": "高对比度主题的默认颜色。应为十六进制颜色值 (#RRGGBB[AA]) 或是主题颜色标识符,其提供默认值。", "invalid.colorConfiguration": "\"configuration.colors\" 必须是数组", "invalid.default.colorType": "{0} 必须为十六进制颜色值 (#RRGGBB[AA] 或 #RGB[A]) 或是主题颜色标识符,其提供默认值。", + "invalid.id": "必须定义 \"configuration.colors.id\",且不能为空", "invalid.id.format": "\"configuration.colors.id\" 必须满足 word[.word]*", + "invalid.description": "必须定义 \"configuration.colors.description\",且不能为空", "invalid.defaults": "必须定义 “configuration.colors.defaults”,且须包含 \"light\"(浅色)、\"dark\"(深色) 和 \"highContrast\"(高对比度)" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/chs/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 8a712411c27..7b7cfbc9ea7 100644 --- a/i18n/chs/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -14,7 +14,6 @@ "selectWorkspace": "选择文件夹作为工作区", "removeFolderFromWorkspace": "将文件夹从工作区删除", "saveWorkspaceAsAction": "将工作区另存为...", - "saveEmptyWorkspaceNotSupported": "请先打开一个工作区再保存。", "save": "保存(&&S)", "saveWorkspace": "保存工作区", "openWorkspaceAction": "打开工作区...", diff --git a/i18n/chs/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..08ebcb29e96 --- /dev/null +++ b/i18n/chs/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} 操作" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 15235fff2c5..f0b871bf751 100644 --- a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,6 +12,7 @@ "breakpointRemoved": "已删除断点,行 {0},文件 {1}", "compoundMustHaveConfigurations": "复合项必须拥有 \"configurations\" 属性集,才能启动多个配置。", "configMissing": "\"launch.json\" 中缺少配置“{0}”。", + "debugRequesMissing": "所选的启动配置缺少调试请求", "debugTypeNotSupported": "配置的类型“{0}”不受支持。", "debugTypeMissing": "所选的启动配置缺少属性 \"type\"。", "preLaunchTaskErrors": "preLaunchTask“{0}”期间检测到多个生成错误。", diff --git a/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index 4b54f4bccd1..0ccd1274af5 100644 --- a/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -51,9 +51,8 @@ "showLanguageExtensionsShort": "语言扩展", "showAzureExtensions": "显示 Azure 扩展", "showAzureExtensionsShort": "Azure 扩展", - "configureWorkspaceRecommendedExtensions": "配置建议的扩展(工作区)", - "ConfigureWorkspaceRecommendations.noWorkspace": "建议仅在工作区文件夹上可用。", "OpenExtensionsFile.failed": "无法在 \".vscode\" 文件夹({0})内创建 \"extensions.json\" 文件。", + "configureWorkspaceRecommendedExtensions": "配置建议的扩展(工作区)", "builtin": "内置", "disableAll": "禁用所有已安装的扩展", "disableAllWorkspace": "禁用此工作区的所有已安装的扩展", diff --git a/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index fefc047fe76..a6386fe575c 100644 --- a/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "打开键盘快捷方式文件", "openWorkspaceSettings": "打开工作区设置", "openFolderSettings": "打开文件夹设置", - "pickFolder": "选择文件夹", "configureLanguageBasedSettings": "配置语言特定的设置...", "languageDescriptionConfigured": "({0})", "pickLanguage": "选择语言" diff --git a/i18n/chs/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index d54e22f7680..432af5ba012 100644 --- a/i18n/chs/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,7 +6,5 @@ { "relaunchSettingMessage": "设置已更改,需要重启才能生效。", "relaunchSettingDetail": "按下“重启”按钮以重新启动 {0} 并启用该设置。", - "restart": "重启", - "relaunchWorkspaceMessage": "此工作区更改需要重载扩展系统。", - "reload": "重新加载" + "restart": "重启" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index 234516b6743..df96046e5e4 100644 --- a/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "任务", - "ConfigureTaskRunnerAction.noWorkspace": "任务仅在工作区文件夹上可用。", - "ConfigureTaskRunnerAction.quickPick.template": "选择任务运行程序", - "ConfigureTaskRunnerAction.autoDetecting": "适用于 {0} 的自动检测任务", - "ConfigureTaskRunnerAction.autoDetect": "自动检测系统任务失败。请使用默认模板。有关详细信息,请参阅任务输出。", - "ConfigureTaskRunnerAction.autoDetectError": "自动检测任务系统时出现错误。有关详细信息,请参阅任务输出。", - "ConfigureTaskRunnerAction.failed": "无法在 \".vscode\" 文件夹中创建 \"tasks.json\" 文件。查看任务输出了解详细信息。", - "ConfigureTaskRunnerAction.label": "配置任务运行程序", + "ConfigureTaskRunnerAction.label": "配置任务", "ConfigureBuildTaskAction.label": "配置生成任务", "CloseMessageAction.label": "关闭", "ShowTerminalAction.label": "查看终端", @@ -47,22 +41,16 @@ "configured": "已配置的任务", "detected": "检测到的任务", "TaskService.fetchingBuildTasks": "正在获取生成任务...", - "TaskService.noBuildTaskTerminal": "未能找到生成任务。按“配置生成任务”来定义一个。", "TaskService.pickBuildTask": "选择要运行的生成任务", "TaskService.fetchingTestTasks": "正在获取测试任务...", - "TaskService.noTestTaskTerminal": "未能找到测试任务。按“配置任务运行程序”来定义一个。", "TaskService.pickTestTask": "选择要运行的测试任务", - "TaskService.noTaskRunning": "当前没有任务在运行。", "TaskService.tastToTerminate": "选择要终止的任务", "TerminateAction.noProcess": "启动的进程不再存在。如果任务衍生的后台任务退出 VS Code,则可能会导致出现孤立的进程。", "TerminateAction.failed": "未能终止运行中的任务", - "TaskService.noTaskToRestart": "没有要重启的任务。", "TaskService.tastToRestart": "选择要重启的任务", - "TaskService.defaultBuildTaskExists": "{0} 已被标记为默认生成任务。", "TaskService.pickDefaultBuildTask": "选择要用作默认生成任务的任务", "TaskService.defaultTestTaskExists": "{0} 已被标记为默认测试任务。", "TaskService.pickDefaultTestTask": "选择要用作默认测试任务的任务", - "TaskService.noTaskIsRunning": "没有任务在运行。", "TaskService.pickShowTask": "选择要显示输出的任务", "ShowLogAction.label": "显示任务日志", "RunTaskAction.label": "运行任务", diff --git a/i18n/chs/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/chs/src/vs/workbench/services/configuration/node/configuration.i18n.json index 2f7035049db..6a7da8e17c6 100644 --- a/i18n/chs/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/chs/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -13,7 +13,6 @@ "invalid.title": "configuration.title 必须是字符串", "vscode.extension.contributes.defaultConfiguration": "按语言提供默认编辑器配置设置。", "invalid.properties": "configuration.properties 必须是对象", - "workspaceConfig.folders.description": "要在工作区中加载的文件夹列表。必须为文件夹完整路径。例如 \"/root/folderA\" 或 \"./folderA\"。后者表示根据工作区文件位置进行解析的相对路径。", - "workspaceConfig.folder.description": "文件路径。例如 \"/root/folderA\" 或 \"./folderA\"。后者表示根据工作区文件位置进行解析的相对路径。", + "workspaceConfig.path.description": "文件路径。例如 \"/root/folderA\" 或 \"./folderA\"。后者表示根据工作区文件位置进行解析的相对路径。", "workspaceConfig.settings.description": "工作区设置" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/chs/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..80b697be3d3 --- /dev/null +++ b/i18n/chs/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "文件似乎是二进制文件,无法作为文档打开" +} \ No newline at end of file diff --git a/i18n/cht/extensions/css/package.i18n.json b/i18n/cht/extensions/css/package.i18n.json index 86489b3522c..b346ac6c6b8 100644 --- a/i18n/cht/extensions/css/package.i18n.json +++ b/i18n/cht/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "參數數目無效", "css.lint.boxModel.desc": "使用填補或框線時不要使用寬度或高度。", "css.lint.compatibleVendorPrefixes.desc": "在使用廠商專屬的前置詞時,請確定也包括其他所有的廠商特定屬性。", @@ -25,6 +26,7 @@ "css.trace.server.desc": "追蹤 VS Code 與 CSS 語言伺服器之間的通訊。", "css.validate.title": "控制 CSS 驗證與問題嚴重性。", "css.validate.desc": "啟用或停用所有驗證", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "參數數目無效", "less.lint.boxModel.desc": "使用填補或框線時不要使用寬度或高度。", "less.lint.compatibleVendorPrefixes.desc": "在使用廠商專屬的前置詞時,請確定也包括其他所有的廠商特定屬性。", @@ -45,6 +47,7 @@ "less.lint.zeroUnits.desc": "零不需要任何單位", "less.validate.title": "控制 LESS 驗證與問題嚴重性。", "less.validate.desc": "啟用或停用所有驗證", + "scss.title": "SCSS (Sass)", "scss.lint.argumentsInColorFunction.desc": "參數數目無效", "scss.lint.boxModel.desc": "使用填補或框線時不要使用寬度或高度。", "scss.lint.compatibleVendorPrefixes.desc": "在使用廠商專屬的前置詞時,請確定也包括其他所有的廠商特定屬性。", diff --git a/i18n/cht/src/vs/code/electron-main/menus.i18n.json b/i18n/cht/src/vs/code/electron-main/menus.i18n.json index fe521f0b990..c6347c60ba9 100644 --- a/i18n/cht/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/cht/src/vs/code/electron-main/menus.i18n.json @@ -171,8 +171,6 @@ "miRunningTask": "顯示執行中的工作(&&G)...", "miRestartTask": "重新開始執行工作(&&E)...", "miTerminateTask": "終止工作(&&T)...", - "miConfigureTask": "設定工作(&&C)", - "miConfigureBuildTask": "設定預設建置工作(&&F)", "accessibilityOptionsWindowTitle": "協助工具選項", "miRestartToUpdate": "重新啟動以更新...", "miCheckingForUpdates": "正在查看是否有更新...", diff --git a/i18n/cht/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/cht/src/vs/editor/common/config/commonEditorConfig.i18n.json index b44b05e5981..b2a9d91c6b1 100644 --- a/i18n/cht/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/cht/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -88,6 +88,7 @@ "accessibilitySupport": "控制編輯器是否應於已為螢幕助讀程式最佳化的模式中執行。", "links": "控制編輯器是否應偵測連結且讓它可點擊", "colorDecorators": "控制編輯器是否應轉譯內嵌色彩裝飾項目與色彩選擇器。", + "codeActions": "啟用程式動作燈泡提示", "sideBySide": "控制 Diff 編輯器要並排或內嵌顯示差異", "ignoreTrimWhitespace": "控制 Diff 編輯器是否將開頭或尾端空白字元的變更顯示為差異", "renderIndicators": "控制 Diff 編輯器是否要為新增的/移除的變更顯示 +/- 標記", diff --git a/i18n/cht/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/cht/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 2a73c1b3b28..91ed221b018 100644 --- a/i18n/cht/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/cht/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "擴充功能無效: package.json 不是 JSON 檔案。", - "restartCode": "請先重新啟動 Code,再重新安裝 {0}。", - "installDependeciesConfirmation": "安裝 '{0}' 也會安裝其相依性。要繼續嗎?", - "install": "是", - "doNotInstall": "否", + "restartCodeLocal": "請先重新啟動 Code,再重新安裝 {0}。", + "restartCodeGallery": "重新安裝之前,請先重新啟動 Code。", "uninstallDependeciesConfirmation": "只要將 '{0}' 解除安裝,或要包含其相依性?", "uninstallOnly": "只有", "uninstallAll": "全部", diff --git a/i18n/cht/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/cht/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index 9e42e641acc..50abb35f281 100644 --- a/i18n/cht/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/cht/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -16,6 +16,7 @@ "vscode.extension.activationEvents": "VS Code 擴充功能的啟動事件。", "vscode.extension.activationEvents.onLanguage": "當指定語言檔案開啟時激發該事件", "vscode.extension.activationEvents.onCommand": "當指定的命令被調用時激發該事件", + "vscode.extension.activationEvents.onDebug": "當使用者正要開始偵錯或是設定偵錯組態時激發該事件", "vscode.extension.activationEvents.workspaceContains": "當開啟指定的文件夾包含glob模式匹配的文件時激發該事件", "vscode.extension.activationEvents.onView": "當指定的檢視被擴展時激發該事件", "vscode.extension.activationEvents.star": "當VS Code啟動時激發該事件,為了確保最好的使用者體驗,當您的擴充功能沒有其他組合作業時,請激活此事件.", diff --git a/i18n/cht/src/vs/platform/theme/common/colorExtensionPoint.i18n.json b/i18n/cht/src/vs/platform/theme/common/colorExtensionPoint.i18n.json index 75d3b7558fd..4c27d1b8aa4 100644 --- a/i18n/cht/src/vs/platform/theme/common/colorExtensionPoint.i18n.json +++ b/i18n/cht/src/vs/platform/theme/common/colorExtensionPoint.i18n.json @@ -13,6 +13,8 @@ "contributes.defaults.highContrast": "高對比佈景主題的預設色彩。應為十六進位 (#RRGGBB[AA]) 的色彩值,或提供預設的可設定佈景主題色彩。", "invalid.colorConfiguration": "'configuration.colors' 必須是陣列", "invalid.default.colorType": "{0} 必須是十六進位 (#RRGGBB[AA] or #RGB[A]) 的色彩值,或是提供預設的可設定佈景主題色彩之識別碼。", + "invalid.id": "'configuration.colors.id' 必須定義且不得為空白", "invalid.id.format": "'configuration.colors.id' 必須依照 word[.word]*", + "invalid.description": "'configuration.colors.description' 必須定義且不得為空白", "invalid.defaults": "'configuration.colors.defaults' 必須定義,且必須包含 'light'、'dark' 及 'highContrast'" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/cht/src/vs/workbench/browser/actions/workspaceActions.i18n.json index c90e6e584f7..de3c6d6122f 100644 --- a/i18n/cht/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -14,7 +14,6 @@ "selectWorkspace": "為工作區選取資料夾", "removeFolderFromWorkspace": "將資料夾從工作區移除", "saveWorkspaceAsAction": "另存工作區為...", - "saveEmptyWorkspaceNotSupported": "請先開啟工作區以進行儲存。", "save": "儲存(&&S)", "saveWorkspace": "儲存工作區", "openWorkspaceAction": "開啟工作區...", diff --git a/i18n/cht/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..6894078d8f2 --- /dev/null +++ b/i18n/cht/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} 個動作" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/cht/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index 072260a2e3b..4a4fd03e15a 100644 --- a/i18n/cht/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -51,9 +51,8 @@ "showLanguageExtensionsShort": "語言擴充功能", "showAzureExtensions": "顯示 Azure 延伸模組", "showAzureExtensionsShort": "Azure 延伸模組", - "configureWorkspaceRecommendedExtensions": "設定建議的延伸模組 (工作區)", - "ConfigureWorkspaceRecommendations.noWorkspace": "只有在工作區資料夾中才能使用建議。", "OpenExtensionsFile.failed": "無法在 '.vscode' 資料夾 ({0}) 中建立 'extensions.json' 檔案。", + "configureWorkspaceRecommendedExtensions": "設定建議的延伸模組 (工作區)", "builtin": "內建", "disableAll": "停用所有已安裝的延伸模組", "disableAllWorkspace": "停用此工作區的所有已安裝延伸模組", diff --git a/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index f0f4cd2a6a4..21867210659 100644 --- a/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "開啟鍵盤快速鍵檔案", "openWorkspaceSettings": "開啟工作區設定", "openFolderSettings": "開啟資料夾設定", - "pickFolder": "選取資料夾", "configureLanguageBasedSettings": "設定語言專屬設定...", "languageDescriptionConfigured": "({0})", "pickLanguage": "選取語言" diff --git a/i18n/cht/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index 2fbf166712a..6b3119f6f49 100644 --- a/i18n/cht/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,7 +6,5 @@ { "relaunchSettingMessage": "設定已經變更,必須重新啟動才會生效。", "relaunchSettingDetail": "請按 [重新啟動] 按鈕以重新啟動 {0} 並啟用設定。", - "restart": "重新啟動", - "relaunchWorkspaceMessage": "必須重新載入延伸模組系統才可變更此工作區。", - "reload": "重新載入" + "restart": "重新啟動" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index e43759a7db8..a279a7e25ba 100644 --- a/i18n/cht/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "工作", - "ConfigureTaskRunnerAction.noWorkspace": "這些工作只會出現在工作區資料夾中。", - "ConfigureTaskRunnerAction.quickPick.template": "選取工作執行器", - "ConfigureTaskRunnerAction.autoDetecting": "自動偵測 {0} 的工作", - "ConfigureTaskRunnerAction.autoDetect": "自動偵測工作系統失敗。正在使用預設範本。如需詳細資料,請參閱工作輸出。", - "ConfigureTaskRunnerAction.autoDetectError": "自動偵測工作系統產生的錯誤。如需詳細資料,請查看工作輸出。", - "ConfigureTaskRunnerAction.failed": "無法在 '.vscode' 資料夾中建立 'tasks.json' 檔案。如需詳細資訊,請參閱工作輸出。", - "ConfigureTaskRunnerAction.label": "設定工作執行器", + "ConfigureTaskRunnerAction.label": "設定工作", "ConfigureBuildTaskAction.label": "設定建置工作", "CloseMessageAction.label": "關閉", "ShowTerminalAction.label": "檢視終端機", @@ -47,22 +41,16 @@ "configured": "設定的工作", "detected": "偵測到的工作", "TaskService.fetchingBuildTasks": "正在擷取組建工作...", - "TaskService.noBuildTaskTerminal": "找不到任何組建工作。請按一下 [設定組建工作] 以加以定義。", "TaskService.pickBuildTask": "請選取要執行的組建工作", "TaskService.fetchingTestTasks": "正在擷取測試工作...", - "TaskService.noTestTaskTerminal": "找不到任何測試工作。請按一下 [設定測試執行器] 以加以定義。", "TaskService.pickTestTask": "請選取要執行的測試工作", - "TaskService.noTaskRunning": "目前沒有執行中的工作。", "TaskService.tastToTerminate": "請選取要終止的工作", "TerminateAction.noProcess": "啟動的處理序已不存在。如果工作繁衍的背景工作結束,VS Code 可能會產生孤立的處理序。", "TerminateAction.failed": "無法終止執行中的工作", - "TaskService.noTaskToRestart": "沒有任何要重新啟動的工作。", "TaskService.tastToRestart": "請選取要重新啟動的工作", - "TaskService.defaultBuildTaskExists": "已經將 {0} 標記為預設組建工作。", "TaskService.pickDefaultBuildTask": "請選取要用作預設組建工作的工作", "TaskService.defaultTestTaskExists": "已經將 {0} 標記為預設測試工作。", "TaskService.pickDefaultTestTask": "請選取要用作預設測試工作的工作", - "TaskService.noTaskIsRunning": "沒有執行中的工作。", "TaskService.pickShowTask": "選取要顯示輸出的工作", "ShowLogAction.label": "顯示工作記錄檔", "RunTaskAction.label": "執行工作", diff --git a/i18n/cht/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/cht/src/vs/workbench/services/configuration/node/configuration.i18n.json index 53d51ad9b47..b9826aee605 100644 --- a/i18n/cht/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/cht/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -13,7 +13,6 @@ "invalid.title": "'configuration.title' 必須是字串", "vscode.extension.contributes.defaultConfiguration": "依語言貢獻預設編輯器組態設定。", "invalid.properties": "'configuration.properties' 必須是物件", - "workspaceConfig.folders.description": "要在工作區中載入之資料夾的清單。必須是檔案路徑,例如 `/root/folderA` 或 `./folderA` 即為會對工作區檔案位置解析的相關路徑。", - "workspaceConfig.folder.description": "檔案路徑,例如 `/root/folderA` 或 `./folderA` 即為會對工作區檔案位置解析的相關路徑。", + "workspaceConfig.path.description": "檔案路徑,例如 `/root/folderA` 或 `./folderA` 即為會對工作區檔案位置解析的相關路徑。", "workspaceConfig.settings.description": "工作區設定" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/cht/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..067f2923a48 --- /dev/null +++ b/i18n/cht/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "檔案似乎是二進位檔,因此無法當做文字開啟" +} \ No newline at end of file diff --git a/i18n/deu/extensions/azure-account/out/azure-account.i18n.json b/i18n/deu/extensions/azure-account/out/azure-account.i18n.json index 888fa9b955d..e3df1915bad 100644 --- a/i18n/deu/extensions/azure-account/out/azure-account.i18n.json +++ b/i18n/deu/extensions/azure-account/out/azure-account.i18n.json @@ -6,6 +6,7 @@ { "azure-account.copyAndOpen": "Kopieren & Öffnen", "azure-account.close": "Schließen", + "azure-account.login": "Einloggen", "azure-account.loginFirst": "Nicht angemeldet, bitte zuerst anmelden.", "azure-account.userCodeFailed": "Fehler beim Erfassen von Benutzercode.", "azure-account.tokenFailed": "Token wird mit Gerätecode erfasst", diff --git a/i18n/deu/src/vs/code/electron-main/menus.i18n.json b/i18n/deu/src/vs/code/electron-main/menus.i18n.json index 790e6e94cd1..49cfdddcd5d 100644 --- a/i18n/deu/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/deu/src/vs/code/electron-main/menus.i18n.json @@ -175,8 +175,6 @@ "miRunningTask": "Aktive Auf&&gaben anzeigen...", "miRestartTask": "Aktuell&&e Aufgabe neu starten...", "miTerminateTask": "&&Aufgabe beenden...", - "miConfigureTask": "Aufgaben &&konfigurieren", - "miConfigureBuildTask": "Standardbuildaufgabe kon&&figurieren", "accessibilityOptionsWindowTitle": "Optionen für erleichterte Bedienung", "miRestartToUpdate": "Zum Aktualisieren neu starten...", "miCheckingForUpdates": "Überprüfen auf Updates...", diff --git a/i18n/deu/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/deu/src/vs/editor/common/config/commonEditorConfig.i18n.json index 17755d6a385..0afb44a967e 100644 --- a/i18n/deu/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/deu/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -88,6 +88,7 @@ "accessibilitySupport": "Steuert, ob der Editor in einem Modus ausgeführt werden soll, in dem er für die Sprachausgabe optimiert wird.", "links": "Steuert, ob der Editor Links erkennen und anklickbar machen soll", "colorDecorators": "Steuert, ob der Editor die Inline-Farbdecorators und die Farbauswahl rendern soll.", + "codeActions": "Ermöglicht die Code-Aktion \"lightbulb\"", "sideBySide": "Steuert, ob der Diff-Editor das Diff nebeneinander oder inline anzeigt.", "ignoreTrimWhitespace": "Steuert, ob der Diff-Editor Änderungen in führenden oder nachgestellten Leerzeichen als Diffs anzeigt.", "renderIndicators": "Steuert, ob der Diff-Editor die Indikatoren \"+\" und \"-\" für hinzugefügte/entfernte Änderungen anzeigt.", diff --git a/i18n/deu/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/deu/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index cd123a52668..c43709d2e6c 100644 --- a/i18n/deu/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/deu/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,7 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "Die Erweiterung ist ungültig: \"package.json\" ist keine JSON-Datei.", - "restartCode": "Bitte starten Sie Code vor der Neuinstallation von {0} neu.", - "installDependeciesConfirmation": "Durch das Installieren von \"{0}\" werden auch die abhängigen Komponenten installiert. Möchten Sie den Vorgang fortsetzen?", - "install": "Ja", - "doNotInstall": "Nein", + "restartCodeLocal": "Bitte starten Sie Code vor der Neuinstallation von {0} neu.", "uninstallDependeciesConfirmation": "Möchten Sie nur \"{0}\" oder auch die zugehörigen Abhängigkeiten deinstallieren?", "uninstallOnly": "Nur", "uninstallAll": "Alle", diff --git a/i18n/deu/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/deu/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 4529b938efc..13a7e15f206 100644 --- a/i18n/deu/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -14,7 +14,6 @@ "selectWorkspace": "Ordner für den Arbeitsbereich auswählen", "removeFolderFromWorkspace": "Ordner aus dem Arbeitsbereich entfernen", "saveWorkspaceAsAction": "Arbeitsbereich speichern unter...", - "saveEmptyWorkspaceNotSupported": "Öffnen Sie zum Speichern zunächst einen Arbeitsbereich.", "save": "&&Speichern", "saveWorkspace": "Arbeitsbereich speichern", "openWorkspaceAction": "Arbeitsbereich öffnen...", diff --git a/i18n/deu/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..b7eb39e941e --- /dev/null +++ b/i18n/deu/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0}-Aktionen" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/deu/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index e6677c7d0b8..9285fd4e2a9 100644 --- a/i18n/deu/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -51,9 +51,8 @@ "showLanguageExtensionsShort": "Spracherweiterungen", "showAzureExtensions": "Azure-Erweiterungen anzeigen", "showAzureExtensionsShort": "Azure-Erweiterungen", - "configureWorkspaceRecommendedExtensions": "Empfohlene Erweiterungen konfigurieren (Arbeitsbereich)", - "ConfigureWorkspaceRecommendations.noWorkspace": "Empfehlungen sind nur für einen Arbeitsbereichsordner verfügbar.", "OpenExtensionsFile.failed": "Die Datei \"extensions.json\" kann nicht im Ordner \".vscode\" erstellt werden ({0}).", + "configureWorkspaceRecommendedExtensions": "Empfohlene Erweiterungen konfigurieren (Arbeitsbereich)", "builtin": "Integriert", "disableAll": "Alle installierten Erweiterungen löschen", "disableAllWorkspace": "Alle installierten Erweiterungen für diesen Arbeitsbereich deaktivieren", diff --git a/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index 73113cf6294..503c8aa631f 100644 --- a/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "Datei mit Tastaturkurzbefehlen öffnen", "openWorkspaceSettings": "Arbeitsbereichseinstellungen öffnen", "openFolderSettings": "Ordnereinstellungen öffnen", - "pickFolder": "Ordner auswählen", "configureLanguageBasedSettings": "Sprachspezifische Einstellungen konfigurieren...", "languageDescriptionConfigured": "({0})", "pickLanguage": "Sprache auswählen" diff --git a/i18n/deu/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index 4e537daf3e5..b3f84ac1c6e 100644 --- a/i18n/deu/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,7 +6,5 @@ { "relaunchSettingMessage": "Eine Einstellung wurde geändert, welche einen Neustart benötigt.", "relaunchSettingDetail": "Drücke den Neu starten-Button, um {0} neuzustarten und die Einstellung zu aktivieren.", - "restart": "Neu starten", - "relaunchWorkspaceMessage": "Dieser Arbeitsbereich erfordert das erneute Laden des Erweiterungssystems.", - "reload": "Neu starten" + "restart": "Neu starten" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index d5bb26dd92c..26d75ccd2bf 100644 --- a/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "Aufgaben", - "ConfigureTaskRunnerAction.noWorkspace": "Aufgaben sind nur für einen Arbeitsbereichsordner verfügbar.", - "ConfigureTaskRunnerAction.quickPick.template": "Taskausführung auswählen", - "ConfigureTaskRunnerAction.autoDetecting": "Tasks für {0} werden automatisch erkannt.", - "ConfigureTaskRunnerAction.autoDetect": "Fehler bei der automatischen Erkennung des Tasksystems. Die Standardvorlage wird verwendet. Einzelheiten finden Sie in der Taskausgabe.", - "ConfigureTaskRunnerAction.autoDetectError": "Bei der automatischen Erkennung des Tasksystems sind Fehler aufgetreten. Einzelheiten finden Sie in der Taskausgabe.", - "ConfigureTaskRunnerAction.failed": "Die Datei \"tasks.json\" kann nicht im Ordner \".vscode\" erstellt werden. Einzelheiten finden Sie in der Taskausgabe.", - "ConfigureTaskRunnerAction.label": "Taskausführung konfigurieren", + "ConfigureTaskRunnerAction.label": "Aufgabe konfigurieren", "ConfigureBuildTaskAction.label": "Buildtask konfigurieren", "CloseMessageAction.label": "Schließen", "ShowTerminalAction.label": "Terminal anzeigen", @@ -47,22 +41,16 @@ "configured": "konfigurierte Aufgaben", "detected": "erkannte Aufgaben", "TaskService.fetchingBuildTasks": "Buildaufgaben werden abgerufen...", - "TaskService.noBuildTaskTerminal": "Es wurde keine Buildaufgabe gefunden. Klicken Sie auf \"Buildtask konfigurieren\", um eine Aufgabe zu definieren.", "TaskService.pickBuildTask": "Auszuführende Buildaufgabe auswählen", "TaskService.fetchingTestTasks": "Testaufgaben werden abgerufen...", - "TaskService.noTestTaskTerminal": "Es wurde keine Testaufgabe gefunden. Klicken Sie auf \"Taskausführung konfigurieren\", um eine Aufgabe zu definieren.", "TaskService.pickTestTask": "Auszuführende Testaufgabe auswählen", - "TaskService.noTaskRunning": "Zurzeit wird keine Aufgabe ausgeführt.", "TaskService.tastToTerminate": "Zu beendende Aufgabe auswählen", "TerminateAction.noProcess": "Der gestartete Prozess ist nicht mehr vorhanden. Wenn der Task Hintergrundtasks erzeugt hat, kann das Beenden von VS Code ggf. zu verwaisten Prozessen führen.", "TerminateAction.failed": "Fehler beim Beenden des ausgeführten Tasks.", - "TaskService.noTaskToRestart": "Es ist keine neu zu startende Aufgabe vorhanden.", "TaskService.tastToRestart": "Neu zu startende Aufgabe auswählen", - "TaskService.defaultBuildTaskExists": "{0} ist bereits als Standardbuildaufgabe markiert.", "TaskService.pickDefaultBuildTask": "Als Standardbuildaufgabe zu verwendende Aufgabe auswählen", "TaskService.defaultTestTaskExists": "{0} ist bereits als Standardtestaufgabe markiert.", "TaskService.pickDefaultTestTask": "Als Standardtestaufgabe zu verwendende Aufgabe auswählen", - "TaskService.noTaskIsRunning": "Es wird keine Aufgabe ausgeführt.", "TaskService.pickShowTask": "Aufgabe zum Anzeigen der Ausgabe auswählen", "ShowLogAction.label": "Taskprotokoll anzeigen", "RunTaskAction.label": "Task ausführen", diff --git a/i18n/deu/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/deu/src/vs/workbench/services/configuration/node/configuration.i18n.json index 66444d36312..d135d2e6051 100644 --- a/i18n/deu/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/deu/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -13,7 +13,6 @@ "invalid.title": "configuration.title muss eine Zeichenfolge sein.", "vscode.extension.contributes.defaultConfiguration": "Trägt zu Konfigurationeinstellungen des Standard-Editors für die jeweilige Sprache bei.", "invalid.properties": "\"configuration.properties\" muss ein Objekt sein.", - "workspaceConfig.folders.description": "Liste von Ordnern, die in den Arbeitsbereich geladen werden. Hierbei muss es sich um einen Dateipfad handeln, z. B. \" /root/folderA\" oder \"./folderA\" bei einem relativen Pfad, der in Bezug auf den Speicherort der Arbeitsbereichsdatei aufgelöst wird.", - "workspaceConfig.folder.description": "Ein Dateipfad, z. B. \" /root/folderA\" oder \"./folderA\" bei einem relativen Pfad, der in Bezug auf den Speicherort der Arbeitsbereichsdatei aufgelöst wird.", + "workspaceConfig.path.description": "Ein Dateipfad, z. B. \" /root/folderA\" oder \"./folderA\" bei einem relativen Pfad, der in Bezug auf den Speicherort der Arbeitsbereichsdatei aufgelöst wird.", "workspaceConfig.settings.description": "Arbeitsbereichseinstellungen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/deu/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..ed6cda9de2a --- /dev/null +++ b/i18n/deu/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "Die Datei scheint eine Binärdatei zu sein und kann nicht als Text geöffnet werden." +} \ No newline at end of file diff --git a/i18n/esn/src/vs/code/electron-main/menus.i18n.json b/i18n/esn/src/vs/code/electron-main/menus.i18n.json index 01a9a2bd0ce..484face7717 100644 --- a/i18n/esn/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/esn/src/vs/code/electron-main/menus.i18n.json @@ -175,8 +175,8 @@ "miRunningTask": "Mostrar las &&tareas en ejecución", "miRestartTask": "R&&einiciar tarea en ejecución...", "miTerminateTask": "&&Finalizar tarea...", - "miConfigureTask": "&&Configurar tarea", - "miConfigureBuildTask": "Configurar tarea de compilación predeterminada", + "miConfigureTask": "&&Configurar Tareas...", + "miConfigureBuildTask": "Configurar Tarea de Compilación &&Predeterminada...", "accessibilityOptionsWindowTitle": "Opciones de accesibilidad", "miRestartToUpdate": "Reiniciar para actualizar...", "miCheckingForUpdates": "Buscando actualizaciones...", diff --git a/i18n/esn/src/vs/code/electron-main/windows.i18n.json b/i18n/esn/src/vs/code/electron-main/windows.i18n.json index 228ae40964f..0cc1e6ac83a 100644 --- a/i18n/esn/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/esn/src/vs/code/electron-main/windows.i18n.json @@ -18,6 +18,7 @@ "openFolder": "Abrir carpeta", "openFile": "Abrir archivo", "workspaceOpenedMessage": "No se puede guardar el espacio de trabajo '{0}'", + "workspaceOpenedDetail": "El espacio de trabajo ya está abierto en otra ventana. Por favor, cierre primero la ventana y vuelta a intentarlo de nuevo.", "openWorkspace": "&&Abrir...", "openWorkspaceTitle": "Abrir área de trabajo", "save": "&&Guardar", diff --git a/i18n/esn/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/esn/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index 253f50641c3..c9693e97782 100644 --- a/i18n/esn/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/esn/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,6 +13,7 @@ "vscode.extension.contributes.menuItem.group": "Grupo al que pertenece este comando", "vscode.extension.contributes.menus": "Contribuye con elementos de menú al editor", "menus.commandPalette": "La paleta de comandos", + "menus.touchBar": "Barra táctil (sólo macOS)", "menus.editorTitle": "El menú de título del editor", "menus.editorContext": "El menú contextual del editor", "menus.explorerContext": "El menú contextual del explorador de archivos", diff --git a/i18n/esn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/esn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 89b2efaccfe..d12f2822486 100644 --- a/i18n/esn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/esn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "Extensión no válida: package.json no es un archivo JSON.", - "restartCode": "Reinicie Code antes de volver a instalar {0}.", - "installDependeciesConfirmation": "Al instalar '{0}', se instalan también sus dependencias. ¿Quiere continuar?", - "install": "Sí", - "doNotInstall": "No", + "restartCodeLocal": "Reinicie Code antes de volver a instalar {0}.", + "restartCodeGallery": "Por favor reinicie Code antes de reinstalar.", "uninstallDependeciesConfirmation": "¿Quiere desinstalar solo '{0}' o también sus dependencias?", "uninstallOnly": "Solo", "uninstallAll": "Todo", diff --git a/i18n/esn/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/esn/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 9e8733c7faf..81bfd015f9e 100644 --- a/i18n/esn/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -14,9 +14,9 @@ "selectWorkspace": "Seleccionar carpetas para el área de trabajo", "removeFolderFromWorkspace": "Quitar carpeta del área de trabajo", "saveWorkspaceAsAction": "Guardar área de trabajo como...", - "saveEmptyWorkspaceNotSupported": "Abra un área de trabajo antes de guardar.", "save": "&&Guardar", "saveWorkspace": "Guardar área de trabajo", "openWorkspaceAction": "Abrir área de trabajo...", - "openWorkspaceConfigFile": "Abrir archivo de configuración del área de trabajo" + "openWorkspaceConfigFile": "Abrir archivo de configuración del área de trabajo", + "workspaceFolderPickerPlaceholder": "Seleccionar la carpeta del área de trabajo" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index e50bfab447c..5f8d21bad14 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -35,6 +35,7 @@ "openPreviousEditorInGroup": "Abrir el editor anterior en el grupo", "navigateNext": "Hacia delante", "navigatePrevious": "Hacia atrás", + "navigateLast": "Vaya al último", "reopenClosedEditor": "Volver a abrir el editor cerrado", "clearRecentFiles": "Borrar abiertos recientemente", "showEditorsInFirstGroup": "Mostrar editores del primer grupo", diff --git a/i18n/esn/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..62933f6b509 --- /dev/null +++ b/i18n/esn/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} acciones" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/esn/src/vs/workbench/electron-browser/main.contribution.i18n.json index a142099af46..bc271ff5ade 100644 --- a/i18n/esn/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,8 +10,11 @@ "workspaces": "Áreas de trabajo", "developer": "Desarrollador", "showEditorTabs": "Controla si los editores abiertos se deben mostrar o no en pestañas.", + "workbench.editor.labelFormat.default": "Mostrar el nombre del archivo. Cuando las pestañas están habilitadas y dos archivos tienen el mismo nombre en un grupo, se agregan las secciones distintivas de la ruta de acceso de cada archivo. Cuando las pestañas están deshabilitadas, se muestra la ruta de acceso relativa a la raíz del espacio de trabajo si el editor está activo.", "workbench.editor.labelFormat.short": "Mostrar el nombre del archivo seguido de su nombre de directorio.", "workbench.editor.labelFormat.medium": "Mostrar el nombre del archivo seguido de la ruta de acceso relativo a la raíz del espacio de trabajo.", + "workbench.editor.labelFormat.long": "Mostrar el nombre del archivo seguido de la ruta de acceso absoluta.", + "tabDescription": "Controla el formato de la etiqueta para un editor. Modificar este ajuste puede hacer, por ejemplo, que sea más fácil entender la ubicación de un archivo: - corta: 'parent' - media: 'workspace/src/parent' - larga: '/home/user/workspace/src/parect' - por defecto: '.../parent', cuando otra pestaña comparte el mismo título, o la ruta de acceso relativa del espacio de trabajo si las pestañas están deshabilitadas", "editorTabCloseButton": "Controla la posición de los botones de cierre de pestañas del editor o los deshabilita si se establece en \"off\".", "showIcons": "Controla si los editores abiertos deben mostrarse o no con un icono. Requiere que también se habilite un tema de icono.", "enablePreview": "Controla si los editores abiertos se muestran en vista previa. Los editores en vista previa se reutilizan hasta que se guardan (por ejemplo, mediante doble clic o editándolos).", diff --git a/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json b/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json index 42304193db2..110e697ca94 100644 --- a/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json @@ -36,5 +36,7 @@ "schema.indentationRules.unIndentedLinePattern": "Si una línea coincide con este patrón, su sangría no se debe cambiar y no se debe evaluar utilizando las otras reglas.", "schema.indentationRules.unIndentedLinePattern.pattern": "El patrón de RegExp para unIndentedLinePattern.", "schema.indentationRules.unIndentedLinePattern.flags": "Las marcas de RegExp para unIndentedLinePattern.", - "schema.indentationRules.unIndentedLinePattern.errorMessage": "Debe coincidir con el patrón `/^([gimuy]+)$/`." + "schema.indentationRules.unIndentedLinePattern.errorMessage": "Debe coincidir con el patrón `/^([gimuy]+)$/`.", + "schema.folding": "Configuración del plegamiento de idioma.", + "schema.folding.offSide": "Un idioma se adhiere a la regla del fuera de juego si los bloques en ese idioma se expresan por su sangría. Si se establece, las líneas vacías pertenecen al bloque posterior." } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index 25236ca4769..f2fa7ffeb2a 100644 --- a/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -51,9 +51,9 @@ "showLanguageExtensionsShort": "Extensiones del lenguaje", "showAzureExtensions": "Mostrar extensiones de Azure", "showAzureExtensionsShort": "Extensiones de Azure", - "configureWorkspaceRecommendedExtensions": "Configurar extensiones recomendadas (área de trabajo)", - "ConfigureWorkspaceRecommendations.noWorkspace": "Las recomendaciones solo están disponibles en una carpeta de área de trabajo.", "OpenExtensionsFile.failed": "No se puede crear el archivo \"extensions.json\" dentro de la carpeta \".vscode\" ({0}).", + "configureWorkspaceRecommendedExtensions": "Configurar extensiones recomendadas (área de trabajo)", + "configureWorkspaceFolderRecommendedExtensions": "Configurar extensiones recomendadas (Carpeta del área de trabajo)", "builtin": "Integrada", "disableAll": "Deshabilitar todas las extensiones instaladas", "disableAllWorkspace": "Deshabilitar todas las extensiones instaladas para esta área de trabajo", diff --git a/i18n/esn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index 06f719f73f0..b07ed05e826 100644 --- a/i18n/esn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -14,6 +14,8 @@ "files.exclude.boolean": "El patrón global con el que se harán coincidir las rutas de acceso de los archivos. Establézcalo en true o false para habilitarlo o deshabilitarlo.", "files.exclude.when": "Comprobación adicional de los elementos del mismo nivel de un archivo coincidente. Use $(nombreBase) como variable para el nombre de archivo que coincide.", "associations": "Configure asociaciones de archivo para los lenguajes (por ejemplo, \"*.extension\": \"html\"). Estas asociaciones tienen prioridad sobre las asociaciones predeterminadas de los lenguajes instalados.", + "encoding": "La codificación del juego de caracteres predeterminada que debe utilizarse al leer y escribir archivos. Este ajuste puede configurarse también por idioma.", + "autoGuessEncoding": "Cuando está activada, intentará adivinar la codificación del juego de caracteres al abrir archivos. Este ajuste puede configurarse también por idioma.", "eol": "Carácter predeterminado de final de línea. Utilice \\n para LF y \\r\\n para CRLF.", "trimTrailingWhitespace": "Si se habilita, se recortará el espacio final cuando se guarde un archivo.", "insertFinalNewline": "Si se habilita, inserte una nueva línea final al final del archivo cuando lo guarde.", diff --git a/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index 2bfe512b1d5..402cc5d581e 100644 --- a/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "Abrir el archivo de métodos abreviados de teclado", "openWorkspaceSettings": "Abrir configuración del área de trabajo", "openFolderSettings": "Abrir Configuración de carpeta", - "pickFolder": "Seleccionar carpeta", "configureLanguageBasedSettings": "Configurar opciones específicas del lenguaje...", "languageDescriptionConfigured": "({0})", "pickLanguage": "Seleccionar lenguaje" diff --git a/i18n/esn/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index a447e55f2de..417500fd04a 100644 --- a/i18n/esn/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,7 +6,5 @@ { "relaunchSettingMessage": "Ha cambiado un ajuste que requiere un reinicio para ser efectivo.", "relaunchSettingDetail": "Pulse el botón de reinicio para reiniciar {0} y habilitar el ajuste.", - "restart": "Reiniciar", - "relaunchWorkspaceMessage": "Este cambio de área de trabajo requiere recargar nuestro sistema de extensiones.", - "reload": "Recargar" + "restart": "Reiniciar" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index 38790781315..5c65b30517e 100644 --- a/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "scm providers": "Proveedores de Control de Código fuente", "commitMessage": "Message (press {0} to commit)", "installAdditionalSCMProviders": "Instalar proveedores adicionales de SCM...", "no open repo": "No hay proveedores de control de código fuente activos.", diff --git a/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index 300ec37121d..6e97b49f6db 100644 --- a/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "Tareas", - "ConfigureTaskRunnerAction.noWorkspace": "Las tareas solo están disponibles en una carpeta del área de trabajo.", - "ConfigureTaskRunnerAction.quickPick.template": "Seleccionar un ejecutador de tareas", - "ConfigureTaskRunnerAction.autoDetecting": "Detectando tareas automáticamente para {0}", - "ConfigureTaskRunnerAction.autoDetect": "Error de detección automática del sistema de tareas. Se usa la plantilla predeterminada. Consulte el resultado de la tarea para obtener más detalles", - "ConfigureTaskRunnerAction.autoDetectError": "Error de detección automática del sistema de tareas. Consulte el resultado de la tarea para obtener más detalles", - "ConfigureTaskRunnerAction.failed": "No se puede crear el archivo \"tasks.json\" dentro de la carpeta \".vscode\". Consulte el resultado de la tarea para obtener más detalles.", - "ConfigureTaskRunnerAction.label": "Configurar ejecutor de tareas", + "ConfigureTaskRunnerAction.label": "Configurar tarea", "ConfigureBuildTaskAction.label": "Configurar tarea de compilación", "CloseMessageAction.label": "Cerrar", "ShowTerminalAction.label": "Ver terminal", @@ -19,11 +13,13 @@ "manyMarkers": "Más de 99", "runningTasks": "Mostrar tareas en ejecución", "tasks": "Tareas", + "TaskSystem.noHotSwap": "Cambiar el motor de ejecución de tareas con una tarea activa ejecutandose, requiere recargar la ventana", "TaskService.noBuildTask1": "No se ha definido ninguna tarea de compilación. Marque una tarea con \"isBuildCommand\" en el archivo tasks.json.", "TaskService.noBuildTask2": "No se ha definido ninguna tarea de compilación. Marque una tarea con un grupo \"build\" en el archivo tasks.json. ", "TaskService.noTestTask1": "No se ha definido ninguna tarea de prueba. Marque una tarea con \"isTestCommand\" en el archivo tasks.json.", "TaskService.noTestTask2": "No se ha definido ninguna tarea de prueba. Marque una tarea con \"test\" en el archivo tasks.json.", "TaskServer.noTask": "No se encuentra la tarea {0} que se ha solicitado para ejecutarla.", + "TaskService.associate": "asociar", "TaskService.attachProblemMatcher.continueWithout": "Continuar sin examinar la salida de la tarea", "TaskService.attachProblemMatcher.never": "No examinar nunca la salida de la tarea", "TaskService.attachProblemMatcher.learnMoreAbout": "Más información acerca del examen de la salida de la tarea", @@ -35,6 +31,7 @@ "TaskSystem.active": "Ya hay una tarea en ejecución. Finalícela antes de ejecutar otra tarea.", "TaskSystem.restartFailed": "No se pudo terminar y reiniciar la tarea {0}", "TaskSystem.configurationErrors": "Error: La configuración de la tarea proporcionada tiene errores de validación y no se puede usar. Corrija los errores primero.", + "taskService.ignoreingFolder": "Ignorando las configuraciones de tareas para la carpeta del área de trabajo {0}. El soporte de carpetas multi-raíz requiere que todas las carpetas usen la versión 2.0.0 de las tareas\n", "TaskSystem.invalidTaskJson": "Error: El contenido del archivo tasks.json tiene errores de sintaxis. Corríjalos antes de ejecutar una tarea.", "TaskSystem.runningTask": "Hay una tarea en ejecución. ¿Quiere finalizarla?", "TaskSystem.terminateTask": "&&Finalizar tarea", @@ -46,24 +43,30 @@ "recentlyUsed": "Tareas usadas recientemente", "configured": "tareas configuradas", "detected": "tareas detectadas", + "TaskService.pickRunTask": "Seleccione la tarea a ejecutar", + "TaslService.noEntryToRun": "No se encontraron tareas para ejecutar. Configurar tareas...", "TaskService.fetchingBuildTasks": "Obteniendo tareas de compilación...", - "TaskService.noBuildTaskTerminal": "No se encontraron Tareas de Compilación. Pulse 'Configurar Tarea de Compilación' para definir una.", "TaskService.pickBuildTask": "Seleccione la tarea de compilación para ejecutar", + "TaskService.noBuildTask": "No se encontraron tareas de compilación para ejecutar. Configurar tareas...", "TaskService.fetchingTestTasks": "Capturando tareas de prueba...", - "TaskService.noTestTaskTerminal": "No se encontraron tareas de prueba. Presione \"Configurar ejecutor de tareas\" para definir una.", "TaskService.pickTestTask": "Seleccione la tarea de prueba para ejecutar", - "TaskService.noTaskRunning": "Ninguna tarea se está ejecutando actualmente.", + "TaskService.noTestTaskTerminal": "No se encontraron tareas de prueba para ejecutar. Configurar tareas...", "TaskService.tastToTerminate": "Seleccione la tarea para finalizar", + "TaskService.noTaskRunning": "Ninguna tarea se está ejecutando actualmente", "TerminateAction.noProcess": "El proceso iniciado ya no existe. Si la tarea generó procesos en segundo plano al salir de VS Code, puede dar lugar a procesos huérfanos.", "TerminateAction.failed": "No se pudo finalizar la tarea en ejecución", - "TaskService.noTaskToRestart": "No hay tareas para reiniciar.", "TaskService.tastToRestart": "Seleccione la tarea para reiniciar", - "TaskService.defaultBuildTaskExists": "{0} ya se ha marcado como la tarea de compilación predeterminada.", + "TaskService.noTaskToRestart": "No hay tareas para reiniciar", + "TaskService.template": "Seleccione una plantilla de tarea", + "TaskService.createJsonFile": "Crear archivo tasks.json desde plantilla", + "TaskService.openJsonFile": "Abrir archivo tasks.json", + "TaskService.pickTask": "Seleccione una tarea para configurar", + "TaskService.defaultBuildTaskExists": "{0} está marcado ya como la tarea de compilación predeterminada", "TaskService.pickDefaultBuildTask": "Seleccione la tarea que se va a utilizar como tarea de compilación predeterminada", "TaskService.defaultTestTaskExists": "{0} ya se ha marcado como la tarea de prueba predeterminada.", "TaskService.pickDefaultTestTask": "Seleccione la tarea que se va a usar como la tarea de prueba predeterminada ", - "TaskService.noTaskIsRunning": "No hay ninguna tarea en ejecución.", "TaskService.pickShowTask": "Seleccione la tarea de la que desea ver la salida", + "TaskService.noTaskIsRunning": "Ninguna tarea se está ejecutando", "ShowLogAction.label": "Mostrar registro de tareas", "RunTaskAction.label": "Ejecutar tarea", "RestartTaskAction.label": "Reiniciar la tarea en ejecución", diff --git a/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json b/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json index 99a6eef0566..a3bf48c132e 100644 --- a/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "TerminalTaskSystem.unknownError": "Error desconocido durante la ejecución de una tarea. Vea el registro de resultados de la tarea para obtener más detalles.", + "dependencyFailed": "No se pudo resolver la tarea dependiente '{0}' en la carpeta del área de trabajo '{1}'", "TerminalTaskSystem.terminalName": "Tarea - {0}", "reuseTerminal": "Las tareas reutilizarán el terminal, presione cualquier tecla para cerrarlo.", "TerminalTaskSystem": "No se puede ejecutar un comando shell en una unidad UNC.", diff --git a/i18n/esn/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/esn/src/vs/workbench/services/configuration/node/configuration.i18n.json index 87e6573dc45..a038f4e9746 100644 --- a/i18n/esn/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/esn/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -14,7 +14,10 @@ "vscode.extension.contributes.defaultConfiguration": "Contribuye a la configuración de los parámetros del editor predeterminados por lenguaje.", "invalid.properties": "configuration.properties debe ser un objeto", "invalid.allOf": "'configuration.allOf' está en desuso y ya no debe ser utilizado. En cambio, pasar varias secciones de configuración como una matriz al punto de contribución de 'configuración'.", - "workspaceConfig.folders.description": "Lista de carpetas que debe cargarse en el área de trabajo. Debe ser una ruta de acceso de archivo; por ejemplo, \"/raíz/carpetaA\" o \"./carpetaA\" para una ruta de acceso relativa que se resolverá respecto a la ubicación del archivo del área de trabajo.", - "workspaceConfig.folder.description": "Ruta de acceso de archivo; por ejemplo, \"/raíz/carpetaA\" o \"./carpetaA\" para una ruta de acceso de archivo que se resolverá respecto a la ubicación del archivo del área de trabajo.", - "workspaceConfig.settings.description": "Configuración de área de trabajo" + "workspaceConfig.folders.description": "Lista de carpetas para cargar en el área de trabajo. ", + "workspaceConfig.path.description": "Ruta de acceso de archivo; por ejemplo, \"/raíz/carpetaA\" o \"./carpetaA\" para una ruta de acceso de archivo que se resolverá respecto a la ubicación del archivo del área de trabajo.", + "workspaceConfig.name.description": "Un nombre opcional para la carpeta. ", + "workspaceConfig.uri.description": "URI de la carpeta", + "workspaceConfig.settings.description": "Configuración de área de trabajo", + "workspaceConfig.extensions.description": "Extensiones del área de trabajo" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/esn/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..1d8632efe35 --- /dev/null +++ b/i18n/esn/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "El archivo parece ser binario y no se puede abrir como texto" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/esn/src/vs/workbench/services/files/node/fileService.i18n.json index 64389cb9764..32802572ad8 100644 --- a/i18n/esn/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/esn/src/vs/workbench/services/files/node/fileService.i18n.json @@ -10,6 +10,7 @@ "fileTooLargeError": "Archivo demasiado grande para abrirlo", "fileBinaryError": "El archivo parece ser binario y no se puede abrir como texto", "fileNotFoundError": "Archivo no encontrado ({0})", + "fileExists": "El archivo a crear ya existe ({0})", "fileMoveConflict": "No se puede mover o copiar. El archivo ya existe en la ubicación de destino. ", "unableToMoveCopyError": "No se puede mover o copiar. El archivo reemplazaría a la carpeta que lo contiene.", "foldersCopyError": "No se pueden copiar carpetas en el área de trabajo. Seleccione archivos individuales para copiarlos.", diff --git a/i18n/fra/extensions/css/package.i18n.json b/i18n/fra/extensions/css/package.i18n.json index 161a45a8a78..a6f0b6d471f 100644 --- a/i18n/fra/extensions/css/package.i18n.json +++ b/i18n/fra/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "Nombre de paramètres non valide", "css.lint.boxModel.desc": "Ne pas utiliser la largeur ou la hauteur avec une marge intérieure ou une bordure", "css.lint.compatibleVendorPrefixes.desc": "Lors de l'utilisation d'un préfixe spécifique à un fabricant, toujours inclure également toutes les propriétés spécifiques au fabricant", @@ -25,6 +26,7 @@ "css.trace.server.desc": "Trace la communication entre VS Code et le serveur de langage CSS.", "css.validate.title": "Contrôle la validation CSS et la gravité des problèmes.", "css.validate.desc": "Active ou désactive toutes les validations", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "Nombre de paramètres non valide", "less.lint.boxModel.desc": "Ne pas utiliser la largeur ou la hauteur avec une marge intérieure ou une bordure", "less.lint.compatibleVendorPrefixes.desc": "Lors de l'utilisation d'un préfixe spécifique à un fabricant, toujours inclure également toutes les propriétés spécifiques au fabricant", @@ -45,6 +47,7 @@ "less.lint.zeroUnits.desc": "Aucune unité nécessaire pour zéro", "less.validate.title": "Contrôle la validation LESS et la gravité des problèmes.", "less.validate.desc": "Active ou désactive toutes les validations", + "scss.title": "SCSS (Sass)", "scss.lint.argumentsInColorFunction.desc": "Nombre de paramètres non valide", "scss.lint.boxModel.desc": "Ne pas utiliser la largeur ou la hauteur avec une marge intérieure ou une bordure", "scss.lint.compatibleVendorPrefixes.desc": "Lors de l'utilisation d'un préfixe spécifique à un fabricant, toujours inclure également toutes les propriétés spécifiques au fabricant", diff --git a/i18n/fra/src/vs/code/electron-main/menus.i18n.json b/i18n/fra/src/vs/code/electron-main/menus.i18n.json index 4b6ddec2020..58e75c2db36 100644 --- a/i18n/fra/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/fra/src/vs/code/electron-main/menus.i18n.json @@ -151,6 +151,10 @@ "mZoom": "Zoom", "mBringToFront": "Mettre tout au premier plan", "miSwitchWindow": "Changer de &&fenêtre...", + "mShowPreviousTab": "Afficher l’onglet précédent", + "mShowNextTab": "Afficher l’onglet suivant", + "mMoveTabToNewWindow": "Déplacer l’onglet vers une nouvelle fenêtre", + "mMergeAllWindows": "Fusionner toutes les fenêtres", "miToggleDevTools": "Activer/désactiver les ou&&tils de développement", "miAccessibilityOptions": "&&Options d'accessibilité", "miReportIssues": "S&&ignaler les problèmes", @@ -171,7 +175,7 @@ "miRunningTask": "Afficher les &&tâches en cours...", "miRestartTask": "R&&edémarrer la tâche en cours d'exécution...", "miTerminateTask": "&&Terminer la tâche...", - "miConfigureTask": "&&Configurer les tâches", + "miConfigureTask": "&&Configurer les tâches...", "miConfigureBuildTask": "Configurer la tâche de génération par dé&&faut", "accessibilityOptionsWindowTitle": "Options d'accessibilité", "miRestartToUpdate": "Redémarrer pour mettre à jour...", diff --git a/i18n/fra/src/vs/code/electron-main/windows.i18n.json b/i18n/fra/src/vs/code/electron-main/windows.i18n.json index 99857324e72..c85aba4cc7b 100644 --- a/i18n/fra/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/fra/src/vs/code/electron-main/windows.i18n.json @@ -17,6 +17,8 @@ "open": "Ouvrir", "openFolder": "Ouvrir le dossier", "openFile": "Ouvrir le fichier", + "workspaceOpenedMessage": "Impossible d’enregistrer l’espace de travail '{0}'", + "workspaceOpenedDetail": "L’espace de travail est déjà ouvert dans une autre fenêtre. Veuillez s’il vous plaît d’abord fermer cette fenêtre et puis essayez à nouveau.", "openWorkspace": "&&Ouvrir...", "openWorkspaceTitle": "Ouvrir un espace de travail", "save": "&&Enregistrer", diff --git a/i18n/fra/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/fra/src/vs/editor/common/config/commonEditorConfig.i18n.json index 65942745629..e31fe031927 100644 --- a/i18n/fra/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/fra/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -88,6 +88,7 @@ "accessibilitySupport": "Contrôle si l'éditeur doit s'exécuter dans un mode optimisé pour les lecteurs d'écran.", "links": "Contrôle si l'éditeur doit détecter les liens et les rendre cliquables", "colorDecorators": "Contrôle si l'éditeur doit afficher les éléments décoratifs de couleurs inline et le sélecteur de couleurs.", + "codeActions": "Active l'ampoule d'action de code", "sideBySide": "Contrôle si l'éditeur de différences affiche les différences en mode côte à côte ou inline", "ignoreTrimWhitespace": "Contrôle si l'éditeur de différences affiche les changements liés aux espaces blancs de début ou de fin comme des différences", "renderIndicators": "Contrôle si l'éditeur de différences affiche les indicateurs +/- pour les modifications ajoutées/supprimées", diff --git a/i18n/fra/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/fra/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index 4ec0caa12c1..ca7209bfd1d 100644 --- a/i18n/fra/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/fra/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,6 +13,7 @@ "vscode.extension.contributes.menuItem.group": "Groupe auquel cette commande appartient", "vscode.extension.contributes.menus": "Contribue à fournir des éléments de menu à l'éditeur", "menus.commandPalette": "Palette de commandes", + "menus.touchBar": "La touch bar (macOS uniquement)", "menus.editorTitle": "Menu de titre de l'éditeur", "menus.editorContext": "Menu contextuel de l'éditeur", "menus.explorerContext": "Menu contextuel de l'Explorateur de fichiers", diff --git a/i18n/fra/src/vs/platform/environment/node/argv.i18n.json b/i18n/fra/src/vs/platform/environment/node/argv.i18n.json index f8792338e56..2f3ab904009 100644 --- a/i18n/fra/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/fra/src/vs/platform/environment/node/argv.i18n.json @@ -15,6 +15,7 @@ "reuseWindow": "Forcez l'ouverture d'un fichier ou dossier dans la dernière fenêtre active.", "userDataDir": "Spécifie le répertoire où sont conservées les données des utilisateurs. S'avère utile pour une exécution en tant que root.", "verbose": "Affichez la sortie détaillée (implique --wait).", + "wait": "Attendre que les fichiers soient fermés avant de retourner.", "extensionHomePath": "Définissez le chemin racine des extensions.", "listExtensions": "Listez les extensions installées.", "showVersions": "Affichez les versions des extensions installées, quand --list-extension est utilisé.", diff --git a/i18n/fra/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/fra/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 38f12473526..e6693aebb79 100644 --- a/i18n/fra/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/fra/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "Extension non valide : package.json n'est pas un fichier JSON.", - "restartCode": "Redémarrez Code avant de réinstaller {0}.", - "installDependeciesConfirmation": "L'installation de '{0}' entraîne également l'installation de ses dépendances. Voulez-vous continuer ?", - "install": "Oui", - "doNotInstall": "Non", + "restartCodeLocal": "Redémarrez Code avant de réinstaller {0}.", + "restartCodeGallery": "Veuillez s’il vous plaît redémarrer Code avant la réinstallation.", "uninstallDependeciesConfirmation": "Voulez-vous désinstaller uniquement '{0}' ou également ses dépendances ?", "uninstallOnly": "Uniquement", "uninstallAll": "Tout", diff --git a/i18n/fra/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/fra/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index 29156c8b5c9..77c19000246 100644 --- a/i18n/fra/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/fra/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -16,6 +16,7 @@ "vscode.extension.activationEvents": "Événements d'activation pour l'extension VS Code.", "vscode.extension.activationEvents.onLanguage": "Événement d'activation envoyé quand un fichier résolu dans le langage spécifié est ouvert.", "vscode.extension.activationEvents.onCommand": "Événement d'activation envoyé quand la commande spécifiée est appelée.", + "vscode.extension.activationEvents.onDebug": "Un événement d’activation émis chaque fois qu’un utilisateur est sur le point de démarrer le débogage ou sur le point de la déboguer des configurations.", "vscode.extension.activationEvents.workspaceContains": "Événement d'activation envoyé quand un dossier ouvert contient au moins un fichier correspondant au modèle glob spécifié.", "vscode.extension.activationEvents.onView": "Événement d'activation envoyé quand la vue spécifiée est développée.", "vscode.extension.activationEvents.star": "Événement d'activation envoyé au démarrage de VS Code. Pour garantir la qualité de l'expérience utilisateur, utilisez cet événement d'activation dans votre extension uniquement quand aucune autre combinaison d'événements d'activation ne fonctionne dans votre cas d'utilisation.", diff --git a/i18n/fra/src/vs/platform/theme/common/colorExtensionPoint.i18n.json b/i18n/fra/src/vs/platform/theme/common/colorExtensionPoint.i18n.json index bed03d02fba..9bf03d39312 100644 --- a/i18n/fra/src/vs/platform/theme/common/colorExtensionPoint.i18n.json +++ b/i18n/fra/src/vs/platform/theme/common/colorExtensionPoint.i18n.json @@ -13,6 +13,8 @@ "contributes.defaults.highContrast": "La couleur par défaut pour les thèmes de contraste élevé. Soit une valeur de couleur en hexadécimal (#RRGGBB[AA]) ou l’identifiant d’une couleur dont le thème peut être changé qui fournit la valeur par défaut.", "invalid.colorConfiguration": "'configuration.colors' doit être un tableau", "invalid.default.colorType": "{0} doit être soit une valeur de couleur en hexadécimal (#RRGGBB[AA] ou #RGB[A]) ou l’identifiant d’une couleur dont le thème peut être changé qui fournit la valeur par défaut.", + "invalid.id": "'configuration.colors.id' doit être défini et ne peut pas être vide", "invalid.id.format": "'configuration.colors.id' doit suivre le word[.word]*", + "invalid.description": "'configuration.colors.description' doit être défini et ne peut pas être vide", "invalid.defaults": "'configuration.colors.defaults' doit être défini et doit contenir 'light', 'dark' et 'highContrast'" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/fra/src/vs/workbench/browser/actions/workspaceActions.i18n.json index c65ee0c9b33..857489eaa8f 100644 --- a/i18n/fra/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -14,9 +14,9 @@ "selectWorkspace": "Sélectionner les dossiers pour l’espace de travail", "removeFolderFromWorkspace": "Supprimer le dossier de l'espace de travail", "saveWorkspaceAsAction": "Enregistrer l’espace de travail sous...", - "saveEmptyWorkspaceNotSupported": "Veuillez d’abord ouvrir un espace de travail pour enregistrer.", "save": "&&Enregistrer", "saveWorkspace": "Enregistrer l’espace de travail", "openWorkspaceAction": "Ouvrir un espace de travail...", - "openWorkspaceConfigFile": "Ouvrir le Fichier de Configuration d’espace de travail" + "openWorkspaceConfigFile": "Ouvrir le Fichier de Configuration d’espace de travail", + "workspaceFolderPickerPlaceholder": "Sélectionner le dossier de l’espace de travail" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json index 1147d510ce6..1bd02d3dbad 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json @@ -6,6 +6,7 @@ { "badgeTitle": "{0} - {1}", "titleKeybinding": "{0} ({1})", + "removeFromActivityBar": "Masquer de la barre d’activités", "keepInActivityBar": "Conserver dans la barre d'activités", "additionalViews": "Vues supplémentaires", "numberBadge": "{0} ({1})", diff --git a/i18n/fra/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index 2ebd48c5bc8..a7e57354829 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -35,6 +35,7 @@ "openPreviousEditorInGroup": "Ouvrir l'éditeur précédent du groupe", "navigateNext": "Suivant", "navigatePrevious": "Précédent", + "navigateLast": "Aller au dernier", "reopenClosedEditor": "Rouvrir l'éditeur fermé", "clearRecentFiles": "Effacer les fichiers récemment ouverts", "showEditorsInFirstGroup": "Afficher les éditeurs du premier groupe", diff --git a/i18n/fra/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..4868e0b0e11 --- /dev/null +++ b/i18n/fra/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} actions" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/fra/src/vs/workbench/electron-browser/actions.i18n.json index 55e38a54c34..fc7be7db920 100644 --- a/i18n/fra/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/fra/src/vs/workbench/electron-browser/actions.i18n.json @@ -42,5 +42,10 @@ "navigateUp": "Naviguer vers l'affichage au-dessus", "navigateDown": "Naviguer vers l'affichage en dessous", "increaseViewSize": "Augmenter la taille de l'affichage actuel", - "decreaseViewSize": "Diminuer la taille de l'affichage actuel" + "decreaseViewSize": "Diminuer la taille de l'affichage actuel", + "showPreviousTab": "Afficher l’onglet de la fenêtre précédente", + "showNextWindowTab": "Afficher l’onglet de la fenêtre suivante", + "moveWindowTabToNewWindow": "Déplacer l’onglet de la fenêtre vers la nouvelle fenêtre", + "mergeAllWindowTabs": "Fusionner toutes les fenêtres", + "toggleWindowTabsBar": "Activer/désactiver la barre de fenêtres d’onglets" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/fra/src/vs/workbench/electron-browser/main.contribution.i18n.json index cd1097afbbd..5ce67b4843a 100644 --- a/i18n/fra/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,6 +10,11 @@ "workspaces": "Espaces de travail", "developer": "Développeur", "showEditorTabs": "Contrôle si les éditeurs ouverts doivent s'afficher ou non sous des onglets.", + "workbench.editor.labelFormat.default": "Indiquer le nom du fichier. Lorsque les onglets sont activés et deux fichiers portent le même nom dans un groupe, les sections distinctes du chemin de chaque fichier sont ajoutées. Lorsque les onglets sont désactivées, le chemin relatif à la racine de l’espace de travail est affiché si l’éditeur est actif.", + "workbench.editor.labelFormat.short": "Indiquer le nom du fichier suivi de son nom de répertoire.", + "workbench.editor.labelFormat.medium": "Indiquer le nom du fichier suivi de son chemin d’accès relatif à la racine de l’espace de travail.", + "workbench.editor.labelFormat.long": "Indiquer le nom du fichier suivi de son chemin d’accès absolu.", + "tabDescription": "Contrôle le format de l’étiquette d’un éditeur. La modification de ce paramètre peut par exemple rendre plus facile la compréhension de l’emplacement d’un fichier :\n- short: 'parent'\n- medium: 'workspace/src/parent'\n- long: '/home/user/workspace/src/parent'\n- default: '.../parent', quand un autre onglet partage le même titre, ou la chemin d’accès relatif à l'espace de travail si les onglets sont désactivés", "editorTabCloseButton": "Contrôle la position des boutons de fermeture des onglets de l'éditeur, ou les désactive quand le paramètre a la valeur 'off'.", "showIcons": "Contrôle si les éditeurs ouverts doivent s'afficher ou non avec une icône. Cela implique notamment l'activation d'un thème d'icône.", "enablePreview": "Contrôle si les éditeurs ouverts s'affichent en mode aperçu. Les éditeurs en mode aperçu sont réutilisés jusqu'à ce qu'ils soient conservés (par exemple, après un double-clic ou une modification).", diff --git a/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json b/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json index 7e1c234e5c3..f97dc7aa91f 100644 --- a/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json @@ -36,5 +36,7 @@ "schema.indentationRules.unIndentedLinePattern": "Si une ligne correspond à ce modèle, sa mise en retrait ne doit pas être changée et la ligne ne doit pas être évaluée par rapport aux autres règles.", "schema.indentationRules.unIndentedLinePattern.pattern": "Modèle RegExp pour unIndentedLinePattern.", "schema.indentationRules.unIndentedLinePattern.flags": "Indicateurs RegExp pour unIndentedLinePattern.", - "schema.indentationRules.unIndentedLinePattern.errorMessage": "Doit valider l'expression régulière `/^([gimuy]+)$/`." + "schema.indentationRules.unIndentedLinePattern.errorMessage": "Doit valider l'expression régulière `/^([gimuy]+)$/`.", + "schema.folding": "Paramètres de repliage de la langue.", + "schema.folding.offSide": "Un langage adhère à la règle du hors-champ si les blocs dans ce langage sont exprimées par leur indentation. Si spécifié, les lignes vides appartiennent au bloc suivant." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index d60a025a1a0..ff99f2314ff 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,6 +12,8 @@ "breakpointRemoved": "Point d'arrêt supprimé, ligne {0}, fichier {1}", "compoundMustHaveConfigurations": "L'attribut \"configurations\" du composé doit être défini pour permettre le démarrage de plusieurs configurations.", "configMissing": "Il manque la configuration '{0}' dans 'launch.json'.", + "debugRequestNotSupported": "La requête de débogage configurée '{0}' n'est pas prise en charge.", + "debugRequesMissing": "La requête de débogage est manquante pour la configuration de lancement choisie.", "debugTypeNotSupported": "Le type de débogage '{0}' configuré n'est pas pris en charge.", "debugTypeMissing": "Propriété 'type' manquante pour la configuration de lancement choisie.", "preLaunchTaskErrors": "Des erreurs de build ont été détectées durant le preLaunchTask '{0}'.", diff --git a/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json b/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json index c9d61f5102b..d2552c4f0ca 100644 --- a/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json @@ -29,6 +29,13 @@ "view id": "ID", "view name": "Nom", "view location": "Emplacement", + "colorThemes": "Thèmes de couleurs ({0})", + "iconThemes": "Thèmes d’icônes ({0})", + "colors": "Couleurs ({0})", + "colorId": "Id", + "defaultDark": "Défaut pour le thème sombre", + "defaultLight": "Défaut pour le thème clair", + "defaultHC": "Défaut pour le thème de contraste élevé", "JSON Validation": "Validation JSON ({0})", "commands": "Commandes ({0})", "command name": "Nom", diff --git a/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index bb40909dd1c..2d42d92f27e 100644 --- a/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -51,9 +51,9 @@ "showLanguageExtensionsShort": "Extensions de langage", "showAzureExtensions": "Afficher les Extensions Azure", "showAzureExtensionsShort": "Extensions Azure", - "configureWorkspaceRecommendedExtensions": "Configurer les extensions recommandées (espace de travail)", - "ConfigureWorkspaceRecommendations.noWorkspace": "Les recommandations ne sont disponibles que pour un dossier d'espace de travail.", "OpenExtensionsFile.failed": "Impossible de créer le fichier 'extensions.json' dans le dossier '.vscode' ({0}).", + "configureWorkspaceRecommendedExtensions": "Configurer les extensions recommandées (espace de travail)", + "configureWorkspaceFolderRecommendedExtensions": "Configurer les extensions recommandées (Dossier d'espace de travail)", "builtin": "Intégrée", "disableAll": "Désactiver toutes les extensions installées", "disableAllWorkspace": "Désactiver toutes les extensions installées pour cet espace de travail", diff --git a/i18n/fra/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index c3da7244da9..db6ba3d69b2 100644 --- a/i18n/fra/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -14,6 +14,8 @@ "files.exclude.boolean": "Modèle Glob auquel les chemins de fichiers doivent correspondre. Affectez la valeur true ou false pour activer ou désactiver le modèle.", "files.exclude.when": "Vérification supplémentaire des frères d'un fichier correspondant. Utilisez $(basename) comme variable pour le nom de fichier correspondant.", "associations": "Configurez les associations entre les fichiers et les langages (par exemple, \"*.extension\": \"html\"). Celles-ci ont priorité sur les associations par défaut des langages installés.", + "encoding": "L'encodage du jeu de caractères par défaut à utiliser durant la lecture et l'écriture des fichiers. Ce paramètre peut également être configuré par langage.", + "autoGuessEncoding": "Quand cette option est activée, tente de deviner l'encodage du jeu de caractères à l'ouverture des fichiers. Ce paramètre peut également être configuré par langage.", "eol": "Caractère de fin de ligne par défaut. Utilisez \\n pour LF et \\r\\n pour CRLF.", "trimTrailingWhitespace": "Si l'option est activée, l'espace blanc de fin est supprimé au moment de l'enregistrement d'un fichier.", "insertFinalNewline": "Quand l'option est activée, une nouvelle ligne finale est insérée à la fin du fichier au moment de son enregistrement.", diff --git a/i18n/fra/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json b/i18n/fra/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json index 0a89ce8a7c8..457666ad7bb 100644 --- a/i18n/fra/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "dirtyFile": "1 fichier non enregistré", "dirtyFiles": "{0} fichiers non enregistrés" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index 829d423c32e..740f133866c 100644 --- a/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "Ouvrir le fichier des raccourcis clavier", "openWorkspaceSettings": "Ouvrir les paramètres d'espace de travail", "openFolderSettings": "Ouvrir le dossier Paramètres", - "pickFolder": "Sélectionner le dossier", "configureLanguageBasedSettings": "Configurer les paramètres spécifiques au langage...", "languageDescriptionConfigured": "({0})", "pickLanguage": "Sélectionner un langage" diff --git a/i18n/fra/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index df36de368d3..46bb91f2672 100644 --- a/i18n/fra/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,7 +6,5 @@ { "relaunchSettingMessage": "Un paramètre a changé et nécessite un redémarrage pour être appliqué.", "relaunchSettingDetail": "Appuyez sur le bouton de redémarrage pour redémarrer {0} et activer le paramètre.", - "restart": "Redémarrer", - "relaunchWorkspaceMessage": "Ce changement d’espace de travail nécessite un rechargement de notre système d’extension.", - "reload": "Recharger" + "restart": "Redémarrer" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/fra/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index a7fc2987a18..f2a4104bb7f 100644 --- a/i18n/fra/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -4,8 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "scm providers": "Fournisseurs de contrôle de code source", "commitMessage": "Message (press {0} to commit)", "installAdditionalSCMProviders": "Installer des fournisseurs SCM supplémentaires...", + "no open repo": "Il n’y a aucun fournisseur de contrôle de code source actif.", "source control": "Contrôle de code source", "viewletTitle": "{0} : {1}" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json b/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json index 27c0397de03..b8f73f7acad 100644 --- a/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json @@ -4,5 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "snippet.suggestions.label": "Insérer un extrait de code" + "snippet.suggestions.label": "Insérer un extrait de code", + "sep.userSnippet": "Extraits de code de l'utilisateur", + "sep.extSnippet": "Extraits de code d’extension" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index 7f0f8335a8c..b340098147f 100644 --- a/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -10,6 +10,7 @@ "vscode.extension.contributes.snippets": "Ajoute des extraits de code.", "vscode.extension.contributes.snippets-language": "Identificateur de langage pour lequel cet extrait de code est ajouté.", "vscode.extension.contributes.snippets-path": "Chemin du fichier d'extraits de code. Le chemin est relatif au dossier d'extensions et commence généralement par './snippets/'.", + "badFile": "Le fichier d’extrait \"{0}\" n’a pas pu être lu.", "badVariableUse": "L'extrait de code \"{0}\" confond très probablement les variables et les espaces réservés d'extrait de code. Consultez https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax pour plus d'informations.", "source.snippet": "Extrait de code utilisateur", "detail.snippet": "{0} ({1})", diff --git a/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index be9fba5ac79..9c8b1eb40b1 100644 --- a/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "Tâches", - "ConfigureTaskRunnerAction.noWorkspace": "Les tâches ne sont disponibles que dans un dossier d'espace de travail.", - "ConfigureTaskRunnerAction.quickPick.template": "Sélectionner un exécuteur de tâches", - "ConfigureTaskRunnerAction.autoDetecting": "Détection automatique des tâches pour {0}", - "ConfigureTaskRunnerAction.autoDetect": "En raison de l'échec de la détection automatique du système de tâche, le modèle par défaut va être utilisé. Pour plus d'informations, consultez la sortie de la tâche.", - "ConfigureTaskRunnerAction.autoDetectError": "La détection automatique du système de tâche a produit des erreurs. Consultez la sortie de la tâche pour plus d'informations.", - "ConfigureTaskRunnerAction.failed": "Impossible de créer le fichier 'tasks.json' dans le dossier '.vscode'. Pour plus d'informations, consultez la sortie de la tâche.", - "ConfigureTaskRunnerAction.label": "Configurer l'exécuteur de tâches", + "ConfigureTaskRunnerAction.label": "Configurer une tâche", "ConfigureBuildTaskAction.label": "Configurer une tâche de build", "CloseMessageAction.label": "Fermer", "ShowTerminalAction.label": "Afficher le terminal", @@ -19,11 +13,13 @@ "manyMarkers": "99", "runningTasks": "Afficher les tâches en cours d'exécution", "tasks": "Tâches", + "TaskSystem.noHotSwap": "Changer le moteur d’exécution de tâches avec une tâche active en cours d’exécution nécessite de recharger la fenêtre", "TaskService.noBuildTask1": "Aucune tâche de build définie. Marquez une tâche avec 'isBuildCommand' dans le fichier tasks.json.", "TaskService.noBuildTask2": "Aucune tâche de génération définie. Marquez une tâche comme groupe 'build' dans le fichier tasks.json.", "TaskService.noTestTask1": "Aucune tâche de test définie. Marquez une tâche avec 'isTestCommand' dans le fichier tasks.json.", "TaskService.noTestTask2": "Aucune tâche de test définie. Marquez une tâche comme groupe 'test' dans le fichier tasks.json.", "TaskServer.noTask": "La tâche {0} à exécuter est introuvable.", + "TaskService.associate": "associer", "TaskService.attachProblemMatcher.continueWithout": "Continuer sans analyser la sortie de la tâche", "TaskService.attachProblemMatcher.never": "Ne jamais vérifier la sortie de la tâche", "TaskService.attachProblemMatcher.learnMoreAbout": "En savoir plus sur la sortie de la tâche de numérisation", @@ -35,6 +31,7 @@ "TaskSystem.active": "Une tâche est déjà en cours d'exécution. Terminez-la avant d'exécuter une autre tâche.", "TaskSystem.restartFailed": "Échec de la fin de l'exécution de la tâche {0}", "TaskSystem.configurationErrors": "Erreur : la configuration de tâche fournie comporte des erreurs de validation et ne peut pas être utilisée. Corrigez d'abord les erreurs.", + "taskService.ignoreingFolder": "Ignorer les tâches de configuration pour le dossier de l’espace de travail {0}. Le support de dossiers racine multiples requiert que tous les dossiers utilisent task version 2.0.0\n", "TaskSystem.invalidTaskJson": "Erreur : le fichier tasks.json contient des erreurs de syntaxe. Corrigez-les avant d'exécuter une tâche.\n", "TaskSystem.runningTask": "Une tâche est en cours d'exécution. Voulez-vous la terminer ?", "TaskSystem.terminateTask": "&&Terminer la tâche", @@ -46,24 +43,30 @@ "recentlyUsed": "tâches récemment utilisées", "configured": "tâches configurées", "detected": "tâches détectées", + "TaskService.pickRunTask": "Sélectionner la tâche à exécuter", + "TaslService.noEntryToRun": "Aucune tâche à exécuter n'a été trouvée. Configurer les tâches...", "TaskService.fetchingBuildTasks": "Récupération des tâches de génération...", - "TaskService.noBuildTaskTerminal": "Aucune tâche de génération. Appuyez sur 'Configurer une tâche de génération' pour en définir une.", "TaskService.pickBuildTask": "Sélectionner la tâche de génération à exécuter", + "TaskService.noBuildTask": "Aucune tâche de génération à exécuter n'a été trouvée. Configurer les tâches...", "TaskService.fetchingTestTasks": "Récupération des tâches de test...", - "TaskService.noTestTaskTerminal": "Aucune tâche de test. Appuyez sur 'Configurer un exécuteur de tâches' pour en définir un.", "TaskService.pickTestTask": "Sélectionner la tâche de test à exécuter", - "TaskService.noTaskRunning": "Aucune tâche en cours d'exécution.", + "TaskService.noTestTaskTerminal": "Aucune tâche de test à exécuter n'a été trouvée. Configurer les tâches...", "TaskService.tastToTerminate": "Sélectionner une tâche à terminer", + "TaskService.noTaskRunning": "Aucune tâche en cours d’exécution", "TerminateAction.noProcess": "Le processus lancé n'existe plus. Si la tâche a engendré des tâches en arrière-plan, la sortie de VS Code risque de donner lieu à des processus orphelins.", "TerminateAction.failed": "Échec de la fin de l'exécution de la tâche", - "TaskService.noTaskToRestart": "Aucune tâche à redémarrer.", "TaskService.tastToRestart": "Sélectionner la tâche à redémarrer", - "TaskService.defaultBuildTaskExists": "{0} est déjà marquée comme tâche de génération par défaut.", + "TaskService.noTaskToRestart": "Aucune tâche à redémarrer.", + "TaskService.template": "Sélectionner un modèle de tâche", + "TaskService.createJsonFile": "Créer le fichier tasks.json à partir d'un modèle", + "TaskService.openJsonFile": "Ouvrir le fichier tasks.json", + "TaskService.pickTask": "Sélectionner une tâche à configurer", + "TaskService.defaultBuildTaskExists": "{0} est déjà marquée comme la tâche de génération par défaut", "TaskService.pickDefaultBuildTask": "Sélectionner la tâche à utiliser comme tâche de génération par défaut", "TaskService.defaultTestTaskExists": "{0} est déjà marquée comme tâche de test par défaut.", "TaskService.pickDefaultTestTask": "Sélectionner la tâche à utiliser comme tâche de test par défaut", - "TaskService.noTaskIsRunning": "Aucune tâche n’est en cours d’exécution.", "TaskService.pickShowTask": "Sélectionner la tâche pour montrer sa sortie", + "TaskService.noTaskIsRunning": "Aucune tâche n’est en cours d’exécution", "ShowLogAction.label": "Afficher le journal des tâches", "RunTaskAction.label": "Exécuter la tâche", "RestartTaskAction.label": "Redémarrer la tâche en cours d'exécution", diff --git a/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json b/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json index 413680671bf..2265e06f9f3 100644 --- a/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "TerminalTaskSystem.unknownError": "Une erreur inconnue s'est produite durant l'exécution d'une tâche. Pour plus d'informations, consultez le journal de sortie des tâches.", + "dependencyFailed": "Impossible de résoudre la tâche dépendante '{0}' dans le dossier de l’espace de travail '{1}'", "TerminalTaskSystem.terminalName": "Tâche - {0}", "reuseTerminal": "Le terminal sera réutilisé par les tâches, appuyez sur une touche pour le fermer.", "TerminalTaskSystem": "Impossible d'exécuter une commande d'interpréteur de commandes sur un lecteur UNC.", diff --git a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index bd855cdf8da..c06b522fc53 100644 --- a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -38,5 +38,6 @@ "workbench.action.terminal.focusFindWidget": "Focus sur le widget de recherche", "workbench.action.terminal.hideFindWidget": "Masquer le widget de recherche", "nextTerminalFindTerm": "Afficher le terme de recherche suivant", - "previousTerminalFindTerm": "Afficher le terme de recherche précédent" + "previousTerminalFindTerm": "Afficher le terme de recherche précédent", + "quickOpenTerm": "Changer de terminal actif" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json index 55c06f2a2f3..89f1b826995 100644 --- a/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json @@ -8,5 +8,6 @@ "terminal.foreground": "Couleur de premier plan du terminal.", "terminalCursor.foreground": "La couleur de premier plan du curseur du terminal.", "terminalCursor.background": "La couleur d’arrière-plan du curseur terminal. Permet de personnaliser la couleur d’un caractère recouvert par un curseur de bloc.", + "terminal.selectionBackground": "La couleur d’arrière-plan de sélection du terminal.", "terminal.ansiColor": "Couleur ansi '{0}' dans le terminal." } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json b/i18n/fra/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json index 8f490ebe701..10ab78c5e42 100644 --- a/i18n/fra/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json @@ -10,6 +10,7 @@ "welcomePage.newFile": "Nouveau fichier", "welcomePage.openFolder": "Ouvrir un dossier...", "welcomePage.cloneGitRepository": "Cloner le dépôt Git...", + "welcomePage.addWorkspaceFolder": "Ajouter un dossier d’espace de travail...", "welcomePage.recent": "Récent", "welcomePage.moreRecent": "Plus...", "welcomePage.noRecentFolders": "Aucun dossier récent", diff --git a/i18n/fra/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/fra/src/vs/workbench/services/configuration/node/configuration.i18n.json index 82a641c7444..08d373ab90a 100644 --- a/i18n/fra/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/fra/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -13,7 +13,11 @@ "invalid.title": "'configuration.title' doit être une chaîne", "vscode.extension.contributes.defaultConfiguration": "Contribue aux paramètres de configuration d'éditeur par défaut en fonction du langage.", "invalid.properties": "'configuration.properties' doit être un objet", - "workspaceConfig.folders.description": "Liste des dossiers à charger dans l’espace de travail. Doit être un chemin de fichier, par exemple, '/root/folderA' ou './folderA' pour un chemin relatif résolu selon l’emplacement du fichier d’espace de travail.", - "workspaceConfig.folder.description": "Un chemin de fichier, par exemple, '/root/folderA' ou './folderA' pour un chemin relatif résolu selon l’emplacement du fichier d’espace de travail.", - "workspaceConfig.settings.description": "Paramètres de l’espace de travail" + "invalid.allOf": "'configuration.allOf' est obsolète et ne doit plus être utilisé. Au lieu de cela, passez plusieurs sections de configuration sous forme de tableau au point de contribution 'configuration'.", + "workspaceConfig.folders.description": "Liste des dossiers à être chargés dans l’espace de travail.", + "workspaceConfig.path.description": "Un chemin de fichier, par exemple, '/root/folderA' ou './folderA' pour un chemin relatif résolu selon l’emplacement du fichier d’espace de travail.", + "workspaceConfig.name.description": "Un nom facultatif pour le dossier. ", + "workspaceConfig.uri.description": "URI du dossier", + "workspaceConfig.settings.description": "Paramètres de l’espace de travail", + "workspaceConfig.extensions.description": "Extensions de l’espace de travail" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/fra/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..8ca568a2f40 --- /dev/null +++ b/i18n/fra/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "Il semble que le fichier soit binaire. Impossible de l'ouvrir en tant que texte" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/fra/src/vs/workbench/services/files/node/fileService.i18n.json index 53f8c612cf7..e5bf54a3941 100644 --- a/i18n/fra/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/fra/src/vs/workbench/services/files/node/fileService.i18n.json @@ -5,10 +5,12 @@ // Do not edit this file. It is machine generated. { "fileInvalidPath": "Ressource de fichier non valide ({0})", + "fileIsDirectoryError": "Le fichier est un répertoire", "fileNotModifiedError": "Fichier non modifié depuis", "fileTooLargeError": "Fichier trop volumineux pour être ouvert", "fileBinaryError": "Il semble que le fichier soit binaire. Impossible de l'ouvrir en tant que texte", "fileNotFoundError": "Fichier introuvable ({0})", + "fileExists": "Le fichier à créer existe déjà ({0})", "fileMoveConflict": "Déplacement/copie impossible. Le fichier existe déjà dans la destination.", "unableToMoveCopyError": "Impossible de déplacer/copier. Le fichier remplace le dossier qui le contient.", "foldersCopyError": "Impossible de copier des dossiers dans l'espace de travail. Sélectionnez les fichiers à copier individuellement.", diff --git a/i18n/hun/src/vs/code/electron-main/menus.i18n.json b/i18n/hun/src/vs/code/electron-main/menus.i18n.json index 5c7640234ef..62fae0da197 100644 --- a/i18n/hun/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/hun/src/vs/code/electron-main/menus.i18n.json @@ -175,8 +175,8 @@ "miRunningTask": "&&Futó feladatok megjelenítése...", "miRestartTask": "Futó f&&eladat újraindítása...", "miTerminateTask": "Felada&&t megszakítása...", - "miConfigureTask": "Feladatok &&konfigurálása", - "miConfigureBuildTask": "Alapértelmezett buildelési &&feladat beállítása", + "miConfigureTask": "Feladatok &&konfigurálása...", + "miConfigureBuildTask": "Alapértelmezett buildelési &&feladat beállítása...", "accessibilityOptionsWindowTitle": "Kisegítő lehetőségek beállításai", "miRestartToUpdate": "Újraindítás a frissítéshez...", "miCheckingForUpdates": "Frissítések keresése...", diff --git a/i18n/hun/src/vs/code/electron-main/windows.i18n.json b/i18n/hun/src/vs/code/electron-main/windows.i18n.json index 46466fb1dfe..ca0e590ceea 100644 --- a/i18n/hun/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/hun/src/vs/code/electron-main/windows.i18n.json @@ -18,6 +18,7 @@ "openFolder": "Mappa megnyitása", "openFile": "Fájl megnyitása", "workspaceOpenedMessage": "Nem sikerült menteni a(z) '{0}' munkaterületet", + "workspaceOpenedDetail": "A munkaterület már meg van nyitva egy másik ablakban. Zárja be azt az ablakot, majd próbálja újra!", "openWorkspace": "&&Megnyitás", "openWorkspaceTitle": "Munkaterület megnyitása", "save": "Menté&&s", diff --git a/i18n/hun/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/hun/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index e935364b995..a2afa5b9e5e 100644 --- a/i18n/hun/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/hun/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,6 +13,7 @@ "vscode.extension.contributes.menuItem.group": "A csoport, amibe a parancs tartozik", "vscode.extension.contributes.menus": "Menüket szolgáltat a szerkesztőhöz", "menus.commandPalette": "A parancskatalógus", + "menus.touchBar": "A Touch Bar (csak macOS-en)", "menus.editorTitle": "A szerkesztőablak címsora menüje", "menus.editorContext": "A szerkesztőablak helyi menüje", "menus.explorerContext": "A fájlkezelő helyi menüje", diff --git a/i18n/hun/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/hun/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 9a21167685a..339d7b60e78 100644 --- a/i18n/hun/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/hun/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "A kiegészítő érvénytelen: a package.json nem egy JSON-fájl.", - "restartCode": "Indítsa újra a Code-ot a(z) {0} újratelepítése előtt.", - "installDependeciesConfirmation": "A(z) '{0}' teleítése során annak függőségei is telepítve lesznek. Szeretné folytatni?", - "install": "Igen", - "doNotInstall": "Nem", + "restartCodeLocal": "Indítsa újra a Code-ot a(z) {0} újratelepítése előtt.", + "restartCodeGallery": "Indítsa újra a Code-ot az újratelepítés előtt!", "uninstallDependeciesConfirmation": "Csak a(z) '{0}' kiegészítőt szeretné eltávolítani vagy annak függőségeit is?", "uninstallOnly": "Csak ezt", "uninstallAll": "Mindent", diff --git a/i18n/hun/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/hun/src/vs/workbench/browser/actions/workspaceActions.i18n.json index c7a76624e3d..64c1ec455b3 100644 --- a/i18n/hun/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/hun/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -14,9 +14,9 @@ "selectWorkspace": "Válassza ki a munkaterület mappáit!", "removeFolderFromWorkspace": "Mappa eltávolítása a munkaterületről", "saveWorkspaceAsAction": "Munkaterület mentése másként...", - "saveEmptyWorkspaceNotSupported": "A mentéshez először nyisson meg egy munkaterületet.", "save": "Menté&&s", "saveWorkspace": "Munkaterület mentése", "openWorkspaceAction": "Munkaterület megnyitása...", - "openWorkspaceConfigFile": "Munkaterület konfigurációs fájljának megnyitása" + "openWorkspaceConfigFile": "Munkaterület konfigurációs fájljának megnyitása", + "workspaceFolderPickerPlaceholder": "Válasszon munkaterület-mappát!" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/hun/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..30ba124e291 --- /dev/null +++ b/i18n/hun/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} művelet" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json b/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json index 92cdf300946..4e6291acf38 100644 --- a/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json @@ -36,5 +36,6 @@ "schema.indentationRules.unIndentedLinePattern": "Ha egy sor illeszkedik erre a mintára, akkor az indentálása nem változik, és nem lesz kiértékelve más szabályok alapján.", "schema.indentationRules.unIndentedLinePattern.pattern": "Az unIndentedLinePatternhöz tartozó reguláris kifejezés.", "schema.indentationRules.unIndentedLinePattern.flags": "Az unIndentedLinePatternhöz tartozó reguláris kifejezés beállításai.", - "schema.indentationRules.unIndentedLinePattern.errorMessage": "Illeszkednie kell a következő mintára: `/^([gimuy]+)$/`." + "schema.indentationRules.unIndentedLinePattern.errorMessage": "Illeszkednie kell a következő mintára: `/^([gimuy]+)$/`.", + "schema.folding": "A nyelv kódrészek bezárásával kapcsolatos beállításai." } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index 01fc6a8fbf9..01cf97bbd71 100644 --- a/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -51,9 +51,9 @@ "showLanguageExtensionsShort": "Nyelvi kiegészítők", "showAzureExtensions": "Azure-kiegészítők megjelenítése", "showAzureExtensionsShort": "Azure-kiegészítők", - "configureWorkspaceRecommendedExtensions": "Ajánlott kiegészítők konfigurálása (munkaterületre vonatkozóan)", - "ConfigureWorkspaceRecommendations.noWorkspace": "Az ajánlatok csak egy munkaterület mappájára vonatkozóan érhetők el.", "OpenExtensionsFile.failed": "Nem sikerült létrehozni az 'extensions.json' fájlt a '.vscode' mappánan ({0}).", + "configureWorkspaceRecommendedExtensions": "Ajánlott kiegészítők konfigurálása (munkaterületre vonatkozóan)", + "configureWorkspaceFolderRecommendedExtensions": "Ajánlott kiegészítők konfigurálása (munkaterület-mappára vonatkozóan)", "builtin": "Beépített", "disableAll": "Összes telepített kiegészítő letiltása", "disableAllWorkspace": "Összes telepített kiegészítő letiltása a munkaterületre vonatkozóan", diff --git a/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index d7bd56c34cc..4d1cfca9683 100644 --- a/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "Billentyűparancsfájl megnyitása", "openWorkspaceSettings": "Munkaterület beállításainak megnyitása", "openFolderSettings": "Mappa beállításainak megnyitása", - "pickFolder": "Válasszon mappát!", "configureLanguageBasedSettings": "Nyelvspecifikus beállítások konfigurálása...", "languageDescriptionConfigured": "(({0})", "pickLanguage": "Nyelv kiválasztása" diff --git a/i18n/hun/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/hun/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index 2100b3de8db..2c74ca18207 100644 --- a/i18n/hun/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,7 +6,5 @@ { "relaunchSettingMessage": "Egy olyan beállítás változott, melynek hatályba lépéséhez újraindítás szükséges.", "relaunchSettingDetail": "A beállítás engedélyezéséhez nyomja meg az újraindítás gombot a {0} újraindításához.", - "restart": "Újraindítás", - "relaunchWorkspaceMessage": "A munkaterület módosítása miatt a kiegészítőrendszer újratöltésére van szükség.", - "reload": "Újratöltés" + "restart": "Újraindítás" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/hun/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index 5fe5fb61f23..ba0f414b2c2 100644 --- a/i18n/hun/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "scm providers": "Verziókezelő rendszerek", "commitMessage": "Üzenet (nyomja meg a következőt a commithoz: {0})", "installAdditionalSCMProviders": "További verziókezelő rendszerek telepítése...", "no open repo": "Nincs aktív verziókezelő rendszer.", diff --git a/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index d6497ea60ab..ffce26d0024 100644 --- a/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "Feladatok", - "ConfigureTaskRunnerAction.noWorkspace": "A feladatok csak egy munkaterület mappájára vonatkozóan érhetők el.", - "ConfigureTaskRunnerAction.quickPick.template": "Feladatfuttató rendszer választása", - "ConfigureTaskRunnerAction.autoDetecting": "Feladatok automatikus felderítése a következőhöz: {0}", - "ConfigureTaskRunnerAction.autoDetect": "A feladatfuttató rendszer automatikus felderítése nem sikerült. Az alapértelmezett sablon használata. Tekintse meg a feladatkimenetet a részletekért.", - "ConfigureTaskRunnerAction.autoDetectError": "A feladatfuttató rendszer automatikus felderítése hibákat eredményezett. Tekintse meg a feladatkimenetet a részletekért.", - "ConfigureTaskRunnerAction.failed": "Nem sikerült létrehozni a 'tasks.json' fájlt a '.vscode' mappában. Tekintse meg a feladatkimenetet a részletekért.", - "ConfigureTaskRunnerAction.label": "Feladatfuttató rendszer beállítása", + "ConfigureTaskRunnerAction.label": "Feladat beállítása", "ConfigureBuildTaskAction.label": "Buildelési feladat beállítása", "CloseMessageAction.label": "Bezárás", "ShowTerminalAction.label": "Terminál megtekintése", @@ -19,6 +13,7 @@ "manyMarkers": "99+", "runningTasks": "Futó feladatok megjelenítése", "tasks": "Feladatok", + "TaskSystem.noHotSwap": "A feladatvégrehajtó motor megváltoztatása egy futó, aktív feladat esetén az ablak újraindítását igényli.", "TaskService.noBuildTask1": "Nincs buildelési feladat definiálva. Jelöljön meg egy feladatot az 'isBuildCommand' tulajdonsággal a tasks.json fájlban!", "TaskService.noBuildTask2": "Nincs buildelési feladat definiálva. Jelöljön meg egy feladatot a 'build' csoporttal a tasks.json fájlban!", "TaskService.noTestTask1": "Nincs tesztelési feladat definiálva. Jelöljön meg egy feladatot az 'isTestCommand' tulajdonsággal a tasks.json fájlban!", @@ -47,22 +42,16 @@ "configured": "konfigurált feladatok", "detected": "talált feladatok", "TaskService.fetchingBuildTasks": "Buildelési feladatok lekérése...", - "TaskService.noBuildTaskTerminal": "Buildelési feladat nem található. Futtassa a 'Buildelési feladat beállítása' parancsot a létrehozáshoz!", "TaskService.pickBuildTask": "Válassza ki a futtatandó buildelési feladatot!", "TaskService.fetchingTestTasks": "Tesztelési feladatok lekérése...", - "TaskService.noTestTaskTerminal": "Buildelési feladat nem található. Futtassa a 'Feladatfuttató rendszer beállítása' parancsot a létrehozáshoz!", "TaskService.pickTestTask": "Válassza ki a futtatandó tesztelési feladatot", - "TaskService.noTaskRunning": "Jelenleg nem fut feladat.", "TaskService.tastToTerminate": "Válassza ki a megszakítandó feladatot!", "TerminateAction.noProcess": "Az elindított folyamat már nem létezik. Ha a feladat háttérfeladatokat indított, a VS Code-ból való kilépés árva folyamatokat eredményezhet. ", "TerminateAction.failed": "Nem sikerült megszakítani a futó feladatot", - "TaskService.noTaskToRestart": "Nincs újraindítható feladat.", "TaskService.tastToRestart": "Válassza ki az újraindítandó feladatot!", - "TaskService.defaultBuildTaskExists": "A(z) {0} már meg van jelölve alapértelmezett buildelési feladatként.", "TaskService.pickDefaultBuildTask": "Válassza ki az alpértelmezett buildelési feladatként használt feladatot!", "TaskService.defaultTestTaskExists": "A(z) {0} már meg van jelölve alapértelmezett tesztelési feladatként.", "TaskService.pickDefaultTestTask": "Válassza ki az alpértelmezett tesztelési feladatként használt feladatot!", - "TaskService.noTaskIsRunning": "Nem fut feladat.", "TaskService.pickShowTask": "Válassza ki a feladatot a kimenet megjelenítéséhez!", "ShowLogAction.label": "Feladatnapló megtekintése", "RunTaskAction.label": "Feladat futtatása", diff --git a/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json b/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json index cbc547d3e4a..496170af36e 100644 --- a/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json +++ b/i18n/hun/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "TerminalTaskSystem.unknownError": "Ismeretlen hiba történt a feladat végrehajtása közben. Részletek a feladat kimeneti naplójában találhatók.", + "dependencyFailed": "Nem sikerült feloldani a(z) '{0}' függő feladatot a(z) '{1}' munkaterületi mappában", "TerminalTaskSystem.terminalName": "Feladat – {0}", "reuseTerminal": "A terminál újra lesz hasznosítva a feladatok által. Nyomjon meg egy billentyűt a bezáráshoz.", "TerminalTaskSystem": "Rendszerparancsok nem hajthatók végre UNC-meghajtókon.", diff --git a/i18n/hun/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/hun/src/vs/workbench/services/configuration/node/configuration.i18n.json index 4ec73bfcb21..3936a1aba7b 100644 --- a/i18n/hun/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/hun/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -14,7 +14,9 @@ "vscode.extension.contributes.defaultConfiguration": "Adott nyelvre vonatkozóan szerkesztőbeállításokat szolgáltat.", "invalid.properties": "A 'configuration.properties' értékét egy objektumként kell megadni", "invalid.allOf": "A 'configuration.allOf' elavult, és használata nem javasolt. Helyette több konfigurációs szakaszt kell átadni tömbként a 'configuration' értékeként.", - "workspaceConfig.folders.description": "A munkaterületre betöltött mappák listája. Elérési útnak kell lennie, pl. `/root/folderA` vagy `./folderA` relatív elérési út esetén, ami a munkaterületfájl helye alapján lesz feloldva.", - "workspaceConfig.folder.description": "Egy fájl elérési útja, pl. `/root/folderA` vagy `./folderA` relatív elérési út esetén, ami a munkaterületfájl helye alapján lesz feloldva.", - "workspaceConfig.settings.description": "Munkaterület-beállítások" + "workspaceConfig.path.description": "Egy fájl elérési útja, pl. `/root/folderA` vagy `./folderA` relatív elérési út esetén, ami a munkaterületfájl helye alapján lesz feloldva.", + "workspaceConfig.name.description": "A mappa neve. Nem kötelező megadni.", + "workspaceConfig.uri.description": "A mappa URI-ja", + "workspaceConfig.settings.description": "Munkaterület-beállítások", + "workspaceConfig.extensions.description": "Munkaterület-kiegészítők" } \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/hun/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..f77948f5276 --- /dev/null +++ b/i18n/hun/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "A fájl binárisnak tűnik és nem nyitható meg szövegként" +} \ No newline at end of file diff --git a/i18n/hun/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/hun/src/vs/workbench/services/files/node/fileService.i18n.json index 94c9d3c7732..5dbccfabb8d 100644 --- a/i18n/hun/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/hun/src/vs/workbench/services/files/node/fileService.i18n.json @@ -10,6 +10,7 @@ "fileTooLargeError": "A fájl túl nagy a megnyitáshoz", "fileBinaryError": "A fájl binárisnak tűnik és nem nyitható meg szövegként", "fileNotFoundError": "Fájl nem található ({0})", + "fileExists": "A létrehozandó fájl már létezik ({0})", "fileMoveConflict": "Nem lehet áthelyezni vagy másolni. A fájl már létezik a célhelyen.", "unableToMoveCopyError": "Nem lehet áthelyezni vagy másolni. A fájl felülírná a mappát, amiben található.", "foldersCopyError": "A munkaterületre nem másolhatók mappák. Válasszon ki egyedi fájlokat a másoláshoz.", diff --git a/i18n/ita/src/vs/code/electron-main/menus.i18n.json b/i18n/ita/src/vs/code/electron-main/menus.i18n.json index fbec1e5bf9c..d950c064592 100644 --- a/i18n/ita/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/ita/src/vs/code/electron-main/menus.i18n.json @@ -171,8 +171,6 @@ "miRunningTask": "Mostra attività in esec&&uzione...", "miRestartTask": "Ria&&vvia attività in esecuzione...", "miTerminateTask": "&&Termina attività...", - "miConfigureTask": "&&Configura attività", - "miConfigureBuildTask": "Configura atti&&vità di compilazione predefinita", "accessibilityOptionsWindowTitle": "Opzioni accessibilità", "miRestartToUpdate": "Riavvia per aggiornare...", "miCheckingForUpdates": "Verifica della disponibilità di aggiornamenti...", diff --git a/i18n/ita/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/ita/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 2c46cc8fbb5..943d334ccda 100644 --- a/i18n/ita/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/ita/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,7 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "Estensione non valida: package.json non è un file JSON.", - "restartCode": "Riavviare Code prima di reinstallare {0}.", - "installDependeciesConfirmation": "Se si installa '{0}', verranno installate anche le relative dipendenze. Continuare?", - "install": "Sì", - "doNotInstall": "No", + "restartCodeLocal": "Riavviare Code prima di reinstallare {0}.", "uninstallDependeciesConfirmation": "Disinstallare solo '{0}' o anche le relative dipendenze?", "uninstallOnly": "Solo", "uninstallAll": "Tutto", diff --git a/i18n/ita/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/ita/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 86e9486ae88..0c7b03c458a 100644 --- a/i18n/ita/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -14,7 +14,6 @@ "selectWorkspace": "Seleziona cartelle per l'area di lavoro", "removeFolderFromWorkspace": "Rimuovi cartella dall'area di lavoro", "saveWorkspaceAsAction": "Salva area di lavoro come...", - "saveEmptyWorkspaceNotSupported": "Aprire prima un'area di lavoro da salvare.", "save": "&&Salva", "saveWorkspace": "Salva area di lavoro", "openWorkspaceAction": "Apri area di lavoro...", diff --git a/i18n/ita/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..a7b1c661726 --- /dev/null +++ b/i18n/ita/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "Azioni di {0}" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index f3e714c0677..fe25758722c 100644 --- a/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -51,9 +51,8 @@ "showLanguageExtensionsShort": "Estensioni del linguaggio", "showAzureExtensions": "Mostra estensioni di Azure", "showAzureExtensionsShort": "Estensioni di Azure", - "configureWorkspaceRecommendedExtensions": "Configura estensioni consigliate (area di lavoro)", - "ConfigureWorkspaceRecommendations.noWorkspace": "Gli elementi consigliati sono disponibili solo per una cartella dell'area di lavoro.", "OpenExtensionsFile.failed": "Non è possibile creare il file 'extensions.json' all'interno della cartella '.vscode' ({0}).", + "configureWorkspaceRecommendedExtensions": "Configura estensioni consigliate (area di lavoro)", "builtin": "Predefinita", "disableAll": "Disabilita tutte le estensioni installate", "disableAllWorkspace": "Disabilita tutte le estensioni installate per questa area di lavoro", diff --git a/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index b5f2514add4..a5a6e8a1bba 100644 --- a/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "Apri file dei tasti di scelta rapida", "openWorkspaceSettings": "Apri impostazioni area di lavoro", "openFolderSettings": "Apri impostazioni cartella", - "pickFolder": "Seleziona cartella", "configureLanguageBasedSettings": "Configura impostazioni specifiche del linguaggio...", "languageDescriptionConfigured": "({0})", "pickLanguage": "Seleziona linguaggio" diff --git a/i18n/ita/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/ita/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index 0a301a74cb4..fa6e01989cf 100644 --- a/i18n/ita/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,7 +6,5 @@ { "relaunchSettingMessage": "È necessario riavviare per rendere effettiva un'impostazione modificata.", "relaunchSettingDetail": "Fare clic sul pulsante di riavvio per riavviare {0} e abilitare l'impostazione.", - "restart": "Riavvia", - "relaunchWorkspaceMessage": "Questo cambiamento di area di lavoro richiede un ricaricamento del nostro sistema di estensione.", - "reload": "Ricarica" + "restart": "Riavvia" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/ita/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index 2d3712bd868..1cb08dc3cfc 100644 --- a/i18n/ita/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "Attività", - "ConfigureTaskRunnerAction.noWorkspace": "Le attività sono disponibili solo per una cartella dell'area di lavoro.", - "ConfigureTaskRunnerAction.quickPick.template": "Seleziona strumento di esecuzione attività", - "ConfigureTaskRunnerAction.autoDetecting": "Rilevamento automatico delle attività per {0}", - "ConfigureTaskRunnerAction.autoDetect": "Il rilevamento automatico del sistema dell'attività non è riuscito. Verrà usato il modello predefinito. Per i dettagli, vedere l'output dell'attività.", - "ConfigureTaskRunnerAction.autoDetectError": "Il rilevamento automatico del sistema dell'attività ha restituito errori. Per i dettagli, vedere l'output dell'attività.", - "ConfigureTaskRunnerAction.failed": "Non è possibile creare il file 'tasks.json' all'interno della cartella '.vscode'. Per dettagli, vedere l'output dell'attività.", - "ConfigureTaskRunnerAction.label": "Configura esecuzione attività", + "ConfigureTaskRunnerAction.label": "Configura attività", "ConfigureBuildTaskAction.label": "Configura attività di compilazione", "CloseMessageAction.label": "Chiudi", "ShowTerminalAction.label": "Visualizza terminale", @@ -47,22 +41,16 @@ "configured": "attività configurate", "detected": "attività rilevate", "TaskService.fetchingBuildTasks": "Recupero delle attività di compilazione...", - "TaskService.noBuildTaskTerminal": "Non è stata trovata alcuna attività di compilazione. Fare clic su 'Configura attività di compilazione' per definirne una.", "TaskService.pickBuildTask": "Selezionare l'attività di compilazione da eseguire", "TaskService.fetchingTestTasks": "Recupero delle attività di test...", - "TaskService.noTestTaskTerminal": "Non è stata trovata alcuna attività di test. Fare clic su 'Configura Test Runner' per definirne una.", "TaskService.pickTestTask": "Selezionare l'attività di test da eseguire", - "TaskService.noTaskRunning": "Non ci sono attività attualmente in esecuzione.", "TaskService.tastToTerminate": "Selezionare l'attività da terminare", "TerminateAction.noProcess": "Il processo avviato non esiste più. Se l'attività implica la generazione di attività in background, uscendo da Visual Studio Code potrebbero essere presenti processi orfani.", "TerminateAction.failed": "Non è stato possibile terminare l'attività in esecuzione", - "TaskService.noTaskToRestart": "Non ci sono attività da riavviare.", "TaskService.tastToRestart": "Selezionare l'attività da riavviare", - "TaskService.defaultBuildTaskExists": "{0} è già contrassegnato come attività di compilazione predefinita.", "TaskService.pickDefaultBuildTask": "Selezionare l'attività da usare come attività di compilazione predefinita", "TaskService.defaultTestTaskExists": "{0} è già contrassegnato come attività di test predefinita.", "TaskService.pickDefaultTestTask": "Selezionare l'attività da usare come attività di test predefinita", - "TaskService.noTaskIsRunning": "Nessuna attività è in esecuzione.", "TaskService.pickShowTask": "Selezionare l'attività di cui mostrare l'output", "ShowLogAction.label": "Mostra log attività", "RunTaskAction.label": "Esegui attività", diff --git a/i18n/ita/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/ita/src/vs/workbench/services/configuration/node/configuration.i18n.json index ccaa20ccc11..2a16527c203 100644 --- a/i18n/ita/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/ita/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -13,7 +13,6 @@ "invalid.title": "'configuration.title' deve essere una stringa", "vscode.extension.contributes.defaultConfiguration": "Aggiunge come contributo le impostazioni di configurazione predefinite dell'editor in base al linguaggio.", "invalid.properties": "'configuration.properties' deve essere un oggetto", - "workspaceConfig.folders.description": "Elenco delle cartelle da caricare nell'area di lavoro. Deve essere un percorso di file, ad esempio `/root/folderA` o `./folderA` per un percorso relativo che verrà risolto in base alla posizione del file dell'area di lavoro.", - "workspaceConfig.folder.description": "Percorso di file, ad esempio `/root/folderA` o `./folderA` per un percorso relativo che verrà risolto in base alla posizione del file dell'area di lavoro.", + "workspaceConfig.path.description": "Percorso di file, ad esempio `/root/folderA` o `./folderA` per un percorso relativo che verrà risolto in base alla posizione del file dell'area di lavoro.", "workspaceConfig.settings.description": "Impostazioni di area di lavoro" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/ita/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..6952c245dd7 --- /dev/null +++ b/i18n/ita/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "Il file sembra essere binario e non può essere aperto come file di testo" +} \ No newline at end of file diff --git a/i18n/jpn/extensions/css/package.i18n.json b/i18n/jpn/extensions/css/package.i18n.json index e24d5a99b9b..5ff9ba2550a 100644 --- a/i18n/jpn/extensions/css/package.i18n.json +++ b/i18n/jpn/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "正しくないパラメーターの数", "css.lint.boxModel.desc": "パディングまたは枠線を使用する場合は幅または高さを使用しないでください", "css.lint.compatibleVendorPrefixes.desc": "ベンダー固有のプレフィックスを使用する場合は、他のすべてのベンダー固有のプロパティも必ず含めてください", @@ -25,6 +26,7 @@ "css.trace.server.desc": "VS Code と CSS 言語サーバー間の通信をトレースします。", "css.validate.title": "CSS の検証と問題の重大度を制御します。", "css.validate.desc": "すべての検証を有効または無効にします", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "正しくないパラメーターの数", "less.lint.boxModel.desc": "パディングまたは枠線を使用する場合は幅または高さを使用しないでください", "less.lint.compatibleVendorPrefixes.desc": "ベンダー固有のプレフィックスを使用する場合は、他のすべてのベンダー固有のプロパティも必ず含めてください", @@ -45,6 +47,7 @@ "less.lint.zeroUnits.desc": "0 の単位は必要ありません", "less.validate.title": "LESS の検証と問題の重大度を制御します。", "less.validate.desc": "すべての検証を有効または無効にします", + "scss.title": "SCSS (Sass)", "scss.lint.argumentsInColorFunction.desc": "正しくないパラメーターの数", "scss.lint.boxModel.desc": "パディングまたは枠線を使用する場合は幅または高さを使用しないでください", "scss.lint.compatibleVendorPrefixes.desc": "ベンダー固有のプレフィックスを使用する場合は、他のすべてのベンダー固有のプロパティも必ず含めてください", diff --git a/i18n/jpn/extensions/git/out/commands.i18n.json b/i18n/jpn/extensions/git/out/commands.i18n.json index 072e2fc7089..af7b32febd1 100644 --- a/i18n/jpn/extensions/git/out/commands.i18n.json +++ b/i18n/jpn/extensions/git/out/commands.i18n.json @@ -34,7 +34,7 @@ "delete files": "複数のファイルを削除", "there are untracked files single": "破棄すると次の未追跡ファイルがディスクから削除されます: {0}。", "there are untracked files": "破棄すると {0} 個の未追跡ファイルがディスクから削除されます。", - "confirm discard all 2": "{0}\n\nこの変更は元に戻すことはできません、現在のワーキング セットは永久に失われます。", + "confirm discard all 2": "{0}\n\nこの変更は元に戻すことはできません。現在のワーキング セットは永久に失われます。", "yes discard tracked": "1 つの追跡ファイルを破棄", "yes discard tracked multiple": "{0} 個の追跡ファイルを破棄", "no staged changes": "コミットするステージされた変更がありません。\n\nすべての変更を自動的にステージして、直接コミットしますか?", diff --git a/i18n/jpn/src/vs/code/electron-main/menus.i18n.json b/i18n/jpn/src/vs/code/electron-main/menus.i18n.json index fc66e6ab241..a4f82d97faf 100644 --- a/i18n/jpn/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/jpn/src/vs/code/electron-main/menus.i18n.json @@ -151,6 +151,10 @@ "mZoom": "ズーム", "mBringToFront": "すべてを前面に配置", "miSwitchWindow": "ウィンドウの切り替え(&&W)...", + "mShowPreviousTab": "前のタブを表示", + "mShowNextTab": "次のタブを表示", + "mMoveTabToNewWindow": "タブを新しいウィンドウに移動", + "mMergeAllWindows": "すべてのウィンドウを統合", "miToggleDevTools": "開発者ツールの切り替え(&&T)", "miAccessibilityOptions": "ユーザー補助オプション(&&O)", "miReportIssues": "問題の報告(&&I)", @@ -171,8 +175,6 @@ "miRunningTask": "実行中のタスクを表示(&&G)...", "miRestartTask": "実行中のタスクの再起動(&&E)...", "miTerminateTask": "タスクの終了(&&T)...", - "miConfigureTask": "タスクの構成(&&C)", - "miConfigureBuildTask": "既定のビルド タスクの構成(&&F)", "accessibilityOptionsWindowTitle": "ユーザー補助オプション", "miRestartToUpdate": "再起動して更新...", "miCheckingForUpdates": "更新を確認しています...", diff --git a/i18n/jpn/src/vs/code/electron-main/windows.i18n.json b/i18n/jpn/src/vs/code/electron-main/windows.i18n.json index 83ca2a71403..7558f5d726f 100644 --- a/i18n/jpn/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/jpn/src/vs/code/electron-main/windows.i18n.json @@ -17,6 +17,8 @@ "open": "開く", "openFolder": "フォルダーを開く", "openFile": "ファイルを開く", + "workspaceOpenedMessage": "ワークスペース '{0}' を保存できません", + "workspaceOpenedDetail": "ワークスペースは既に別のウィンドウで開いています。最初にそのウィンドウを閉じててから、もう一度やり直してください。", "openWorkspace": "開く(&&O)", "openWorkspaceTitle": "ワークスペースを開く", "save": "保存(&&S)", diff --git a/i18n/jpn/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/jpn/src/vs/editor/common/config/commonEditorConfig.i18n.json index 28b5711561e..25be0c66adb 100644 --- a/i18n/jpn/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/jpn/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -88,6 +88,7 @@ "accessibilitySupport": "エディターをスクリーン リーダーに最適化されたモードで実行するかどうかを制御します。", "links": "エディターがリンクを検出してクリック可能な状態にするかどうかを制御します", "colorDecorators": "エディターでインライン カラー デコレーターと色の選択を表示する必要があるかどうかを制御します。", + "codeActions": "コード アクション (lightbulb) を有効にする", "sideBySide": "差分エディターが差分を横に並べて表示するか、行内に表示するかを制御します", "ignoreTrimWhitespace": "差分エディターが、先頭または末尾の空白の変更を差分として表示するかどうかを制御します。", "renderIndicators": "差分エディターが追加/削除された変更に +/- インジケーターを示すかどうかを制御します", diff --git a/i18n/jpn/src/vs/platform/environment/node/argv.i18n.json b/i18n/jpn/src/vs/platform/environment/node/argv.i18n.json index 65f0ae56870..1545142948e 100644 --- a/i18n/jpn/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/jpn/src/vs/platform/environment/node/argv.i18n.json @@ -15,7 +15,7 @@ "reuseWindow": "最後のアクティブ ウィンドウにファイルまたはフォルダーを強制的に開きます。", "userDataDir": "ユーザー データを保持するディレクトリを指定します。ルートで実行している場合に役立ちます。", "verbose": "詳細出力を表示します (--wait を含みます)。", - "wait": "戻る前にファイルが閉じるまでお待ちください。", + "wait": "現在のファイルが閉じられるまで待機します。", "extensionHomePath": "拡張機能のルート パスを設定します。", "listExtensions": "インストールされている拡張機能を一覧表示します。", "showVersions": "--list-extension と使用するとき、インストールされている拡張機能のバージョンを表示します。", diff --git a/i18n/jpn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/jpn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 2753d38a6d2..4b1099e0421 100644 --- a/i18n/jpn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/jpn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,7 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "正しくない拡張機能: package.json は JSON ファイルではありません。", - "restartCode": "{0} を再インストールする前に、Code を再起動してください。", - "installDependeciesConfirmation": "'{0}' をインストールすると、その依存関係もインストールされます。続行してもよろしいですか?", - "install": "はい", - "doNotInstall": "いいえ", + "restartCodeLocal": "{0} を再インストールする前に、Code を再起動してください。", "uninstallDependeciesConfirmation": "'{0}' のみをアンインストールしますか、または依存関係もアンインストールしますか?", "uninstallOnly": "限定", "uninstallAll": "すべて", diff --git a/i18n/jpn/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/jpn/src/vs/workbench/browser/actions/workspaceActions.i18n.json index a93dd60c185..6d5c23d570a 100644 --- a/i18n/jpn/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -14,7 +14,6 @@ "selectWorkspace": "ワークスペースのフォルダーを選択", "removeFolderFromWorkspace": "ワークスペースからフォルダーを削除", "saveWorkspaceAsAction": "名前を付けてワークスペースを保存...", - "saveEmptyWorkspaceNotSupported": "最初に保存するためのワークスペースを開いてください。", "save": "保存(&&S)", "saveWorkspace": "ワークスペースを保存", "openWorkspaceAction": "ワークスペースを開く...", diff --git a/i18n/jpn/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json index 4a9a751d98c..8cee18d4c69 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json @@ -6,6 +6,7 @@ { "badgeTitle": "{0} - {1}", "titleKeybinding": "{0} ({1})", + "removeFromActivityBar": "アクティビティ バーから非表示", "keepInActivityBar": "アクティビティ バーに保持", "additionalViews": "その他のビュー", "numberBadge": "{0} ({1})", diff --git a/i18n/jpn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index d1ccb18830d..5c802777acf 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -35,6 +35,7 @@ "openPreviousEditorInGroup": "グループ内で前のエディターを開く", "navigateNext": "次に進む", "navigatePrevious": "前に戻る", + "navigateLast": "戻る", "reopenClosedEditor": "閉じたエディターを再度開く", "clearRecentFiles": "最近開いた項目をクリア", "showEditorsInFirstGroup": "最初のグループのエディターを表示する", diff --git a/i18n/jpn/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..6bcbcb522f9 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} 個のアクション" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/jpn/src/vs/workbench/electron-browser/actions.i18n.json index 8938e8dd9e8..a31924013b2 100644 --- a/i18n/jpn/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/jpn/src/vs/workbench/electron-browser/actions.i18n.json @@ -42,5 +42,10 @@ "navigateUp": "上のビュー部分に移動", "navigateDown": "下のビュー部分に移動", "increaseViewSize": "現在のビューのサイズの拡大", - "decreaseViewSize": "現在のビューのサイズの縮小" + "decreaseViewSize": "現在のビューのサイズの縮小", + "showPreviousTab": "前のウィンドウ タブを表示", + "showNextWindowTab": "次のウィンドウ タブを表示", + "moveWindowTabToNewWindow": "ウィンドウ タブを新しいウィンドウに移動", + "mergeAllWindowTabs": "すべてのウィンドウを統合", + "toggleWindowTabsBar": "ウィンドウ タブ バーの切り替え" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/jpn/src/vs/workbench/electron-browser/main.contribution.i18n.json index 6061715ea0e..903ec7ec36c 100644 --- a/i18n/jpn/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,6 +10,11 @@ "workspaces": "ワークスペース", "developer": "開発者", "showEditorTabs": "開いているエディターをタブに表示するかどうかを制御します。", + "workbench.editor.labelFormat.default": "ファイルの名前を表示します。タブが有効かつ1 つのグループの2 つの同名ファイルに各ファイルのパスの区切り記号が追加されます。タブを無効にすると、エディターがアクティブな時にワークスペースのルートへの相対パスが表示されます。", + "workbench.editor.labelFormat.short": "ディレクトリ名に続けてファイル名を表示します。", + "workbench.editor.labelFormat.medium": "ワークスペース ルートからの相対パスに続けてファイル名を表示します。", + "workbench.editor.labelFormat.long": "絶対パスに続けてファイル名を表示します。", + "tabDescription": "エディターのラベルの書式を制御します。例としてこの設定を変更することでファイルの場所を理解しやすくなります:\n- short: 'parent'\n- medium: 'workspace/src/parent'\n- long: '/home/user/workspace/src/parent'\n- default: '.../parent',  別タブで、同じタイトルを共有する場合や、相対的なワークスペース パス タブが無効になっている場合", "editorTabCloseButton": "エディター タブの閉じるボタンの位置を制御するか、[off] に設定した場合に無効にします。", "showIcons": "開いているエディターをアイコンで表示するかどうかを制御します。これには、アイコンのテーマを有効にする必要もあります。", "enablePreview": "開いているエディターをプレビューとして表示するかどうかを制御します。プレビュー エディターは、保持されている間、再利用されます (ダブルクリックまたは編集などによって)。", diff --git a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index 6754c23d67a..e47e23b4326 100644 --- a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,6 +12,8 @@ "breakpointRemoved": "ブレークポイントを削除しました。行 {0}、ファイル {1}", "compoundMustHaveConfigurations": "複合構成を開始するには、複合に \"configurations\" 属性が設定されている必要があります。", "configMissing": "構成 '{0}' が 'launch.json' 内にありません。", + "debugRequestNotSupported": "構成されているデバッグ要求の '{0}' はサポートされていません", + "debugRequesMissing": "選択している起動構成にデバッグ要求が含まれていません", "debugTypeNotSupported": "構成されているデバッグの種類 '{0}' はサポートされていません。", "debugTypeMissing": "選択された起動構成のプロパティ 'type' がありません。", "preLaunchTaskErrors": "preLaunchTask '{0}' の実行中にビルド エラーが検出されました。", diff --git a/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json b/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json index 6681f4c4778..16b98008acb 100644 --- a/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json @@ -29,7 +29,13 @@ "view id": "ID", "view name": "名前", "view location": "場所", + "colorThemes": "配色テーマ ({0})", + "iconThemes": "アイコン テーマ ({0})", + "colors": "配色 ({0})", "colorId": "Id", + "defaultDark": "ダーク テーマの既定値", + "defaultLight": "ライト テーマの既定値", + "defaultHC": "ハイ コントラストの既定値", "JSON Validation": "JSON 検証 ({0})", "commands": "コマンド ({0})", "command name": "名前", diff --git a/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index 473ed0e7c04..d53e187ce18 100644 --- a/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -51,9 +51,8 @@ "showLanguageExtensionsShort": "言語の拡張機能", "showAzureExtensions": "Azure 拡張機能の表示", "showAzureExtensionsShort": "Azure 拡張機能", - "configureWorkspaceRecommendedExtensions": "お勧めの拡張機能の構成 (ワークスペース)", - "ConfigureWorkspaceRecommendations.noWorkspace": "推奨事項はワークスペース フォルダーでのみ利用可能です。", "OpenExtensionsFile.failed": "'.vscode' ファルダー ({0}) 内に 'extensions.json' ファイルを作成できません。", + "configureWorkspaceRecommendedExtensions": "お勧めの拡張機能の構成 (ワークスペース)", "builtin": "ビルトイン", "disableAll": "インストール済みのすべての拡張機能を無効にする", "disableAllWorkspace": "このワークスペースのインストール済みの拡張機能をすべて無効にする", diff --git a/i18n/jpn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/jpn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index 9cfd4305ea8..2729f6aada9 100644 --- a/i18n/jpn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -14,6 +14,8 @@ "files.exclude.boolean": "ファイル パスの照合基準となる glob パターン。これを true または false に設定すると、パターンがそれぞれ有効/無効になります。", "files.exclude.when": "一致するファイルの兄弟をさらにチェックします。一致するファイル名の変数として $(basename) を使用します。", "associations": "言語に対するファイルの関連付け (例 \"*.extension\": \"html\") を構成します。これらの関連付けは、インストールされている言語の既定の関連付けより優先されます。", + "encoding": "ファイルの読み取り/書き込みで使用する既定の文字セット エンコーディング。言語ごとに構成することも可能です。", + "autoGuessEncoding": "有効な場合、ファイルを開くときに文字セット エンコードを推測します。言語ごとに構成することも可能です。", "eol": "既定の改行文字。LF の場合には \\n を CRLF の場合には \\r\\n を使用してください。", "trimTrailingWhitespace": "有効にすると、ファイルの保存時に末尾の空白をトリミングします。", "insertFinalNewline": "有効にすると、ファイルの保存時に最新の行を末尾に挿入します。", diff --git a/i18n/jpn/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json b/i18n/jpn/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json index e8bcfe52d77..a21e553496c 100644 --- a/i18n/jpn/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "dirtyFile": "1 つの未保存のファイル", "dirtyFiles": "{0} 個の未保存のファイル" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index c1aa63ce163..3257770db15 100644 --- a/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "キーボード ショートカット ファイルを開く", "openWorkspaceSettings": "ワークスペース設定を開く", "openFolderSettings": "フォルダーの設定を開く", - "pickFolder": "フォルダーの選択", "configureLanguageBasedSettings": "言語固有の設定を構成します...", "languageDescriptionConfigured": "({0})", "pickLanguage": "言語の選択" diff --git a/i18n/jpn/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/jpn/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index 34db8f687ec..52988cf3a91 100644 --- a/i18n/jpn/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,7 +6,5 @@ { "relaunchSettingMessage": "再起動が必要な設定を変更しました。", "relaunchSettingDetail": "{0} を再起動ボタンで再起動して、設定を有効にしてください。", - "restart": "再起動", - "relaunchWorkspaceMessage": "このワークスペースの変更には、拡張システムの再読み込みが必要です。", - "reload": "再読み込み" + "restart": "再起動" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json b/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json index c3de7d0fb34..cc309b1f286 100644 --- a/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json @@ -4,5 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "snippet.suggestions.label": "スニペットの挿入" + "snippet.suggestions.label": "スニペットの挿入", + "sep.userSnippet": "ユーザー スニペット", + "sep.extSnippet": "拡張機能のスニペット" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index 5543f202fbd..adb4b5b9a1d 100644 --- a/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -10,6 +10,7 @@ "vscode.extension.contributes.snippets": "スニペットを提供します。", "vscode.extension.contributes.snippets-language": "このスニペットの提供先の言語識別子です。", "vscode.extension.contributes.snippets-path": "スニペット ファイルのパス。拡張機能フォルダーの相対パスであり、通常 './snippets/' で始まります。", + "badFile": "スニペット ファイル \"{0}\" を読み込むことができませんでした。", "badVariableUse": "スニペット \"{0}\" は、スニペット変数とスニペット プレースホルダーを混乱させる可能性が非常にあります。詳細については https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax をご覧ください。", "source.snippet": "ユーザー スニペット", "detail.snippet": "{0} ({1})", diff --git a/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index 2308da613b4..ff372f92e2c 100644 --- a/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "タスク", - "ConfigureTaskRunnerAction.noWorkspace": "タスクはワークスペース フォルダーでのみ利用可能です。", - "ConfigureTaskRunnerAction.quickPick.template": "タスク ランナーを選択", - "ConfigureTaskRunnerAction.autoDetecting": "{0} のタスクを自動検出", - "ConfigureTaskRunnerAction.autoDetect": "タスク システムの自動検出が失敗しました。既定のテンプレートを使用しています。詳細については、タスク出力を参照してください", - "ConfigureTaskRunnerAction.autoDetectError": "タスク システムの自動検出でエラーが発生しました。詳細については、タスク出力を参照してください。", - "ConfigureTaskRunnerAction.failed": "'.vscode' フォルダー内に 'tasks.json' ファイルを作成できません。詳細については、タスク出力を参照してください。", - "ConfigureTaskRunnerAction.label": "タスク ランナーの構成", + "ConfigureTaskRunnerAction.label": "タスクの構成", "ConfigureBuildTaskAction.label": "ビルド タスクを構成します", "CloseMessageAction.label": "閉じる", "ShowTerminalAction.label": "ターミナルの表示", @@ -19,6 +13,7 @@ "manyMarkers": "99+", "runningTasks": "実行中のタスクを表示", "tasks": "タスク", + "TaskSystem.noHotSwap": "アクティブなタスクを実行しているタスク実行エンジンを変更するには、ウィンドウの再読み込みが必要です", "TaskService.noBuildTask1": "ビルド タスクが定義されていません。tasks.json ファイルでタスクに 'isBuildCommand' というマークを付けてください。", "TaskService.noBuildTask2": "ビルド タスクが定義されていません。tasks.json ファイルでタスクに 'build' グループとしてマークを付けてください。", "TaskService.noTestTask1": "テスト タスクが定義されていません。tasks.json ファイルでタスクに 'isTestCommand' というマークを付けてください。", @@ -47,22 +42,16 @@ "configured": "構成済みのタスク", "detected": "検出されたタスク", "TaskService.fetchingBuildTasks": "ビルド タスクをフェッチしています...", - "TaskService.noBuildTaskTerminal": "ビルド タスクが見つかりません。定義するには 'Configure Build Task' (ビルド タスクを構成します) を押してください。", "TaskService.pickBuildTask": "実行するビルド タスクを選択", "TaskService.fetchingTestTasks": "テスト タスクをフェッチしています...", - "TaskService.noTestTaskTerminal": "テスト タスクが見つかりません。定義するには 'Configure Build Task' (タスク ランナーの構成) を押してください。", "TaskService.pickTestTask": "実行するテスト タスクを選択してください", - "TaskService.noTaskRunning": "現在実行中のタスクはありません。", "TaskService.tastToTerminate": "終了するタスクを選択", "TerminateAction.noProcess": "起動したプロセスは既に存在しません。タスクを起動したバックグラウンド タスクが VS コードで終了すると、プロセスが孤立することがあります。", "TerminateAction.failed": "実行中のタスクの終了に失敗しました", - "TaskService.noTaskToRestart": "再起動するタスクがありません。", "TaskService.tastToRestart": "再起動するタスクを選択してください", - "TaskService.defaultBuildTaskExists": "{0} は既に既定のビルド タスクとしてマークされています。", "TaskService.pickDefaultBuildTask": "既定のビルド タスクとして使用するタスクを選択", "TaskService.defaultTestTaskExists": "{0} は既に既定のテスト タスクとしてマークされています。", "TaskService.pickDefaultTestTask": "既定のテスト タスクとして使用するタスクを選択", - "TaskService.noTaskIsRunning": "実行中のタスクはありません。", "TaskService.pickShowTask": "出力を表示するタスクを選択", "ShowLogAction.label": "タスク ログの表示", "RunTaskAction.label": "タスクの実行", diff --git a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index b957e64c6eb..3c51dcd1d5d 100644 --- a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -38,5 +38,6 @@ "workbench.action.terminal.focusFindWidget": "検索ウィジェットにフォーカスする", "workbench.action.terminal.hideFindWidget": "検索ウィジェットを非表示にする", "nextTerminalFindTerm": "次の検索語句を表示", - "previousTerminalFindTerm": "前の検索語句を表示" + "previousTerminalFindTerm": "前の検索語句を表示", + "quickOpenTerm": "アクティブなターミナルの切り替え" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json index b44e4e0fdf7..6cc81e64612 100644 --- a/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json @@ -8,5 +8,6 @@ "terminal.foreground": "ターミナルの前景色。", "terminalCursor.foreground": "ターミナルのカーソル前景色。", "terminalCursor.background": "ターミナルのカーソルの背景色。ブロックカーソルで重ねた文字の色をカスタマイズできます。", + "terminal.selectionBackground": "ターミナルの選択範囲の背景色。", "terminal.ansiColor": "ターミナルの '{0}' ANSI カラー。" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json b/i18n/jpn/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json index 6b8b81bf3c1..4228aaf4caf 100644 --- a/i18n/jpn/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json @@ -10,6 +10,7 @@ "welcomePage.newFile": "新しいファイル", "welcomePage.openFolder": "フォルダーを開く...", "welcomePage.cloneGitRepository": "Git リポジトリを複製...", + "welcomePage.addWorkspaceFolder": "ワークスペース フォルダーを追加…", "welcomePage.recent": "最近", "welcomePage.moreRecent": "その他", "welcomePage.noRecentFolders": "最近使用したフォルダーなし", diff --git a/i18n/jpn/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/jpn/src/vs/workbench/services/configuration/node/configuration.i18n.json index 50b9ab7d867..610c4b1b63b 100644 --- a/i18n/jpn/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/jpn/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -13,7 +13,7 @@ "invalid.title": "'configuration.title' は、文字列である必要があります", "vscode.extension.contributes.defaultConfiguration": "言語ごとに既定のエディター構成の設定を提供します。", "invalid.properties": "'configuration.properties' は、オブジェクトである必要があります", - "workspaceConfig.folders.description": "ワークスペースで読み込まれるフォルダーのリスト。ファイル パスである必要があります。例: `/root/folderA` または `./folderA` のようなワークスペース ファイルの場所に対して解決される相対パス。", - "workspaceConfig.folder.description": "ファイルパス。例: `/root/folderA` または `./folderA` のようなワークスペース ファイルの場所に対して解決される相対パス。", + "invalid.allOf": "'configuration.allOf' は非推奨で使用できなくなります。代わりに 'configuration' コントリビューション ポイントに複数の構成セクションを配列として渡します。", + "workspaceConfig.path.description": "ファイルパス。例: `/root/folderA` または `./folderA` のようなワークスペース ファイルの場所に対して解決される相対パス。", "workspaceConfig.settings.description": "ワークスペースの設定" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/jpn/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..26fc5404882 --- /dev/null +++ b/i18n/jpn/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "ファイルはバイナリのようなので、テキストとして開くことができません" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/jpn/src/vs/workbench/services/files/node/fileService.i18n.json index 8c65920db65..af58e0c5a88 100644 --- a/i18n/jpn/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/jpn/src/vs/workbench/services/files/node/fileService.i18n.json @@ -5,10 +5,12 @@ // Do not edit this file. It is machine generated. { "fileInvalidPath": "ファイルのリソース ({0}) が無効です", + "fileIsDirectoryError": "ファイルはディレクトリです", "fileNotModifiedError": "ファイルは次の時点以後に変更されていません:", "fileTooLargeError": "開くファイルが大きすぎます", "fileBinaryError": "ファイルはバイナリのようなので、テキストとして開くことができません", "fileNotFoundError": "ファイルが見つかりません ({0})", + "fileExists": "生成しようとしているファイル ({0}) は既に存在しています", "fileMoveConflict": "移動/コピーできません。移動/コピー先にファイルが既に存在します。", "unableToMoveCopyError": "移動/コピーできません。ファイルが含まれるフォルダーが置き換わることになります。", "foldersCopyError": "フォルダーをワークスペース内にコピーできません。個々のファイルを選択してコピーしてください。", diff --git a/i18n/kor/src/vs/code/electron-main/menus.i18n.json b/i18n/kor/src/vs/code/electron-main/menus.i18n.json index 46251c50573..1e29745ea9b 100644 --- a/i18n/kor/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/kor/src/vs/code/electron-main/menus.i18n.json @@ -171,8 +171,6 @@ "miRunningTask": "실행 중인 작업 표시(&&G)...", "miRestartTask": "실행 중인 작업 다시 시작(&&E)...", "miTerminateTask": "작업 종료(&&T)...", - "miConfigureTask": "작업 구성(&&C)", - "miConfigureBuildTask": "기본 빌드 작업 구성(&&F)", "accessibilityOptionsWindowTitle": "접근성 옵션", "miRestartToUpdate": "다시 시작하여 업데이트...", "miCheckingForUpdates": "업데이트를 확인하는 중...", diff --git a/i18n/kor/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/kor/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 7119dd38b12..d726014f30a 100644 --- a/i18n/kor/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/kor/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,7 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "잘못된 확장: package.json이 JSON 파일이 아닙니다.", - "restartCode": "{0}을(를) 다시 설치하기 전에 Code를 다시 시작하세요.", - "installDependeciesConfirmation": "'{0}'을(를) 설치하면 종속성도 설치됩니다. 계속할까요?", - "install": "예", - "doNotInstall": "아니요", + "restartCodeLocal": "{0}을(를) 다시 설치하기 전에 Code를 다시 시작하세요.", "uninstallDependeciesConfirmation": "'{0}'만 제거할까요, 아니면 종속성도 제거할까요?", "uninstallOnly": "만", "uninstallAll": "모두", diff --git a/i18n/kor/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/kor/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 82079af3e4a..ae23e97e23b 100644 --- a/i18n/kor/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -14,7 +14,6 @@ "selectWorkspace": "작업 영역 폴더 선택", "removeFolderFromWorkspace": "작업 영역에서 폴더 삭제", "saveWorkspaceAsAction": "작업 영역을 다른 이름으로 저장", - "saveEmptyWorkspaceNotSupported": "저장하려면 먼저 작업 영역을 여세요.", "save": "저장(&&S)", "saveWorkspace": "작업 영역 저장", "openWorkspaceAction": "작업 영역 열기...", diff --git a/i18n/kor/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..8d20ba83c9a --- /dev/null +++ b/i18n/kor/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} 동작" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/kor/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index 8c1877159e1..4740dad8c10 100644 --- a/i18n/kor/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -51,9 +51,8 @@ "showLanguageExtensionsShort": "언어 확장", "showAzureExtensions": "Azure 확장 표시", "showAzureExtensionsShort": "Azure 확장", - "configureWorkspaceRecommendedExtensions": "권장 확장 구성(작업 영역)", - "ConfigureWorkspaceRecommendations.noWorkspace": "권장 사항은 작업 영역 폴더에서만 사용할 수 있습니다.", "OpenExtensionsFile.failed": "'.vscode' 폴더({0}) 내에 'extensions.json' 파일을 만들 수 없습니다.", + "configureWorkspaceRecommendedExtensions": "권장 확장 구성(작업 영역)", "builtin": "기본 제공", "disableAll": "설치된 모든 확장 사용 안 함", "disableAllWorkspace": "이 작업 영역에 대해 설치된 모든 확장 사용 안 함", diff --git a/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index 392c06bedeb..3ded239f7d2 100644 --- a/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "바로 가기 키 파일 열기", "openWorkspaceSettings": "작업 영역 설정 열기", "openFolderSettings": "폴더 설정 열기", - "pickFolder": "폴더 선택", "configureLanguageBasedSettings": "언어별 설정 구성...", "languageDescriptionConfigured": "({0})", "pickLanguage": "언어 선택" diff --git a/i18n/kor/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/kor/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index f2e2d333694..9aafe17b284 100644 --- a/i18n/kor/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,7 +6,5 @@ { "relaunchSettingMessage": "설정이 변경되어 다시 시작해야만 적용됩니다.", "relaunchSettingDetail": "[다시 시작] 단추를 눌러 {0}을(를) 다시 시작하고 설정을 사용하도록 설정하세요.", - "restart": "다시 시작", - "relaunchWorkspaceMessage": "이 작업 영역을 변경하려면 확장 시스템을 다시 로드해야 합니다.", - "reload": "다시 로드" + "restart": "다시 시작" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/kor/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index f3414039077..00792047669 100644 --- a/i18n/kor/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "작업", - "ConfigureTaskRunnerAction.noWorkspace": "작업은 작업 영역 폴더에서만 사용할 수 있습니다.", - "ConfigureTaskRunnerAction.quickPick.template": "Task Runner 선택", - "ConfigureTaskRunnerAction.autoDetecting": "{0} 작업을 자동 검색 중", - "ConfigureTaskRunnerAction.autoDetect": "작업 시스템을 자동으로 감지하지 못했습니다. 기본 템플릿을 사용하는 중입니다. 자세한 내용은 작업 출력을 참조하세요.", - "ConfigureTaskRunnerAction.autoDetectError": "작업 시스템을 자동으로 감지하는 중 오류가 발생했습니다. 자세한 내용은 작업 출력을 참조하세요.", - "ConfigureTaskRunnerAction.failed": "'.vscode' 폴더 내에 'tasks.json' 파일을 만들 수 없습니다. 자세한 내용은 작업 출력을 참조하세요.", - "ConfigureTaskRunnerAction.label": "Task Runner 구성", + "ConfigureTaskRunnerAction.label": "작업 구성", "ConfigureBuildTaskAction.label": "빌드 작업 구성", "CloseMessageAction.label": "닫기", "ShowTerminalAction.label": "터미널 보기", @@ -47,22 +41,16 @@ "configured": "구성된 작업", "detected": "감지된 작업", "TaskService.fetchingBuildTasks": "빌드 작업을 페치하는 중...", - "TaskService.noBuildTaskTerminal": "빌드 작업을 찾을 수 없습니다. '빌드 작업 구성'을 눌러서 빌드 작업을 정의하세요.", "TaskService.pickBuildTask": "실행할 빌드 작업 선택", "TaskService.fetchingTestTasks": "테스트 작업을 페치하는 중...", - "TaskService.noTestTaskTerminal": "테스트 작업을 찾을 수 없습니다. 'Task Runner 구성'을 눌러서 테스트 작업을 정의하세요.", "TaskService.pickTestTask": "실행할 테스트 작업 선택", - "TaskService.noTaskRunning": "현재 실행 중인 작업이 없습니다.", "TaskService.tastToTerminate": "종료할 작업 선택", "TerminateAction.noProcess": "시작된 프로세스가 더 이상 존재하지 않습니다. 작업에서 생성된, VS Code를 끝내는 백그라운드 작업이 분리된 프로세스가 될 수 있습니다.", "TerminateAction.failed": "실행 중인 작업을 종료하지 못했습니다.", - "TaskService.noTaskToRestart": "다시 시작할 작업이 없습니다.", "TaskService.tastToRestart": "다시 시작할 작업 선택", - "TaskService.defaultBuildTaskExists": "{0}은(는) 이미 기본 빌드 작업으로 표시되어 있습니다.", "TaskService.pickDefaultBuildTask": "기본 빌드 작업으로 사용할 작업을 선택", "TaskService.defaultTestTaskExists": "{0}은(는) 이미 기본 테스트 작업으로 표시되어 있습니다.", "TaskService.pickDefaultTestTask": "기본 테스트 작업으로 사용할 작업 선택", - "TaskService.noTaskIsRunning": "실행 중인 작업이 없습니다.", "TaskService.pickShowTask": "출력을 표시할 작업 선택", "ShowLogAction.label": "작업 로그 표시", "RunTaskAction.label": "작업 실행", diff --git a/i18n/kor/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/kor/src/vs/workbench/services/configuration/node/configuration.i18n.json index 529c4144533..0082a801e64 100644 --- a/i18n/kor/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/kor/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -13,7 +13,6 @@ "invalid.title": "'configuration.title'은 문자열이어야 합니다.", "vscode.extension.contributes.defaultConfiguration": "언어별로 기본 편집기 구성 설정을 적용합니다.", "invalid.properties": "'configuration.properties'는 개체여야 합니다.", - "workspaceConfig.folders.description": "작업 영역에 로드할 폴더 목록입니다. 파일 경로를 사용해야 합니다. 예: `/root/folderA` 또는 `./folderA`(작업 영역 파일의 위치를 기준으로 확인할 상대 경로인 경우)", - "workspaceConfig.folder.description": "파일 경로입니다. 예: `/root/folderA` 또는 `./folderA`(작업 영역 파일의 위치를 기준으로 확인할 상대 경로인 경우)", + "workspaceConfig.path.description": "파일 경로입니다. 예: `/root/folderA` 또는 `./folderA`(작업 영역 파일의 위치를 기준으로 확인할 상대 경로인 경우)", "workspaceConfig.settings.description": "작업 영역 설정" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/kor/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..d48fe3d053e --- /dev/null +++ b/i18n/kor/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "파일이 이진인 것 같으므로 테스트로 열 수 없습니다." +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/code/electron-main/menus.i18n.json b/i18n/ptb/src/vs/code/electron-main/menus.i18n.json index 709c9b4bbc4..286ab62d136 100644 --- a/i18n/ptb/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/ptb/src/vs/code/electron-main/menus.i18n.json @@ -175,8 +175,6 @@ "miRunningTask": "Mostrar &&Tarefas Em Execução...", "miRestartTask": "R&&einiciar Tarefa em Execução", "miTerminateTask": "&&Finalizar Tarefa", - "miConfigureTask": "&&Configurar tarefas", - "miConfigureBuildTask": "Configurar Tarefa de Compilação &&Padrão", "accessibilityOptionsWindowTitle": "Opções de Acessibilidade", "miRestartToUpdate": "Reinicie para Atualizar...", "miCheckingForUpdates": "Verificando Atualizações...", diff --git a/i18n/ptb/src/vs/code/electron-main/windows.i18n.json b/i18n/ptb/src/vs/code/electron-main/windows.i18n.json index c8c821ec8a6..1921b2686e9 100644 --- a/i18n/ptb/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/ptb/src/vs/code/electron-main/windows.i18n.json @@ -18,6 +18,7 @@ "openFolder": "Abrir Pasta", "openFile": "Abrir Arquivo", "workspaceOpenedMessage": "Não é possível salvar espaço de trabalho '{0}'", + "workspaceOpenedDetail": "O espaço de trabalho já está aberto em outra janela. Por favor, feche a janela primeiro e tente novamente.", "openWorkspace": "&&Abrir", "openWorkspaceTitle": "Abrir o Espaço de Trabalho", "save": "&&Salvar", diff --git a/i18n/ptb/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/ptb/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index d7ef91038db..cea37b5ae9c 100644 --- a/i18n/ptb/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/ptb/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,6 +13,7 @@ "vscode.extension.contributes.menuItem.group": "Grupo ao qual pertence este comando", "vscode.extension.contributes.menus": "Contribui itens de menu ao editor", "menus.commandPalette": "Paleta de comandos", + "menus.touchBar": "A barra de toque (somente macOS)", "menus.editorTitle": "Meno do título editor", "menus.editorContext": "Mostrar o menu de contexto do editor", "menus.explorerContext": "Menu no contexto de explorador de arquivos", diff --git a/i18n/ptb/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/ptb/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index a6c5a37ab05..e90957df5d7 100644 --- a/i18n/ptb/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/ptb/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "Extensão inválida: pacote.json nao é um arquivo JSON válido", - "restartCode": "Por favor reinicie Code antes de reinstalar {0}.", - "installDependeciesConfirmation": "A instalação de '{0}' também inclui suas dependências. Gostaria de continuar?", - "install": "Sim", - "doNotInstall": "Não", + "restartCodeLocal": "Por favor reinicie Code antes de reinstalar {0}.", + "restartCodeGallery": "Por favor reinicie o Code antes de reinstalar.", "uninstallDependeciesConfirmation": "Gostaria de desinstalar '{0}' somente, ou suas dependências também?", "uninstallOnly": "Apenas", "uninstallAll": "Todos", diff --git a/i18n/ptb/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/ptb/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 64f25e29725..5663c3ba47c 100644 --- a/i18n/ptb/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -14,7 +14,6 @@ "selectWorkspace": "Selecionar pastas para espaço de trabalho", "removeFolderFromWorkspace": "Remover pasta da área de trabalho", "saveWorkspaceAsAction": "Salvar o espaço de trabalho como...", - "saveEmptyWorkspaceNotSupported": "Por favor, abra um espaço de trabalho antes de salvar.", "save": "&&Salvar", "saveWorkspace": "Salvar o espaço de trabalho", "openWorkspaceAction": "Abrir o Espaço de Trabalho...", diff --git a/i18n/ptb/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/ptb/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..32207b28d40 --- /dev/null +++ b/i18n/ptb/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} ações " +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index fc84602f2f7..3bbf66ae160 100644 --- a/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -51,9 +51,8 @@ "showLanguageExtensionsShort": "Extensões de Linguagem", "showAzureExtensions": "Mostrar extensões para o Azure", "showAzureExtensionsShort": "Extensões do Azure", - "configureWorkspaceRecommendedExtensions": "Configurar Extensões Recomendadas (Espaço de Trabalho)", - "ConfigureWorkspaceRecommendations.noWorkspace": "As recomendações somente estão disponíveis em uma pasta do espaço de trabalho.", "OpenExtensionsFile.failed": "Não foi possível criar o arquivo 'extensions.json' na pasta '.vscode' ({0}).", + "configureWorkspaceRecommendedExtensions": "Configurar Extensões Recomendadas (Espaço de Trabalho)", "builtin": "Intrínseco", "disableAll": "Desabilitar Todas as Extensões Instaladas", "disableAllWorkspace": "Desabilitar Todas as Extensões Instaladas para este Espaço de Trabalho", diff --git a/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index 57cd480b3ed..0abf761f3b5 100644 --- a/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "Abrir Arquivo de Atalhos de Teclado", "openWorkspaceSettings": "Abrir as configurações do espaço de trabalho", "openFolderSettings": "Abrir configurações da pasta", - "pickFolder": "Selecionar a Pasta", "configureLanguageBasedSettings": "Definir Configurações Específicas de Linguagem...", "languageDescriptionConfigured": "({0})", "pickLanguage": "Selecionar Linguagem" diff --git a/i18n/ptb/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index 0b8f8925f7c..0f11464989e 100644 --- a/i18n/ptb/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,7 +6,5 @@ { "relaunchSettingMessage": "Uma configuração que requer uma reinicialização foi alterada.", "relaunchSettingDetail": "Pressione o botão de reinicialização para reiniciar {0} e habilitar a configuração.", - "restart": "Reiniciar", - "relaunchWorkspaceMessage": "Esta mudança de espaço de trabalho exige o recarregamento do nosso sistema de extensão.", - "reload": "Recarregar" + "restart": "Reiniciar" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index 69380915390..92d57ef9275 100644 --- a/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -6,7 +6,6 @@ { "commitMessage": "Mensagem (tecle {0} para confirmar)", "installAdditionalSCMProviders": "Instalar provedores de SCM adicionais...", - "no open repo": "Não há nenhum provedor de controle de fonte ativo.", "source control": "Controle de código-fonte", "viewletTitle": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index a14587dfc3c..dd52522c3a8 100644 --- a/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/ptb/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "Tarefas", - "ConfigureTaskRunnerAction.noWorkspace": "Tarefas somente estão disponíveis em uma pasta da área de trabalho.", - "ConfigureTaskRunnerAction.quickPick.template": "Selecione um gerenciador de tarefa", - "ConfigureTaskRunnerAction.autoDetecting": "Tarefas de auto detecção para {0}", - "ConfigureTaskRunnerAction.autoDetect": "A tarefa de sistema de auto detecção falhou. Usando o modelo padrão. Consulte a saída da tarefa para detalhes.", - "ConfigureTaskRunnerAction.autoDetectError": "A tarefa de sistema de auto detecção produziu erros. Consulte a saída da tarefa para detalhes.", - "ConfigureTaskRunnerAction.failed": "Não é possível criar o arquivo 'tasks.json' na pasta '.vscode'. Consulte a saída da tarefa para detalhes.", - "ConfigureTaskRunnerAction.label": "Configure o gerenciador de tarefas", + "ConfigureTaskRunnerAction.label": "Configurar a tarefa", "ConfigureBuildTaskAction.label": "Configurar Tarefa de Compilação", "CloseMessageAction.label": "Fechar", "ShowTerminalAction.label": "Terminal Visualização", @@ -19,6 +13,7 @@ "manyMarkers": "99+", "runningTasks": "Mostrar tarefas em execução", "tasks": "Tarefas", + "TaskSystem.noHotSwap": "Alterar o mecanismo de execução da tarefa com uma tarefa ativa executando exige que a janela seja recarregada", "TaskService.noBuildTask1": "Nenhuma tarefa de compilação definida. Marque uma tarefa com 'isBuildCommand' no arquivo tasks.json.", "TaskService.noBuildTask2": "Nenhuma tarefa de compilação definida. Marque uma tarefa como um grupo 'build' no arquivo tasks.json.", "TaskService.noTestTask1": "Nenhuma tarefa de teste definida. Marque uma tarefa com 'isTestCommand' no arquivo tasks.json.", @@ -47,22 +42,16 @@ "configured": "tarefas configuradas", "detected": "tarefas detectadas", "TaskService.fetchingBuildTasks": "Buscando tarefas de compilação...", - "TaskService.noBuildTaskTerminal": "Nenhuma tarefa de compilação encontrada. Pressione 'Configurar Tarefa de Compilação' para definir um.", "TaskService.pickBuildTask": "Selecione a tarefa de compilação para executar", "TaskService.fetchingTestTasks": "Buscando tarefas de teste...", - "TaskService.noTestTaskTerminal": "Nenhuma tarefa de teste encontrada. Pressione 'Configurar Tarefa de Execução' para definir uma.", "TaskService.pickTestTask": "Selecione a tarefa de teste para executar", - "TaskService.noTaskRunning": "Nenhuma tarefa está sendo executada.", "TaskService.tastToTerminate": "Selecione a tarefa para terminar", "TerminateAction.noProcess": "O processo executado não existe mais. Se a tarefa produziu processos em background, finalizar o VS Code pode resultar em processos órfãos.", "TerminateAction.failed": "Falha ao finalizar a tarefa sendo executada", - "TaskService.noTaskToRestart": "Não há tarefa para reiniciar.", "TaskService.tastToRestart": "Selecione a tarefa para reiniciar", - "TaskService.defaultBuildTaskExists": "{0} já está marcado como a tarefa de compilação padrão.", "TaskService.pickDefaultBuildTask": "Selecione a tarefa a ser usada como a tarefa de compilação padrão", "TaskService.defaultTestTaskExists": "{0} já está marcado como a tarefa de teste padrão.", "TaskService.pickDefaultTestTask": "Selecione a tarefa a ser usada como a tarefa de teste padrão", - "TaskService.noTaskIsRunning": "Nenhuma tarefa em execução.", "TaskService.pickShowTask": "Selecione a tarefa para mostrar sua saída", "ShowLogAction.label": "Visualizar o Log de Tarefas", "RunTaskAction.label": "Executar Tarefa", diff --git a/i18n/ptb/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/ptb/src/vs/workbench/services/configuration/node/configuration.i18n.json index 3eda0fa5544..6681047110e 100644 --- a/i18n/ptb/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/ptb/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -14,7 +14,6 @@ "vscode.extension.contributes.defaultConfiguration": "Contribui às definições de configuração padrão do editor por linguagem.", "invalid.properties": "'configuration.properties' deve ser um objeto", "invalid.allOf": "'configuration.allOf' está obsoleto e não deve ser usado. Em vez disso, passe várias seções de configuração como uma matriz para o ponto de contribuição 'configuration'.", - "workspaceConfig.folders.description": "Lista de pastas para ser carregada no espaço de trabalho. Deve ser um caminho para um arquivo. Por exemplo '/root/pastaA' ou './pastaA' para um caminho relativo que será determinado de acordo com o local do arquivo no espaço de trabalho.", - "workspaceConfig.folder.description": "Um caminho para um arquivo. Por exemplo, '/root /pastaA' ou './pastaA' para um caminho relativo que será determinado de acordo com o local do arquivo no espaço de trabalho.", + "workspaceConfig.path.description": "Um caminho para um arquivo. Por exemplo, '/root /pastaA' ou './pastaA' para um caminho relativo que será determinado de acordo com o local do arquivo no espaço de trabalho.", "workspaceConfig.settings.description": "Configurações de espaço de trabalho" } \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/ptb/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..7b91deaec2e --- /dev/null +++ b/i18n/ptb/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "Arquivo parece ser binário e não pode ser aberto como texto" +} \ No newline at end of file diff --git a/i18n/ptb/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/ptb/src/vs/workbench/services/files/node/fileService.i18n.json index 1eeed79c955..e6423a5b25c 100644 --- a/i18n/ptb/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/ptb/src/vs/workbench/services/files/node/fileService.i18n.json @@ -10,6 +10,7 @@ "fileTooLargeError": "Arquivo muito grande para abrir", "fileBinaryError": "Arquivo parece ser binário e não pode ser aberto como texto", "fileNotFoundError": "Arquivo não encontrado ({0})", + "fileExists": "Arquivo a ser criado já existe ({0})", "fileMoveConflict": "Não é possível mover/copiar. Arquivo já existe no destino.", "unableToMoveCopyError": "Não é possível mover/copiar. Arquivo poderia substituir a pasta em que está contida.", "foldersCopyError": "Pastas não podem ser copiadas para a área de trabalho. Por favor selecione arquivos individuais para serem copiados.", diff --git a/i18n/rus/src/vs/code/electron-main/menus.i18n.json b/i18n/rus/src/vs/code/electron-main/menus.i18n.json index 696280aa197..d5553161f35 100644 --- a/i18n/rus/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/rus/src/vs/code/electron-main/menus.i18n.json @@ -171,8 +171,6 @@ "miRunningTask": "Показать выполняющ&&иеся задачи...", "miRestartTask": "П&&ерезапустить запущенную задачу...", "miTerminateTask": "&&Завершить задачу...", - "miConfigureTask": "&&Настроить задачи", - "miConfigureBuildTask": "Настроить задачу сборки по у&&молчанию", "accessibilityOptionsWindowTitle": "Специальные возможности", "miRestartToUpdate": "Перезапустить программу для обновления...", "miCheckingForUpdates": "Идет проверка наличия обновлений...", diff --git a/i18n/rus/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/rus/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 60652be3521..0e8a5193ce9 100644 --- a/i18n/rus/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/rus/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,7 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "Недопустимое расширение: package.json не является файлом JSON.", - "restartCode": "Перезапустите код перед переустановкой {0}.", - "installDependeciesConfirmation": "При установке \"{0}\" также устанавливаются зависимости. Вы хотите продолжить?", - "install": "Да", - "doNotInstall": "Нет", + "restartCodeLocal": "Перезапустите код перед переустановкой {0}.", "uninstallDependeciesConfirmation": "Вы хотите удалить \"{0}\" отдельно или вместе с зависимостями?", "uninstallOnly": "Только", "uninstallAll": "Все", diff --git a/i18n/rus/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/rus/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 9c00cba356f..b82df283bae 100644 --- a/i18n/rus/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -14,7 +14,6 @@ "selectWorkspace": "Выбрать папки для рабочей области", "removeFolderFromWorkspace": "Удалить папку из рабочей области", "saveWorkspaceAsAction": "Сохранить рабочую область как...", - "saveEmptyWorkspaceNotSupported": "Перед сохранением рабочей области откройте ее. ", "save": "Сохранить", "saveWorkspace": "Сохранить рабочую область", "openWorkspaceAction": "Открыть рабочую область...", diff --git a/i18n/rus/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..761072edd67 --- /dev/null +++ b/i18n/rus/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "Действий: {0}" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/rus/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index d49f2b5aee8..6c4879d3c3f 100644 --- a/i18n/rus/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -51,9 +51,8 @@ "showLanguageExtensionsShort": "Расширения языка", "showAzureExtensions": "Показать расширения Azure", "showAzureExtensionsShort": "Расширения Azure", - "configureWorkspaceRecommendedExtensions": "Настроить рекомендуемые расширения (рабочая область)", - "ConfigureWorkspaceRecommendations.noWorkspace": "Рекомендации доступны только для папки рабочей области.", "OpenExtensionsFile.failed": "Не удается создать файл \"extensions.json\" в папке \".vscode\" ({0}).", + "configureWorkspaceRecommendedExtensions": "Настроить рекомендуемые расширения (рабочая область)", "builtin": "Встроенное", "disableAll": "Отключить все установленные расширения", "disableAllWorkspace": "Отключить все установленные расширения для этой рабочей области", diff --git a/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index e7a2b6b75ec..db8d5850260 100644 --- a/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "Открыть файл сочетаний клавиш", "openWorkspaceSettings": "Открыть параметры рабочей области", "openFolderSettings": "Открыть параметры папок", - "pickFolder": "Выбрать папку", "configureLanguageBasedSettings": "Настроить параметры языка...", "languageDescriptionConfigured": "({0})", "pickLanguage": "Выбрать язык" diff --git a/i18n/rus/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/rus/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index cb591fb1f5f..74fdb766725 100644 --- a/i18n/rus/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,7 +6,5 @@ { "relaunchSettingMessage": "После изменения параметра необходима выполнить перезагрузку, чтобы изменения вступили в силу.", "relaunchSettingDetail": "Нажмите кнопку \"Перезагрузить\", чтобы перезагрузить {0} и включить параметр.", - "restart": "Перезапустить", - "relaunchWorkspaceMessage": "Для изменения этой рабочей области требуется перезагрузить нашу систему расширений.", - "reload": "Перезагрузка" + "restart": "Перезапустить" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/rus/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index edbb663b01e..60bc03c5518 100644 --- a/i18n/rus/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "Задачи", - "ConfigureTaskRunnerAction.noWorkspace": "Задачи доступны только в папке рабочей области.", - "ConfigureTaskRunnerAction.quickPick.template": "Выбрать средство выполнения задач", - "ConfigureTaskRunnerAction.autoDetecting": "Автообнаружение задач для {0}", - "ConfigureTaskRunnerAction.autoDetect": "Не удалось автоматически определить систему задачи, используется шаблон по умолчанию. Подробности см. в выходных данных задачи.", - "ConfigureTaskRunnerAction.autoDetectError": "При определении системы задачи возникли ошибки. Дополнительные сведения см. в выходных данных задачи.", - "ConfigureTaskRunnerAction.failed": "Не удается создать файл tasks.json в папке .vscode. Подробности см. в выходных данных задачи.", - "ConfigureTaskRunnerAction.label": "Настроить средство выполнения задач", + "ConfigureTaskRunnerAction.label": "Настроить задачу", "ConfigureBuildTaskAction.label": "Настроить задачу сборки", "CloseMessageAction.label": "Закрыть", "ShowTerminalAction.label": "Ознакомиться с терминалом", @@ -47,22 +41,16 @@ "configured": "настроенные задачи", "detected": "обнаруженные задачи", "TaskService.fetchingBuildTasks": "Получение задач сборки...", - "TaskService.noBuildTaskTerminal": "Задача сборки не найдена. Нажмите кнопку \"Настроить задачу сборки\", чтобы определить задачу сборки.", "TaskService.pickBuildTask": "Выберите задачу сборки для запуска", "TaskService.fetchingTestTasks": "Получение задач тестирования...", - "TaskService.noTestTaskTerminal": "Задача тестирования не найдена. Нажмите кнопку \"Настроить задачу тестирования\", чтобы определить задачу сборки. ", "TaskService.pickTestTask": "Выберите задачу тестирования для запуска", - "TaskService.noTaskRunning": "Ни одной задачи не запущено.", "TaskService.tastToTerminate": "Выберите задачи для завершения", "TerminateAction.noProcess": "Запущенный процесс больше не существует. Если задача породила фоновые задачи, выход из Visual Studio Code может привести к появлению потерянных процессов.", "TerminateAction.failed": "Не удалось завершить запущенную задачу", - "TaskService.noTaskToRestart": "Задачи для перезапуска не найдены.", "TaskService.tastToRestart": "Выберите задачу для перезапуска", - "TaskService.defaultBuildTaskExists": "{0} уже помечена как задача сборки по умолчанию.", "TaskService.pickDefaultBuildTask": "Выберите задачу, которая будет использоваться в качестве задачи сборки по умолчанию.", "TaskService.defaultTestTaskExists": "{0} уже помечена как задача сборки по умолчанию. ", "TaskService.pickDefaultTestTask": "Выберите задачу, которая будет использоваться в качестве задачи тестирования по умолчанию. ", - "TaskService.noTaskIsRunning": "Ни одной задачи не запущено.", "TaskService.pickShowTask": "Выберите задачу, выходные данные для которой нужно отобразить", "ShowLogAction.label": "Показать журнал задач", "RunTaskAction.label": "Выполнить задачу", diff --git a/i18n/rus/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/rus/src/vs/workbench/services/configuration/node/configuration.i18n.json index dd33949d1f2..ba1ed604879 100644 --- a/i18n/rus/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/rus/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -13,7 +13,6 @@ "invalid.title": "configuration.title должно быть строкой", "vscode.extension.contributes.defaultConfiguration": "Предоставляет параметры конфигурации редактора по умолчанию в соответствии с языком.", "invalid.properties": "configuration.properties должно быть объектом", - "workspaceConfig.folders.description": "Список папок, которые будут загружены в рабочую область. Необходимо указывать пути к файлам, например, \"/root/folderA\" или \"./folderA\" для пути по отношению к файлу рабочей области.", - "workspaceConfig.folder.description": "Путь к файлу, например, \"/root/folderA\" или \"./folderA\" для пути по отношению к файлу рабочей области.", + "workspaceConfig.path.description": "Путь к файлу, например, \"/root/folderA\" или \"./folderA\" для пути по отношению к файлу рабочей области.", "workspaceConfig.settings.description": "Параметры рабочей области" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/rus/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..54fbd1ada7b --- /dev/null +++ b/i18n/rus/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "Похоже, файл является двоичным, и его нельзя открыть как текстовый." +} \ No newline at end of file diff --git a/i18n/trk/extensions/css/package.i18n.json b/i18n/trk/extensions/css/package.i18n.json index c2596bffcb3..c3c20d04321 100644 --- a/i18n/trk/extensions/css/package.i18n.json +++ b/i18n/trk/extensions/css/package.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "css.title": "CSS", "css.lint.argumentsInColorFunction.desc": "Geçersiz sayıda parametre", "css.lint.boxModel.desc": "Doldurma veya kenarlık kullanırken genişlik veya yükseklik kullanmayın", "css.lint.compatibleVendorPrefixes.desc": "Satıcıya özgü bir ön ek kullanırken satıcıya özgü diğer tüm özellikleri de dahil ettiğinizden emin olun", @@ -25,6 +26,7 @@ "css.trace.server.desc": "VS Code ve CSS dil sunucusu arasındaki iletişimi izler.", "css.validate.title": "CSS doğrulamasını ve sorunların önem derecelerini denetler.", "css.validate.desc": "Tüm doğrulamaları etkinleştirir veya devre dışı bırakır", + "less.title": "LESS", "less.lint.argumentsInColorFunction.desc": "Geçersiz sayıda parametre", "less.lint.boxModel.desc": "Doldurma veya kenarlık kullanırken genişlik veya yükseklik kullanmayın", "less.lint.compatibleVendorPrefixes.desc": "Satıcıya özgü bir ön ek kullanırken satıcıya özgü diğer tüm özellikleri de dahil ettiğinizden emin olun", @@ -45,6 +47,7 @@ "less.lint.zeroUnits.desc": "Sıfır için birim gerekmez", "less.validate.title": "LESS doğrulamasını ve sorunların önem derecelerini denetler.", "less.validate.desc": "Tüm doğrulamaları etkinleştirir veya devre dışı bırakır", + "scss.title": "SCSS (Sass)", "scss.lint.argumentsInColorFunction.desc": "Geçersiz sayıda parametre", "scss.lint.boxModel.desc": "Doldurma veya kenarlık kullanırken genişlik veya yükseklik kullanmayın", "scss.lint.compatibleVendorPrefixes.desc": "Satıcıya özgü bir ön ek kullanırken satıcıya özgü diğer tüm özellikleri de dahil ettiğinizden emin olun", diff --git a/i18n/trk/src/vs/code/electron-main/menus.i18n.json b/i18n/trk/src/vs/code/electron-main/menus.i18n.json index 2a2c04a9be2..245e33677c8 100644 --- a/i18n/trk/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/trk/src/vs/code/electron-main/menus.i18n.json @@ -151,6 +151,10 @@ "mZoom": "Yakınlaştırma", "mBringToFront": "Tümünü Öne Getir", "miSwitchWindow": "&&Pencere Değiştir...", + "mShowPreviousTab": "Önceki Sekmeyi Göster", + "mShowNextTab": "Sonraki Sekmeyi Göster", + "mMoveTabToNewWindow": "Sekmeyi Yeni Pencereye Taşı", + "mMergeAllWindows": "Tüm Pencereleri Birleştir", "miToggleDevTools": "&&Geliştirici Araçlarını Aç/Kapat", "miAccessibilityOptions": "&&Erişilebilirlik Seçenekleri", "miReportIssues": "So&&run Bildir", @@ -171,8 +175,8 @@ "miRunningTask": "Ça&&lışan Görevleri Göster...", "miRestartTask": "Çalışan Görevi &&Yeniden Başlat...", "miTerminateTask": "&&Görevi Sonlandır...", - "miConfigureTask": "Görevleri Ya&&pılandır", - "miConfigureBuildTask": "&&Varsayılan Derleme Görevini Yapılandır", + "miConfigureTask": "Görevleri Ya&&pılandır...", + "miConfigureBuildTask": "&&Varsayılan Derleme Görevini Yapılandır...", "accessibilityOptionsWindowTitle": "Erişilebilirlik Seçenekleri", "miRestartToUpdate": "Güncelleştirmek için Yeniden Başlat...", "miCheckingForUpdates": "Güncelleştirmeler Denetleniyor...", diff --git a/i18n/trk/src/vs/code/electron-main/windows.i18n.json b/i18n/trk/src/vs/code/electron-main/windows.i18n.json index 1331e489083..d5deb1a8663 100644 --- a/i18n/trk/src/vs/code/electron-main/windows.i18n.json +++ b/i18n/trk/src/vs/code/electron-main/windows.i18n.json @@ -17,6 +17,8 @@ "open": "Aç", "openFolder": "Klasör Aç", "openFile": "Dosya Aç", + "workspaceOpenedMessage": "Çalışma alanı '{0}' kaydedilemiyor", + "workspaceOpenedDetail": "Çalışma alanı zaten başka bir pencerede açılmış. Lütfen ilk olarak o pencereyi kapatın ve tekrar deneyin.", "openWorkspace": "&&Aç", "openWorkspaceTitle": "Çalışma Alanı Aç", "save": "&&Kaydet", diff --git a/i18n/trk/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/trk/src/vs/editor/common/config/commonEditorConfig.i18n.json index f638cd37b77..e5aafd9e455 100644 --- a/i18n/trk/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/trk/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -88,6 +88,7 @@ "accessibilitySupport": "Düzenleyicinin ekran okuyucular için optimize edilmiş bir modda çalışıp çalışmayacağını denetler.", "links": "Düzenleyicinin bağlantıları otomatik algılayıp, onları tıklanabilir yapıp yapmayacağını denetler", "colorDecorators": "Düzenleyicinin satır içi renk dekoratörlerini ve renk seçiciyi gösterip göstermemesini denetler.", + "codeActions": "Kod eylemleri ampulunu etkinleştirir", "sideBySide": "Karşılaştırma düzenleyicisinin farklılıkları yan yana mı yoksa satır içinde mi göstereceğini denetler", "ignoreTrimWhitespace": "Karşılaştırma düzenleyicisinin baştaki veya sondaki boşluklardaki değişmeleri farklılık olarak gösterip göstermemesini denetler", "renderIndicators": "Karşılaştırma düzenleyicisinin ekleme/çıkarma değişiklikleri için +/- göstergeleri gösterip göstermemesini denetler.", diff --git a/i18n/trk/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json b/i18n/trk/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json index 1fc7a735690..cd79d1e6d7c 100644 --- a/i18n/trk/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json +++ b/i18n/trk/src/vs/platform/actions/electron-browser/menusExtensionPoint.i18n.json @@ -13,6 +13,7 @@ "vscode.extension.contributes.menuItem.group": "Bu komutun ait olduğu gruba ekle", "vscode.extension.contributes.menus": "Düzenleyiciye menü ögeleri ekler", "menus.commandPalette": "Komut Paleti", + "menus.touchBar": "Touch bar (sadece macOS)", "menus.editorTitle": "Düzenleyici başlık menüsü", "menus.editorContext": "Düzenleyici bağlam menüsü", "menus.explorerContext": "Dosya gezgini bağlam menüsü", diff --git a/i18n/trk/src/vs/platform/environment/node/argv.i18n.json b/i18n/trk/src/vs/platform/environment/node/argv.i18n.json index 2954082001b..0e8cbe0d850 100644 --- a/i18n/trk/src/vs/platform/environment/node/argv.i18n.json +++ b/i18n/trk/src/vs/platform/environment/node/argv.i18n.json @@ -15,6 +15,7 @@ "reuseWindow": "Bir dosya veya klasörü son etkin pencerede açmaya zorlayın.", "userDataDir": "Kullanıcı verilerinin tutulacağı klasörü belirtir, root olarak çalışırken yararlıdır.", "verbose": "Ayrıntılı çıktı oluştur (--wait anlamına gelir).", + "wait": "Geri dönmeden önce dosyaların kapanmasını bekle.", "extensionHomePath": "Eklentilerin kök dizinini belirle.", "listExtensions": "Yüklü eklentileri listele.", "showVersions": "--list-extensions'u kullanırken, yüklü eklentilerin sürümlerini gösterir.", diff --git a/i18n/trk/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/trk/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 46113aaf483..c32c5815cff 100644 --- a/i18n/trk/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/trk/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -5,10 +5,8 @@ // Do not edit this file. It is machine generated. { "invalidManifest": "Eklenti geçersiz: package.json bir JSON dosyası değil.", - "restartCode": "{0} eklentisini yeniden yüklemeden önce lütfen Code'u yeniden başlatın.", - "installDependeciesConfirmation": "'{0}' eklentisini yüklediğinizde onun bağımlılıkları da yüklenir. Devam etmek istiyor musunuz?", - "install": "Evet", - "doNotInstall": "Hayır", + "restartCodeLocal": "{0} eklentisini yeniden yüklemeden önce lütfen Code'u yeniden başlatın.", + "restartCodeGallery": "Yeniden yüklemeden önce lütfen Code'u yeniden başlatın.", "uninstallDependeciesConfirmation": "Yalnızca '{0}' eklentisini mi yoksa bağımlılıklarını da kaldırmak ister misiniz?", "uninstallOnly": "Sadece Eklenti", "uninstallAll": "Tümü", diff --git a/i18n/trk/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/trk/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index ed2a8dac4ad..bf95a5cb19e 100644 --- a/i18n/trk/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/trk/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -16,6 +16,7 @@ "vscode.extension.activationEvents": "VS Code eklentisi için etkinleştirme olayları.", "vscode.extension.activationEvents.onLanguage": "Belirtilen dilde çözümlenen bir dosya her açıldığında bir etkinleştirme olayı yayınlanır.", "vscode.extension.activationEvents.onCommand": "Belirtilen komut her çağrıldığında bir etkinleştirme olayı yayınlanır.", + "vscode.extension.activationEvents.onDebug": "Bir kullanıcının hata ayıklamaya başlamak veya hata ayıklama yapılandırmasını ayarlamak üzere olduğu her an bir etkinleştirme olayı yayınlanır.", "vscode.extension.activationEvents.workspaceContains": "Belirtilen glob deseni ile eşleşen en az bir dosya içeren bir klasör her açıldığında bir etkinleştirme olayı yayınlanır.", "vscode.extension.activationEvents.onView": "Belirtilen görünüm her genişletildiğinde bir etkinleştirme olayı yayınlanır.", "vscode.extension.activationEvents.star": "VS Code başlatıldığında yayılan etkinleştirme olayı. Mükemmel bir son kullanıcı deneyimi sağlandığından emin olmak için, lütfen bu etkinleştirme olayını eklentinizde sadece kullanım durumunuzda başka hiçbir aktivasyon olayı kombinasyonu çalışmıyorsa kullanın.", diff --git a/i18n/trk/src/vs/platform/theme/common/colorExtensionPoint.i18n.json b/i18n/trk/src/vs/platform/theme/common/colorExtensionPoint.i18n.json index 9f47144f8a2..bf71ff9729b 100644 --- a/i18n/trk/src/vs/platform/theme/common/colorExtensionPoint.i18n.json +++ b/i18n/trk/src/vs/platform/theme/common/colorExtensionPoint.i18n.json @@ -13,6 +13,8 @@ "contributes.defaults.highContrast": "Yüksek karşıtlık temalarının varsayılan rengi. Ya hex biçiminde bir renk değeri (#RRGGBB[AA]) ya da varsayılanı sağlayan bir tema olarak kullanılabilir rengin tanımlayıcısı olabilir.", "invalid.colorConfiguration": "'configuration.colors' bir dizi olmalıdır", "invalid.default.colorType": "{0}, ya hex biçiminde bir renk değeri (#RRGGBB[AA] veya #RGB[A]) ya da varsayılanı sağlayan bir tema olarak kullanılabilir rengin tanımlayıcısı olabilir.", + "invalid.id": "'configuration.colors.id' tanımlanmalı ve boş olmamalıdır", "invalid.id.format": "'configuration.colors.id' sözcük[.sözcük]* şeklinde olmalıdır", + "invalid.description": "'configuration.colors.description' tanımlanmalı ve boş olmamalıdır", "invalid.defaults": "'configuration.colors.defaults' tanımlanmalı ve 'light', 'dark' ve 'highContrast' değerlerini içermelidir" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/actions/workspaceActions.i18n.json b/i18n/trk/src/vs/workbench/browser/actions/workspaceActions.i18n.json index 543577ab634..ed0caa5b58f 100644 --- a/i18n/trk/src/vs/workbench/browser/actions/workspaceActions.i18n.json +++ b/i18n/trk/src/vs/workbench/browser/actions/workspaceActions.i18n.json @@ -14,9 +14,9 @@ "selectWorkspace": "Çalışma Alanı İçin Klasörleri Seçin", "removeFolderFromWorkspace": "Çalışma Alanından Klasör Kaldır", "saveWorkspaceAsAction": "Çalışma Alanını Farklı Kaydet...", - "saveEmptyWorkspaceNotSupported": "Lütfen kaydetmek için ilk olarak bir çalışma alanı açın.", "save": "&&Kaydet", "saveWorkspace": "Çalışma Alanını Kaydet", "openWorkspaceAction": "Çalışma Alanı Aç...", - "openWorkspaceConfigFile": "Çalışma Alanı Yapılandırma Dosyasını Aç" + "openWorkspaceConfigFile": "Çalışma Alanı Yapılandırma Dosyasını Aç", + "workspaceFolderPickerPlaceholder": "Çalışma alanı klasörü seçin" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json index 087f6d6789f..4dac5bcdce6 100644 --- a/i18n/trk/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json +++ b/i18n/trk/src/vs/workbench/browser/parts/activitybar/activitybarActions.i18n.json @@ -6,6 +6,7 @@ { "badgeTitle": "{0} - {1}", "titleKeybinding": "{0} ({1})", + "removeFromActivityBar": "Etkinlik Çubuğunda Gizle", "keepInActivityBar": "Etkinlik Çubuğunda Tut", "additionalViews": "Ek Görünümler", "numberBadge": "{0} ({1})", diff --git a/i18n/trk/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index 54fedd4e20f..a5fd9ca0033 100644 --- a/i18n/trk/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/trk/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -35,6 +35,7 @@ "openPreviousEditorInGroup": "Gruptaki Önceki Düzenleyiciyi Aç", "navigateNext": "İleri Git", "navigatePrevious": "Geri Dön", + "navigateLast": "Bir Öncekine Git", "reopenClosedEditor": "Kapatılan Düzenleyiciyi Yeniden Aç", "clearRecentFiles": "Son Açılanları Temizle", "showEditorsInFirstGroup": "İlk Gruptaki Düzenleyicileri Göster", diff --git a/i18n/trk/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json b/i18n/trk/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json new file mode 100644 index 00000000000..13520a7bd48 --- /dev/null +++ b/i18n/trk/src/vs/workbench/browser/parts/views/panelViewlet.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "viewToolbarAriaLabel": "{0} eylem" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/electron-browser/actions.i18n.json b/i18n/trk/src/vs/workbench/electron-browser/actions.i18n.json index 6e119bd4a9c..84919f4ec14 100644 --- a/i18n/trk/src/vs/workbench/electron-browser/actions.i18n.json +++ b/i18n/trk/src/vs/workbench/electron-browser/actions.i18n.json @@ -42,5 +42,10 @@ "navigateUp": "Üstteki Görünüme Git", "navigateDown": "Alttaki Görünüme Git", "increaseViewSize": "Geçerli Görünüm Boyutunu Artır", - "decreaseViewSize": "Geçerli Görünüm Boyutunu Azalt" + "decreaseViewSize": "Geçerli Görünüm Boyutunu Azalt", + "showPreviousTab": "Önceki Pencere Sekmesini Göster", + "showNextWindowTab": "Sonraki Pencere Sekmesini Göster", + "moveWindowTabToNewWindow": "Pencere Sekmesini Yeni Pencereye Taşı", + "mergeAllWindowTabs": "Tüm Pencereleri Birleştir", + "toggleWindowTabsBar": "Pencere Sekmeleri Çubuğunu Gizle/Göster" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/electron-browser/main.contribution.i18n.json b/i18n/trk/src/vs/workbench/electron-browser/main.contribution.i18n.json index 9681d8dffc6..3bbf02cf526 100644 --- a/i18n/trk/src/vs/workbench/electron-browser/main.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/electron-browser/main.contribution.i18n.json @@ -10,6 +10,11 @@ "workspaces": "Çalışma Alanları", "developer": "Geliştirici", "showEditorTabs": "Açık düzenleyicilerin sekmelerde gösterilip gösterilmeyeceğini denetler", + "workbench.editor.labelFormat.default": "Dosyanın adını göster. Sekmeler etkinleştirilmiş ve bir grupta iki dosya aynı ada sahiplerse, her dosyanın yolundaki ayırt edici bölümler eklenir. Sekmeler devre dışı ve düzenleyici aktifse, çalışma alanı kök klasörüne göreli yol gösterilir.", + "workbench.editor.labelFormat.short": "Dosyanın adını ve ardından dizin adını göster.", + "workbench.editor.labelFormat.medium": "Dosyanın adını ve ardından çalışma alanı kök klasörüne göreli yolunu göster.", + "workbench.editor.labelFormat.long": "Dosyanın adını ve ardından mutlak yolunu göster.", + "tabDescription": "Bir düzenleyici için etiketin biçimini denetler. Bu ayarı değiştirmek; örneğin, bir dosyanın konumunun daha kolay anlaşılmasını sağlar:\n- short: 'ustklasor'\n- medium: 'calismaalani/src/ustklasor'\n- long: '/home/user/calismaalani/src/ustklasor'\n- default: diğer bir sekme aynı başlığı paylaşıyorsa '.../ustklasor' veya sekmeler devre dışı ise göreli çalışma alanı yolu", "editorTabCloseButton": "Düzenleyici sekmelerinin kapat butonlarının konumunu denetler veya 'off' olarak ayarlandığında devre dışı bırakır.", "showIcons": "Açık düzenleyicilerin bir simge ile gösterilip gösterilmemelerini denetler. Bu, bir simge temasının etkinleştirilmesini de gerektirir.", "enablePreview": "Açık düzenleyicilerin önizleme olarak gösterilip gösterilmeyeceğini denetler. Önizleme düzenleyicileri kalıcı olarak açılana kadar (ör. çift tıklama veya düzenleme ile) tekrar kullanılırlar.", diff --git a/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json b/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json index efc71dc00cf..aa4162006c6 100644 --- a/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.i18n.json @@ -36,5 +36,7 @@ "schema.indentationRules.unIndentedLinePattern": "Bir satır bu kalıpla eşleşirse, o satırın girintisi değiştirilmemelidir ve diğer kurallara karşı değerlendirilmemelidir.", "schema.indentationRules.unIndentedLinePattern.pattern": "unIndentedLinePattern için Düzenli İfade.", "schema.indentationRules.unIndentedLinePattern.flags": "unIndentedLinePattern için Düzenli İfade işaretleri.", - "schema.indentationRules.unIndentedLinePattern.errorMessage": "`/^([gimuy]+)$/` kalıbı ile eşleşmelidir." + "schema.indentationRules.unIndentedLinePattern.errorMessage": "`/^([gimuy]+)$/` kalıbı ile eşleşmelidir.", + "schema.folding": "Dilin katlama ayarları.", + "schema.folding.offSide": "Bir dildeki bloklar girintilendirmeleriyle ifade edilirse, o dil için off-side kuralı uygulanır. Eğer ayarlanırsa, boş satırlar sonraki bloğa ait olur." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json b/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json index c7e63743c9f..48c31c797e6 100644 --- a/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/debug/electron-browser/debugService.i18n.json @@ -12,6 +12,8 @@ "breakpointRemoved": "Kesme noktası kaldırıldı, {0}. satır, {1} dosyası", "compoundMustHaveConfigurations": "Bileşik, birden çok yapılandırmayı başlatmak için \"configurations\" özniteliği bulundurmalıdır.", "configMissing": "'launch.json' dosyasında '{0}' yapılandırması eksik.", + "debugRequestNotSupported": "Yapılandırılan hata ayıklama isteği '{0}' desteklenmiyor.", + "debugRequesMissing": "Hata ayıklama isteği, seçilen başlatma yapılandırılmasında eksik", "debugTypeNotSupported": "Yapılandırılan hata ayıklama türü '{0}', desteklenmiyor.", "debugTypeMissing": "Seçilen başlatma yapılandırması için 'type' özelliği eksik.", "preLaunchTaskErrors": "'{0}' ön başlatma görevi sırasında derleme hataları algılandı.", diff --git a/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json b/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json index 39b6be390d3..4c3d5d2ef5f 100644 --- a/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionEditor.i18n.json @@ -29,6 +29,13 @@ "view id": "ID", "view name": "Adı", "view location": "Yeri", + "colorThemes": "Renk Temaları ({0})", + "iconThemes": "Simge Temaları ({0})", + "colors": "Renkler ({0})", + "colorId": "Kimlik", + "defaultDark": "Koyu Varsayılan", + "defaultLight": "Açık Varsayılan", + "defaultHC": "Yüksek Karşıtlık Varsayılan", "JSON Validation": "JSON Doğrulama ({0})", "commands": "Komutlar ({0})", "command name": "Adı", diff --git a/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json b/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json index 71c438668c3..aae0444fd86 100644 --- a/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/extensions/browser/extensionsActions.i18n.json @@ -51,9 +51,9 @@ "showLanguageExtensionsShort": "Dil Eklentileri", "showAzureExtensions": "Azure Eklentilerini Göster", "showAzureExtensionsShort": "Azure Eklentileri", - "configureWorkspaceRecommendedExtensions": "Tavsiye Edilen Eklentileri Yapılandır (Çalışma Alanı)", - "ConfigureWorkspaceRecommendations.noWorkspace": "Tavsiyeler, sadece çalışma alanı klasöründe mevcuttur.", "OpenExtensionsFile.failed": " '.vscode' klasörü içinde 'extensions.json' dosyası oluşturulamıyor ({0}).", + "configureWorkspaceRecommendedExtensions": "Tavsiye Edilen Eklentileri Yapılandır (Çalışma Alanı)", + "configureWorkspaceFolderRecommendedExtensions": "Tavsiye Edilen Eklentileri Yapılandır (Çalışma Alanı Klasörü)", "builtin": "Yerleşik", "disableAll": "Yüklü Tüm Eklentileri Devre Dışı Bırak", "disableAllWorkspace": "Bu Çalışma Alanı için Yüklü Tüm Eklentileri Devre Dışı Bırak", diff --git a/i18n/trk/src/vs/workbench/parts/files/browser/files.contribution.i18n.json b/i18n/trk/src/vs/workbench/parts/files/browser/files.contribution.i18n.json index dbc5b99d24f..55fe27e5276 100644 --- a/i18n/trk/src/vs/workbench/parts/files/browser/files.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/files/browser/files.contribution.i18n.json @@ -14,6 +14,8 @@ "files.exclude.boolean": "Dosya yollarının eşleştirileceği glob deseni. Deseni etkinleştirmek veya devre dışı bırakmak için true veya false olarak ayarlayın.", "files.exclude.when": "Eşleşen bir dosyanın eşdüzey dosyalarında ek denetim. Eşleşen dosya adı için değişken olarak $(basename) kullanın.", "associations": "Dillerle dosya ilişkilendirmelerini yapılandırın (ör. \"*.uzanti\": \"html\"). Bunların, kurulu olan dillerin varsayılan ilişkilendirmeleri karşısında önceliği vardır.", + "encoding": "Dosyalar okunurken ve yazılırken kullanılacak varsayılan karakter kümesi kodlaması. Bu ayar her bir dil için de yapılandırılabilir.", + "autoGuessEncoding": "Etkinleştirildiğinde, dosyaları açarken karakter kümesini tahmin etmeye çalışır. Bu ayar her bir dil için de yapılandırılabilir.", "eol": "Varsayılan satır sonu karakteri. LF için \\n ve CRLF için \\r\\n kullan.", "trimTrailingWhitespace": "Etkinleştirildiğinde, bir dosyayı kaydettiğinizde sondaki boşluk kırpılır.", "insertFinalNewline": "Etkinleştirildiğinde, bir dosyayı kaydederken dosya sonuna bir boş satır ekler.", diff --git a/i18n/trk/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json b/i18n/trk/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json index 0f88a5b2332..1a8d190f659 100644 --- a/i18n/trk/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/files/common/dirtyFilesTracker.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "dirtyFile": "1 kaydedilmemiş dosya", "dirtyFiles": "{0} kaydedilmemiş dosya" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json b/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json index 37e5169f3a8..fad9ab4f40b 100644 --- a/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/preferences/browser/preferencesActions.i18n.json @@ -9,7 +9,6 @@ "openGlobalKeybindingsFile": "Klavye Kısayolları Dosyasını Aç", "openWorkspaceSettings": "Çalışma Alanı Ayarlarını Aç", "openFolderSettings": "Klasör Ayarlarını Aç", - "pickFolder": "Klasör Seç", "configureLanguageBasedSettings": "Dile Özel Ayarları Yapılandır...", "languageDescriptionConfigured": "({0})", "pickLanguage": "Dili Seç" diff --git a/i18n/trk/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json b/i18n/trk/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json index 31778d735c7..3375526320d 100644 --- a/i18n/trk/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.i18n.json @@ -6,7 +6,5 @@ { "relaunchSettingMessage": "Yürürlüğe girmesi için yeniden başlatma gerektiren bir ayar değişti.", "relaunchSettingDetail": "{0} uygulamasını yeniden başlatmak ve bu ayarı etkinleştirmek için lütfen yeniden başlat butonuna basın.", - "restart": "Yeniden Başlat", - "relaunchWorkspaceMessage": "Bu çalışma alanı değişikliği eklenti sistemimizi yeniden başlatmayı gerektirir.", - "reload": "Yeniden Yükle" + "restart": "Yeniden Başlat" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json b/i18n/trk/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json index 1aac20564f2..1b8eebb304e 100644 --- a/i18n/trk/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/scm/electron-browser/scmViewlet.i18n.json @@ -4,8 +4,10 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "scm providers": "Kaynak Kontrolü Sağlayıcıları", "commitMessage": "Mesaj (commit'lemek için {0} tuşlarına basın)", "installAdditionalSCMProviders": "Ek SCM Sağlayıcıları Yükle...", + "no open repo": "Aktif bir kaynak kontrolü sağlayıcısı yok.", "source control": "Kaynak Kontrolü", "viewletTitle": "{0}: {1}" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json b/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json index c8734bde48f..e8d5b2a4732 100644 --- a/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/insertSnippet.i18n.json @@ -4,5 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "snippet.suggestions.label": "Parçacık Ekle" + "snippet.suggestions.label": "Parçacık Ekle", + "sep.userSnippet": "Kullanıcı Parçacıkları", + "sep.extSnippet": "Eklenti Parçacıkları" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json b/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json index 432caec4bb9..52c84a18c00 100644 --- a/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/snippets/electron-browser/snippetsService.i18n.json @@ -10,6 +10,7 @@ "vscode.extension.contributes.snippets": "Parçacıklara ekleme yapar.", "vscode.extension.contributes.snippets-language": "Bu parçacığın ekleneceği dilin tanımlayıcısı.", "vscode.extension.contributes.snippets-path": "Parçacıklar dosyasının yolu. Yol, eklenti klasörüne görecelidir ve genellikle './snippets/' ile başlar.", + "badFile": "Parçacık dosyası \"{0}\" okunamadı.", "badVariableUse": "\"{0}\"-parçacığı yüksek olasılıkla parçacık değişkenleri ile parçacık yer tutucularını karıştırıyor. Daha fazla bilgi için https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax adresini ziyaret edin.", "source.snippet": "Kullanıcı Parçacığı", "detail.snippet": "{0} ({1})", diff --git a/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json b/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json index 8998948fe3b..1821c3a3b7c 100644 --- a/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/task.contribution.i18n.json @@ -5,13 +5,7 @@ // Do not edit this file. It is machine generated. { "tasksCategory": "Görevler", - "ConfigureTaskRunnerAction.noWorkspace": "Görevler, sadece çalışma alanı klasöründe mevcuttur.", - "ConfigureTaskRunnerAction.quickPick.template": "Bir Görev Çalıştırıcısı Seç", - "ConfigureTaskRunnerAction.autoDetecting": "{0} görevleri otomatik algılanıyor", - "ConfigureTaskRunnerAction.autoDetect": "Görev sisteminin otomatik algılanması başarısız oldu. Varsayılan şablon kullanılıyor. Ayrıntılar için görev çıktısına bakın.", - "ConfigureTaskRunnerAction.autoDetectError": "Görev sisteminin otomatik algılanması sırasında hatalar oluştu. Ayrıntılar için görev çıktısına bakın.", - "ConfigureTaskRunnerAction.failed": " '.vscode' klasörü içinde 'tasks.json' dosyası oluşturulamıyor. Ayrıntılar için görev çıktısına bakın.", - "ConfigureTaskRunnerAction.label": "Görev Çalıştırıcısını Yapılandır", + "ConfigureTaskRunnerAction.label": "Görevi Yapılandır", "ConfigureBuildTaskAction.label": "Derleme Görevini Yapılandır", "CloseMessageAction.label": "Kapat", "ShowTerminalAction.label": "Terminali Görüntüle", @@ -19,11 +13,13 @@ "manyMarkers": "99+", "runningTasks": "Çalışan Görevleri Göster", "tasks": "Görevler", + "TaskSystem.noHotSwap": "Aktif bir görev çalıştıran görev yürütme motorunu değiştirmek pencereyi yeniden yüklemeyi gerektirir", "TaskService.noBuildTask1": "Derleme görevi tanımlanmamış. tasks.json dosyasındaki bir görevi 'isBuildCommand' ile işaretleyin.", "TaskService.noBuildTask2": "Derleme görevi tanımlanmamış. tasks.json dosyasındaki bir görevi, bir 'build' grubu olarak işaretleyin.", "TaskService.noTestTask1": "Test görevi tanımlanmamış. tasks.json dosyasındaki bir testi 'isTestCommand' ile işaretleyin.", "TaskService.noTestTask2": "Test görevi tanımlanmamış. tasks.json dosyasındaki bir görevi, bir 'test' grubu olarak işaretleyin.", "TaskServer.noTask": " Çalıştırılmak istenen {0} görevi bulunamadı.", + "TaskService.associate": "ilişkili", "TaskService.attachProblemMatcher.continueWithout": "Görev çıktısını taramadan devam et", "TaskService.attachProblemMatcher.never": "Hiçbir zaman görev çıktısını tarama", "TaskService.attachProblemMatcher.learnMoreAbout": "Görev çıktısını tarama hakkında daha fazla bilgi edin", @@ -35,6 +31,7 @@ "TaskSystem.active": "Çalışan bir görev zaten var. Bir başkasını çalıştırmadan önce bu görevi sonlandırın.", "TaskSystem.restartFailed": "{0} görevini sonlandırma ve yeniden başlatma başarısız oldu", "TaskSystem.configurationErrors": "Hata: belirtilen görev yapılandırmasında doğrulama hataları var ve kullanılamıyor. Lütfen ilk olarak hataları düzeltin.", + "taskService.ignoreingFolder": "{0} çalışma alanı klasörü için görev yapılandırmaları yok sayılıyor. Çoklu kök klasör desteği, tüm klasörlerin 2.0.0 görev sürümünü kullanmasını gerektirir\n", "TaskSystem.invalidTaskJson": "Hata: tasks.json dosyasının içeriğinde sentaks hataları var. Lütfen, bir görevi çalıştırmadan önce hataları düzeltin.\n", "TaskSystem.runningTask": "Çalışan bir görev var. Bu görevi sonlandırmak istiyor musunuz?", "TaskSystem.terminateTask": "&&Görevi Sonlandır", @@ -46,24 +43,30 @@ "recentlyUsed": "yakınlarda kullanılan görevler", "configured": "yapılandırılmış görevler", "detected": "algılanan görevler", + "TaskService.pickRunTask": "Çalıştırılacak görevi seçin", + "TaslService.noEntryToRun": "Çalıştırılacak hiçbir görev bulunamadı. Görevleri Yapılandır...", "TaskService.fetchingBuildTasks": "Derleme görevleri alınıyor...", - "TaskService.noBuildTaskTerminal": "Derleme görevi bulunamadı. Yeni bir tane tanımlamak için 'Derleme Görevini Yapılandır'a basın.", "TaskService.pickBuildTask": "Çalıştırılacak derleme görevini seçin", + "TaskService.noBuildTask": "Çalıştırılacak hiçbir derleme görevi bulunamadı. Görevleri Yapılandır...", "TaskService.fetchingTestTasks": "Test görevleri alınıyor...", - "TaskService.noTestTaskTerminal": "Test görevi bulunamadı. Yeni bir tane tanımlamak için 'Görev Çalıştırıcısını Yapılandır'a basın.", "TaskService.pickTestTask": "Çalıştırılacak test görevini seçin", - "TaskService.noTaskRunning": "Şu an çalışan bir görev yok.", + "TaskService.noTestTaskTerminal": "Çalıştırılacak hiçbir test görevi bulunamadı. Görevleri Yapılandır...", "TaskService.tastToTerminate": "Sonlandırılacak görevi seçin", + "TaskService.noTaskRunning": "Şu an çalışan bir görev yok", "TerminateAction.noProcess": "Başlatılan işlem artık mevcut değil. Eğer görev arka plan görevleri oluşturduysa, VS Code'dan çıkmak işlemlerin sahipsiz kalmasına neden olabilir.", "TerminateAction.failed": "Çalışan görevi sonlandırma başarısız oldu.", - "TaskService.noTaskToRestart": "Yeniden başlatılacak bir görev yok.", "TaskService.tastToRestart": "Yeniden başlatılacak görevi seçin", - "TaskService.defaultBuildTaskExists": "{0} zaten varsayılan derleme görevi olarak işaretlenmiş.", + "TaskService.noTaskToRestart": "Yeniden başlatılacak bir görev yok", + "TaskService.template": "Bir Görev Şablonu Seçin", + "TaskService.createJsonFile": "Şablondan tasks.json dosyası oluştur", + "TaskService.openJsonFile": "tasks.json dosyasını aç", + "TaskService.pickTask": "Yapılandırmak için bir görev seçin", + "TaskService.defaultBuildTaskExists": "{0} zaten varsayılan derleme görevi olarak işaretlenmiş", "TaskService.pickDefaultBuildTask": "Varsayılan derleme görevi olarak kullanılacak görevi seçin", "TaskService.defaultTestTaskExists": "{0} zaten varsayılan test görevi olarak işaretlenmiş.", "TaskService.pickDefaultTestTask": "Varsayılan test görevi olarak kullanılacak görevi seçin", - "TaskService.noTaskIsRunning": "Çalışan bir görev yok.", "TaskService.pickShowTask": "Çıktısını göstermek için görev seçin", + "TaskService.noTaskIsRunning": "Çalışan bir görev yok", "ShowLogAction.label": "Görev Günlüğünü Göster", "RunTaskAction.label": "Görevi Çalıştır", "RestartTaskAction.label": "Çalışan Görevi Yeniden Başlat", diff --git a/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json b/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json index d3492257f35..2e339c2d029 100644 --- a/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.i18n.json @@ -5,6 +5,7 @@ // Do not edit this file. It is machine generated. { "TerminalTaskSystem.unknownError": "Görev çalıştırılırken bir hata oluştu. Detaylar için görev çıktısı günlüğüne bakın.", + "dependencyFailed": "'{1}' çalışma alanı klasöründe, '{0}' bağımlı görevi çözümlenemiyor", "TerminalTaskSystem.terminalName": "Görev - {0}", "reuseTerminal": "Terminal görevler tarafından tekrar kullanılacak, kapatmak için herhangi bir tuşa basın.", "TerminalTaskSystem": "UNC sürücüsünde kabuk komutu yürütülemez.", diff --git a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json index 8325d1451ce..8d8d4cb77d3 100644 --- a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalActions.i18n.json @@ -38,5 +38,6 @@ "workbench.action.terminal.focusFindWidget": "Bulma Aracına Odakla", "workbench.action.terminal.hideFindWidget": "Bulma Aracını Gizle", "nextTerminalFindTerm": "Sonraki Arama Terimini Göster", - "previousTerminalFindTerm": "Önceki Arama Terimini Göster" + "previousTerminalFindTerm": "Önceki Arama Terimini Göster", + "quickOpenTerm": "Aktif Terminali Değiştir" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json index 69009eea2db..a994ebe0909 100644 --- a/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/terminal/electron-browser/terminalColorRegistry.i18n.json @@ -8,5 +8,6 @@ "terminal.foreground": "Terminalin ön plan rengi.", "terminalCursor.foreground": "Terminal imlecinin ön plan rengi.", "terminalCursor.background": "Terminal imlecinin arka plan rengi. Bir blok imlecinin kapladığı bir karakterin rengini özelleştirmeyi sağlar.", + "terminal.selectionBackground": "Terminalin seçim arkaplanı rengi.", "terminal.ansiColor": "Terminalde '{0}' ANSI rengi." } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json b/i18n/trk/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json index 8098995a486..5370096e708 100644 --- a/i18n/trk/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json +++ b/i18n/trk/src/vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page.i18n.json @@ -10,6 +10,7 @@ "welcomePage.newFile": "Yeni dosya", "welcomePage.openFolder": "Klasör aç...", "welcomePage.cloneGitRepository": "Git deposu kopyala...", + "welcomePage.addWorkspaceFolder": "Çalışma alanı klasörü ekle...", "welcomePage.recent": "Son Kullanılanlar", "welcomePage.moreRecent": "Diğerleri...", "welcomePage.noRecentFolders": "Son kullanılan klasör yok", diff --git a/i18n/trk/src/vs/workbench/services/configuration/node/configuration.i18n.json b/i18n/trk/src/vs/workbench/services/configuration/node/configuration.i18n.json index 22fb2b8b560..a2e1bebe9d9 100644 --- a/i18n/trk/src/vs/workbench/services/configuration/node/configuration.i18n.json +++ b/i18n/trk/src/vs/workbench/services/configuration/node/configuration.i18n.json @@ -13,7 +13,11 @@ "invalid.title": "'configuration.title' bir dize olmalıdır", "vscode.extension.contributes.defaultConfiguration": "Varsayılan düzenleyici yapılandırma ayarlarına dil bazında ekleme yapar.", "invalid.properties": "'configuration.properties' bir nesne olmalıdır", - "workspaceConfig.folders.description": "Çalışma alanında yüklenecek klasörler listesi. Bir dosya yolu olmalıdır. ör. `/root/folderA` veya çalışma alanı dosyasının konumuna karşı çözümlenecek göreceli bir yol için `./folderA`.", - "workspaceConfig.folder.description": "Bir dosya yolu. ör. `/root/folderA` veya çalışma alanı dosyasının konumuna karşı çözümlenecek göreceli bir yol için `./folderA`.", - "workspaceConfig.settings.description": "Çalışma alanı ayarları" + "invalid.allOf": "'configuration.allOf' kullanım dışıdır ve artık kullanılmamalıdır. Bunun yerine, birden çok yapılandırma bölümlerini bir dizi olarak 'configuration' ekleme noktasına geçirin.", + "workspaceConfig.folders.description": "Çalışma alanına yüklenecek klasörler listesi.", + "workspaceConfig.path.description": "Bir dosya yolu. ör. `/root/folderA` veya çalışma alanı dosyasının konumuna karşı çözümlenecek göreceli bir yol için `./folderA`.", + "workspaceConfig.name.description": "Klasör için isteğe bağlı bir ad.", + "workspaceConfig.uri.description": "Klasörün URI'si", + "workspaceConfig.settings.description": "Çalışma alanı ayarları", + "workspaceConfig.extensions.description": "Çalışma alanı eklentileri" } \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json b/i18n/trk/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json new file mode 100644 index 00000000000..320c074b5d2 --- /dev/null +++ b/i18n/trk/src/vs/workbench/services/files/electron-browser/remoteFileService.i18n.json @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +// Do not edit this file. It is machine generated. +{ + "fileBinaryError": "Dosya ikili olarak görünüyor ve metin olarak açılamıyor" +} \ No newline at end of file diff --git a/i18n/trk/src/vs/workbench/services/files/node/fileService.i18n.json b/i18n/trk/src/vs/workbench/services/files/node/fileService.i18n.json index 8b8dee30b02..0c8d70cb473 100644 --- a/i18n/trk/src/vs/workbench/services/files/node/fileService.i18n.json +++ b/i18n/trk/src/vs/workbench/services/files/node/fileService.i18n.json @@ -5,10 +5,12 @@ // Do not edit this file. It is machine generated. { "fileInvalidPath": "Geçersiz dosya kaynağı ({0})", + "fileIsDirectoryError": "Dosya bir dizindir", "fileNotModifiedError": "Dosya şu tarihten beri değiştirilmemiş:", "fileTooLargeError": "Dosya, açmak için çok büyük", "fileBinaryError": "Dosya ikili olarak görünüyor ve metin olarak açılamıyor", "fileNotFoundError": "Dosya bulunamadı ({0})", + "fileExists": "Oluşturulacak dosya zaten mevcut ({0})", "fileMoveConflict": "Taşıma/kopyalama yapılamadı. Dosya, hedefte zaten mevcut.", "unableToMoveCopyError": "Taşıma/kopyalama yapılamadı. Dosya, içinde bulunduğu klasörü değiştiriyor.", "foldersCopyError": "Klasörler çalışma alanına kopyalanamaz. Lütfen kopyalamak için dosyaları tek tek seçin.", From 65b9a0de2d5e9625bb39233765a434af4357a2c6 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 22 Sep 2017 12:51:49 -0700 Subject: [PATCH 239/281] Autoshow suggestions for jsdoc param Fixes #34853 --- .../typescript/src/features/completionItemProvider.ts | 10 +++++++++- extensions/typescript/src/typescriptMain.ts | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/extensions/typescript/src/features/completionItemProvider.ts b/extensions/typescript/src/features/completionItemProvider.ts index 4c5d88ede58..795230ae0b7 100644 --- a/extensions/typescript/src/features/completionItemProvider.ts +++ b/extensions/typescript/src/features/completionItemProvider.ts @@ -190,13 +190,21 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP } if (context.triggerCharacter === '/') { - // make sure we are in something that looks line an import path + // make sure we are in something that looks like an import path const line = document.lineAt(position.line).text.slice(0, position.character); if (!line.match(/^import .+? from\s*["'][^'"]*$/) && !line.match(/\b(import|require)\(['"][^'"]*$/)) { return Promise.resolve([]); } } + if (context.triggerCharacter === '@') { + // make sure we are in something that looks like the start of a jsdoc comment + const line = document.lineAt(position.line).text.slice(0, position.character); + if (!line.match(/^\s*\*[ ]?@/) && !line.match(/\/\*\*+[ ]?@/)) { + return Promise.resolve([]); + } + } + const args: CompletionsRequestArgs = vsPositionToTsFileLocation(file, position); return this.client.execute('completions', args, token).then((msg) => { // This info has to come from the tsserver. See https://github.com/Microsoft/TypeScript/issues/2831 diff --git a/extensions/typescript/src/typescriptMain.ts b/extensions/typescript/src/typescriptMain.ts index 6cf20c87391..b4bd55a6357 100644 --- a/extensions/typescript/src/typescriptMain.ts +++ b/extensions/typescript/src/typescriptMain.ts @@ -242,7 +242,7 @@ class LanguageProvider { const completionItemProvider = new (await import('./features/completionItemProvider')).default(client, this.typingsStatus); completionItemProvider.updateConfiguration(); this.toUpdateOnConfigurationChanged.push(completionItemProvider); - this.disposables.push(languages.registerCompletionItemProvider(selector, completionItemProvider, '.', '"', '\'', '/')); + this.disposables.push(languages.registerCompletionItemProvider(selector, completionItemProvider, '.', '"', '\'', '/', '@')); this.disposables.push(languages.registerCompletionItemProvider(selector, new (await import('./features/directiveCommentCompletionProvider')).default(client), '@')); From 6ec697a29a5b836128dd5096a69a59a4f6290f87 Mon Sep 17 00:00:00 2001 From: Ramya Achutha Rao Date: Fri, 22 Sep 2017 15:00:33 -0700 Subject: [PATCH 240/281] Telemetry to differentiate all recommendations view from the others --- .../parts/extensions/electron-browser/extensionsViews.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts index 1317316f3ee..37f9a6e4e16 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViews.ts @@ -294,6 +294,7 @@ export class ExtensionsListView extends CollapsibleView { .filter(name => local.every(ext => `${ext.publisher}.${ext.name}` !== name)) .filter(name => name.toLowerCase().indexOf(value) > -1); + this.telemetryService.publicLog('extensionAllRecommendations:open', { count: names.length }); if (!names.length) { return TPromise.as(new PagedModel([])); } From 6069a52022751730ec3b36d6a13cb214cfcba9c3 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 22 Sep 2017 15:13:41 -0700 Subject: [PATCH 241/281] Fix failing tests --- src/vs/workbench/api/node/extHost.api.impl.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 845f114f678..31121d10c1c 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -439,7 +439,7 @@ export function createApiFactory( let uriPromise: TPromise; let options = uriOrFileNameOrOptions as { language?: string; content?: string; }; - if (!options || typeof options === 'object') { + if (!options && (typeof options.language === 'string' || typeof options.content === 'string')) { uriPromise = extHostDocuments.createDocumentData(options); } else if (typeof uriOrFileNameOrOptions === 'string') { uriPromise = TPromise.as(URI.file(uriOrFileNameOrOptions)); From cc32157235ebd7e9d4e687b7fb856b31461681a0 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 22 Sep 2017 15:16:43 -0700 Subject: [PATCH 242/281] Update TS insiders version --- extensions/npm-shrinkwrap.json | 6 +++--- extensions/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/npm-shrinkwrap.json b/extensions/npm-shrinkwrap.json index cf47f857cf2..884010a7c42 100644 --- a/extensions/npm-shrinkwrap.json +++ b/extensions/npm-shrinkwrap.json @@ -3,9 +3,9 @@ "version": "0.0.1", "dependencies": { "typescript": { - "version": "2.5.3-insiders.20170919", - "from": "typescript@2.5.3-insiders.20170919", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3-insiders.20170919.tgz" + "version": "2.5.3-insiders.20170922", + "from": "typescript@2.5.3-insiders.20170922", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3-insiders.20170922.tgz" } } } diff --git a/extensions/package.json b/extensions/package.json index 9e0ef9f6fd2..30339830b0a 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "2.5.3-insiders.20170919" + "typescript": "2.5.3-insiders.20170922" }, "scripts": { "postinstall": "node ./postinstall" From cb7e0bffd08d21e4001e962697a935e71b64312c Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 22 Sep 2017 15:32:00 -0700 Subject: [PATCH 243/281] Prototype TSC watch task contribution (#33865) * Prototype TSC watch task contribution * Update to make use of optional properties in task definitions --- extensions/typescript/package.json | 3 ++ .../typescript/src/features/taskProvider.ts | 48 ++++++++----------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/extensions/typescript/package.json b/extensions/typescript/package.json index 1bab55ee7e3..a5093c1f0c3 100644 --- a/extensions/typescript/package.json +++ b/extensions/typescript/package.json @@ -516,6 +516,9 @@ "tsconfig": { "type": "string", "description": "The tsconfig file that defines the TS build" + }, + "option": { + "type": "string" } } } diff --git a/extensions/typescript/src/features/taskProvider.ts b/extensions/typescript/src/features/taskProvider.ts index 7b88988257e..46dce9fa311 100644 --- a/extensions/typescript/src/features/taskProvider.ts +++ b/extensions/typescript/src/features/taskProvider.ts @@ -28,6 +28,7 @@ const exists = (file: string): Promise => interface TypeScriptTaskDefinition extends vscode.TaskDefinition { tsconfig: string; + option?: string; } /** @@ -53,7 +54,7 @@ class TscTaskProvider implements vscode.TaskProvider { for (const project of await this.getAllTsConfigs(token)) { if (!configPaths.has(project.path)) { configPaths.add(project.path); - tasks.push(await this.getBuildTaskForProject(project)); + tasks.push(...(await this.getTasksForProject(project))); } } return tasks; @@ -135,18 +136,6 @@ class TscTaskProvider implements vscode.TaskProvider { return 'tsc'; } - private shouldUseWatchForBuild(configFile: TSConfig): boolean { - try { - const config = JSON.parse(fs.readFileSync(configFile.path, 'utf-8')); - if (config) { - return !!config.compileOnSave; - } - } catch (e) { - // noop - } - return false; - } - private getActiveTypeScriptFile(): string | null { const editor = vscode.window.activeTextEditor; if (editor) { @@ -158,7 +147,7 @@ class TscTaskProvider implements vscode.TaskProvider { return null; } - private async getBuildTaskForProject(project: TSConfig): Promise { + private async getTasksForProject(project: TSConfig): Promise { const command = await this.getCommand(project); let label: string = project.path; @@ -178,22 +167,27 @@ class TscTaskProvider implements vscode.TaskProvider { } } - const watch = false && this.shouldUseWatchForBuild(project); - const identifier: TypeScriptTaskDefinition = { type: 'typescript', tsconfig: label }; + const buildTaskidentifier: TypeScriptTaskDefinition = { type: 'typescript', tsconfig: label }; const buildTask = new vscode.Task( - identifier, - watch - ? localize('buildAndWatchTscLabel', 'watch - {0}', label) - : localize('buildTscLabel', 'build - {0}', label), + buildTaskidentifier, + localize('buildTscLabel', 'build - {0}', label), 'tsc', - new vscode.ShellExecution(`${command} ${watch ? '--watch' : ''} -p "${project.path}"`), - watch - ? '$tsc-watch' - : '$tsc' - ); + new vscode.ShellExecution(`${command} -p "${project.path}"`), + '$tsc'); buildTask.group = vscode.TaskGroup.Build; - buildTask.isBackground = watch; - return buildTask; + buildTask.isBackground = false; + + const watchTaskidentifier: TypeScriptTaskDefinition = { type: 'typescript', tsconfig: label, option: 'watch' }; + const watchTask = new vscode.Task( + watchTaskidentifier, + localize('buildAndWatchTscLabel', 'watch - {0}', label), + 'tsc', + new vscode.ShellExecution(`${command} --watch -p "${project.path}"`), + '$tsc-watch'); + watchTask.group = vscode.TaskGroup.Build; + watchTask.isBackground = true; + + return [buildTask, watchTask]; } } From 982277d9d1c024924fb56d8aa977c097e82a1062 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 22 Sep 2017 15:52:39 -0700 Subject: [PATCH 244/281] Really fix test on options --- src/vs/workbench/api/node/extHost.api.impl.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 31121d10c1c..d7334dde35c 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -439,7 +439,7 @@ export function createApiFactory( let uriPromise: TPromise; let options = uriOrFileNameOrOptions as { language?: string; content?: string; }; - if (!options && (typeof options.language === 'string' || typeof options.content === 'string')) { + if (!options || (options && (typeof options.language === 'string' || typeof options.content === 'string'))) { uriPromise = extHostDocuments.createDocumentData(options); } else if (typeof uriOrFileNameOrOptions === 'string') { uriPromise = TPromise.as(URI.file(uriOrFileNameOrOptions)); From f8023e7e1bb3eaf3ba6efc2704c8dd6d435e9359 Mon Sep 17 00:00:00 2001 From: Ramya Achutha Rao Date: Fri, 22 Sep 2017 16:23:00 -0700 Subject: [PATCH 245/281] Add sourceInfo when installing from welcomePage or cli --- src/vs/code/node/cliProcessMain.ts | 2 +- .../parts/welcome/page/electron-browser/welcomePage.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index a09c9c3685e..c822b373b3c 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -110,7 +110,7 @@ class Main { return TPromise.as(null); } - return this.extensionGalleryService.query({ names: [id] }) + return this.extensionGalleryService.query({ names: [id], source: 'cli' }) .then>(null, err => { if (err.responseText) { try { diff --git a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts index c57f74e828a..90336d7e2ff 100644 --- a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts +++ b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts @@ -365,7 +365,7 @@ class WelcomePage { this.messageService.show(Severity.Info, strings.alreadyInstalled.replace('{0}', extensionSuggestion.name)); return; } - const foundAndInstalled = installedExtension ? TPromise.as(true) : this.extensionGalleryService.query({ names: [extensionSuggestion.id] }) + const foundAndInstalled = installedExtension ? TPromise.as(true) : this.extensionGalleryService.query({ names: [extensionSuggestion.id], source: telemetryFrom }) .then(result => { const [extension] = result.firstPage; if (!extension) { From 2de946548cb703551bd3f0b4315fc7446e43ea90 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 22 Sep 2017 16:33:56 -0700 Subject: [PATCH 246/281] Check type of token that triggered the quick suggestions Fixes #34863 **Bug** Quick suggestions currently check the token at the cursor location to determine if we are in a string or comment. Because token spans are setup like: `[start, end)`, this results in the incorrect token being checked when the quick suggestions are triggered immediatly before a comment or string **Fix** Check the token one index back from the cursor --- src/vs/editor/contrib/suggest/browser/suggestModel.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggestModel.ts b/src/vs/editor/contrib/suggest/browser/suggestModel.ts index e71781a9f33..f74fda9bbed 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestModel.ts @@ -301,11 +301,11 @@ export class SuggestModel implements IDisposable { } else if (quickSuggestions === true) { // all good } else { + // Check the type of the token that triggered this model.tokenizeIfCheap(pos.lineNumber); const { tokenType } = model .getLineTokens(pos.lineNumber) - .findTokenAtOffset(pos.column - 1); - + .findTokenAtOffset(Math.max(pos.column - 1 - 1, 0)); const inValidScope = quickSuggestions.other && tokenType === StandardTokenType.Other || quickSuggestions.comments && tokenType === StandardTokenType.Comment || quickSuggestions.strings && tokenType === StandardTokenType.String; From 848923bf089e7e48c5134f2d1ceeb41ab39ce7bd Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 22 Sep 2017 16:39:21 -0700 Subject: [PATCH 247/281] Enable proposed api in api-tests --- extensions/vscode-api-tests/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/vscode-api-tests/package.json b/extensions/vscode-api-tests/package.json index 93ac38acad8..1b3e93e88ec 100644 --- a/extensions/vscode-api-tests/package.json +++ b/extensions/vscode-api-tests/package.json @@ -3,6 +3,7 @@ "description": "API tests for VS Code", "version": "0.0.1", "publisher": "vscode", + "enableProposedApi": true, "private": true, "engines": { "vscode": "*" From 8462f119898133f410f27deb63de14dd74051567 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sat, 23 Sep 2017 08:30:13 +0200 Subject: [PATCH 248/281] lookup files.encoding properly --- .../parts/files/browser/files.contribution.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/files.contribution.ts b/src/vs/workbench/parts/files/browser/files.contribution.ts index 6e1442f74e6..8c7539cbc7a 100644 --- a/src/vs/workbench/parts/files/browser/files.contribution.ts +++ b/src/vs/workbench/parts/files/browser/files.contribution.ts @@ -14,7 +14,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions, Configur import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory, EditorInput, IFileEditorInput } from 'vs/workbench/common/editor'; -import { AutoSaveConfiguration, HotExitConfiguration, SUPPORTED_ENCODINGS } from 'vs/platform/files/common/files'; +import { AutoSaveConfiguration, HotExitConfiguration, SUPPORTED_ENCODINGS, IFilesConfiguration } from 'vs/platform/files/common/files'; import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { FILE_EDITOR_INPUT_ID, VIEWLET_ID, SortOrderConfiguration } from 'vs/workbench/parts/files/common/files'; import { FileEditorTracker } from 'vs/workbench/parts/files/common/editors/fileEditorTracker'; @@ -29,8 +29,8 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import * as platform from 'vs/base/common/platform'; -import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { DirtyFilesTracker } from 'vs/workbench/parts/files/common/dirtyFilesTracker'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; // Viewlet Action export class OpenExplorerViewletAction extends ToggleViewletAction { @@ -113,7 +113,7 @@ interface ISerializedFileInput { class FileEditorInputFactory implements IEditorInputFactory { constructor( - @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService + @ITextResourceConfigurationService private configurationService: ITextResourceConfigurationService ) { } @@ -126,13 +126,19 @@ class FileEditorInputFactory implements IEditorInputFactory { }; const encoding = fileEditorInput.getPreferredEncoding(); - if (encoding && encoding !== this.configurationService.lookup('files.encoding', { resource }).value) { + if (encoding && encoding !== this.getConfiguredEncoding(resource)) { fileInput.encoding = encoding; } return JSON.stringify(fileInput); } + private getConfiguredEncoding(resource: URI): string { + const configuration = this.configurationService.getConfiguration(resource); + + return configuration && configuration.files && configuration.files.encoding; + } + public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): FileEditorInput { return instantiationService.invokeFunction(accessor => { const fileInput: ISerializedFileInput = JSON.parse(serializedEditorInput); From 6f7cabae9e36ce07723daeee389b7f96ca713826 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sat, 23 Sep 2017 08:31:30 +0200 Subject: [PATCH 249/281] disable test on proposed API --- .../vscode-api-tests/src/window.test.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/extensions/vscode-api-tests/src/window.test.ts b/extensions/vscode-api-tests/src/window.test.ts index c197808fd9e..df08d550a58 100644 --- a/extensions/vscode-api-tests/src/window.test.ts +++ b/extensions/vscode-api-tests/src/window.test.ts @@ -349,17 +349,17 @@ suite('window namespace tests', () => { return Promise.all([a, b]); }); - test('showWorkspaceFolderPick', function () { - const p = (window).showWorkspaceFolderPick(undefined); + // test('showWorkspaceFolderPick', function () { + // const p = (window).showWorkspaceFolderPick(undefined); - return commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem').then(() => { - return p.then(workspace => { - assert.ok(true); - }, error => { - assert.ok(false); - }); - }); - }); + // return commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem').then(() => { + // return p.then(workspace => { + // assert.ok(true); + // }, error => { + // assert.ok(false); + // }); + // }); + // }); test('Default value for showInput Box accepted even if fails validateInput, #33691', function () { const result = window.showInputBox({ From a1f240181682a8c99c9e4f93ae0bfce20f003134 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 21 Sep 2017 15:07:18 +0200 Subject: [PATCH 250/281] fix missing dirty diff decorations --- .../electron-browser/dirtydiffDecorator.ts | 65 ++++++++++++------- src/vs/workbench/services/scm/common/scm.ts | 1 - .../services/scm/common/scmService.ts | 3 - 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts index e512ed141a0..e29d4a29225 100644 --- a/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/parts/scm/electron-browser/dirtydiffDecorator.ts @@ -9,11 +9,12 @@ import nls = require('vs/nls'); import 'vs/css!./media/dirtydiffDecorator'; import { ThrottledDelayer, always } from 'vs/base/common/async'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; +import { any as anyEvent, filterEvent } from 'vs/base/common/event'; import * as ext from 'vs/workbench/common/contributions'; import * as common from 'vs/editor/common/editorCommon'; -import * as widget from 'vs/editor/browser/codeEditor'; +import { CodeEditor } from 'vs/editor/browser/codeEditor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IMessageService } from 'vs/platform/message/common/message'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -23,7 +24,7 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; import URI from 'vs/base/common/uri'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { ISCMService } from 'vs/workbench/services/scm/common/scm'; +import { ISCMService, ISCMRepository } from 'vs/workbench/services/scm/common/scm'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations'; import { registerThemingParticipant, ITheme, ICssStyleCollector, themeColorFromId } from 'vs/platform/theme/common/themeService'; import { registerColor } from 'vs/platform/theme/common/colorRegistry'; @@ -87,15 +88,17 @@ class DirtyDiffModelDecorator { } }); - private decorations: string[]; + private decorations: string[] = []; private baselineModel: common.IModel; private diffDelayer: ThrottledDelayer; private _originalURIPromise: TPromise; - private toDispose: IDisposable[]; + + private repositoryDisposables = new Set(); + private toDispose: IDisposable[] = []; constructor( private model: common.IModel, - private uri: URI, + // private editor: CodeEditor, @ISCMService private scmService: ISCMService, @IModelService private modelService: IModelService, @IEditorWorkerService private editorWorkerService: IEditorWorkerService, @@ -103,12 +106,28 @@ class DirtyDiffModelDecorator { @IWorkspaceContextService private contextService: IWorkspaceContextService, @ITextModelService private textModelResolverService: ITextModelService ) { - this.decorations = []; this.diffDelayer = new ThrottledDelayer(200); - this.toDispose = []; - this.triggerDiff(); + this.toDispose.push(model.onDidChangeContent(() => this.triggerDiff())); - this.toDispose.push(scmService.onDidChangeRepository(() => this.triggerDiff())); + scmService.onDidAddRepository(this.onDidAddRepository, this, this.toDispose); + scmService.repositories.forEach(r => this.onDidAddRepository(r)); + + this.triggerDiff(); + } + + private onDidAddRepository(repository: ISCMRepository): void { + const disposables: IDisposable[] = []; + + this.repositoryDisposables.add(disposables); + disposables.push(toDisposable(() => this.repositoryDisposables.delete(disposables))); + + const onDidChange = anyEvent(repository.provider.onDidChange, repository.provider.onDidChangeResources); + onDidChange(this.triggerDiff, this, disposables); + + const onDidRemoveThis = filterEvent(this.scmService.onDidRemoveRepository, r => r === repository); + onDidRemoveThis(() => dispose(disposables)); + + this.triggerDiff(); } private triggerDiff(): TPromise { @@ -174,7 +193,7 @@ class DirtyDiffModelDecorator { private async getOriginalResource(): TPromise { for (const repository of this.scmService.repositories) { - const result = repository.provider.getOriginalResource(this.uri); + const result = repository.provider.getOriginalResource(this.model.uri); if (result) { return result; @@ -237,6 +256,9 @@ class DirtyDiffModelDecorator { this.diffDelayer.cancel(); this.diffDelayer = null; } + + this.repositoryDisposables.forEach(d => dispose(d)); + this.repositoryDisposables.clear(); } } @@ -271,28 +293,25 @@ export class DirtyDiffDecorator implements ext.IWorkbenchContribution { .map(e => e.getControl()) // only interested in code editor widgets - .filter(c => c instanceof widget.CodeEditor) + .filter(c => c instanceof CodeEditor) // map to models - .map(e => (e).getModel()) + .map(editor => (editor as CodeEditor).getModel()) // remove nulls and duplicates - .filter((m, i, a) => !!m && !!m.uri && a.indexOf(m, i + 1) === -1) + .filter((m, i, a) => !!m && !!m.uri && a.indexOf(m, i + 1) === -1); - // get the associated resource - .map(m => ({ model: m, uri: m.uri })); + const newModels = models.filter(p => this.models.every(m => p !== m)); + const oldModels = this.models.filter(m => models.every(p => p !== m)); - const newModels = models.filter(p => this.models.every(m => p.model !== m)); - const oldModels = this.models.filter(m => models.every(p => p.model !== m)); - - newModels.forEach(({ model, uri }) => this.onModelVisible(model, uri)); + newModels.forEach(m => this.onModelVisible(m)); oldModels.forEach(m => this.onModelInvisible(m)); - this.models = models.map(p => p.model); + this.models = models; } - private onModelVisible(model: common.IModel, uri: URI): void { - this.decorators[model.id] = this.instantiationService.createInstance(DirtyDiffModelDecorator, model, uri); + private onModelVisible(model: common.IModel): void { + this.decorators[model.id] = this.instantiationService.createInstance(DirtyDiffModelDecorator, model); } private onModelInvisible(model: common.IModel): void { diff --git a/src/vs/workbench/services/scm/common/scm.ts b/src/vs/workbench/services/scm/common/scm.ts index 7147cff15d6..a9337cf69b8 100644 --- a/src/vs/workbench/services/scm/common/scm.ts +++ b/src/vs/workbench/services/scm/common/scm.ts @@ -88,7 +88,6 @@ export interface ISCMService { readonly _serviceBrand: any; readonly onDidAddRepository: Event; readonly onDidRemoveRepository: Event; - readonly onDidChangeRepository: Event; readonly repositories: ISCMRepository[]; diff --git a/src/vs/workbench/services/scm/common/scmService.ts b/src/vs/workbench/services/scm/common/scmService.ts index 6e429c117b1..1a582fa342a 100644 --- a/src/vs/workbench/services/scm/common/scmService.ts +++ b/src/vs/workbench/services/scm/common/scmService.ts @@ -62,9 +62,6 @@ export class SCMService implements ISCMService { private _onDidRemoveProvider = new Emitter(); get onDidRemoveRepository(): Event { return this._onDidRemoveProvider.event; } - private _onDidChangeProvider = new Emitter(); - get onDidChangeRepository(): Event { return this._onDidChangeProvider.event; } - constructor() { } registerSCMProvider(provider: ISCMProvider): ISCMRepository { From 2c263add93c623cbfaf0f9522132c2a6453f4b9b Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Sat, 23 Sep 2017 17:15:51 +0200 Subject: [PATCH 251/281] smoke: fix another focus issue --- test/smoke/src/areas/extensions/extensions.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/test/smoke/src/areas/extensions/extensions.ts b/test/smoke/src/areas/extensions/extensions.ts index af4fdbb47a0..62e0bb936db 100644 --- a/test/smoke/src/areas/extensions/extensions.ts +++ b/test/smoke/src/areas/extensions/extensions.ts @@ -12,26 +12,25 @@ export class Extensions extends Viewlet { super(spectron); } - public async openExtensionsViewlet(): Promise { + async openExtensionsViewlet(): Promise { await this.spectron.command('workbench.view.extensions'); await this.waitForExtensionsViewlet(); } - public async waitForExtensionsViewlet(): Promise { - await this.spectron.client.waitForElement('div.extensions-viewlet[id="workbench.view.extensions"] .search-box.synthetic-focus'); + async waitForExtensionsViewlet(): Promise { + await this.spectron.client.waitForActiveElement('div.extensions-viewlet[id="workbench.view.extensions"] input.search-box'); } - public async searchForExtension(name: string): Promise { + async searchForExtension(name: string): Promise { const searchBoxSelector = 'div.extensions-viewlet[id="workbench.view.extensions"] .search-box'; await this.spectron.client.clearElement(searchBoxSelector); await this.spectron.client.click(searchBoxSelector); - await this.spectron.client.waitForElement('div.extensions-viewlet[id="workbench.view.extensions"] .search-box.synthetic-focus'); + await this.spectron.client.waitForActiveElement('div.extensions-viewlet[id="workbench.view.extensions"] input.search-box'); await this.spectron.client.keys(name); - } - public async installExtension(name: string): Promise { + async installExtension(name: string): Promise { await this.searchForExtension(name); // we might want to wait for a while longer since the Marketplace can be slow From de7ce81e76c3835e4a7e23ee89b4437ab13a817c Mon Sep 17 00:00:00 2001 From: Ramya Achutha Rao Date: Sat, 23 Sep 2017 23:41:44 -0700 Subject: [PATCH 252/281] Alternate fix for #34162 using minscore for fuzzymatching --- extensions/emmet/npm-shrinkwrap.json | 6 +++--- extensions/emmet/package.json | 2 +- extensions/emmet/src/abbreviationActions.ts | 15 +++------------ extensions/emmet/src/defaultCompletionProvider.ts | 2 +- .../emmet/src/test/abbreviationAction.test.ts | 5 +++-- 5 files changed, 11 insertions(+), 19 deletions(-) diff --git a/extensions/emmet/npm-shrinkwrap.json b/extensions/emmet/npm-shrinkwrap.json index e91e4e9c33b..85111c5d6c4 100644 --- a/extensions/emmet/npm-shrinkwrap.json +++ b/extensions/emmet/npm-shrinkwrap.json @@ -38,9 +38,9 @@ "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz" }, "vscode-emmet-helper": { - "version": "1.1.8", - "from": "vscode-emmet-helper@>=1.0.8 <2.0.0", - "resolved": "https://registry.npmjs.org/vscode-emmet-helper/-/vscode-emmet-helper-1.1.8.tgz" + "version": "1.1.9", + "from": "vscode-emmet-helper@>=1.0.9 <2.0.0", + "resolved": "https://registry.npmjs.org/vscode-emmet-helper/-/vscode-emmet-helper-1.1.9.tgz" }, "vscode-languageserver-types": { "version": "3.3.0", diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index 7e6d7155d31..8b67b7f8e89 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -265,7 +265,7 @@ "@emmetio/html-matcher": "^0.3.1", "@emmetio/css-parser": "ramya-rao-a/css-parser#vscode", "@emmetio/math-expression": "^0.1.1", - "vscode-emmet-helper": "^1.1.8", + "vscode-emmet-helper": "^1.1.9", "vscode-languageserver-types": "^3.0.3", "image-size": "^0.5.2", "vscode-nls": "2.0.2" diff --git a/extensions/emmet/src/abbreviationActions.ts b/extensions/emmet/src/abbreviationActions.ts index eaec9939c2e..c0d3758abdb 100644 --- a/extensions/emmet/src/abbreviationActions.ts +++ b/extensions/emmet/src/abbreviationActions.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { Node, HtmlNode, Rule, Property } from 'EmmetNode'; +import { Node, HtmlNode, Rule } from 'EmmetNode'; import { getNode, getInnerRange, getMappingForIncludedLanguages, parseDocument, validate, getEmmetConfiguration } from './util'; import { getExpandOptions, extractAbbreviation, extractAbbreviationFromText, isStyleSheet, isAbbreviationValid, getEmmetMode, expandAbbreviation } from 'vscode-emmet-helper'; @@ -150,7 +150,7 @@ export function expandEmmetAbbreviation(args): Thenable { } let currentNode = getNode(rootNode, position, true); - if (!isValidLocationForEmmetAbbreviation(currentNode, syntax, position, abbreviation)) { + if (!isValidLocationForEmmetAbbreviation(currentNode, syntax, position)) { return; } @@ -182,22 +182,13 @@ function fallbackTab(): Thenable { * @param syntax syntax of the abbreviation * @param position position to validate */ -export function isValidLocationForEmmetAbbreviation(currentNode: Node, syntax: string, position: vscode.Position, abbreviation: string): boolean { +export function isValidLocationForEmmetAbbreviation(currentNode: Node, syntax: string, position: vscode.Position): boolean { // Continue validation only if the file was parse-able and the currentNode has been found if (!currentNode) { return true; } if (isStyleSheet(syntax)) { - - // CSS Emmet snippets are for property-value or in case of colors, just value - if (currentNode.type === 'property' && (currentNode).value) { - if (position.isBefore((currentNode).valueToken.start)) { - return false; - } - return /^#\d+$/.test(abbreviation); - } - // If current node is a rule or at-rule, then perform additional checks to ensure // emmet suggestions are not provided in the rule selector if (currentNode.type !== 'rule' && currentNode.type !== 'at-rule') { diff --git a/extensions/emmet/src/defaultCompletionProvider.ts b/extensions/emmet/src/defaultCompletionProvider.ts index 36b07ea06aa..45daedcb868 100644 --- a/extensions/emmet/src/defaultCompletionProvider.ts +++ b/extensions/emmet/src/defaultCompletionProvider.ts @@ -111,7 +111,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi } } - if (!isValidLocationForEmmetAbbreviation(currentNode, syntax, position, document.getText(document.getWordRangeAtPosition(position)))) { + if (!isValidLocationForEmmetAbbreviation(currentNode, syntax, position)) { return; } return syntax; diff --git a/extensions/emmet/src/test/abbreviationAction.test.ts b/extensions/emmet/src/test/abbreviationAction.test.ts index d35fc4a394b..0a43576e2bb 100644 --- a/extensions/emmet/src/test/abbreviationAction.test.ts +++ b/extensions/emmet/src/test/abbreviationAction.test.ts @@ -11,6 +11,7 @@ import { expandEmmetAbbreviation, wrapWithAbbreviation, wrapIndividualLinesWithA const cssContents = ` .boo { margin: 20px 10px; + m10 background-image: url('tryme.png'); m10 } @@ -189,9 +190,9 @@ suite('Tests for Expand Abbreviations (CSS)', () => { test('Expand abbreviation (CSS)', () => { return withRandomFileEditor(cssContents, 'css', (editor, doc) => { - editor.selection = new Selection(4, 1, 4, 4); + editor.selections = [new Selection(3, 1, 3, 4), new Selection(5, 1, 5, 4)]; return expandEmmetAbbreviation(null).then(() => { - assert.equal(editor.document.getText(), cssContents.replace('m10', 'margin: 10px;')); + assert.equal(editor.document.getText(), cssContents.replace(/m10/g, 'margin: 10px;')); return Promise.resolve(); }); }); From dd7f603376ca3aeb9be42c5a7c4c726ec416336a Mon Sep 17 00:00:00 2001 From: Ramya Achutha Rao Date: Sat, 23 Sep 2017 23:48:29 -0700 Subject: [PATCH 253/281] Trigger emmet completion for numbers Fixes #34877 --- extensions/emmet/src/util.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/extensions/emmet/src/util.ts b/extensions/emmet/src/util.ts index 66f8ba03fc8..3bb9dad8639 100644 --- a/extensions/emmet/src/util.ts +++ b/extensions/emmet/src/util.ts @@ -17,11 +17,11 @@ export const LANGUAGE_MODES: Object = { 'haml': ['!', '.', '}', ':', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], 'xml': ['.', '}', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], 'xsl': ['!', '.', '}', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], - 'css': [':', ';'], - 'scss': [':', ';'], - 'sass': [':'], - 'less': [':', ';'], - 'stylus': [':'], + 'css': [':', ';', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + 'scss': [':', ';', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + 'sass': [':', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + 'less': [':', ';', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + 'stylus': [':', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], 'javascriptreact': ['.', '}', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], 'typescriptreact': ['.', '}', '*', '$', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] }; From e3e9226c53c537fdfa2d0c43dc6d490d500de18c Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Sun, 24 Sep 2017 23:12:43 +0200 Subject: [PATCH 254/281] node-debug@1.17.11 --- build/gulpfile.vscode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 79136915b76..563996296e1 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -45,7 +45,7 @@ const nodeModules = ['electron', 'original-fs'] // Build const builtInExtensions = [ - { name: 'ms-vscode.node-debug', version: '1.17.10' }, + { name: 'ms-vscode.node-debug', version: '1.17.11' }, { name: 'ms-vscode.node-debug2', version: '1.17.3' } ]; From 086352654d7c4ed0ed99f551c820e214742e431b Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Sun, 24 Sep 2017 21:13:03 -0700 Subject: [PATCH 255/281] Fix #34296 --- .../workbench/parts/search/common/queryBuilder.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/parts/search/common/queryBuilder.ts b/src/vs/workbench/parts/search/common/queryBuilder.ts index c91ced37871..c62d13217c5 100644 --- a/src/vs/workbench/parts/search/common/queryBuilder.ts +++ b/src/vs/workbench/parts/search/common/queryBuilder.ts @@ -195,7 +195,7 @@ export class QueryBuilder { const pathPortions = this.expandAbsoluteSearchPaths(pathPortion); return pathPortions.map(searchPath => { return { - searchPath: uri.file(searchPath), + searchPath, pattern: globPortion }; }); @@ -207,14 +207,15 @@ export class QueryBuilder { /** * Takes a searchPath like `./a/foo` and expands it to absolute paths for all the workspaces it matches. */ - private expandAbsoluteSearchPaths(searchPath: string): string[] { + private expandAbsoluteSearchPaths(searchPath: string): uri[] { if (paths.isAbsolute(searchPath)) { - return [paths.normalize(searchPath)]; + // Currently only local resources can be searched for with absolute search paths + return [uri.file(paths.normalize(searchPath))]; } if (this.workspaceContextService.getWorkbenchState() === WorkbenchState.FOLDER) { // TODO: @Sandy Try checking workspace folders length instead. - return [paths.normalize( - paths.join(this.workspaceContextService.getWorkspace().folders[0].uri.fsPath, searchPath))]; + const workspaceUri = this.workspaceContextService.getWorkspace().folders[0].uri; + return [workspaceUri.with({ path: paths.normalize(paths.join(workspaceUri.path, searchPath)) })]; } else if (searchPath === './') { return []; // ./ or ./**/foo makes sense for single-folder but not multi-folder workspaces } else { @@ -225,8 +226,8 @@ export class QueryBuilder { if (matchingRoots.length) { return matchingRoots.map(root => { return relativeSearchPathMatch[2] ? - paths.normalize(paths.join(root.uri.fsPath, relativeSearchPathMatch[2])) : - root.uri.fsPath; + root.uri.with({ path: paths.normalize(paths.join(root.uri.fsPath, relativeSearchPathMatch[2])) }) : + root.uri; }); } else { // No root folder with name From c971716b039fd295a87ac11bfd4c451e060d4e47 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Sun, 24 Sep 2017 21:40:10 -0700 Subject: [PATCH 256/281] node-debug2@1.17.4 --- build/gulpfile.vscode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 563996296e1..8d6b3b0113e 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -46,7 +46,7 @@ const nodeModules = ['electron', 'original-fs'] const builtInExtensions = [ { name: 'ms-vscode.node-debug', version: '1.17.11' }, - { name: 'ms-vscode.node-debug2', version: '1.17.3' } + { name: 'ms-vscode.node-debug2', version: '1.17.4' } ]; const excludedExtensions = [ From 969b1d637de61e5a22c5660bc4c9f6cdf22faa6c Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Sun, 24 Sep 2017 22:32:10 -0700 Subject: [PATCH 257/281] Ensure ripgrep is killed when vscode exits, for #34434 --- src/vs/workbench/services/search/node/fileSearch.ts | 6 +++++- src/vs/workbench/services/search/node/ripgrepTextSearch.ts | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/search/node/fileSearch.ts b/src/vs/workbench/services/search/node/fileSearch.ts index 5bf893c78ca..1ef4cf335bd 100644 --- a/src/vs/workbench/services/search/node/fileSearch.ts +++ b/src/vs/workbench/services/search/node/fileSearch.ts @@ -210,7 +210,11 @@ export class FileWalker { private cmdTraversal(folderQuery: IFolderSearch, onResult: (result: IRawFileMatch) => void, cb: (err?: Error) => void): void { const rootFolder = folderQuery.folder; const isMac = platform.isMacintosh; + let cmd: childProcess.ChildProcess; + const killCmd = () => cmd && cmd.kill(); + let done = (err?: Error) => { + process.removeListener('exit', killCmd); done = () => { }; cb(err); }; @@ -219,7 +223,6 @@ export class FileWalker { const tree = this.initDirectoryTree(); const useRipgrep = this.useRipgrep; - let cmd: childProcess.ChildProcess; let noSiblingsClauses: boolean; let filePatternSeen = false; if (useRipgrep) { @@ -230,6 +233,7 @@ export class FileWalker { cmd = this.spawnFindCmd(folderQuery); } + process.on('exit', killCmd); this.collectStdout(cmd, 'utf8', useRipgrep, (err: Error, stdout?: string, last?: boolean) => { if (err) { done(err); diff --git a/src/vs/workbench/services/search/node/ripgrepTextSearch.ts b/src/vs/workbench/services/search/node/ripgrepTextSearch.ts index 6750ffced0c..ead3ed5e53b 100644 --- a/src/vs/workbench/services/search/node/ripgrepTextSearch.ts +++ b/src/vs/workbench/services/search/node/ripgrepTextSearch.ts @@ -26,6 +26,7 @@ import { ISerializedFileMatch, ISerializedSearchComplete, IRawSearch, IFolderSea export class RipgrepEngine { private isDone = false; private rgProc: cp.ChildProcess; + private killRgProcFn: Function; private postProcessExclusions: glob.ParsedExpression; private ripgrepParser: RipgrepParser; @@ -33,6 +34,7 @@ export class RipgrepEngine { private resultsHandledP: TPromise = TPromise.wrap(null); constructor(private config: IRawSearch) { + this.killRgProcFn = () => this.rgProc && this.rgProc.kill(); } cancel(): void { @@ -44,6 +46,7 @@ export class RipgrepEngine { // TODO@Rob - make promise-based once the old search is gone, and I don't need them to have matching interfaces anymore search(onResult: (match: ISerializedFileMatch) => void, onMessage: (message: ISearchLog) => void, done: (error: Error, complete: ISerializedSearchComplete) => void): void { if (!this.config.folderQueries.length && !this.config.extraFiles.length) { + process.removeListener('exit', this.killRgProcFn); done(null, { limitHit: false, stats: null @@ -69,6 +72,7 @@ export class RipgrepEngine { } }); this.rgProc = cp.spawn(rgPath, rgArgs.globArgs, { cwd }); + process.once('exit', this.killRgProcFn); this.ripgrepParser = new RipgrepParser(this.config.maxResults, cwd); this.ripgrepParser.on('result', (match: ISerializedFileMatch) => { @@ -87,6 +91,7 @@ export class RipgrepEngine { }); this.ripgrepParser.on('hitLimit', () => { this.cancel(); + process.removeListener('exit', this.killRgProcFn); done(null, { limitHit: true, stats: null @@ -115,6 +120,7 @@ export class RipgrepEngine { if (!this.isDone) { this.isDone = true; let displayMsg: string; + process.removeListener('exit', this.killRgProcFn); if (stderr && !gotData && (displayMsg = this.rgErrorMsgForDisplay(stderr))) { done(new Error(displayMsg), { limitHit: false, From 2c192e5b236cb487bd4b097a0b857d3c1387941b Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 25 Sep 2017 07:52:49 +0200 Subject: [PATCH 258/281] touch bar: reuse groups --- src/vs/code/electron-main/window.ts | 96 ++++++++++++++--------------- 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index b4cd79ee7ed..3bd87230457 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -65,6 +65,10 @@ interface IWorkbenchEditorConfiguration { }; } +interface ITouchBarSegment extends Electron.SegmentedControlSegment { + id: string; +} + export class CodeWindow implements ICodeWindow { public static themeStorageKey = 'theme'; @@ -93,7 +97,7 @@ export class CodeWindow implements ICodeWindow { private currentConfig: IWindowConfiguration; private pendingLoadConfig: IWindowConfiguration; - private touchBarGroups: Map; + private touchBarGroups: Electron.TouchBarSegmentedControl[]; constructor( config: IWindowCreationOptions, @@ -104,7 +108,7 @@ export class CodeWindow implements ICodeWindow { @IWorkspacesMainService private workspaceService: IWorkspacesMainService, @IBackupMainService private backupService: IBackupMainService ) { - this.touchBarGroups = new Map(); + this.touchBarGroups = []; this._lastFocusTime = -1; this._readyState = ReadyState.NONE; this.whenReadyCallbacks = []; @@ -116,6 +120,9 @@ export class CodeWindow implements ICodeWindow { // respect configured menu bar visibility this.onConfigurationUpdated(); + // macOS: touch bar support + this.createTouchBar(); + // Eventing this.registerListeners(); } @@ -862,52 +869,50 @@ export class CodeWindow implements ICodeWindow { return; // only supported on macOS } - // Clean up previous groups no longer in use - const groupHashes: string[] = []; - groups.forEach(group => groupHashes.push(this.getTouchBarGroupHash(group))); - this.touchBarGroups.forEach((value, key) => { - if (groupHashes.indexOf(key) === -1) { - this.touchBarGroups.delete(key); - } + // Update segments for all groups. Setting the segments property + // of the group directly prevents ugly flickering from happening + this.touchBarGroups.forEach((touchBarGroup, index) => { + const commands = groups[index]; + touchBarGroup.segments = this.createTouchBarGroupSegments(commands); }); - - // Build touchbar from groups - const touchBarGroups: (Electron.TouchBarGroup | Electron.TouchBarSpacer)[] = []; - groups.forEach(group => { - if (group.length) { - const groupHash = this.getTouchBarGroupHash(group); - - // To avoid flickering, we try to reuse the touch bar group - // as much as possible by checking for a previously created - // group that has the same number of items with same style. - let groupTouchBar: Electron.TouchBarSegmentedControl; - if (this.touchBarGroups.has(groupHash)) { - groupTouchBar = this.touchBarGroups.get(groupHash); - } else { - groupTouchBar = this.createTouchBarGroup(group); - this.touchBarGroups.set(groupHash, groupTouchBar); - } - - // Push and add small space between groups - touchBarGroups.push(groupTouchBar); - touchBarGroups.push(new TouchBar.TouchBarSpacer({ size: 'small' })); - } - }); - - this._win.setTouchBar(new TouchBar({ items: touchBarGroups })); } - private getTouchBarGroupHash(items: ICommandAction[]): string { - let id = ''; - items.forEach(item => id += (item.id + item.title + item.iconPath)); + private createTouchBar(): void { + if (!isMacintosh) { + return; // only supported on macOS + } - return id; + // To avoid flickering, we try to reuse the touch bar group + // as much as possible by creating a large number of groups + // for reusing later. + for (let i = 0; i < 10; i++) { + const groupTouchBar = this.createTouchBarGroup(); + this.touchBarGroups.push(groupTouchBar); + } + + this._win.setTouchBar(new TouchBar({ items: this.touchBarGroups })); } - private createTouchBarGroup(items: ICommandAction[]): Electron.TouchBarSegmentedControl { + private createTouchBarGroup(items: ICommandAction[] = []): Electron.TouchBarSegmentedControl { // Group Segments - const segments = items.map(item => { + const segments = this.createTouchBarGroupSegments(items); + + // Group Control + const control = new TouchBar.TouchBarSegmentedControl({ + segments, + mode: 'buttons', + segmentStyle: 'automatic', + change: (selectedIndex) => { + this.sendWhenReady('vscode:runAction', { id: (control.segments[selectedIndex] as ITouchBarSegment).id, from: 'touchbar' }); + } + }); + + return control; + } + + private createTouchBarGroupSegments(items: ICommandAction[] = []): ITouchBarSegment[] { + const segments: ITouchBarSegment[] = items.map(item => { let icon: Electron.NativeImage; if (item.iconPath) { icon = nativeImage.createFromPath(item.iconPath); @@ -917,20 +922,13 @@ export class CodeWindow implements ICodeWindow { } return { + id: item.id, label: !icon ? item.title as string : void 0, icon }; }); - // Group Touch Bar - return new TouchBar.TouchBarSegmentedControl({ - segments, - mode: 'buttons', - segmentStyle: 'automatic', - change: (selectedIndex) => { - this.sendWhenReady('vscode:runAction', { id: items[selectedIndex].id, from: 'touchbar' }); - } - }); + return segments; } public dispose(): void { From 2c7d05780f75e95dd8cdae4bc3fa33ee803baa84 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Sun, 24 Sep 2017 23:43:56 -0700 Subject: [PATCH 259/281] Fix wrong path join in queryBuilder.ts --- src/vs/workbench/parts/search/common/queryBuilder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/search/common/queryBuilder.ts b/src/vs/workbench/parts/search/common/queryBuilder.ts index c62d13217c5..014ad87db11 100644 --- a/src/vs/workbench/parts/search/common/queryBuilder.ts +++ b/src/vs/workbench/parts/search/common/queryBuilder.ts @@ -226,7 +226,7 @@ export class QueryBuilder { if (matchingRoots.length) { return matchingRoots.map(root => { return relativeSearchPathMatch[2] ? - root.uri.with({ path: paths.normalize(paths.join(root.uri.fsPath, relativeSearchPathMatch[2])) }) : + root.uri.with({ path: paths.normalize(paths.join(root.uri.path, relativeSearchPathMatch[2])) }) : root.uri; }); } else { From 8ec0c6012a2ef3c2c5d62259a8290498a4523f42 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 25 Sep 2017 09:21:29 +0200 Subject: [PATCH 260/281] better fix for #34796 --- src/vs/workbench/api/node/extHost.api.impl.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index d7334dde35c..90df60d5188 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -439,12 +439,12 @@ export function createApiFactory( let uriPromise: TPromise; let options = uriOrFileNameOrOptions as { language?: string; content?: string; }; - if (!options || (options && (typeof options.language === 'string' || typeof options.content === 'string'))) { - uriPromise = extHostDocuments.createDocumentData(options); - } else if (typeof uriOrFileNameOrOptions === 'string') { + if (typeof uriOrFileNameOrOptions === 'string') { uriPromise = TPromise.as(URI.file(uriOrFileNameOrOptions)); } else if (uriOrFileNameOrOptions instanceof URI) { uriPromise = TPromise.as(uriOrFileNameOrOptions); + } else if (!options || typeof options === 'object') { + uriPromise = extHostDocuments.createDocumentData(options); } else { throw new Error('illegal argument - uriOrFileNameOrOptions'); } From 3c66a30bb11f14255bfa514e41912a775c44d1a3 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 25 Sep 2017 09:33:53 +0200 Subject: [PATCH 261/281] :lipstick: --- .../common/editor/untitledEditorModel.ts | 6 +--- .../textfile/common/textFileEditorModel.ts | 33 ++++++++++--------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/vs/workbench/common/editor/untitledEditorModel.ts b/src/vs/workbench/common/editor/untitledEditorModel.ts index f58b37497f1..5442ba80ab6 100644 --- a/src/vs/workbench/common/editor/untitledEditorModel.ts +++ b/src/vs/workbench/common/editor/untitledEditorModel.ts @@ -194,7 +194,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin this.toDispose.push(this.textEditorModel.onDidChangeContent(() => this.onModelContentChanged())); // Listen to mode changes - this.toDispose.push(this.textEditorModel.onDidChangeLanguage(() => this.onModelModeChanged())); + this.toDispose.push(this.textEditorModel.onDidChangeLanguage(() => this.onConfigurationChange())); // mode change can have impact on config return model; }); @@ -234,10 +234,6 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin this.contentChangeEventScheduler.schedule(); } - private onModelModeChanged(): void { - this.onConfigurationChange(); // mode change can have impact on config - } - public dispose(): void { super.dispose(); diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 80db2087ae8..6fbdcf7a435 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -120,16 +120,18 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.toDispose.push(this.fileService.onFileChanges(e => this.onFileChanges(e))); this.toDispose.push(this.textFileService.onAutoSaveConfigurationChange(config => this.updateAutoSaveConfiguration(config))); this.toDispose.push(this.textFileService.onFilesAssociationChange(e => this.onFilesAssociationChange())); - this.toDispose.push(this.onDidStateChange(e => { - if (e === StateChange.REVERTED) { + this.toDispose.push(this.onDidStateChange(e => this.onStateChange(e))); + } - // Cancel any content change event promises as they are no longer valid. - this.contentChangeEventScheduler.cancel(); + private onStateChange(e: StateChange): void { + if (e === StateChange.REVERTED) { - // Refire state change reverted events as content change events - this._onDidContentChange.fire(StateChange.REVERTED); - } - })); + // Cancel any content change event promises as they are no longer valid. + this.contentChangeEventScheduler.cancel(); + + // Refire state change reverted events as content change events + this._onDidContentChange.fire(StateChange.REVERTED); + } } private onFileChanges(e: FileChangesEvent): void { @@ -450,10 +452,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.setDirty(false); } - // See https://github.com/Microsoft/vscode/issues/30189 - // This code has been extracted to a different method because it caused a memory leak - // where `value` was captured in the content change listener closure scope. - this._installChangeContentListener(); + // Model Listeners + this.installModelListeners(); return this; }, error => { @@ -466,13 +466,14 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return this.createTextEditorModelPromise; } - private _installChangeContentListener(): void { + private installModelListeners(): void { + // See https://github.com/Microsoft/vscode/issues/30189 // This code has been extracted to a different method because it caused a memory leak // where `value` was captured in the content change listener closure scope. - this.toDispose.push(this.textEditorModel.onDidChangeContent(() => { - this.onModelContentChanged(); - })); + + // Content Change + this.toDispose.push(this.textEditorModel.onDidChangeContent(() => this.onModelContentChanged())); } private doLoadBackup(backup: URI): TPromise { From f37884c28c93fe83b33ceb9f9da0a02e49571fcc Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 25 Sep 2017 09:49:59 +0200 Subject: [PATCH 262/281] Fixes #34826: write character before cursor to the textarea on OSX to allow the "long-press" composition to work --- .../editor/browser/controller/textAreaHandler.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/vs/editor/browser/controller/textAreaHandler.ts b/src/vs/editor/browser/controller/textAreaHandler.ts index 4b80421d71f..2ce35619e78 100644 --- a/src/vs/editor/browser/controller/textAreaHandler.ts +++ b/src/vs/editor/browser/controller/textAreaHandler.ts @@ -7,6 +7,7 @@ import 'vs/css!./textAreaHandler'; import * as platform from 'vs/base/common/platform'; import * as browser from 'vs/base/browser/browser'; +import * as strings from 'vs/base/common/strings'; import { TextAreaInput, ITextAreaInputHost, IPasteData, ICompositionData } from 'vs/editor/browser/controller/textAreaInput'; import { ISimpleModel, ITypeData, TextAreaState, PagedScreenReaderStrategy } from 'vs/editor/browser/controller/textAreaState'; import { Range } from 'vs/editor/common/core/range'; @@ -164,6 +165,20 @@ export class TextAreaHandler extends ViewPart { if (this._accessibilitySupport === platform.AccessibilitySupport.Disabled) { // We know for a fact that a screen reader is not attached + // On OSX, we write the character before the cursor to allow for "long-press" composition + if (platform.isMacintosh) { + const selection = this._selections[0]; + if (selection.isEmpty()) { + const position = selection.getStartPosition(); + if (position.column > 1) { + const lineContent = this._context.model.getLineContent(position.lineNumber); + const charBefore = lineContent.charAt(position.column - 2); + if (!strings.isHighSurrogate(charBefore.charCodeAt(0))) { + return new TextAreaState(charBefore, 1, 1, position, position); + } + } + } + } return TextAreaState.EMPTY; } From ea22a06e98105e7e6450b72503cd74799f7cf82f Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 25 Sep 2017 10:21:49 +0200 Subject: [PATCH 263/281] Fix #34834 --- .../parts/preferences/browser/preferencesEditor.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts index 1fe5312055f..99baa629377 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesEditor.ts @@ -238,12 +238,12 @@ export class PreferencesEditor extends BaseEditor { } private getSettingsConfigurationTarget(resource: URI): ConfigurationTarget { - if (this.preferencesService.userSettingsResource.fsPath === resource.fsPath) { + if (this.preferencesService.userSettingsResource.toString() === resource.toString()) { return ConfigurationTarget.USER; } const workspaceSettingsResource = this.preferencesService.workspaceSettingsResource; - if (workspaceSettingsResource && workspaceSettingsResource.fsPath === resource.fsPath) { + if (workspaceSettingsResource && workspaceSettingsResource.toString() === resource.toString()) { return ConfigurationTarget.WORKSPACE; } @@ -255,10 +255,10 @@ export class PreferencesEditor extends BaseEditor { } private getSettingsConfigurationTargetUri(resource: URI): URI { - if (this.preferencesService.userSettingsResource.fsPath === resource.fsPath) { + if (this.preferencesService.userSettingsResource.toString() === resource.toString()) { return resource; } - if (this.preferencesService.workspaceSettingsResource.fsPath === resource.fsPath) { + if (this.preferencesService.workspaceSettingsResource.toString() === resource.toString()) { return resource; } @@ -911,17 +911,17 @@ class SettingsEditorContribution extends AbstractSettingsEditorContribution impl return false; } - if (this.preferencesService.userSettingsResource && this.preferencesService.userSettingsResource.fsPath === model.uri.fsPath) { + if (this.preferencesService.userSettingsResource && this.preferencesService.userSettingsResource.toString() === model.uri.toString()) { return true; } - if (this.preferencesService.workspaceSettingsResource && this.preferencesService.workspaceSettingsResource.fsPath === model.uri.fsPath) { + if (this.preferencesService.workspaceSettingsResource && this.preferencesService.workspaceSettingsResource.toString() === model.uri.toString()) { return true; } for (const folder of this.workspaceContextService.getWorkspace().folders) { const folderSettingsResource = this.preferencesService.getFolderSettingsResource(folder.uri); - if (folderSettingsResource && folderSettingsResource.fsPath === model.uri.fsPath) { + if (folderSettingsResource && folderSettingsResource.toString() === model.uri.toString()) { return true; } } From b1c38faa6ba3c721268d7f975b73e66f1a793498 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 25 Sep 2017 10:25:26 +0200 Subject: [PATCH 264/281] handle missing product.commit, #34523 --- src/vs/platform/environment/node/environmentService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index 3e4a655e365..f073e0fce56 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -143,7 +143,7 @@ export class EnvironmentService implements IEnvironmentService { get sharedIPCHandle(): string { return getIPCHandle(this.userDataPath, 'shared'); } @memoize - get nodeCachedDataDir(): string { return this.isBuilt ? path.join(this.userDataPath, 'CachedData', product.commit) : undefined; } + get nodeCachedDataDir(): string { return this.isBuilt ? path.join(this.userDataPath, 'CachedData', product.commit || new Array(41).join('0')) : undefined; } readonly machineUUID: string; From 4d512b26a3e52124fe8812a145d3d85763da01fd Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 25 Sep 2017 10:26:18 +0200 Subject: [PATCH 265/281] mark `commit` as optional, #34523 --- src/vs/platform/node/product.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/node/product.ts b/src/vs/platform/node/product.ts index c2d0ab48510..a986f877135 100644 --- a/src/vs/platform/node/product.ts +++ b/src/vs/platform/node/product.ts @@ -18,7 +18,7 @@ export interface IProductConfiguration { downloadUrl: string; updateUrl?: string; quality?: string; - commit: string; + commit?: string; date: string; extensionsGallery: { serviceUrl: string; @@ -86,4 +86,4 @@ if (process.env['VSCODE_DEV']) { product.dataFolderName += '-dev'; } -export default product; \ No newline at end of file +export default product; From 6762612177542a3e3b1d9b810f1eb34248f04983 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 25 Sep 2017 10:29:29 +0200 Subject: [PATCH 266/281] show console.log from extension host top frame in dev tools (#34936) --- src/bootstrap.js | 24 +++- src/vs/base/node/console.ts | 125 ++++++++++++++++++ src/vs/base/parts/ipc/node/ipc.cp.ts | 18 +-- .../extensions/common/extensionHost.ts | 8 +- .../debug/electron-browser/debugService.ts | 13 +- .../electron-browser/extensionHost.ts | 35 ++--- 6 files changed, 162 insertions(+), 61 deletions(-) create mode 100644 src/vs/base/node/console.ts diff --git a/src/bootstrap.js b/src/bootstrap.js index dad68bf5c80..af713da7509 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -14,10 +14,11 @@ process.noAsar = true; if (!!process.send && process.env.PIPE_LOGGING === 'true') { var MAX_LENGTH = 100000; - // Prevent circular stringify - function safeStringify(args) { + // Prevent circular stringify and convert arguments to real array + function safeToArray(args) { var seen = []; var res; + var argsArray = []; // Massage some arguments with special treatment if (args.length) { @@ -40,11 +41,20 @@ if (!!process.send && process.env.PIPE_LOGGING === 'true') { args[i] = errorObj.toString(); } } + + argsArray.push(args[i]); } } + // Add the stack trace as payload if we are told so. We remove the message and the 2 top frames + // to start the stacktrace where the console message was being written + if (process.env.VSCODE_LOG_STACK === 'true') { + const stack = new Error().stack; + argsArray.push({ __$stack: stack.split('\n').slice(3).join('\n') }); + } + try { - res = JSON.stringify(args, function (key, value) { + res = JSON.stringify(argsArray, function (key, value) { // Objects get special treatment to prevent circles if (value && Object.prototype.toString.call(value) === '[object Object]') { @@ -78,16 +88,16 @@ if (!!process.send && process.env.PIPE_LOGGING === 'true') { // Pass console logging to the outside so that we have it in the main side if told so if (process.env.VERBOSE_LOGGING === 'true') { - console.log = function () { safeSend({ type: '__$console', severity: 'log', arguments: safeStringify(arguments) }); }; - console.info = function () { safeSend({ type: '__$console', severity: 'log', arguments: safeStringify(arguments) }); }; - console.warn = function () { safeSend({ type: '__$console', severity: 'warn', arguments: safeStringify(arguments) }); }; + console.log = function () { safeSend({ type: '__$console', severity: 'log', arguments: safeToArray(arguments) }); }; + console.info = function () { safeSend({ type: '__$console', severity: 'log', arguments: safeToArray(arguments) }); }; + console.warn = function () { safeSend({ type: '__$console', severity: 'warn', arguments: safeToArray(arguments) }); }; } else { console.log = function () { /* ignore */ }; console.warn = function () { /* ignore */ }; console.info = function () { /* ignore */ }; } - console.error = function () { safeSend({ type: '__$console', severity: 'error', arguments: safeStringify(arguments) }); }; + console.error = function () { safeSend({ type: '__$console', severity: 'error', arguments: safeToArray(arguments) }); }; } if (!process.env['VSCODE_ALLOW_IO']) { diff --git a/src/vs/base/node/console.ts b/src/vs/base/node/console.ts new file mode 100644 index 00000000000..fc3cf3baeab --- /dev/null +++ b/src/vs/base/node/console.ts @@ -0,0 +1,125 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import URI from 'vs/base/common/uri'; + +export interface IRemoteConsoleLog { + type: string; + severity: string; + arguments: string; +} + +interface IStackArgument { + __$stack: string; +} + +export interface IStackFrame { + uri: URI; + line: number; + column: number; +} + +export function isRemoteConsoleLog(obj: any): obj is IRemoteConsoleLog { + const entry = obj as IRemoteConsoleLog; + + return entry && typeof entry.type === 'string' && typeof entry.severity === 'string'; +} + +export function parse(entry: IRemoteConsoleLog): { args: any[], stack?: string } { + const args: any[] = []; + let stack: string; + + // Parse Entry + try { + const parsedArguments: any[] = JSON.parse(entry.arguments); + + // Check for special stack entry as last entry + const stackArgument = parsedArguments[parsedArguments.length - 1] as IStackArgument; + if (stackArgument && stackArgument.__$stack) { + parsedArguments.pop(); // stack is handled specially + stack = stackArgument.__$stack; + } + + args.push(...parsedArguments); + } catch (error) { + args.push('Unable to log remote console arguments', entry.arguments); + } + + return { args, stack }; +} + +export function getFirstFrame(entry: IRemoteConsoleLog): IStackFrame; +export function getFirstFrame(stack: string): IStackFrame; +export function getFirstFrame(arg0: IRemoteConsoleLog | string): IStackFrame { + if (typeof arg0 !== 'string') { + return getFirstFrame(parse(arg0).stack); + } + + // Parse a source information out of the stack if we have one. Format: + // at vscode.commands.registerCommand (/Users/someone/Desktop/test-ts/out/src/extension.js:18:17) + const stack = arg0; + if (stack) { + const matches = /.+\((.+):(\d+):(\d+)\)/.exec(stack); + if (matches.length === 4) { + return { + uri: URI.file(matches[1]), + line: Number(matches[2]), + column: Number(matches[3]) + } as IStackFrame; + } + } + + return void 0; +} + +export function log(entry: IRemoteConsoleLog, label: string): void { + const { args, stack } = parse(entry); + + // Determine suffix based on severity of log entry if we have a stack + let suffixColor = 'blue'; + let suffix = ''; + if (stack) { + switch (entry.severity) { + case 'warn': + suffixColor = 'goldenrod'; + suffix = ' WARNING:'; + break; + case 'error': + suffixColor = 'darkred'; + suffix = ' ERROR:'; + break; + } + } + + let consoleArgs = []; + + // First arg is a string + if (typeof args[0] === 'string') { + consoleArgs = [`%c[${label}]%c${suffix} %c${args[0]}`, color('blue'), color(suffixColor), color('black'), ...args.slice(1)]; + } + + // First arg is something else, just apply all + else { + consoleArgs = [`%c[${label}]%c${suffix}`, color('blue'), color(suffixColor), ...args]; + } + + // Stack: use console group + if (stack) { + console.groupCollapsed.apply(console, consoleArgs); + console.log(stack); + console.groupEnd(); + } + + // No stack: just log message + else { + console[entry.severity].apply(console, consoleArgs); + } +} + +function color(color: string): string { + return `color: ${color}; font-weight: normal;`; +} \ No newline at end of file diff --git a/src/vs/base/parts/ipc/node/ipc.cp.ts b/src/vs/base/parts/ipc/node/ipc.cp.ts index 45d401724c4..cb73fe6f937 100644 --- a/src/vs/base/parts/ipc/node/ipc.cp.ts +++ b/src/vs/base/parts/ipc/node/ipc.cp.ts @@ -12,6 +12,7 @@ import { Emitter } from 'vs/base/common/event'; import { fromEventEmitter } from 'vs/base/node/event'; import { createQueuedSender } from 'vs/base/node/processes'; import { ChannelServer as IPCServer, ChannelClient as IPCClient, IChannelClient, IChannel } from 'vs/base/parts/ipc/common/ipc'; +import { isRemoteConsoleLog, log } from 'vs/base/node/console'; export class Server extends IPCServer { constructor() { @@ -151,24 +152,15 @@ export class Client implements IChannelClient, IDisposable { const onRawMessage = fromEventEmitter(this.child, 'message', msg => msg); onRawMessage(msg => { - // Handle console logs specially - if (msg && msg.type === '__$console') { - let args = ['%c[IPC Library: ' + this.options.serverName + ']', 'color: darkgreen']; - try { - const parsed = JSON.parse(msg.arguments); - args = args.concat(Object.getOwnPropertyNames(parsed).map(o => parsed[o])); - } catch (error) { - args.push(msg.arguments); - } - console[msg.severity].apply(console, args); + // Handle remote console logs specially + if (isRemoteConsoleLog(msg)) { + log(msg, `IPC Library: ${this.options.serverName}`); return null; } // Anything else goes to the outside - else { - onMessageEmitter.fire(msg); - } + onMessageEmitter.fire(msg); }); const sender = this.options.useQueue ? createQueuedSender(this.child) : this.child; diff --git a/src/vs/platform/extensions/common/extensionHost.ts b/src/vs/platform/extensions/common/extensionHost.ts index 3466201a199..dd2d2ca92d2 100644 --- a/src/vs/platform/extensions/common/extensionHost.ts +++ b/src/vs/platform/extensions/common/extensionHost.ts @@ -11,10 +11,4 @@ export const EXTENSION_LOG_BROADCAST_CHANNEL = 'vscode:extensionLog'; export const EXTENSION_ATTACH_BROADCAST_CHANNEL = 'vscode:extensionAttach'; export const EXTENSION_TERMINATE_BROADCAST_CHANNEL = 'vscode:extensionTerminate'; export const EXTENSION_RELOAD_BROADCAST_CHANNEL = 'vscode:extensionReload'; -export const EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL = 'vscode:extensionCloseExtensionHost'; - -export interface ILogEntry { - type: string; - severity: string; - arguments: any; -} \ No newline at end of file +export const EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL = 'vscode:extensionCloseExtensionHost'; \ No newline at end of file diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index d25b506caa7..a3d44d3cc0a 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -49,8 +49,9 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { ILogEntry, EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL, EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost'; +import { EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL, EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost'; import { IBroadcastService, IBroadcast } from 'vs/platform/broadcast/electron-browser/broadcastService'; +import { IRemoteConsoleLog, parse } from 'vs/base/node/console'; const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint'; const DEBUG_BREAKPOINTS_ACTIVATED_KEY = 'debug.breakpointactivated'; @@ -163,16 +164,10 @@ export class DebugService implements debug.IDebugService { // an extension logged output, show it inside the REPL if (broadcast.channel === EXTENSION_LOG_BROADCAST_CHANNEL) { - let extensionOutput: ILogEntry = broadcast.payload.logEntry; + let extensionOutput: IRemoteConsoleLog = broadcast.payload.logEntry; let sev = extensionOutput.severity === 'warn' ? severity.Warning : extensionOutput.severity === 'error' ? severity.Error : severity.Info; - let args: any[] = []; - try { - let parsed = JSON.parse(extensionOutput.arguments); - args.push(...Object.getOwnPropertyNames(parsed).map(o => parsed[o])); - } catch (error) { - args.push(extensionOutput.arguments); - } + const { args } = parse(extensionOutput); // add output for each argument logged let simpleVals: any[] = []; diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index cee692ce0e6..d4b17a7fbc3 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -33,8 +33,9 @@ import { IWorkspaceConfigurationService } from 'vs/workbench/services/configurat import { ICrashReporterService } from 'vs/workbench/services/crashReporter/common/crashReporterService'; import { IBroadcastService, IBroadcast } from 'vs/platform/broadcast/electron-browser/broadcastService'; import { isEqual } from 'vs/base/common/paths'; -import { EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL, ILogEntry, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost'; +import { EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IRemoteConsoleLog, log, parse } from 'vs/base/node/console'; export class ExtensionHostProcessWorker { @@ -142,7 +143,8 @@ export class ExtensionHostProcessWorker { VSCODE_WINDOW_ID: String(this._windowService.getCurrentWindowId()), VSCODE_IPC_HOOK_EXTHOST: pipeName, VSCODE_HANDLES_UNCAUGHT_ERRORS: true, - ELECTRON_NO_ASAR: '1' + ELECTRON_NO_ASAR: '1', + VSCODE_LOG_STACK: !this._isExtensionDevTestFromCli && (this._isExtensionDevHost || !this._environmentService.isBuilt || product.quality !== 'stable' || this._environmentService.verbose) }), // We only detach the extension host on windows. Linux and Mac orphan by default // and detach under Linux and Mac create another process group. @@ -195,8 +197,8 @@ export class ExtensionHostProcessWorker { // Support logging from extension host this._extensionHostProcess.on('message', msg => { - if (msg && (msg).type === '__$console') { - this._logExtensionHostMessage(msg); + if (msg && (msg).type === '__$console') { + this._logExtensionHostMessage(msg); } }); @@ -365,33 +367,16 @@ export class ExtensionHostProcessWorker { }); } - private _logExtensionHostMessage(logEntry: ILogEntry) { - let args = []; - try { - let parsed = JSON.parse(logEntry.arguments); - args.push(...Object.getOwnPropertyNames(parsed).map(o => parsed[o])); - } catch (error) { - args.push(logEntry.arguments); - } - - // If the first argument is a string, check for % which indicates that the message - // uses substitution for variables. In this case, we cannot just inject our colored - // [Extension Host] to the front because it breaks substitution. - let consoleArgs = []; - if (typeof args[0] === 'string' && args[0].indexOf('%') >= 0) { - consoleArgs = [`%c[Extension Host]%c ${args[0]}`, 'color: blue', 'color: black', ...args.slice(1)]; - } else { - consoleArgs = ['%c[Extension Host]', 'color: blue', ...args]; - } + private _logExtensionHostMessage(entry: IRemoteConsoleLog) { // Send to local console unless we run tests from cli if (!this._isExtensionDevTestFromCli) { - console[logEntry.severity].apply(console, consoleArgs); + log(entry, 'Extension Host'); } // Log on main side if running tests from cli if (this._isExtensionDevTestFromCli) { - this._windowsService.log(logEntry.severity, ...args); + this._windowsService.log(entry.severity, ...parse(entry).args); } // Broadcast to other windows if we are in development mode @@ -399,7 +384,7 @@ export class ExtensionHostProcessWorker { this._broadcastService.broadcast({ channel: EXTENSION_LOG_BROADCAST_CHANNEL, payload: { - logEntry, + logEntry: entry, debugId: this._environmentService.debugExtensionHost.debugId } }); From c8e58015de1a5bb07df36856a3ec76f8e1d3cb7a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 25 Sep 2017 10:31:45 +0200 Subject: [PATCH 267/281] remove profiling hint as it isn't reliable/valuable enough --- .../performance.contribution.ts | 122 ------------------ 1 file changed, 122 deletions(-) diff --git a/src/vs/workbench/parts/performance/electron-browser/performance.contribution.ts b/src/vs/workbench/parts/performance/electron-browser/performance.contribution.ts index 8b04c59fd2f..fb56e3ed9b7 100644 --- a/src/vs/workbench/parts/performance/electron-browser/performance.contribution.ts +++ b/src/vs/workbench/parts/performance/electron-browser/performance.contribution.ts @@ -5,16 +5,12 @@ 'use strict'; -import product from 'vs/platform/node/product'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IMessageService } from 'vs/platform/message/common/message'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { ITimerService } from 'vs/workbench/services/timer/common/timerService'; import { IWindowsService } from 'vs/platform/windows/common/windows'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkbenchContributionsRegistry, IWorkbenchContribution, Extensions } from 'vs/workbench/common/contributions'; import { Registry } from 'vs/platform/registry/common/platform'; import { ReportPerformanceIssueAction } from 'vs/workbench/electron-browser/actions'; @@ -22,125 +18,8 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { join } from 'path'; import { localize } from 'vs/nls'; import { toPromise, filterEvent } from 'vs/base/common/event'; -import { platform, Platform } from 'vs/base/common/platform'; import { readdir } from 'vs/base/node/pfs'; -import { release } from 'os'; import { stopProfiling } from 'vs/base/node/profiler'; -import { virtualMachineHint } from 'vs/base/node/id'; - -class ProfilingHint implements IWorkbenchContribution { - - // p95 to p95 by os&release - static readonly _percentiles: { [key: string]: [number, number] } = { - ['Windows_6.3.9600']: [35782, 35782], - ['Windows_6.1.7601']: [11160, 18366], - ['Windows_10.0.16199']: [10423, 17222], - ['Windows_10.0.16193']: [7503, 11033], - ['Windows_10.0.16188']: [8544, 8807], - ['Windows_10.0.15063']: [11085, 16837], - ['Windows_10.0.14393']: [12585, 32662], - ['Windows_10.0.10586']: [7047, 10944], - ['Windows_10.0.10240']: [16176, 16176], - ['Mac_16.7.0']: [2192, 4050], - ['Mac_16.6.0']: [8043, 10608], - ['Mac_16.5.0']: [4912, 11348], - ['Mac_16.4.0']: [3900, 4200], - ['Mac_16.3.0']: [7327, 7327], - ['Mac_16.1.0']: [6090, 6555], - ['Mac_16.0.0']: [32574, 32574], - ['Mac_15.6.0']: [16082, 17469], - ['Linux_4.9.0-3-amd64']: [2092, 2197], - ['Linux_4.9.0-2-amd64']: [9779, 9779], - ['Linux_4.8.0-52-generic']: [12803, 13257], - ['Linux_4.8.0-51-generic']: [2670, 2797], - ['Linux_4.8.0-040800-generic']: [3954, 3954], - ['Linux_4.4.0-78-generic']: [4218, 5891], - ['Linux_4.4.0-77-generic']: [6166, 6166], - ['Linux_4.11.2']: [1323, 1323], - ['Linux_4.10.15-200.fc25.x86_64']: [9270, 9480], - ['Linux_4.10.13-1-ARCH']: [7116, 8511], - ['Linux_4.10.11-100.fc24.x86_64']: [1845, 1845], - ['Linux_4.10.0-21-generic']: [14805, 16050], - ['Linux_3.19.0-84-generic']: [4840, 4840], - ['Linux_3.11.10-29-desktop']: [1637, 2891], - }; - - private static readonly _myPercentiles = ProfilingHint._percentiles[`${Platform[platform]}_${release()}`]; - - constructor( - @IWindowsService private readonly _windowsService: IWindowsService, - @ITimerService private readonly _timerService: ITimerService, - @IMessageService private readonly _messageService: IMessageService, - @IEnvironmentService private readonly _envService: IEnvironmentService, - @IStorageService private readonly _storageService: IStorageService, - @ITelemetryService private readonly _telemetryService: ITelemetryService, - ) { - - setTimeout(() => this._checkTimersAndSuggestToProfile(), 5000); - } - - getId(): string { - return 'performance.ProfilingHint'; - } - - private _checkTimersAndSuggestToProfile() { - - // Only initial startups, not when already profiling - if (!this._timerService.isInitialStartup || this._envService.args['prof-startup']) { - return; - } - - // Check that we have some data about this - // OS version to which we can compare this startup. - // Then only go for startups between the 90 and - // 95th percentile. - if (!Array.isArray(ProfilingHint._myPercentiles)) { - return; - } - const [p80, p90] = ProfilingHint._myPercentiles; - const { ellapsed } = this._timerService.startupMetrics; - if (ellapsed < p80 || ellapsed > p90) { - return; - } - - // Ignore virtual machines and only ask users - // to profile with a certain propability - if (virtualMachineHint.value() >= .5 || Math.ceil(Math.random() * 1000) !== 1) { - return; - } - - // Don't ask for the stable version, only - // ask once per version/build - if (this._envService.appQuality === 'stable') { - // don't ask in stable - return; - } - const mementoKey = `performance.didPromptToProfile.${product.commit}`; - const value = this._storageService.get(mementoKey, StorageScope.GLOBAL, undefined); - if (value !== undefined) { - // only ask once per version - return; - } - - const profile = this._messageService.confirm({ - type: 'info', - message: localize('slow', "Slow startup detected"), - detail: localize('slow.detail', "Sorry that you just had a slow startup. Please restart '{0}' with profiling enabled, share the profiles with us, and we will work hard to make startup great again.", this._envService.appNameLong), - primaryButton: 'Restart and profile' - }); - - this._telemetryService.publicLog('profileStartupInvite', { - acceptedInvite: profile - }); - - if (profile) { - this._storageService.store(mementoKey, 'didProfile', StorageScope.GLOBAL); - this._windowsService.relaunch({ addArgs: ['--prof-startup'] }); - } else { - this._storageService.store(mementoKey, 'didReject', StorageScope.GLOBAL); - } - } -} class StartupProfiler implements IWorkbenchContribution { @@ -214,5 +93,4 @@ class StartupProfiler implements IWorkbenchContribution { } const registry = Registry.as(Extensions.Workbench); -registry.registerWorkbenchContribution(ProfilingHint); registry.registerWorkbenchContribution(StartupProfiler); From 04a563521c19534351a4f550f482a39400e3f8d9 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 25 Sep 2017 10:42:38 +0200 Subject: [PATCH 268/281] Fix #33670 --- src/vs/platform/configuration/common/configurationRegistry.ts | 1 + src/vs/workbench/services/configuration/node/configuration.ts | 1 + .../services/workspace/node/workspaceEditingService.ts | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/configuration/common/configurationRegistry.ts b/src/vs/platform/configuration/common/configurationRegistry.ts index 5dc5850c73f..0d3276bf69d 100644 --- a/src/vs/platform/configuration/common/configurationRegistry.ts +++ b/src/vs/platform/configuration/common/configurationRegistry.ts @@ -62,6 +62,7 @@ export interface IConfigurationPropertySchema extends IJSONSchema { overridable?: boolean; isExecutable?: boolean; scope?: ConfigurationScope; + isFromExtensions?: boolean; } export interface IConfigurationNode { diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configuration.ts index dc937676842..e227aedab52 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configuration.ts @@ -182,6 +182,7 @@ function validateProperties(configuration: IConfigurationNode, collector: Extens const message = validateProperty(key); const propertyConfiguration = configuration.properties[key]; propertyConfiguration.scope = propertyConfiguration.scope && propertyConfiguration.scope.toString() === 'resource' ? ConfigurationScope.RESOURCE : ConfigurationScope.WINDOW; + propertyConfiguration.isFromExtensions = true; if (message) { collector.warn(message); delete properties[key]; diff --git a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts index 2c30159804f..aa99ca9f75a 100644 --- a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts @@ -186,7 +186,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { const configurationProperties = Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); const targetWorkspaceConfiguration = {}; for (const key of this.workspaceConfigurationService.keys().workspace) { - if (configurationProperties[key] && configurationProperties[key].scope === ConfigurationScope.WINDOW) { + if (configurationProperties[key] && !configurationProperties[key].isFromExtensions && configurationProperties[key].scope === ConfigurationScope.WINDOW) { targetWorkspaceConfiguration[key] = this.workspaceConfigurationService.lookup(key).workspace; } } From 28180398e9812a05a920a931f7cbf3a4d3c406db Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 25 Sep 2017 11:17:30 +0200 Subject: [PATCH 269/281] Language specific encoding is not used right on startup (fixes #34943) --- .../parts/files/browser/files.contribution.ts | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/parts/files/browser/files.contribution.ts b/src/vs/workbench/parts/files/browser/files.contribution.ts index 8c7539cbc7a..c7def3d064a 100644 --- a/src/vs/workbench/parts/files/browser/files.contribution.ts +++ b/src/vs/workbench/parts/files/browser/files.contribution.ts @@ -14,7 +14,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions, Configur import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory, EditorInput, IFileEditorInput } from 'vs/workbench/common/editor'; -import { AutoSaveConfiguration, HotExitConfiguration, SUPPORTED_ENCODINGS, IFilesConfiguration } from 'vs/platform/files/common/files'; +import { AutoSaveConfiguration, HotExitConfiguration, SUPPORTED_ENCODINGS } from 'vs/platform/files/common/files'; import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { FILE_EDITOR_INPUT_ID, VIEWLET_ID, SortOrderConfiguration } from 'vs/workbench/parts/files/common/files'; import { FileEditorTracker } from 'vs/workbench/parts/files/common/editors/fileEditorTracker'; @@ -122,23 +122,13 @@ class FileEditorInputFactory implements IEditorInputFactory { const resource = fileEditorInput.getResource(); const fileInput: ISerializedFileInput = { resource: resource.toString(), // Keep for backwards compatibility - resourceJSON: resource.toJSON() + resourceJSON: resource.toJSON(), + encoding: fileEditorInput.getEncoding() }; - const encoding = fileEditorInput.getPreferredEncoding(); - if (encoding && encoding !== this.getConfiguredEncoding(resource)) { - fileInput.encoding = encoding; - } - return JSON.stringify(fileInput); } - private getConfiguredEncoding(resource: URI): string { - const configuration = this.configurationService.getConfiguration(resource); - - return configuration && configuration.files && configuration.files.encoding; - } - public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): FileEditorInput { return instantiationService.invokeFunction(accessor => { const fileInput: ISerializedFileInput = JSON.parse(serializedEditorInput); From b900681057da3ee9435d97d7f36a93449bf8766e Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 25 Sep 2017 11:21:33 +0200 Subject: [PATCH 270/281] debug: polish process focusing on continued fixes #34920 --- .../parts/debug/electron-browser/debugService.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index a3d44d3cc0a..9f366e697a0 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -229,7 +229,7 @@ export class DebugService implements debug.IDebugService { } } - private tryToAutoFocusStackFrame(thread: debug.IThread): TPromise { + private autoFocusAndOpenStackFrame(thread: debug.IThread): TPromise { const callStack = thread.getCallStack(); if (!callStack.length || (this.viewModel.focusedStackFrame && this.viewModel.focusedStackFrame.thread.threadId === thread.threadId)) { return TPromise.as(null); @@ -280,7 +280,7 @@ export class DebugService implements debug.IDebugService { // Call fetch call stack twice, the first only return the top stack frame. // Second retrieves the rest of the call stack. For performance reasons #25605 this.model.fetchCallStack(thread).then(() => { - return this.tryToAutoFocusStackFrame(thread); + return this.autoFocusAndOpenStackFrame(thread); }); } }, errors.onUnexpectedError); @@ -309,7 +309,9 @@ export class DebugService implements debug.IDebugService { const threadId = event.body.allThreadsContinued !== false ? undefined : event.body.threadId; this.model.clearThreads(session.getId(), false, threadId); if (this.viewModel.focusedProcess.getId() === session.getId()) { - this.focusStackFrameAndEvaluate(null, this.viewModel.focusedProcess).done(null, errors.onUnexpectedError); + this.focusStackFrameAndEvaluate(undefined).done(() => { + return this.viewModel.focusedStackFrame ? this.viewModel.focusedStackFrame.openInEditor(this.editorService, true) : undefined; + }, errors.onUnexpectedError); } this.updateStateAndEmit(session.getId(), debug.State.Running); })); @@ -520,7 +522,11 @@ export class DebugService implements debug.IDebugService { public focusStackFrameAndEvaluate(stackFrame: debug.IStackFrame, process?: debug.IProcess, explicit?: boolean): TPromise { if (!process) { const processes = this.model.getProcesses(); - process = stackFrame ? stackFrame.thread.process : processes.length ? processes[0] : null; + if (stackFrame) { + process = stackFrame.thread.process; + } else if (processes.length > 0) { + process = processes.filter(p => p.getAllThreads().some(t => t.stopped)).shift() || processes[0]; + } } if (!stackFrame) { const threads = process ? process.getAllThreads() : null; From 236715fe9546b538db341869bf2ab9da55d9b63f Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 25 Sep 2017 11:21:56 +0200 Subject: [PATCH 271/281] build: publish unsigned builds --- build/tfs/darwin/release.sh | 11 +++++++---- build/tfs/win32/3_upload.ps1 | 16 ++++++++++++---- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/build/tfs/darwin/release.sh b/build/tfs/darwin/release.sh index 24ed4c30a78..9547d62f489 100755 --- a/build/tfs/darwin/release.sh +++ b/build/tfs/darwin/release.sh @@ -19,8 +19,11 @@ rm -rf $UNSIGNEDZIP step "Create unsigned archive" \ zip -r -X -y $UNSIGNEDZIP *) -step "Upload unsigned archive" \ - node build/tfs/common/publish.js --upload-only $VSCODE_QUALITY darwin archive-unsigned VSCode-darwin-$VSCODE_QUALITY-unsigned.zip $VERSION false $UNSIGNEDZIP +# step "Upload unsigned archive" \ +# node build/tfs/common/publish.js --upload-only $VSCODE_QUALITY darwin archive-unsigned VSCode-darwin-$VSCODE_QUALITY-unsigned.zip $VERSION false $UNSIGNEDZIP -step "Sign build" \ - node build/tfs/common/enqueue.js $VSCODE_QUALITY \ No newline at end of file +step "Upload unsigned archive" \ + node build/tfs/common/publish.js $VSCODE_QUALITY darwin archive-unsigned VSCode-darwin-$VSCODE_QUALITY-unsigned.zip $VERSION false $UNSIGNEDZIP + +# step "Sign build" \ +# node build/tfs/common/enqueue.js $VSCODE_QUALITY \ No newline at end of file diff --git a/build/tfs/win32/3_upload.ps1 b/build/tfs/win32/3_upload.ps1 index 8d10c908261..c37aba70599 100644 --- a/build/tfs/win32/3_upload.ps1 +++ b/build/tfs/win32/3_upload.ps1 @@ -24,12 +24,20 @@ $env:AZURE_DOCUMENTDB_MASTERKEY = $documentDbKey $assetPlatform = if ($arch -eq "ia32") { "win32" } else { "win32-x64" } -step "Publish archive" { - exec { & node build/tfs/common/publish.js $Quality "$global:assetPlatform-archive" archive "VSCode-win32-$global:arch-$Version.zip" $Version true $Zip } +# step "Publish archive" { +# exec { & node build/tfs/common/publish.js $Quality "$global:assetPlatform-archive" archive "VSCode-win32-$global:arch-$Version.zip" $Version true $Zip } +# } + +# step "Publish setup package" { +# exec { & node build/tfs/common/publish.js $Quality "$global:assetPlatform" setup "VSCodeSetup-$global:arch-$Version.exe" $Version true $Exe } +# } + +step "Publish UNSIGNED archive" { + exec { & node build/tfs/common/publish.js $Quality "$global:assetPlatform-archive" archive-unsigned "VSCode-win32-$global:arch-$Version.zip" $Version false $Zip } } -step "Publish setup package" { - exec { & node build/tfs/common/publish.js $Quality "$global:assetPlatform" setup "VSCodeSetup-$global:arch-$Version.exe" $Version true $Exe } +step "Publish UNSIGNED setup package" { + exec { & node build/tfs/common/publish.js $Quality "$global:assetPlatform" setup-unsigned "VSCodeSetup-$global:arch-$Version.exe" $Version false $Exe } } done \ No newline at end of file From 01ad59eb9a5cf3f99c75f67d2d72b9fd344e1e43 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 25 Sep 2017 11:49:00 +0200 Subject: [PATCH 272/281] Hook extension console into debug console (#34938) * hook into debug console * simpler impl --- src/vs/workbench/parts/debug/common/debug.ts | 4 ++-- .../parts/debug/common/debugSource.ts | 11 +++++++-- .../debug/electron-browser/debugService.ts | 24 +++++++++++++++---- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index 465742b8560..43566b44db9 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -14,7 +14,7 @@ import { IModel as EditorIModel, IEditorContribution } from 'vs/editor/common/ed import { IEditor } from 'vs/platform/editor/common/editor'; import { Position } from 'vs/editor/common/core/position'; import { ISuggestion } from 'vs/editor/common/modes'; -import { Source } from 'vs/workbench/parts/debug/common/debugSource'; +import { Source, ISource } from 'vs/workbench/parts/debug/common/debugSource'; import { Range, IRange } from 'vs/editor/common/core/range'; import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; @@ -77,7 +77,7 @@ export interface IReplElement extends ITreeElement { } export interface IReplElementSource { - source: Source; + source: ISource; lineNumber: number; column: number; } diff --git a/src/vs/workbench/parts/debug/common/debugSource.ts b/src/vs/workbench/parts/debug/common/debugSource.ts index 73be541a020..eeae9b440b7 100644 --- a/src/vs/workbench/parts/debug/common/debugSource.ts +++ b/src/vs/workbench/parts/debug/common/debugSource.ts @@ -13,7 +13,14 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Source"); -export class Source { +export interface ISource { + readonly uri: uri; + name: string; + + openInEditor(editorService: IWorkbenchEditorService, selection: IRange, preserveFocus?: boolean, sideBySide?: boolean): TPromise; +} + +export class Source implements ISource { public readonly uri: uri; public available: boolean; @@ -68,4 +75,4 @@ export class Source { } }, sideBySide); } -} +} \ No newline at end of file diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 9f366e697a0..ddb4bb6edfe 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -51,7 +51,7 @@ import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/p import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL, EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost'; import { IBroadcastService, IBroadcast } from 'vs/platform/broadcast/electron-browser/broadcastService'; -import { IRemoteConsoleLog, parse } from 'vs/base/node/console'; +import { IRemoteConsoleLog, parse, getFirstFrame } from 'vs/base/node/console'; const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint'; const DEBUG_BREAKPOINTS_ACTIVATED_KEY = 'debug.breakpointactivated'; @@ -167,7 +167,21 @@ export class DebugService implements debug.IDebugService { let extensionOutput: IRemoteConsoleLog = broadcast.payload.logEntry; let sev = extensionOutput.severity === 'warn' ? severity.Warning : extensionOutput.severity === 'error' ? severity.Error : severity.Info; - const { args } = parse(extensionOutput); + const { args, stack } = parse(extensionOutput); + let source: debug.IReplElementSource; + if (stack) { + const frame = getFirstFrame(stack); + if (frame) { + source = { + column: frame.column, + lineNumber: frame.line, + source: process.getSource({ + name: resources.basenameOrAuthority(frame.uri), + path: frame.uri.fsPath + }) + }; + } + } // add output for each argument logged let simpleVals: any[] = []; @@ -189,12 +203,12 @@ export class DebugService implements debug.IDebugService { // flush any existing simple values logged if (simpleVals.length) { - this.logToRepl(simpleVals.join(' '), sev); + this.logToRepl(simpleVals.join(' '), sev, source); simpleVals = []; } // show object - this.logToRepl(new OutputNameValueElement((a).prototype, a, undefined, nls.localize('snapshotObj', "Only primitive values are shown for this object.")), sev); + this.logToRepl(new OutputNameValueElement((a).prototype, a, undefined, nls.localize('snapshotObj', "Only primitive values are shown for this object.")), sev, source); } // string: watch out for % replacement directive @@ -224,7 +238,7 @@ export class DebugService implements debug.IDebugService { // flush simple values // always append a new line for output coming from an extension such that separate logs go to separate lines #23695 if (simpleVals.length) { - this.logToRepl(simpleVals.join(' ') + '\n', sev); + this.logToRepl(simpleVals.join(' ') + '\n', sev, source); } } } From be3e1c36a5cfcfd1f4b0a0870c309d80f2bee09b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 25 Sep 2017 12:08:23 +0200 Subject: [PATCH 273/281] Update the schemas model on schema changes --- .../common/jsonContributionRegistry.ts | 25 ++++++--------- .../common/preferencesContentProvider.ts | 32 +++++++++++++++---- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/vs/platform/jsonschemas/common/jsonContributionRegistry.ts b/src/vs/platform/jsonschemas/common/jsonContributionRegistry.ts index 5d4f91c0dff..b9c921d4505 100644 --- a/src/vs/platform/jsonschemas/common/jsonContributionRegistry.ts +++ b/src/vs/platform/jsonschemas/common/jsonContributionRegistry.ts @@ -5,9 +5,8 @@ 'use strict'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import platform = require('vs/platform/registry/common/platform'); -import { EventEmitter } from 'vs/base/common/eventEmitter'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import * as platform from 'vs/platform/registry/common/platform'; +import Event, { Emitter } from 'vs/base/common/event'; export const Extensions = { JSONContribution: 'base.contributions.json' @@ -19,6 +18,8 @@ export interface ISchemaContributions { export interface IJSONContributionRegistry { + readonly onDidChangeSchema: Event; + /** * Register a schema to the registry. */ @@ -28,12 +29,6 @@ export interface IJSONContributionRegistry { * Get all schemas */ getSchemaContributions(): ISchemaContributions; - - /** - * Adds a change listener - */ - addRegistryChangedListener(callback: (e: IJSONContributionRegistryEvent) => void): IDisposable; - } export interface IJSONContributionRegistryEvent { @@ -50,21 +45,19 @@ function normalizeId(id: string) { class JSONContributionRegistry implements IJSONContributionRegistry { + private schemasById: { [id: string]: IJSONSchema }; - private eventEmitter: EventEmitter; + + private _onDidChangeSchema: Emitter = new Emitter(); + readonly onDidChangeSchema: Event = this._onDidChangeSchema.event; constructor() { this.schemasById = {}; - this.eventEmitter = new EventEmitter(); - } - - public addRegistryChangedListener(callback: (e: IJSONContributionRegistryEvent) => void): IDisposable { - return this.eventEmitter.addListener('registryChanged', callback); } public registerSchema(uri: string, unresolvedSchemaContent: IJSONSchema): void { this.schemasById[normalizeId(uri)] = unresolvedSchemaContent; - this.eventEmitter.emit('registryChanged', {}); + this._onDidChangeSchema.fire(uri); } public getSchemaContributions(): ISchemaContributions { diff --git a/src/vs/workbench/parts/preferences/common/preferencesContentProvider.ts b/src/vs/workbench/parts/preferences/common/preferencesContentProvider.ts index 4b58705c22b..33141c96052 100644 --- a/src/vs/workbench/parts/preferences/common/preferencesContentProvider.ts +++ b/src/vs/workbench/parts/preferences/common/preferencesContentProvider.ts @@ -14,6 +14,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { IPreferencesService } from 'vs/workbench/parts/preferences/common/preferences'; +import { dispose } from 'vs/base/common/lifecycle'; const schemaRegistry = Registry.as(JSONContributionRegistry.Extensions.JSONContribution); @@ -33,18 +34,16 @@ export class PreferencesContentProvider implements IWorkbenchContribution { } private start(): void { + this.textModelResolverService.registerTextModelContentProvider('vscode', { provideTextContent: (uri: URI): TPromise => { if (uri.scheme !== 'vscode') { return null; } if (uri.authority === 'schemas') { - let schemas = schemaRegistry.getSchemaContributions().schemas; - let schema = schemas[uri.toString()]; - if (schema) { - let modelContent = JSON.stringify(schema); - let mode = this.modeService.getOrCreateMode('json'); - return TPromise.as(this.modelService.createModel(modelContent, mode, uri)); + const schemaModel = this.getSchemaModel(uri); + if (schemaModel) { + return TPromise.as(schemaModel); } } return this.preferencesService.resolveContent(uri) @@ -59,4 +58,25 @@ export class PreferencesContentProvider implements IWorkbenchContribution { } }); } + + private getSchemaModel(uri: URI): IModel { + let schema = schemaRegistry.getSchemaContributions().schemas[uri.toString()]; + if (schema) { + const modelContent = JSON.stringify(schema); + const mode = this.modeService.getOrCreateMode('json'); + const model = this.modelService.createModel(modelContent, mode, uri); + + let disposables = []; + disposables.push(schemaRegistry.onDidChangeSchema(schemaUri => { + if (schemaUri === uri.toString()) { + schema = schemaRegistry.getSchemaContributions().schemas[uri.toString()]; + model.setValue(JSON.stringify(schema)); + } + })); + disposables.push(model.onWillDispose(() => dispose(disposables))); + + return model; + } + return null; + } } From 7cb8ac43e692ebf2e71c1f2f8771aba5d297c3c4 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 25 Sep 2017 12:40:35 +0200 Subject: [PATCH 274/281] allow to reuse the same function/context when listening to events --- src/vs/base/common/callbackList.ts | 62 +++-------- src/vs/base/common/event.ts | 6 +- src/vs/base/common/linkedList.ts | 103 ++++++++++++++++++ src/vs/base/test/common/event.test.ts | 25 ++++- src/vs/base/test/common/linkedList.test.ts | 72 ++++++++++++ .../node/extHostDocumentSaveParticipant.ts | 8 +- 6 files changed, 222 insertions(+), 54 deletions(-) create mode 100644 src/vs/base/common/linkedList.ts create mode 100644 src/vs/base/test/common/linkedList.test.ts diff --git a/src/vs/base/common/callbackList.ts b/src/vs/base/common/callbackList.ts index 9a27d3b844b..96e0781ba87 100644 --- a/src/vs/base/common/callbackList.ts +++ b/src/vs/base/common/callbackList.ts @@ -6,47 +6,21 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { LinkedList } from 'vs/base/common/linkedList'; export default class CallbackList { - private _callbacks: Function[]; - private _contexts: any[]; + private _callbacks: LinkedList<[Function, any]>; - public add(callback: Function, context: any = null, bucket?: IDisposable[]): void { + public add(callback: Function, context: any = null, bucket?: IDisposable[]): () => void { if (!this._callbacks) { - this._callbacks = []; - this._contexts = []; + this._callbacks = new LinkedList<[Function, any]>(); } - this._callbacks.push(callback); - this._contexts.push(context); - + const remove = this._callbacks.insert([callback, context]); if (Array.isArray(bucket)) { - bucket.push({ dispose: () => this.remove(callback, context) }); - } - } - - public remove(callback: Function, context: any = null): void { - if (!this._callbacks) { - return; - } - - let foundCallbackWithDifferentContext = false; - for (let i = 0, len = this._callbacks.length; i < len; i++) { - if (this._callbacks[i] === callback) { - if (this._contexts[i] === context) { - // callback & context match => remove it - this._callbacks.splice(i, 1); - this._contexts.splice(i, 1); - return; - } else { - foundCallbackWithDifferentContext = true; - } - } - } - - if (foundCallbackWithDifferentContext) { - throw new Error('When adding a listener with a context, you should remove it with the same context'); + bucket.push({ dispose: remove }); } + return remove; } public invoke(...args: any[]): any[] { @@ -54,13 +28,12 @@ export default class CallbackList { return undefined; } - const ret: any[] = [], - callbacks = this._callbacks.slice(0), - contexts = this._contexts.slice(0); + const ret: any[] = []; + const elements = this._callbacks.toArray(); - for (let i = 0, len = callbacks.length; i < len; i++) { + for (const [callback, context] of elements) { try { - ret.push(callbacks[i].apply(contexts[i], args)); + ret.push(callback.apply(context, args)); } catch (e) { onUnexpectedError(e); } @@ -68,19 +41,20 @@ export default class CallbackList { return ret; } - public isEmpty(): boolean { - return !this._callbacks || this._callbacks.length === 0; - } - public entries(): [Function, any][] { if (!this._callbacks) { return []; } - return this._callbacks.map((fn, index) => <[Function, any]>[fn, this._contexts[index]]); + return this._callbacks + ? this._callbacks.toArray() + : []; + } + + public isEmpty(): boolean { + return !this._callbacks || this._callbacks.isEmpty(); } public dispose(): void { this._callbacks = undefined; - this._contexts = undefined; } } diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index 9ca573aac02..19ad6dd8657 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -82,7 +82,7 @@ export class Emitter { this._options.onFirstListenerAdd(this); } - this._callbacks.add(listener, thisArgs); + const remove = this._callbacks.add(listener, thisArgs); if (firstListener && this._options && this._options.onFirstListenerDidAdd) { this._options.onFirstListenerDidAdd(this); @@ -97,7 +97,7 @@ export class Emitter { dispose: () => { result.dispose = Emitter._noop; if (!this._disposed) { - this._callbacks.remove(listener, thisArgs); + remove(); if (this._options && this._options.onLastListenerRemove && this._callbacks.isEmpty()) { this._options.onLastListenerRemove(this); } @@ -545,4 +545,4 @@ export class Relay implements IDisposable { this.disposable.dispose(); this.emitter.dispose(); } -} \ No newline at end of file +} diff --git a/src/vs/base/common/linkedList.ts b/src/vs/base/common/linkedList.ts new file mode 100644 index 00000000000..e908f3c0e57 --- /dev/null +++ b/src/vs/base/common/linkedList.ts @@ -0,0 +1,103 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +class Node { + element: E; + next: Node; + prev: Node; + + constructor(element: E) { + this.element = element; + } +} + +export class LinkedList { + + private _first: Node; + private _last: Node; + + isEmpty(): boolean { + return !this._first; + } + + insert(element: E) { + const newNode = new Node(element); + if (!this._first) { + this._first = newNode; + this._last = newNode; + } else { + const oldLast = this._last; + this._last = newNode; + newNode.prev = oldLast; + oldLast.next = newNode; + } + + return () => { + + for (let candidate = this._first; candidate instanceof Node; candidate = candidate.next) { + if (candidate !== newNode) { + continue; + } + if (candidate.prev && candidate.next) { + // middle + let anchor = candidate.prev; + anchor.next = candidate.next; + candidate.next.prev = anchor; + + } else if (!candidate.prev && !candidate.next) { + // only node + this._first = undefined; + this._last = undefined; + + } else if (!candidate.next) { + // last + this._last = this._last.prev; + this._last.next = undefined; + + } else if (!candidate.prev) { + // first + this._first = this._first.next; + this._first.prev = undefined; + } + + // done + break; + } + }; + } + + iterator() { + let _done: boolean; + let _value: E; + let element = { + get done() { return _done; }, + get value() { return _value; } + }; + let node = this._first; + return { + next(): { done: boolean; value: E } { + if (!node) { + _done = true; + _value = undefined; + } else { + _done = false; + _value = node.element; + node = node.next; + } + return element; + } + }; + } + + toArray(): E[] { + let result: E[] = []; + for (let node = this._first; node instanceof Node; node = node.next) { + result.push(node.element); + } + return result; + } +} diff --git a/src/vs/base/test/common/event.test.ts b/src/vs/base/test/common/event.test.ts index 2e26cb50b0c..c11572642b1 100644 --- a/src/vs/base/test/common/event.test.ts +++ b/src/vs/base/test/common/event.test.ts @@ -179,6 +179,29 @@ suite('Event', function () { } }); + test('reusing event function and context', function () { + let counter = 0; + function listener() { + counter += 1; + } + const context = {}; + + let emitter = new Emitter(); + let reg1 = emitter.event(listener, context); + let reg2 = emitter.event(listener, context); + + emitter.fire(); + assert.equal(counter, 2); + + reg1.dispose(); + emitter.fire(); + assert.equal(counter, 3); + + reg2.dispose(); + emitter.fire(); + assert.equal(counter, 3); + }); + test('Debounce Event', function (done: () => void) { let doc = new Samples.Document3(); @@ -660,4 +683,4 @@ suite('Event utils', () => { assert.deepEqual(result, [1, 2, 3, 4, 5]); }); }); -}); \ No newline at end of file +}); diff --git a/src/vs/base/test/common/linkedList.test.ts b/src/vs/base/test/common/linkedList.test.ts new file mode 100644 index 00000000000..267eccaa806 --- /dev/null +++ b/src/vs/base/test/common/linkedList.test.ts @@ -0,0 +1,72 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as assert from 'assert'; +import { LinkedList } from 'vs/base/common/linkedList'; + +suite('LinkedList', function () { + + function assertElements(list: LinkedList, ...elements: E[]) { + // first: assert toArray + assert.deepEqual(list.toArray(), elements); + + // second: assert iterator + for (let iter = list.iterator(), element = iter.next(); !element.done; element = iter.next()) { + assert.equal(elements.shift(), element.value); + } + assert.equal(elements.length, 0); + } + + test('Insert/Iter', function () { + const list = new LinkedList(); + list.insert(0); + list.insert(1); + list.insert(2); + assertElements(list, 0, 1, 2); + }); + + test('Insert/Remove', function () { + let list = new LinkedList(); + let disp = list.insert(0); + list.insert(1); + list.insert(2); + disp(); + assertElements(list, 1, 2); + + list = new LinkedList(); + list.insert(0); + disp = list.insert(1); + list.insert(2); + disp(); + assertElements(list, 0, 2); + + list = new LinkedList(); + list.insert(0); + list.insert(1); + disp = list.insert(2); + disp(); + assertElements(list, 0, 1); + }); + + test('Insert/toArray', function () { + let list = new LinkedList(); + list.insert('foo'); + list.insert('bar'); + list.insert('far'); + list.insert('boo'); + + assert.deepEqual( + list.toArray(), + [ + 'foo', + 'bar', + 'far', + 'boo', + ] + ); + }); +}); diff --git a/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts b/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts index f1adf5fdf56..3be0250cf70 100644 --- a/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts +++ b/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts @@ -37,12 +37,8 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic get onWillSaveTextDocumentEvent(): Event { return (listener, thisArg, disposables) => { - this._callbacks.add(listener, thisArg); - const result = { - dispose: () => { - this._callbacks.remove(listener, thisArg); - } - }; + const remove = this._callbacks.add(listener, thisArg); + const result = { dispose: remove }; if (Array.isArray(disposables)) { disposables.push(result); } From 23d53e96080cbfc1ab4338de42a80e564b4d9f8a Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 25 Sep 2017 12:45:09 +0200 Subject: [PATCH 275/281] Fix #34254 --- src/vs/workbench/services/configuration/node/configuration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configuration.ts index e227aedab52..8fed9ed5247 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configuration.ts @@ -537,10 +537,10 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat this.workspace.folders = configuredFolders; this.onFoldersChanged() .then(configurationChanged => { - this._onDidChangeWorkspaceFolders.fire(changes); if (configurationChanged) { this.triggerConfigurationChange(); } + this._onDidChangeWorkspaceFolders.fire(changes); }); } else { const configurationChanged = this.updateWorkspaceConfiguration(true); From 51de5e575425ba20c32d8537d1b4f2fb86fa949f Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 25 Sep 2017 11:37:26 +0200 Subject: [PATCH 276/281] Style changes --- .../comment/common/blockCommentCommand.ts | 50 +++++++++---------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/src/vs/editor/contrib/comment/common/blockCommentCommand.ts b/src/vs/editor/contrib/comment/common/blockCommentCommand.ts index ffefd02ed8c..ef32a22bb45 100644 --- a/src/vs/editor/contrib/comment/common/blockCommentCommand.ts +++ b/src/vs/editor/contrib/comment/common/blockCommentCommand.ts @@ -26,12 +26,12 @@ export class BlockCommentCommand implements editorCommon.ICommand { if (offset < 0) { return false; } - var needleLength = needle.length; - var haystackLength = haystack.length; + const needleLength = needle.length; + const haystackLength = haystack.length; if (offset + needleLength > haystackLength) { return false; } - for (var i = 0; i < needleLength; i++) { + for (let i = 0; i < needleLength; i++) { if (haystack.charCodeAt(offset + i) !== needle.charCodeAt(i)) { return false; } @@ -40,21 +40,21 @@ export class BlockCommentCommand implements editorCommon.ICommand { } private _createOperationsForBlockComment(selection: Range, config: ICommentsConfiguration, model: editorCommon.ITokenizedModel, builder: editorCommon.IEditOperationBuilder): void { - var startLineNumber = selection.startLineNumber; - var startColumn = selection.startColumn; - var endLineNumber = selection.endLineNumber; - var endColumn = selection.endColumn; + const startLineNumber = selection.startLineNumber; + const startColumn = selection.startColumn; + const endLineNumber = selection.endLineNumber; + const endColumn = selection.endColumn; - var startToken = config.blockCommentStartToken; - var endToken = config.blockCommentEndToken; + let startToken = config.blockCommentStartToken; + let endToken = config.blockCommentEndToken; - var startTokenIndex = model.getLineContent(startLineNumber).lastIndexOf(startToken, startColumn - 1 + startToken.length); - var endTokenIndex = model.getLineContent(endLineNumber).indexOf(endToken, endColumn - 1 - endToken.length); + const startTokenIndex = model.getLineContent(startLineNumber).lastIndexOf(startToken, startColumn - 1 + startToken.length); + let endTokenIndex = model.getLineContent(endLineNumber).indexOf(endToken, endColumn - 1 - endToken.length); - var ops: editorCommon.IIdentifiedSingleEditOperation[]; + let ops: editorCommon.IIdentifiedSingleEditOperation[]; if (startTokenIndex !== -1 && endTokenIndex !== -1) { - var endTokenBeforeCursorIndex = model.getLineContent(startLineNumber).lastIndexOf(endToken, startColumn - 1 + endToken.length); + const endTokenBeforeCursorIndex = model.getLineContent(startLineNumber).lastIndexOf(endToken, startColumn - 1 + endToken.length); if (endTokenBeforeCursorIndex > startTokenIndex + startToken.length - 1) { ops = BlockCommentCommand._createAddBlockCommentOperations(selection, startToken, endToken); this._usedEndToken = ops.length === 1 ? endToken : null; @@ -78,13 +78,13 @@ export class BlockCommentCommand implements editorCommon.ICommand { this._usedEndToken = ops.length === 1 ? endToken : null; } - for (var i = 0; i < ops.length; i++) { + for (let i = 0; i < ops.length; i++) { builder.addTrackedEditOperation(ops[i].range, ops[i].text); } } public static _createRemoveBlockCommentOperations(r: Range, startToken: string, endToken: string): editorCommon.IIdentifiedSingleEditOperation[] { - var res: editorCommon.IIdentifiedSingleEditOperation[] = []; + let res: editorCommon.IIdentifiedSingleEditOperation[] = []; if (!Range.isEmpty(r)) { // Remove block comment start @@ -110,7 +110,7 @@ export class BlockCommentCommand implements editorCommon.ICommand { } public static _createAddBlockCommentOperations(r: Range, startToken: string, endToken: string): editorCommon.IIdentifiedSingleEditOperation[] { - var res: editorCommon.IIdentifiedSingleEditOperation[] = []; + let res: editorCommon.IIdentifiedSingleEditOperation[] = []; if (!Range.isEmpty(r)) { // Insert block comment start @@ -130,10 +130,8 @@ export class BlockCommentCommand implements editorCommon.ICommand { } public getEditOperations(model: editorCommon.ITokenizedModel, builder: editorCommon.IEditOperationBuilder): void { - var startLineNumber = this._selection.startLineNumber; - var startColumn = this._selection.startColumn; - var endLineNumber = this._selection.endLineNumber; - var endColumn = this._selection.endColumn; + const startLineNumber = this._selection.startLineNumber; + const startColumn = this._selection.startColumn; model.tokenizeIfCheap(startLineNumber); let languageId = model.getLanguageIdAtPosition(startLineNumber, startColumn); @@ -144,15 +142,15 @@ export class BlockCommentCommand implements editorCommon.ICommand { } this._createOperationsForBlockComment( - new Range(startLineNumber, startColumn, endLineNumber, endColumn), config, model, builder + this._selection, config, model, builder ); } public computeCursorState(model: editorCommon.ITokenizedModel, helper: editorCommon.ICursorStateComputerData): Selection { - var inverseEditOperations = helper.getInverseEditOperations(); + const inverseEditOperations = helper.getInverseEditOperations(); if (inverseEditOperations.length === 2) { - var startTokenEditOperation = inverseEditOperations[0]; - var endTokenEditOperation = inverseEditOperations[1]; + const startTokenEditOperation = inverseEditOperations[0]; + const endTokenEditOperation = inverseEditOperations[1]; return new Selection( startTokenEditOperation.range.endLineNumber, @@ -161,8 +159,8 @@ export class BlockCommentCommand implements editorCommon.ICommand { endTokenEditOperation.range.startColumn ); } else { - var srcRange = inverseEditOperations[0].range; - var deltaColumn = this._usedEndToken ? -this._usedEndToken.length - 1 : 0; // minus 1 space before endToken + const srcRange = inverseEditOperations[0].range; + const deltaColumn = this._usedEndToken ? -this._usedEndToken.length - 1 : 0; // minus 1 space before endToken return new Selection( srcRange.endLineNumber, srcRange.endColumn + deltaColumn, From 1114cfef4662b41dbbf712c9a9cf7b94c96949c0 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 25 Sep 2017 12:46:47 +0200 Subject: [PATCH 277/281] Fixes #34618: Recover from wrong fix for #30358 (5c58b8cb2d59e1151c87cf2fbe46f69b41a3620f) --- .../comment/common/blockCommentCommand.ts | 60 +++++++++++++------ .../test/common/blockCommentCommand.test.ts | 13 ++++ 2 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/vs/editor/contrib/comment/common/blockCommentCommand.ts b/src/vs/editor/contrib/comment/common/blockCommentCommand.ts index ef32a22bb45..933dff3f46b 100644 --- a/src/vs/editor/contrib/comment/common/blockCommentCommand.ts +++ b/src/vs/editor/contrib/comment/common/blockCommentCommand.ts @@ -45,34 +45,58 @@ export class BlockCommentCommand implements editorCommon.ICommand { const endLineNumber = selection.endLineNumber; const endColumn = selection.endColumn; + const startLineText = model.getLineContent(startLineNumber); + const endLineText = model.getLineContent(endLineNumber); + let startToken = config.blockCommentStartToken; let endToken = config.blockCommentEndToken; - const startTokenIndex = model.getLineContent(startLineNumber).lastIndexOf(startToken, startColumn - 1 + startToken.length); - let endTokenIndex = model.getLineContent(endLineNumber).indexOf(endToken, endColumn - 1 - endToken.length); + let startTokenIndex = startLineText.lastIndexOf(startToken, startColumn - 1 + startToken.length); + let endTokenIndex = endLineText.indexOf(endToken, endColumn - 1 - endToken.length); + + if (startTokenIndex !== -1 && endTokenIndex !== -1) { + + if (startLineNumber === endLineNumber) { + const lineBetweenTokens = startLineText.substring(startTokenIndex + startToken.length, endTokenIndex); + + if (lineBetweenTokens.indexOf(endToken) >= 0) { + // force to add a block comment + startTokenIndex = -1; + endTokenIndex = -1; + } + } else { + const startLineAfterStartToken = startLineText.substring(startTokenIndex + startToken.length); + const endLineBeforeEndToken = endLineText.substring(0, endTokenIndex); + + if (startLineAfterStartToken.indexOf(endToken) >= 0 || endLineBeforeEndToken.indexOf(endToken) >= 0) { + // force to add a block comment + startTokenIndex = -1; + endTokenIndex = -1; + } + } + } let ops: editorCommon.IIdentifiedSingleEditOperation[]; if (startTokenIndex !== -1 && endTokenIndex !== -1) { - const endTokenBeforeCursorIndex = model.getLineContent(startLineNumber).lastIndexOf(endToken, startColumn - 1 + endToken.length); - if (endTokenBeforeCursorIndex > startTokenIndex + startToken.length - 1) { - ops = BlockCommentCommand._createAddBlockCommentOperations(selection, startToken, endToken); - this._usedEndToken = ops.length === 1 ? endToken : null; - } else { - // We have to adjust to possible inner white space - // For Space after startToken, add Space to startToken - range math will work out - if (model.getLineContent(startLineNumber).charCodeAt(startTokenIndex + startToken.length) === CharCode.Space) { - startToken += ' '; + // Consider spaces as part of the comment tokens + if (startTokenIndex + startToken.length < startLineText.length) { + if (startLineText.charCodeAt(startTokenIndex + startToken.length) === CharCode.Space) { + // Pretend the start token contains a trailing space + startToken = startToken + ' '; } - // For Space before endToken, add Space before endToken and shift index one left - if (model.getLineContent(endLineNumber).charCodeAt(endTokenIndex - 1) === CharCode.Space) { + } + + if (endTokenIndex > 0) { + if (endLineText.charCodeAt(endTokenIndex - 1) === CharCode.Space) { + // Pretend the end token contains a leading space endToken = ' ' + endToken; endTokenIndex -= 1; } - ops = BlockCommentCommand._createRemoveBlockCommentOperations( - new Range(startLineNumber, startTokenIndex + 1 + startToken.length, endLineNumber, endTokenIndex + 1), startToken, endToken - ); } + ops = BlockCommentCommand._createRemoveBlockCommentOperations( + new Range(startLineNumber, startTokenIndex + startToken.length + 1, endLineNumber, endTokenIndex + 1), startToken, endToken + ); } else { ops = BlockCommentCommand._createAddBlockCommentOperations(selection, startToken, endToken); this._usedEndToken = ops.length === 1 ? endToken : null; @@ -134,8 +158,8 @@ export class BlockCommentCommand implements editorCommon.ICommand { const startColumn = this._selection.startColumn; model.tokenizeIfCheap(startLineNumber); - let languageId = model.getLanguageIdAtPosition(startLineNumber, startColumn); - let config = LanguageConfigurationRegistry.getComments(languageId); + const languageId = model.getLanguageIdAtPosition(startLineNumber, startColumn); + const config = LanguageConfigurationRegistry.getComments(languageId); if (!config || !config.blockCommentStartToken || !config.blockCommentEndToken) { // Mode does not support block comments return; diff --git a/src/vs/editor/contrib/comment/test/common/blockCommentCommand.test.ts b/src/vs/editor/contrib/comment/test/common/blockCommentCommand.test.ts index e204aa44255..4b5ea60286d 100644 --- a/src/vs/editor/contrib/comment/test/common/blockCommentCommand.test.ts +++ b/src/vs/editor/contrib/comment/test/common/blockCommentCommand.test.ts @@ -457,4 +457,17 @@ suite('Editor Contrib - Block Comment Command', () => { new Selection(1, 16, 1, 22) ); }); + + test('issue #34618', function () { + testBlockCommentCommand( + [ + '<0 0> middle end', + ], + new Selection(1, 4, 1, 4), + [ + ' middle end' + ], + new Selection(1, 1, 1, 1) + ); + }); }); From 3eadcbe392f4f93ab20209e4b931a49e00970fbf Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Mon, 25 Sep 2017 13:52:56 +0200 Subject: [PATCH 278/281] Fixes #29769: Update the locale.json schema to always be in sync with supported languages --- .../actions => electron-browser}/configureLocale.ts | 8 +++++++- src/vs/workbench/workbench.main.ts | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) rename src/vs/workbench/{browser/actions => electron-browser}/configureLocale.ts (94%) diff --git a/src/vs/workbench/browser/actions/configureLocale.ts b/src/vs/workbench/electron-browser/configureLocale.ts similarity index 94% rename from src/vs/workbench/browser/actions/configureLocale.ts rename to src/vs/workbench/electron-browser/configureLocale.ts index 41ca1f377c5..d360f840752 100644 --- a/src/vs/workbench/browser/actions/configureLocale.ts +++ b/src/vs/workbench/electron-browser/configureLocale.ts @@ -69,6 +69,12 @@ class ConfigureLocaleAction extends Action { const registry = Registry.as(Extensions.WorkbenchActions); registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureLocaleAction, ConfigureLocaleAction.ID, ConfigureLocaleAction.LABEL), 'Configure Language'); +let enumValues: string[] = ['de', 'en', 'en-US', 'es', 'fr', 'it', 'ja', 'ko', 'ru', 'zh-CN', 'zh-TW']; +import product from 'vs/platform/node/product'; +if (product.quality !== 'stable') { + enumValues.push('hu'); +} + const schemaId = 'vscode://schemas/locale'; // Keep en-US since we generated files with that content. const schema: IJSONSchema = @@ -83,7 +89,7 @@ const schema: IJSONSchema = properties: { locale: { type: 'string', - enum: ['de', 'en', 'en-US', 'es', 'fr', 'it', 'ja', 'ko', 'ru', 'zh-CN', 'zh-TW'], + enum: enumValues, description: nls.localize('JsonSchema.locale', 'The UI Language to use.') } } diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index d5c4c9ebf03..b162fb6a023 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -27,7 +27,6 @@ import 'vs/workbench/browser/actions/toggleEditorLayout'; import 'vs/workbench/browser/actions/toggleZenMode'; import 'vs/workbench/parts/preferences/browser/preferences.contribution'; import 'vs/workbench/parts/preferences/browser/keybindingsEditorContribution'; -import 'vs/workbench/browser/actions/configureLocale'; import 'vs/workbench/browser/parts/quickopen/quickopen.contribution'; import 'vs/workbench/parts/quickopen/browser/quickopen.contribution'; @@ -73,6 +72,7 @@ import 'vs/workbench/parts/terminal/browser/terminalQuickOpen'; import 'vs/workbench/parts/terminal/electron-browser/terminalPanel'; // can be packaged separately import 'vs/workbench/electron-browser/workbench'; +import 'vs/workbench/electron-browser/configureLocale'; import 'vs/workbench/parts/trust/electron-browser/unsupportedWorkspaceSettings.contribution'; From 31caa015c0b198682e7ab35ce8ca14c5f83561c6 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 25 Sep 2017 14:01:46 +0200 Subject: [PATCH 279/281] debug: remove ISource --- src/vs/workbench/parts/debug/common/debug.ts | 4 ++-- src/vs/workbench/parts/debug/common/debugSource.ts | 9 +-------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index 43566b44db9..465742b8560 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -14,7 +14,7 @@ import { IModel as EditorIModel, IEditorContribution } from 'vs/editor/common/ed import { IEditor } from 'vs/platform/editor/common/editor'; import { Position } from 'vs/editor/common/core/position'; import { ISuggestion } from 'vs/editor/common/modes'; -import { Source, ISource } from 'vs/workbench/parts/debug/common/debugSource'; +import { Source } from 'vs/workbench/parts/debug/common/debugSource'; import { Range, IRange } from 'vs/editor/common/core/range'; import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; @@ -77,7 +77,7 @@ export interface IReplElement extends ITreeElement { } export interface IReplElementSource { - source: ISource; + source: Source; lineNumber: number; column: number; } diff --git a/src/vs/workbench/parts/debug/common/debugSource.ts b/src/vs/workbench/parts/debug/common/debugSource.ts index eeae9b440b7..74a2e4c4b25 100644 --- a/src/vs/workbench/parts/debug/common/debugSource.ts +++ b/src/vs/workbench/parts/debug/common/debugSource.ts @@ -13,14 +13,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Source"); -export interface ISource { - readonly uri: uri; - name: string; - - openInEditor(editorService: IWorkbenchEditorService, selection: IRange, preserveFocus?: boolean, sideBySide?: boolean): TPromise; -} - -export class Source implements ISource { +export class Source { public readonly uri: uri; public available: boolean; From 4a3dbb6c44f763f84b4cb3a597d3da93152ca89d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 25 Sep 2017 14:11:32 +0200 Subject: [PATCH 280/281] Revert "allow to reuse the same function/context when listening to events" This reverts commit 7cb8ac43e692ebf2e71c1f2f8771aba5d297c3c4. --- src/vs/base/common/callbackList.ts | 62 ++++++++--- src/vs/base/common/event.ts | 6 +- src/vs/base/common/linkedList.ts | 103 ------------------ src/vs/base/test/common/event.test.ts | 25 +---- src/vs/base/test/common/linkedList.test.ts | 72 ------------ .../node/extHostDocumentSaveParticipant.ts | 8 +- 6 files changed, 54 insertions(+), 222 deletions(-) delete mode 100644 src/vs/base/common/linkedList.ts delete mode 100644 src/vs/base/test/common/linkedList.test.ts diff --git a/src/vs/base/common/callbackList.ts b/src/vs/base/common/callbackList.ts index 96e0781ba87..9a27d3b844b 100644 --- a/src/vs/base/common/callbackList.ts +++ b/src/vs/base/common/callbackList.ts @@ -6,21 +6,47 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { LinkedList } from 'vs/base/common/linkedList'; export default class CallbackList { - private _callbacks: LinkedList<[Function, any]>; + private _callbacks: Function[]; + private _contexts: any[]; - public add(callback: Function, context: any = null, bucket?: IDisposable[]): () => void { + public add(callback: Function, context: any = null, bucket?: IDisposable[]): void { if (!this._callbacks) { - this._callbacks = new LinkedList<[Function, any]>(); + this._callbacks = []; + this._contexts = []; } - const remove = this._callbacks.insert([callback, context]); + this._callbacks.push(callback); + this._contexts.push(context); + if (Array.isArray(bucket)) { - bucket.push({ dispose: remove }); + bucket.push({ dispose: () => this.remove(callback, context) }); + } + } + + public remove(callback: Function, context: any = null): void { + if (!this._callbacks) { + return; + } + + let foundCallbackWithDifferentContext = false; + for (let i = 0, len = this._callbacks.length; i < len; i++) { + if (this._callbacks[i] === callback) { + if (this._contexts[i] === context) { + // callback & context match => remove it + this._callbacks.splice(i, 1); + this._contexts.splice(i, 1); + return; + } else { + foundCallbackWithDifferentContext = true; + } + } + } + + if (foundCallbackWithDifferentContext) { + throw new Error('When adding a listener with a context, you should remove it with the same context'); } - return remove; } public invoke(...args: any[]): any[] { @@ -28,12 +54,13 @@ export default class CallbackList { return undefined; } - const ret: any[] = []; - const elements = this._callbacks.toArray(); + const ret: any[] = [], + callbacks = this._callbacks.slice(0), + contexts = this._contexts.slice(0); - for (const [callback, context] of elements) { + for (let i = 0, len = callbacks.length; i < len; i++) { try { - ret.push(callback.apply(context, args)); + ret.push(callbacks[i].apply(contexts[i], args)); } catch (e) { onUnexpectedError(e); } @@ -41,20 +68,19 @@ export default class CallbackList { return ret; } + public isEmpty(): boolean { + return !this._callbacks || this._callbacks.length === 0; + } + public entries(): [Function, any][] { if (!this._callbacks) { return []; } - return this._callbacks - ? this._callbacks.toArray() - : []; - } - - public isEmpty(): boolean { - return !this._callbacks || this._callbacks.isEmpty(); + return this._callbacks.map((fn, index) => <[Function, any]>[fn, this._contexts[index]]); } public dispose(): void { this._callbacks = undefined; + this._contexts = undefined; } } diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index 19ad6dd8657..9ca573aac02 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -82,7 +82,7 @@ export class Emitter { this._options.onFirstListenerAdd(this); } - const remove = this._callbacks.add(listener, thisArgs); + this._callbacks.add(listener, thisArgs); if (firstListener && this._options && this._options.onFirstListenerDidAdd) { this._options.onFirstListenerDidAdd(this); @@ -97,7 +97,7 @@ export class Emitter { dispose: () => { result.dispose = Emitter._noop; if (!this._disposed) { - remove(); + this._callbacks.remove(listener, thisArgs); if (this._options && this._options.onLastListenerRemove && this._callbacks.isEmpty()) { this._options.onLastListenerRemove(this); } @@ -545,4 +545,4 @@ export class Relay implements IDisposable { this.disposable.dispose(); this.emitter.dispose(); } -} +} \ No newline at end of file diff --git a/src/vs/base/common/linkedList.ts b/src/vs/base/common/linkedList.ts deleted file mode 100644 index e908f3c0e57..00000000000 --- a/src/vs/base/common/linkedList.ts +++ /dev/null @@ -1,103 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -class Node { - element: E; - next: Node; - prev: Node; - - constructor(element: E) { - this.element = element; - } -} - -export class LinkedList { - - private _first: Node; - private _last: Node; - - isEmpty(): boolean { - return !this._first; - } - - insert(element: E) { - const newNode = new Node(element); - if (!this._first) { - this._first = newNode; - this._last = newNode; - } else { - const oldLast = this._last; - this._last = newNode; - newNode.prev = oldLast; - oldLast.next = newNode; - } - - return () => { - - for (let candidate = this._first; candidate instanceof Node; candidate = candidate.next) { - if (candidate !== newNode) { - continue; - } - if (candidate.prev && candidate.next) { - // middle - let anchor = candidate.prev; - anchor.next = candidate.next; - candidate.next.prev = anchor; - - } else if (!candidate.prev && !candidate.next) { - // only node - this._first = undefined; - this._last = undefined; - - } else if (!candidate.next) { - // last - this._last = this._last.prev; - this._last.next = undefined; - - } else if (!candidate.prev) { - // first - this._first = this._first.next; - this._first.prev = undefined; - } - - // done - break; - } - }; - } - - iterator() { - let _done: boolean; - let _value: E; - let element = { - get done() { return _done; }, - get value() { return _value; } - }; - let node = this._first; - return { - next(): { done: boolean; value: E } { - if (!node) { - _done = true; - _value = undefined; - } else { - _done = false; - _value = node.element; - node = node.next; - } - return element; - } - }; - } - - toArray(): E[] { - let result: E[] = []; - for (let node = this._first; node instanceof Node; node = node.next) { - result.push(node.element); - } - return result; - } -} diff --git a/src/vs/base/test/common/event.test.ts b/src/vs/base/test/common/event.test.ts index c11572642b1..2e26cb50b0c 100644 --- a/src/vs/base/test/common/event.test.ts +++ b/src/vs/base/test/common/event.test.ts @@ -179,29 +179,6 @@ suite('Event', function () { } }); - test('reusing event function and context', function () { - let counter = 0; - function listener() { - counter += 1; - } - const context = {}; - - let emitter = new Emitter(); - let reg1 = emitter.event(listener, context); - let reg2 = emitter.event(listener, context); - - emitter.fire(); - assert.equal(counter, 2); - - reg1.dispose(); - emitter.fire(); - assert.equal(counter, 3); - - reg2.dispose(); - emitter.fire(); - assert.equal(counter, 3); - }); - test('Debounce Event', function (done: () => void) { let doc = new Samples.Document3(); @@ -683,4 +660,4 @@ suite('Event utils', () => { assert.deepEqual(result, [1, 2, 3, 4, 5]); }); }); -}); +}); \ No newline at end of file diff --git a/src/vs/base/test/common/linkedList.test.ts b/src/vs/base/test/common/linkedList.test.ts deleted file mode 100644 index 267eccaa806..00000000000 --- a/src/vs/base/test/common/linkedList.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -import * as assert from 'assert'; -import { LinkedList } from 'vs/base/common/linkedList'; - -suite('LinkedList', function () { - - function assertElements(list: LinkedList, ...elements: E[]) { - // first: assert toArray - assert.deepEqual(list.toArray(), elements); - - // second: assert iterator - for (let iter = list.iterator(), element = iter.next(); !element.done; element = iter.next()) { - assert.equal(elements.shift(), element.value); - } - assert.equal(elements.length, 0); - } - - test('Insert/Iter', function () { - const list = new LinkedList(); - list.insert(0); - list.insert(1); - list.insert(2); - assertElements(list, 0, 1, 2); - }); - - test('Insert/Remove', function () { - let list = new LinkedList(); - let disp = list.insert(0); - list.insert(1); - list.insert(2); - disp(); - assertElements(list, 1, 2); - - list = new LinkedList(); - list.insert(0); - disp = list.insert(1); - list.insert(2); - disp(); - assertElements(list, 0, 2); - - list = new LinkedList(); - list.insert(0); - list.insert(1); - disp = list.insert(2); - disp(); - assertElements(list, 0, 1); - }); - - test('Insert/toArray', function () { - let list = new LinkedList(); - list.insert('foo'); - list.insert('bar'); - list.insert('far'); - list.insert('boo'); - - assert.deepEqual( - list.toArray(), - [ - 'foo', - 'bar', - 'far', - 'boo', - ] - ); - }); -}); diff --git a/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts b/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts index 3be0250cf70..f1adf5fdf56 100644 --- a/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts +++ b/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts @@ -37,8 +37,12 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic get onWillSaveTextDocumentEvent(): Event { return (listener, thisArg, disposables) => { - const remove = this._callbacks.add(listener, thisArg); - const result = { dispose: remove }; + this._callbacks.add(listener, thisArg); + const result = { + dispose: () => { + this._callbacks.remove(listener, thisArg); + } + }; if (Array.isArray(disposables)) { disposables.push(result); } From 24829c4fea083b58708874065597029a1eed522b Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Mon, 25 Sep 2017 14:17:25 +0200 Subject: [PATCH 281/281] node-debug@1.17.12 --- build/gulpfile.vscode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 8d6b3b0113e..b4465b4a505 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -45,7 +45,7 @@ const nodeModules = ['electron', 'original-fs'] // Build const builtInExtensions = [ - { name: 'ms-vscode.node-debug', version: '1.17.11' }, + { name: 'ms-vscode.node-debug', version: '1.17.12' }, { name: 'ms-vscode.node-debug2', version: '1.17.4' } ];