From aba0fcbb58d49edaf8f8fb3cbbdce6f831b9325d Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 28 Jan 2019 10:54:45 +0100 Subject: [PATCH 001/207] Delay extension host until workspace is completely initialized --- .../electron-browser/mainThreadWorkspace.ts | 17 +++-- src/vs/workbench/api/node/extHost.api.impl.ts | 36 +++++----- src/vs/workbench/api/node/extHost.protocol.ts | 10 ++- .../api/node/extHostConfiguration.ts | 12 ++-- .../workbench/api/node/extHostDebugService.ts | 67 ++++++++++--------- .../api/node/extHostExtensionService.ts | 27 ++++---- src/vs/workbench/api/node/extHostQuickOpen.ts | 2 +- src/vs/workbench/api/node/extHostTask.ts | 53 ++++++++------- src/vs/workbench/api/node/extHostWorkspace.ts | 49 +++++++++++++- .../electron-browser/extensionHost.ts | 1 - .../extensions/node/extensionHostMain.ts | 7 +- .../services/extensions/node/proxyResolver.ts | 6 +- .../api/extHostConfiguration.test.ts | 12 ++-- .../api/extHostWorkspace.test.ts | 44 ++++++------ 14 files changed, 204 insertions(+), 139 deletions(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts index 6a435ed4660..647478faf8b 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts @@ -14,13 +14,13 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { IFolderQuery, IPatternInfo, ISearchConfiguration, ISearchProgressItem, ISearchService, QueryType, IFileQuery, IFileMatch } from 'vs/platform/search/common/search'; import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { IWindowService } from 'vs/platform/windows/common/windows'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import { QueryBuilder, ITextQueryBuilderOptions } from 'vs/workbench/parts/search/common/queryBuilder'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; -import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, MainThreadWorkspaceShape } from '../node/extHost.protocol'; +import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, MainThreadWorkspaceShape, IWorkspaceData } from '../node/extHost.protocol'; import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation'; import { TextSearchComplete } from 'vscode'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; @@ -45,6 +45,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { @ILabelService private readonly _labelService: ILabelService ) { this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostWorkspace); + this._contextService.getCompleteWorkspace().then(workspace => this._proxy.$initializeWorkspace(this.getWorkspaceData(workspace))); this._contextService.onDidChangeWorkspaceFolders(this._onDidChangeWorkspace, this, this._toDispose); this._contextService.onDidChangeWorkbenchState(this._onDidChangeWorkspace, this, this._toDispose); } @@ -102,13 +103,19 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { } private _onDidChangeWorkspace(): void { - const workspace = this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : this._contextService.getWorkspace(); - this._proxy.$acceptWorkspaceData(workspace ? { + this._proxy.$acceptWorkspaceData(this.getWorkspaceData(this._contextService.getWorkspace())); + } + + private getWorkspaceData(workspace: IWorkspace): IWorkspaceData | null { + if (this._contextService.getWorkbenchState() === WorkbenchState.EMPTY) { + return null; + } + return { configuration: workspace.configuration, folders: workspace.folders, id: workspace.id, name: this._labelService.getWorkspaceLabel(workspace) - } : null); + }; } // --- search --- diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 249c88fa891..9495cc980d5 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -58,7 +58,7 @@ import * as extHostTypes from 'vs/workbench/api/node/extHostTypes'; import { ExtHostUrls } from 'vs/workbench/api/node/extHostUrls'; import { ExtHostWebviews } from 'vs/workbench/api/node/extHostWebview'; import { ExtHostWindow } from 'vs/workbench/api/node/extHostWindow'; -import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostWorkspace, ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; import { IExtensionDescription, throwProposedApiError, checkProposedApiEnabled, nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import { ProxyIdentifier } from 'vs/workbench/services/extensions/node/proxyIdentifier'; import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry'; @@ -66,7 +66,7 @@ import * as vscode from 'vscode'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; export interface IExtensionApiFactory { - (extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode; + (extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, workspaceProvider: ExtHostWorkspaceProvider, configProvider: ExtHostConfigProvider): typeof vscode; } function proposedApiFunction(extension: IExtensionDescription, fn: T): T { @@ -142,7 +142,7 @@ export function createApiFactory( // Register API-ish commands ExtHostApiCommands.register(extHostCommands); - return function (extension: IExtensionDescription, extensionRegistry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode { + return function (extension: IExtensionDescription, extensionRegistry: ExtensionDescriptionRegistry, workspaceProvider: ExtHostWorkspaceProvider, configProvider: ExtHostConfigProvider): typeof vscode { // Check document selectors for being overly generic. Technically this isn't a problem but // in practice many extensions say they support `fooLang` but need fs-access to do so. Those @@ -505,34 +505,34 @@ export function createApiFactory( // namespace: workspace const workspace: typeof vscode.workspace = { get rootPath() { - return extHostWorkspace.getPath(); + return workspaceProvider.getPath(); }, set rootPath(value) { throw errors.readonly(); }, getWorkspaceFolder(resource) { - return extHostWorkspace.getWorkspaceFolder(resource); + return workspaceProvider.getWorkspaceFolder(resource); }, get workspaceFolders() { - return extHostWorkspace.getWorkspaceFolders(); + return workspaceProvider.getWorkspaceFolders(); }, get name() { - return extHostWorkspace.name; + return workspaceProvider.name; }, set name(value) { throw errors.readonly(); }, updateWorkspaceFolders: (index, deleteCount, ...workspaceFoldersToAdd) => { - return extHostWorkspace.updateWorkspaceFolders(extension, index, deleteCount || 0, ...workspaceFoldersToAdd); + return workspaceProvider.updateWorkspaceFolders(extension, index, deleteCount || 0, ...workspaceFoldersToAdd); }, onDidChangeWorkspaceFolders: function (listener, thisArgs?, disposables?) { - return extHostWorkspace.onDidChangeWorkspace(listener, thisArgs, disposables); + return workspaceProvider.onDidChangeWorkspace(listener, thisArgs, disposables); }, asRelativePath: (pathOrUri, includeWorkspace) => { - return extHostWorkspace.getRelativePath(pathOrUri, includeWorkspace); + return workspaceProvider.getRelativePath(pathOrUri, includeWorkspace); }, findFiles: (include, exclude, maxResults?, token?) => { - return extHostWorkspace.findFiles(typeConverters.GlobPattern.from(include), typeConverters.GlobPattern.from(exclude), maxResults, extension.identifier, token); + return workspaceProvider.findFiles(typeConverters.GlobPattern.from(include), typeConverters.GlobPattern.from(exclude), maxResults, extension.identifier, token); }, findTextInFiles: (query: vscode.TextSearchQuery, optionsOrCallback, callbackOrToken?, token?: vscode.CancellationToken) => { let options: vscode.FindTextInFilesOptions; @@ -547,10 +547,10 @@ export function createApiFactory( token = callbackOrToken; } - return extHostWorkspace.findTextInFiles(query, options || {}, callback, extension.identifier, token); + return workspaceProvider.findTextInFiles(query, options || {}, callback, extension.identifier, token); }, saveAll: (includeUntitled?) => { - return extHostWorkspace.saveAll(includeUntitled); + return workspaceProvider.saveAll(includeUntitled); }, applyEdit(edit: vscode.WorkspaceEdit): Thenable { return extHostEditors.applyWorkspaceEdit(edit); @@ -868,11 +868,11 @@ class Extension implements vscode.Extension { } } -export function initializeExtensionApi(extensionService: ExtHostExtensionService, apiFactory: IExtensionApiFactory, extensionRegistry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): Promise { - return extensionService.getExtensionPathIndex().then(trie => defineAPI(apiFactory, trie, extensionRegistry, configProvider)); +export function initializeExtensionApi(extensionService: ExtHostExtensionService, apiFactory: IExtensionApiFactory, extensionRegistry: ExtensionDescriptionRegistry, workspaceProvider: ExtHostWorkspaceProvider, configProvider: ExtHostConfigProvider): Promise { + return extensionService.getExtensionPathIndex().then(trie => defineAPI(apiFactory, trie, extensionRegistry, workspaceProvider, configProvider)); } -function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchTree, extensionRegistry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): void { +function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchTree, extensionRegistry: ExtensionDescriptionRegistry, workspaceProvider: ExtHostWorkspaceProvider, configProvider: ExtHostConfigProvider): void { // each extension is meant to get its own api implementation const extApiImpl = new Map(); @@ -890,7 +890,7 @@ function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchT if (ext) { let apiImpl = extApiImpl.get(ExtensionIdentifier.toKey(ext.identifier)); if (!apiImpl) { - apiImpl = factory(ext, extensionRegistry, configProvider); + apiImpl = factory(ext, extensionRegistry, workspaceProvider, configProvider); extApiImpl.set(ExtensionIdentifier.toKey(ext.identifier), apiImpl); } return apiImpl; @@ -901,7 +901,7 @@ function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchT let extensionPathsPretty = ''; extensionPaths.forEach((value, index) => extensionPathsPretty += `\t${index} -> ${value.identifier.value}\n`); console.warn(`Could not identify extension for 'vscode' require call from ${parent.filename}. These are the extension path mappings: \n${extensionPathsPretty}`); - defaultApiImpl = factory(nullExtensionDescription, extensionRegistry, configProvider); + defaultApiImpl = factory(nullExtensionDescription, extensionRegistry, workspaceProvider, configProvider); } return defaultApiImpl; }; diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 72e15943a45..1cc97e53c33 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -55,18 +55,21 @@ export interface IEnvironment { globalStorageHome: URI; } -export interface IWorkspaceData { +export interface IStaticWorkspaceData { id: string; name: string; - folders: { uri: UriComponents, name: string, index: number }[]; configuration?: UriComponents; } +export interface IWorkspaceData extends IStaticWorkspaceData { + folders: { uri: UriComponents, name: string, index: number }[]; +} + export interface IInitData { commit: string; parentPid: number; environment: IEnvironment; - workspace: IWorkspaceData; + workspace: IStaticWorkspaceData; resolvedExtensions: ExtensionIdentifier[]; extensions: IExtensionDescription[]; telemetryInfo: ITelemetryInfo; @@ -716,6 +719,7 @@ export interface ExtHostTreeViewsShape { } export interface ExtHostWorkspaceShape { + $initializeWorkspace(workspace: IWorkspaceData): void; $acceptWorkspaceData(workspace: IWorkspaceData): void; $handleTextSearchResult(result: IRawFileMatch2, requestId: number): void; } diff --git a/src/vs/workbench/api/node/extHostConfiguration.ts b/src/vs/workbench/api/node/extHostConfiguration.ts index 3e73209ffbb..02b41e0f546 100644 --- a/src/vs/workbench/api/node/extHostConfiguration.ts +++ b/src/vs/workbench/api/node/extHostConfiguration.ts @@ -7,7 +7,7 @@ import { mixin, deepClone } from 'vs/base/common/objects'; import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import * as vscode from 'vscode'; -import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostWorkspace, ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostConfigurationShape, MainThreadConfigurationShape, IWorkspaceConfigurationChangeEventData, IConfigurationInitData } from './extHost.protocol'; import { ConfigurationTarget as ExtHostConfigurationTarget } from './extHostTypes'; import { IConfigurationData, ConfigurationTarget, IConfigurationModel } from 'vs/platform/configuration/common/configuration'; @@ -57,8 +57,10 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { } $initializeConfiguration(data: IConfigurationInitData): void { - this._actual = new ExtHostConfigProvider(this._proxy, this._extHostWorkspace, data); - this._barrier.open(); + this._extHostWorkspace.getWorkspaceProvider().then(workspaceProvider => { + this._actual = new ExtHostConfigProvider(this._proxy, workspaceProvider, data); + this._barrier.open(); + }); } $acceptConfigurationChanged(data: IConfigurationInitData, eventData: IWorkspaceConfigurationChangeEventData): void { @@ -70,11 +72,11 @@ export class ExtHostConfigProvider { private readonly _onDidChangeConfiguration = new Emitter(); private readonly _proxy: MainThreadConfigurationShape; - private readonly _extHostWorkspace: ExtHostWorkspace; + private readonly _extHostWorkspace: ExtHostWorkspaceProvider; private _configurationScopes: { [key: string]: ConfigurationScope }; private _configuration: Configuration; - constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationInitData) { + constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspaceProvider, data: IConfigurationInitData) { this._proxy = proxy; this._extHostWorkspace = extHostWorkspace; this._configuration = ExtHostConfigProvider.parse(data); diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index a4b106f656b..cdf59f777bf 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -16,7 +16,7 @@ import { import * as vscode from 'vscode'; import { Disposable, Position, Location, SourceBreakpoint, FunctionBreakpoint, DebugAdapterServer, DebugAdapterExecutable } from 'vs/workbench/api/node/extHostTypes'; import { ExecutableDebugAdapter, SocketDebugAdapter, AbstractDebugAdapter } from 'vs/workbench/parts/debug/node/debugAdapter'; -import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostWorkspace, ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors'; import { ITerminalSettings, IDebuggerContribution, IConfig, IDebugAdapter, IDebugAdapterServer, IDebugAdapterExecutable, IAdapterDescriptor } from 'vs/workbench/parts/debug/common/debug'; @@ -360,12 +360,12 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } public async $substituteVariables(folderUri: UriComponents | undefined, config: IConfig): Promise { - const configProvider = await this._configurationService.getConfigProvider(); + const [workspaceProvider, configProvider] = await Promise.all([this._workspaceService.getWorkspaceProvider(), this._configurationService.getConfigProvider()]); if (!this._variableResolver) { - this._variableResolver = new ExtHostVariableResolverService(this._workspaceService, this._editorsService, configProvider); + this._variableResolver = new ExtHostVariableResolverService(workspaceProvider, this._editorsService, configProvider); } let ws: IWorkspaceFolder; - const folder = this.getFolder(folderUri); + const folder = this.getFolder(folderUri, workspaceProvider); if (folder) { ws = { uri: folder.uri, @@ -379,10 +379,11 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { return this._variableResolver.resolveAny(ws, config); } - public $startDASession(debugAdapterHandle: number, sessionDto: IDebugSessionDto): Promise { + public async $startDASession(debugAdapterHandle: number, sessionDto: IDebugSessionDto): Promise { + const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); const mythis = this; - const session = this.getSession(sessionDto); + const session = this.getSession(sessionDto, workspaceProvider); return this.getAdapterDescriptor(this.getAdapterFactoryByType(session.type), session).then(x => { const adapter = this.convertToDto(x); @@ -546,7 +547,8 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { this.fireBreakpointChanges(a, r, c); } - public $provideDebugConfigurations(configProviderHandle: number, folderUri: UriComponents | undefined): Promise { + public async $provideDebugConfigurations(configProviderHandle: number, folderUri: UriComponents | undefined): Promise { + const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); let provider = this.getConfigProviderByHandle(configProviderHandle); if (!provider) { return Promise.reject(new Error('no handler found')); @@ -554,10 +556,11 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { if (!provider.provideDebugConfigurations) { return Promise.reject(new Error('handler has no method provideDebugConfigurations')); } - return asPromise(() => provider.provideDebugConfigurations(this.getFolder(folderUri), CancellationToken.None)); + return asPromise(() => provider.provideDebugConfigurations(this.getFolder(folderUri, workspaceProvider), CancellationToken.None)); } - public $resolveDebugConfiguration(configProviderHandle: number, folderUri: UriComponents | undefined, debugConfiguration: vscode.DebugConfiguration): Promise { + public async $resolveDebugConfiguration(configProviderHandle: number, folderUri: UriComponents | undefined, debugConfiguration: vscode.DebugConfiguration): Promise { + const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); let provider = this.getConfigProviderByHandle(configProviderHandle); if (!provider) { return Promise.reject(new Error('no handler found')); @@ -565,11 +568,12 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { if (!provider.resolveDebugConfiguration) { return Promise.reject(new Error('handler has no method resolveDebugConfiguration')); } - return asPromise(() => provider.resolveDebugConfiguration(this.getFolder(folderUri), debugConfiguration, CancellationToken.None)); + return asPromise(() => provider.resolveDebugConfiguration(this.getFolder(folderUri, workspaceProvider), debugConfiguration, CancellationToken.None)); } // TODO@AW legacy - public $legacyDebugAdapterExecutable(configProviderHandle: number, folderUri: UriComponents | undefined): Promise { + public async $legacyDebugAdapterExecutable(configProviderHandle: number, folderUri: UriComponents | undefined): Promise { + const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); let provider = this.getConfigProviderByHandle(configProviderHandle); if (!provider) { return Promise.reject(new Error('no handler found')); @@ -577,41 +581,42 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { if (!provider.debugAdapterExecutable) { return Promise.reject(new Error('handler has no method debugAdapterExecutable')); } - return asPromise(() => provider.debugAdapterExecutable(this.getFolder(folderUri), CancellationToken.None)).then(x => this.convertToDto(x)); + return asPromise(() => provider.debugAdapterExecutable(this.getFolder(folderUri, workspaceProvider), CancellationToken.None)).then(x => this.convertToDto(x)); } - public $provideDebugAdapter(adapterProviderHandle: number, sessionDto: IDebugSessionDto): Promise { + public async $provideDebugAdapter(adapterProviderHandle: number, sessionDto: IDebugSessionDto): Promise { + const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); let adapterProvider = this.getAdapterProviderByHandle(adapterProviderHandle); if (!adapterProvider) { return Promise.reject(new Error('no handler found')); } - return this.getAdapterDescriptor(adapterProvider, this.getSession(sessionDto)).then(x => this.convertToDto(x)); + return this.getAdapterDescriptor(adapterProvider, this.getSession(sessionDto, workspaceProvider)).then(x => this.convertToDto(x)); } - public $acceptDebugSessionStarted(sessionDto: IDebugSessionDto): void { - - this._onDidStartDebugSession.fire(this.getSession(sessionDto)); + public async $acceptDebugSessionStarted(sessionDto: IDebugSessionDto): Promise { + const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); + this._onDidStartDebugSession.fire(this.getSession(sessionDto, workspaceProvider)); } - public $acceptDebugSessionTerminated(sessionDto: IDebugSessionDto): void { - - const session = this.getSession(sessionDto); + public async $acceptDebugSessionTerminated(sessionDto: IDebugSessionDto): Promise { + const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); + const session = this.getSession(sessionDto, workspaceProvider); if (session) { this._onDidTerminateDebugSession.fire(session); this._debugSessions.delete(session.id); } } - public $acceptDebugSessionActiveChanged(sessionDto: IDebugSessionDto): void { - - this._activeDebugSession = sessionDto ? this.getSession(sessionDto) : undefined; + public async $acceptDebugSessionActiveChanged(sessionDto: IDebugSessionDto): Promise { + const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); + this._activeDebugSession = sessionDto ? this.getSession(sessionDto, workspaceProvider) : undefined; this._onDidChangeActiveDebugSession.fire(this._activeDebugSession); } - public $acceptDebugSessionCustomEvent(sessionDto: IDebugSessionDto, event: any): void { - + public async $acceptDebugSessionCustomEvent(sessionDto: IDebugSessionDto, event: any): Promise { + const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); const ee: vscode.DebugSessionCustomEvent = { - session: this.getSession(sessionDto), + session: this.getSession(sessionDto, workspaceProvider), event: event.event, body: event.body }; @@ -776,12 +781,12 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } } - private getSession(dto: IDebugSessionDto): ExtHostDebugSession { + private getSession(dto: IDebugSessionDto, workspaceProvider: ExtHostWorkspaceProvider): ExtHostDebugSession { if (dto) { if (typeof dto === 'string') { return this._debugSessions.get(dto); } else { - const debugSession = new ExtHostDebugSession(this._debugServiceProxy, dto.id, dto.type, dto.name, this.getFolder(dto.folderUri), dto.configuration); + const debugSession = new ExtHostDebugSession(this._debugServiceProxy, dto.id, dto.type, dto.name, this.getFolder(dto.folderUri, workspaceProvider), dto.configuration); this._debugSessions.set(debugSession.id, debugSession); return debugSession; } @@ -789,10 +794,10 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { return undefined; } - private getFolder(_folderUri: UriComponents | undefined): vscode.WorkspaceFolder | undefined { + private getFolder(_folderUri: UriComponents | undefined, workspaceProvider: ExtHostWorkspaceProvider): vscode.WorkspaceFolder | undefined { if (_folderUri) { const folderURI = URI.revive(_folderUri); - return this._workspaceService.resolveWorkspaceFolder(folderURI); + return workspaceProvider.resolveWorkspaceFolder(folderURI); } return undefined; } @@ -853,7 +858,7 @@ export class ExtHostDebugConsole implements vscode.DebugConsole { export class ExtHostVariableResolverService extends AbstractVariableResolverService { - constructor(workspaceService: ExtHostWorkspace, editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider) { + constructor(workspaceService: ExtHostWorkspaceProvider, editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider) { super({ getFolderUri: (folderName: string): URI => { const folders = workspaceService.getWorkspaceFolders(); diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index 8edbff284ea..dbe9d99623e 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -13,12 +13,12 @@ import { URI } from 'vs/base/common/uri'; import * as pfs from 'vs/base/node/pfs'; import { ILogService } from 'vs/platform/log/common/log'; import { createApiFactory, initializeExtensionApi, IExtensionApiFactory } from 'vs/workbench/api/node/extHost.api.impl'; -import { ExtHostExtensionServiceShape, IEnvironment, IInitData, IMainContext, IWorkspaceData, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape } from 'vs/workbench/api/node/extHost.protocol'; +import { ExtHostExtensionServiceShape, IEnvironment, IInitData, IMainContext, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape, IStaticWorkspaceData } from 'vs/workbench/api/node/extHost.protocol'; import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration'; import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionContext, IExtensionMemento, IExtensionModule } from 'vs/workbench/api/node/extHostExtensionActivator'; import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService'; import { ExtHostStorage } from 'vs/workbench/api/node/extHostStorage'; -import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostWorkspace, ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry'; import { connectProxyResolver } from 'vs/workbench/services/extensions/node/proxyResolver'; @@ -26,6 +26,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation'; import * as errors from 'vs/base/common/errors'; import { ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { IWorkspace } from 'vs/platform/workspace/common/workspace'; class ExtensionMemento implements IExtensionMemento { @@ -80,13 +81,13 @@ class ExtensionMemento implements IExtensionMemento { class ExtensionStoragePath { - private readonly _workspace: IWorkspaceData; + private readonly _workspace: IStaticWorkspaceData; private readonly _environment: IEnvironment; private readonly _ready: Promise; private _value: string; - constructor(workspace: IWorkspaceData, environment: IEnvironment) { + constructor(workspace: IStaticWorkspaceData, environment: IEnvironment) { this._workspace = workspace; this._environment = environment; this._ready = this._getOrCreateWorkspaceStoragePath().then(value => this._value = value); @@ -229,9 +230,10 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { private async _initialize(): Promise { try { const configProvider = await this._extHostConfiguration.getConfigProvider(); - await initializeExtensionApi(this, this._extensionApiFactory, this._registry, configProvider); + const workspaceProvider = await this._extHostWorkspace.getWorkspaceProvider(); + await initializeExtensionApi(this, this._extensionApiFactory, this._registry, workspaceProvider, configProvider); // Do this when extension service exists, but extensions are not being activated yet. - await connectProxyResolver(this._extHostWorkspace, configProvider, this, this._extHostLogService, this._mainThreadTelemetryProxy); + await connectProxyResolver(workspaceProvider, configProvider, this, this._extHostLogService, this._mainThreadTelemetryProxy); this._barrier.open(); } catch (err) { errors.onUnexpectedError(err); @@ -473,15 +475,15 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { // -- eager activation // Handle "eager" activation extensions - private _handleEagerExtensions(): Promise { + private _handleEagerExtensions(workspaceProvider: ExtHostWorkspaceProvider): Promise { this._activateByEvent('*', true).then(undefined, (err) => { console.error(err); }); - return this._handleWorkspaceContainsEagerExtensions(this._initData.workspace); + return this._handleWorkspaceContainsEagerExtensions(workspaceProvider.workspace); } - private _handleWorkspaceContainsEagerExtensions(workspace: IWorkspaceData): Promise { + private _handleWorkspaceContainsEagerExtensions(workspace: IWorkspace): Promise { if (!workspace || workspace.folders.length === 0) { return Promise.resolve(undefined); } @@ -493,7 +495,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { ).then(() => { }); } - private _handleWorkspaceContainsEagerExtension(workspace: IWorkspaceData, desc: IExtensionDescription): Promise { + private _handleWorkspaceContainsEagerExtension(workspace: IWorkspace, desc: IExtensionDescription): Promise { const activationEvents = desc.activationEvents; if (!activationEvents) { return Promise.resolve(undefined); @@ -523,7 +525,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { return Promise.all([fileNamePromise, globPatternPromise]).then(() => { }); } - private async _activateIfFileName(workspace: IWorkspaceData, extensionId: ExtensionIdentifier, fileName: string): Promise { + private async _activateIfFileName(workspace: IWorkspace, extensionId: ExtensionIdentifier, fileName: string): Promise { // find exact path for (const { uri } of workspace.folders) { @@ -637,7 +639,8 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { this._started = true; return this._barrier.wait() - .then(() => this._handleEagerExtensions()) + .then(() => this._extHostWorkspace.getWorkspaceProvider()) + .then(workspaceProvider => this._handleEagerExtensions(workspaceProvider)) .then(() => this._handleExtensionTests()) .then(() => { this._extHostLogService.info(`eager extensions activated`); diff --git a/src/vs/workbench/api/node/extHostQuickOpen.ts b/src/vs/workbench/api/node/extHostQuickOpen.ts index c01fbad3ef8..ab869c83dc0 100644 --- a/src/vs/workbench/api/node/extHostQuickOpen.ts +++ b/src/vs/workbench/api/node/extHostQuickOpen.ts @@ -164,7 +164,7 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape { return undefined; } - return this._workspace.getWorkspaceFolders().filter(folder => folder.uri.toString() === selectedFolder.uri.toString())[0]; + return this._workspace.getWorkspaceProvider().then(workspaceProvider => workspaceProvider.getWorkspaceFolders().filter(folder => folder.uri.toString() === selectedFolder.uri.toString())[0]); }); } diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index 6bbb0f26c42..e1f4043495c 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -16,7 +16,7 @@ import { IExtensionDescription } from 'vs/workbench/services/extensions/common/e import { MainContext, MainThreadTaskShape, ExtHostTaskShape, IMainContext } from 'vs/workbench/api/node/extHost.protocol'; import * as types from 'vs/workbench/api/node/extHostTypes'; -import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostWorkspace, ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; import * as vscode from 'vscode'; import { TaskDefinitionDTO, TaskExecutionDTO, TaskPresentationOptionsDTO, ProcessExecutionOptionsDTO, ProcessExecutionDTO, @@ -219,7 +219,7 @@ namespace TaskDTO { }; return result; } - export function to(value: TaskDTO, workspace: ExtHostWorkspace): types.Task { + export function to(value: TaskDTO, workspace: ExtHostWorkspaceProvider): types.Task { if (value === undefined || value === null) { return undefined; } @@ -296,8 +296,8 @@ class TaskExecutionImpl implements vscode.TaskExecution { } namespace TaskExecutionDTO { - export function to(value: TaskExecutionDTO, tasks: ExtHostTask): vscode.TaskExecution { - return new TaskExecutionImpl(tasks, value.id, TaskDTO.to(value.task, tasks.extHostWorkspace)); + export function to(value: TaskExecutionDTO, tasks: ExtHostTask, workspaceProvider: ExtHostWorkspaceProvider): vscode.TaskExecution { + return new TaskExecutionImpl(tasks, value.id, TaskDTO.to(value.task, workspaceProvider)); } export function from(value: vscode.TaskExecution): TaskExecutionDTO { return { @@ -338,10 +338,6 @@ export class ExtHostTask implements ExtHostTaskShape { this._taskExecutions = new Map(); } - public get extHostWorkspace(): ExtHostWorkspace { - return this._workspaceService; - } - public registerTaskProvider(extension: IExtensionDescription, provider: vscode.TaskProvider): vscode.Disposable { if (!provider) { return new types.Disposable(() => { }); @@ -360,10 +356,11 @@ export class ExtHostTask implements ExtHostTaskShape { } public fetchTasks(filter?: vscode.TaskFilter): Promise { - return this._proxy.$fetchTasks(TaskFilterDTO.from(filter)).then((values) => { + return this._proxy.$fetchTasks(TaskFilterDTO.from(filter)).then(async (values) => { let result: vscode.Task[] = []; + const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); for (let value of values) { - let task = TaskDTO.to(value, this._workspaceService); + let task = TaskDTO.to(value, workspaceProvider); if (task) { result.push(task); } @@ -372,17 +369,18 @@ export class ExtHostTask implements ExtHostTaskShape { }); } - public executeTask(extension: IExtensionDescription, task: vscode.Task): Promise { + public async executeTask(extension: IExtensionDescription, task: vscode.Task): Promise { + const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); let tTask = (task as types.Task); // We have a preserved ID. So the task didn't change. if (tTask._id !== undefined) { - return this._proxy.$executeTask(TaskHandleDTO.from(tTask)).then(value => this.getTaskExecution(value, task)); + return this._proxy.$executeTask(TaskHandleDTO.from(tTask)).then(value => this.getTaskExecution(value, workspaceProvider, task)); } else { let dto = TaskDTO.from(task, extension); if (dto === undefined) { return Promise.reject(new Error('Task is not valid')); } - return this._proxy.$executeTask(dto).then(value => this.getTaskExecution(value, task)); + return this._proxy.$executeTask(dto).then(value => this.getTaskExecution(value, workspaceProvider, task)); } } @@ -403,9 +401,10 @@ export class ExtHostTask implements ExtHostTaskShape { return this._onDidExecuteTask.event; } - public $onDidStartTask(execution: TaskExecutionDTO): void { + public async $onDidStartTask(execution: TaskExecutionDTO): Promise { + const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); this._onDidExecuteTask.fire({ - execution: this.getTaskExecution(execution) + execution: this.getTaskExecution(execution, workspaceProvider) }); } @@ -413,8 +412,9 @@ export class ExtHostTask implements ExtHostTaskShape { return this._onDidTerminateTask.event; } - public $OnDidEndTask(execution: TaskExecutionDTO): void { - const _execution = this.getTaskExecution(execution); + public async $OnDidEndTask(execution: TaskExecutionDTO): Promise { + const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); + const _execution = this.getTaskExecution(execution, workspaceProvider); this._taskExecutions.delete(execution.id); this._onDidTerminateTask.fire({ execution: _execution @@ -425,8 +425,9 @@ export class ExtHostTask implements ExtHostTaskShape { return this._onDidTaskProcessStarted.event; } - public $onDidStartTaskProcess(value: TaskProcessStartedDTO): void { - const execution = this.getTaskExecution(value.id); + public async $onDidStartTaskProcess(value: TaskProcessStartedDTO): Promise { + const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); + const execution = this.getTaskExecution(value.id, workspaceProvider); if (execution) { this._onDidTaskProcessStarted.fire({ execution: execution, @@ -439,8 +440,9 @@ export class ExtHostTask implements ExtHostTaskShape { return this._onDidTaskProcessEnded.event; } - public $onDidEndTaskProcess(value: TaskProcessEndedDTO): void { - const execution = this.getTaskExecution(value.id); + public async $onDidEndTaskProcess(value: TaskProcessEndedDTO): Promise { + const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); + const execution = this.getTaskExecution(value.id, workspaceProvider); if (execution) { this._onDidTaskProcessEnded.fire({ execution: execution, @@ -473,13 +475,14 @@ export class ExtHostTask implements ExtHostTaskShape { public async $resolveVariables(uriComponents: UriComponents, toResolve: { process?: { name: string; cwd?: string; path?: string }, variables: string[] }): Promise<{ process?: string, variables: { [key: string]: string; } }> { const configProvider = await this._configurationService.getConfigProvider(); + const workspaceProvider = await this._workspaceService.getWorkspaceProvider(); let uri: URI = URI.revive(uriComponents); let result = { process: undefined as string, variables: Object.create(null) }; - let workspaceFolder = this._workspaceService.resolveWorkspaceFolder(uri); - let resolver = new ExtHostVariableResolverService(this._workspaceService, this._editorService, configProvider); + let workspaceFolder = workspaceProvider.resolveWorkspaceFolder(uri); + let resolver = new ExtHostVariableResolverService(workspaceProvider, this._editorService, configProvider); let ws: IWorkspaceFolder = { uri: workspaceFolder.uri, name: workspaceFolder.name, @@ -512,7 +515,7 @@ export class ExtHostTask implements ExtHostTaskShape { return this._handleCounter++; } - private getTaskExecution(execution: TaskExecutionDTO | string, task?: vscode.Task): TaskExecutionImpl { + private getTaskExecution(execution: TaskExecutionDTO | string, workspaceProvider: ExtHostWorkspaceProvider, task?: vscode.Task): TaskExecutionImpl { if (typeof execution === 'string') { return this._taskExecutions.get(execution); } @@ -521,7 +524,7 @@ export class ExtHostTask implements ExtHostTaskShape { if (result) { return result; } - result = new TaskExecutionImpl(this, execution.id, task ? task : TaskDTO.to(execution.task, this._workspaceService)); + result = new TaskExecutionImpl(this, execution.id, task ? task : TaskDTO.to(execution.task, workspaceProvider)); this._taskExecutions.set(execution.id, result); return result; } diff --git a/src/vs/workbench/api/node/extHostWorkspace.ts b/src/vs/workbench/api/node/extHostWorkspace.ts index 00fa6ec1cf1..6a4053b9910 100644 --- a/src/vs/workbench/api/node/extHostWorkspace.ts +++ b/src/vs/workbench/api/node/extHostWorkspace.ts @@ -23,8 +23,9 @@ import { Range, RelativePattern } from 'vs/workbench/api/node/extHostTypes'; import { ITextQueryBuilderOptions } from 'vs/workbench/parts/search/common/queryBuilder'; import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import * as vscode from 'vscode'; -import { ExtHostWorkspaceShape, IMainContext, IWorkspaceData, MainContext, MainThreadMessageServiceShape, MainThreadWorkspaceShape } from './extHost.protocol'; +import { ExtHostWorkspaceShape, IWorkspaceData, MainThreadMessageServiceShape, MainThreadWorkspaceShape, IMainContext, MainContext } from './extHost.protocol'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { Barrier } from 'vs/base/common/async'; function isFolderEqual(folderA: URI, folderB: URI): boolean { return isEqual(folderA, folderB, !isLinux); @@ -142,13 +143,55 @@ class ExtHostWorkspaceImpl extends Workspace { export class ExtHostWorkspace implements ExtHostWorkspaceShape { + private readonly _mainContext: IMainContext; + private readonly _logService: ILogService; + private readonly _requestIdProvider: Counter; + private readonly _barrier: Barrier; + private _actual: ExtHostWorkspaceProvider; + + constructor( + mainContext: IMainContext, + logService: ILogService, + requestIdProvider: Counter + ) { + this._mainContext = mainContext; + this._logService = logService; + this._requestIdProvider = requestIdProvider; + this._barrier = new Barrier(); + this._actual = null; + } + + public getWorkspaceProvider(): Promise { + return this._barrier.wait().then(_ => this._actual); + } + + $initializeWorkspace(data: IWorkspaceData): void { + this._actual = new ExtHostWorkspaceProvider(this._mainContext, data, this._logService, this._requestIdProvider); + this._barrier.open(); + } + + $acceptWorkspaceData(workspace: IWorkspaceData): void { + if (this._actual) { + this._actual.$acceptWorkspaceData(workspace); + } + } + + $handleTextSearchResult(result: IRawFileMatch2, requestId: number): void { + if (this._actual) { + this._actual.$handleTextSearchResult(result, requestId); + } + } + +} +export class ExtHostWorkspaceProvider { + private readonly _onDidChangeWorkspace = new Emitter(); - private readonly _proxy: MainThreadWorkspaceShape; private _confirmedWorkspace: ExtHostWorkspaceImpl; private _unconfirmedWorkspace: ExtHostWorkspaceImpl; - private _messageService: MainThreadMessageServiceShape; + private readonly _proxy: MainThreadWorkspaceShape; + private readonly _messageService: MainThreadMessageServiceShape; readonly onDidChangeWorkspace: Event = this._onDidChangeWorkspace.event; diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index b54507fb37e..99b3fa2d6f0 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -426,7 +426,6 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { }, workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : { configuration: workspace.configuration, - folders: workspace.folders, id: workspace.id, name: this._labelService.getWorkspaceLabel(workspace) }, diff --git a/src/vs/workbench/services/extensions/node/extensionHostMain.ts b/src/vs/workbench/services/extensions/node/extensionHostMain.ts index ec9cd8be9e4..1a9fa2f0b5f 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostMain.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostMain.ts @@ -49,7 +49,6 @@ export class ExtensionHostMain { private _isTerminating: boolean; private readonly _environment: IEnvironment; private readonly _extensionService: ExtHostExtensionService; - private readonly _extHostConfiguration: ExtHostConfiguration; private readonly _extHostLogService: ExtHostLogService; private disposables: IDisposable[] = []; @@ -74,13 +73,13 @@ export class ExtensionHostMain { this.disposables.push(this._extHostLogService); this._searchRequestIdProvider = new Counter(); - const extHostWorkspace = new ExtHostWorkspace(rpcProtocol, initData.workspace, this._extHostLogService, this._searchRequestIdProvider); + const extHostWorkspace = new ExtHostWorkspace(rpcProtocol, this._extHostLogService, this._searchRequestIdProvider); this._extHostLogService.info('extension host started'); this._extHostLogService.trace('initData', initData); - this._extHostConfiguration = new ExtHostConfiguration(rpcProtocol.getProxy(MainContext.MainThreadConfiguration), extHostWorkspace); - this._extensionService = new ExtHostExtensionService(nativeExit, initData, rpcProtocol, extHostWorkspace, this._extHostConfiguration, this._extHostLogService); + const extHostConfiguraiton = new ExtHostConfiguration(rpcProtocol.getProxy(MainContext.MainThreadConfiguration), extHostWorkspace); + this._extensionService = new ExtHostExtensionService(nativeExit, initData, rpcProtocol, extHostWorkspace, extHostConfiguraiton, this._extHostLogService); // error forwarding and stack trace scanning Error.stackTraceLimit = 100; // increase number of stack frames (from 10, https://github.com/v8/v8/wiki/Stack-Trace-API) diff --git a/src/vs/workbench/services/extensions/node/proxyResolver.ts b/src/vs/workbench/services/extensions/node/proxyResolver.ts index c330eb973a2..bd4ab8800d6 100644 --- a/src/vs/workbench/services/extensions/node/proxyResolver.ts +++ b/src/vs/workbench/services/extensions/node/proxyResolver.ts @@ -8,7 +8,7 @@ import * as https from 'https'; import * as nodeurl from 'url'; import { assign } from 'vs/base/common/objects'; -import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostConfigProvider } from 'vs/workbench/api/node/extHostConfiguration'; import { ProxyAgent } from 'vscode-proxy-agent'; import { MainThreadTelemetryShape } from 'vs/workbench/api/node/extHost.protocol'; @@ -18,7 +18,7 @@ import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionS import { URI } from 'vs/base/common/uri'; export function connectProxyResolver( - extHostWorkspace: ExtHostWorkspace, + extHostWorkspace: ExtHostWorkspaceProvider, configProvider: ExtHostConfigProvider, extensionService: ExtHostExtensionService, extHostLogService: ExtHostLogService, @@ -32,7 +32,7 @@ export function connectProxyResolver( const maxCacheEntries = 5000; // Cache can grow twice that much due to 'oldCache'. function createProxyAgent( - extHostWorkspace: ExtHostWorkspace, + extHostWorkspace: ExtHostWorkspaceProvider, configProvider: ExtHostConfigProvider, extHostLogService: ExtHostLogService, mainThreadTelemetry: MainThreadTelemetryShape 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 995f762f4b4..b58db1f2440 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { URI } from 'vs/base/common/uri'; -import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostConfigProvider } from 'vs/workbench/api/node/extHostConfiguration'; import { MainThreadConfigurationShape, IConfigurationInitData } from 'vs/workbench/api/node/extHost.protocol'; import { ConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; @@ -31,7 +31,7 @@ suite('ExtHostConfiguration', function () { if (!shape) { shape = new class extends mock() { }; } - return new ExtHostConfigProvider(shape, new ExtHostWorkspace(new TestRPCProtocol(), null, new NullLogService(), new Counter()), createConfigurationData(contents)); + return new ExtHostConfigProvider(shape, new ExtHostWorkspaceProvider(new TestRPCProtocol(), null, new NullLogService(), new Counter()), createConfigurationData(contents)); } function createConfigurationData(contents: any): IConfigurationInitData { @@ -265,7 +265,7 @@ suite('ExtHostConfiguration', function () { test('inspect in no workspace context', function () { const testObject = new ExtHostConfigProvider( new class extends mock() { }, - new ExtHostWorkspace(new TestRPCProtocol(), null, new NullLogService(), new Counter()), + new ExtHostWorkspaceProvider(new TestRPCProtocol(), null, new NullLogService(), new Counter()), { defaults: new ConfigurationModel({ 'editor': { @@ -308,7 +308,7 @@ suite('ExtHostConfiguration', function () { folders[workspaceUri.toString()] = workspace; const testObject = new ExtHostConfigProvider( new class extends mock() { }, - new ExtHostWorkspace(new TestRPCProtocol(), { + new ExtHostWorkspaceProvider(new TestRPCProtocol(), { 'id': 'foo', 'folders': [aWorkspaceFolder(URI.file('foo'), 0)], 'name': 'foo' @@ -382,7 +382,7 @@ suite('ExtHostConfiguration', function () { const testObject = new ExtHostConfigProvider( new class extends mock() { }, - new ExtHostWorkspace(new TestRPCProtocol(), { + new ExtHostWorkspaceProvider(new TestRPCProtocol(), { 'id': 'foo', 'folders': [aWorkspaceFolder(firstRoot, 0), aWorkspaceFolder(secondRoot, 1)], 'name': 'foo' @@ -591,7 +591,7 @@ suite('ExtHostConfiguration', function () { const workspaceFolder = aWorkspaceFolder(URI.file('folder1'), 0); const testObject = new ExtHostConfigProvider( new class extends mock() { }, - new ExtHostWorkspace(new TestRPCProtocol(), { + new ExtHostWorkspaceProvider(new TestRPCProtocol(), { 'id': 'foo', 'folders': [workspaceFolder], 'name': 'foo' 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 45f61e09759..de017d9d841 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { URI } from 'vs/base/common/uri'; import { basename } from 'path'; -import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; import { TestRPCProtocol } from './testRPCProtocol'; import { normalize } from 'vs/base/common/paths'; import { IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace'; @@ -30,7 +30,7 @@ suite('ExtHostWorkspace', function () { version: undefined! }; - function assertAsRelativePath(workspace: ExtHostWorkspace, input: string, expected: string, includeWorkspace?: boolean) { + function assertAsRelativePath(workspace: ExtHostWorkspaceProvider, input: string, expected: string, includeWorkspace?: boolean) { const actual = workspace.getRelativePath(input, includeWorkspace); if (actual === expected) { assert.ok(true); @@ -41,7 +41,7 @@ suite('ExtHostWorkspace', function () { test('asRelativePath', () => { - const ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/Applications/NewsWoWBot'), 0)], name: 'Test' }, new NullLogService(), new Counter()); + const ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/Applications/NewsWoWBot'), 0)], name: 'Test' }, new NullLogService(), new Counter()); 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', @@ -55,7 +55,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 TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService(), new Counter()); + const ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService(), new Counter()); assertAsRelativePath(ws, (input), input); @@ -64,20 +64,20 @@ suite('ExtHostWorkspace', function () { }); test('asRelativePath, no workspace', function () { - const ws = new ExtHostWorkspace(new TestRPCProtocol(), null!, new NullLogService(), new Counter()); + const ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), null!, new NullLogService(), new Counter()); assertAsRelativePath(ws, (''), ''); assertAsRelativePath(ws, ('/foo/bar'), '/foo/bar'); }); test('asRelativePath, multiple folders', function () { - const ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter()); + const ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter()); 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 TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter()); + const mrws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter()); assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt'); assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt', true); @@ -89,7 +89,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 TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0)], name: 'Test' }, new NullLogService(), new Counter()); + const srws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0)], name: 'Test' }, new NullLogService(), new Counter()); 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); @@ -99,24 +99,24 @@ suite('ExtHostWorkspace', function () { }); test('getPath, legacy', function () { - let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); + let ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); assert.equal(ws.getPath(), undefined); - ws = new ExtHostWorkspace(new TestRPCProtocol(), null!, new NullLogService(), new Counter()); + ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), null!, new NullLogService(), new Counter()); assert.equal(ws.getPath(), undefined); - ws = new ExtHostWorkspace(new TestRPCProtocol(), undefined!, new NullLogService(), new Counter()); + ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), undefined!, new NullLogService(), new Counter()); assert.equal(ws.getPath(), undefined); - ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('Folder'), 0), aWorkspaceFolderData(URI.file('Another/Folder'), 1)] }, new NullLogService(), new Counter()); + ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('Folder'), 0), aWorkspaceFolderData(URI.file('Another/Folder'), 1)] }, new NullLogService(), new Counter()); assert.equal(ws.getPath().replace(/\\/g, '/'), '/Folder'); - ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('/Folder'), 0)] }, new NullLogService(), new Counter()); + ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('/Folder'), 0)] }, new NullLogService(), new Counter()); assert.equal(ws.getPath().replace(/\\/g, '/'), '/Folder'); }); test('WorkspaceFolder has name and index', function () { - const ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter()); + const ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter()); const [one, two] = ws.getWorkspaceFolders(); @@ -127,7 +127,7 @@ suite('ExtHostWorkspace', function () { }); test('getContainingWorkspaceFolder', () => { - const ws = new ExtHostWorkspace(new TestRPCProtocol(), { + const ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [ @@ -175,7 +175,7 @@ suite('ExtHostWorkspace', function () { }); test('Multiroot change event should have a delta, #29641', function (done) { - let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); + let ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); let finished = false; const finish = (error?: any) => { @@ -238,7 +238,7 @@ suite('ExtHostWorkspace', function () { }); test('Multiroot change keeps existing workspaces live', function () { - let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService(), new Counter()); + let ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService(), new Counter()); let firstFolder = ws.getWorkspaceFolders()[0]; ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar2'), 0), aWorkspaceFolderData(URI.parse('foo:bar'), 1, 'renamed')] }); @@ -258,7 +258,7 @@ suite('ExtHostWorkspace', function () { }); test('updateWorkspaceFolders - invalid arguments', function () { - let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); + let ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, null!, null!)); assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 0)); @@ -267,7 +267,7 @@ suite('ExtHostWorkspace', function () { assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, 0)); assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, -1)); - ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService(), new Counter()); + ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService(), new Counter()); assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 1, 1)); assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2)); @@ -289,7 +289,7 @@ suite('ExtHostWorkspace', function () { assertRegistered: undefined! }; - const ws = new ExtHostWorkspace(protocol, { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); + const ws = new ExtHostWorkspaceProvider(protocol, { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); // // Add one folder @@ -522,7 +522,7 @@ suite('ExtHostWorkspace', function () { } }; - let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); + let ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter()); let sub = ws.onDidChangeWorkspace(e => { try { assert.throws(() => { @@ -541,7 +541,7 @@ suite('ExtHostWorkspace', function () { }); test('`vscode.workspace.getWorkspaceFolder(file)` don\'t return workspace folder when file open from command line. #36221', function () { - let ws = new ExtHostWorkspace(new TestRPCProtocol(), { + let ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [ aWorkspaceFolderData(URI.file('c:/Users/marek/Desktop/vsc_test/'), 0) ] From 84e812d656c93da7601f334047549b17d7f1abf6 Mon Sep 17 00:00:00 2001 From: Derek Ziemba Date: Wed, 6 Feb 2019 20:05:49 -0600 Subject: [PATCH 002/207] Either open in Peek or go to definition, not BOTH! * Use peek if there are multiple definitions * When using peek, will not navigate to the best match in editor and cause you to lose your spot * If there is only one definition, navigate to best match and NOT open peek --- .../contrib/goToDefinition/goToDefinitionCommands.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts b/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts index 4f99a51c6a6..2f52eccc2f5 100644 --- a/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts +++ b/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts @@ -130,17 +130,13 @@ export class DefinitionAction extends EditorAction { const msg = model.getAriaMessage(); alert(msg); - if (this._configuration.openInPeek) { + if (this._configuration.openInPeek || model.references.length > 1) { this._openInPeek(editorService, editor, model); } else if (editor.hasModel()) { const next = model.nearestReference(editor.getModel().uri, editor.getPosition()); if (next) { - const targetEditor = await this._openReference(editor, editorService, next, this._configuration.openToSide); - if (targetEditor && model.references.length > 1) { - this._openInPeek(editorService, targetEditor, model); - } else { - model.dispose(); - } + await this._openReference(editor, editorService, next, this._configuration.openToSide); + model.dispose(); } } } From 545f9988d198e594e0722d74a096f31d0f10cc51 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 7 Feb 2019 12:51:23 +0100 Subject: [PATCH 003/207] Fix missing import --- src/vs/workbench/api/node/extHostDebugService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index cb47445b4a0..66b12c853bd 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -16,7 +16,7 @@ import { import * as vscode from 'vscode'; import { Disposable, Position, Location, SourceBreakpoint, FunctionBreakpoint, DebugAdapterServer, DebugAdapterExecutable } from 'vs/workbench/api/node/extHostTypes'; import { ExecutableDebugAdapter, SocketDebugAdapter, AbstractDebugAdapter } from 'vs/workbench/contrib/debug/node/debugAdapter'; -import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; +import { ExtHostWorkspace, ExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors'; import { ITerminalSettings, IDebuggerContribution, IConfig, IDebugAdapter, IDebugAdapterServer, IDebugAdapterExecutable, IAdapterDescriptor } from 'vs/workbench/contrib/debug/common/debug'; From 89e24a15a39b2b60753f570d3b3e75b51f12eb6d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 7 Feb 2019 15:17:35 +0100 Subject: [PATCH 004/207] update tsconfig --- src/tsconfig.json | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/tsconfig.json b/src/tsconfig.json index 4b9f4170455..91ef6b4546f 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -4,13 +4,24 @@ "removeComments": false, "preserveConstEnums": true, "sourceMap": false, - "outDir": "../out" + "outDir": "../out", + "target": "es6", + "lib": [ + "dom", + "webworker", + "es5", + "es2015.promise", + "es2015.iterable", + "es2015.collection" + ], }, "include": [ "./typings", "./vs" ], "exclude": [ - "./typings/require-monaco.d.ts" + "./typings/require-monaco.d.ts", + "./typings/es6-promise.d.ts", + "./typings/lib.ie11_safe_es6.d.ts", ] -} \ No newline at end of file +} From 69630b9ae5c4a00883fd8f2dacd576bf36a963d5 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 7 Feb 2019 15:46:32 +0100 Subject: [PATCH 005/207] fix tsconfig.json json --- src/tsconfig.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tsconfig.json b/src/tsconfig.json index 91ef6b4546f..488b1134918 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -13,7 +13,7 @@ "es2015.promise", "es2015.iterable", "es2015.collection" - ], + ] }, "include": [ "./typings", @@ -22,6 +22,6 @@ "exclude": [ "./typings/require-monaco.d.ts", "./typings/es6-promise.d.ts", - "./typings/lib.ie11_safe_es6.d.ts", + "./typings/lib.ie11_safe_es6.d.ts" ] } From ebf6e373e41a6ddddf135f119271cafa5b7bacd7 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 7 Feb 2019 16:25:01 +0100 Subject: [PATCH 006/207] better WeakMap declaration --- src/typings/lib.ie11_safe_es6.d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/typings/lib.ie11_safe_es6.d.ts b/src/typings/lib.ie11_safe_es6.d.ts index ef2e2db7da5..43bde6f7c64 100644 --- a/src/typings/lib.ie11_safe_es6.d.ts +++ b/src/typings/lib.ie11_safe_es6.d.ts @@ -59,7 +59,7 @@ interface SetConstructor { declare var Set: SetConstructor; -interface WeakMap { +interface WeakMap { delete(key: K): boolean; get(key: K): V | undefined; has(key: K): boolean; @@ -70,9 +70,9 @@ interface WeakMap { interface WeakMapConstructor { new(): WeakMap; - new (): WeakMap; + new (): WeakMap; // new (entries?: [K, V][]): WeakMap; - readonly prototype: WeakMap; + readonly prototype: WeakMap; } declare var WeakMap: WeakMapConstructor; From 54c3351ae5a465573d89d693879fe3b9938c04a5 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 7 Feb 2019 16:25:22 +0100 Subject: [PATCH 007/207] tweak tsconfig.json (less differences, less libs) --- src/tsconfig.json | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/tsconfig.json b/src/tsconfig.json index 488b1134918..2458f614ce1 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -8,11 +8,9 @@ "target": "es6", "lib": [ "dom", - "webworker", "es5", - "es2015.promise", "es2015.iterable", - "es2015.collection" + "webworker.importscripts" ] }, "include": [ @@ -20,8 +18,6 @@ "./vs" ], "exclude": [ - "./typings/require-monaco.d.ts", - "./typings/es6-promise.d.ts", - "./typings/lib.ie11_safe_es6.d.ts" + "./typings/require-monaco.d.ts" ] } From b5c6ec384d45032b592797544980566ae8dfa6db Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 7 Feb 2019 16:37:44 +0100 Subject: [PATCH 008/207] make types#create fit for classes --- src/vs/base/common/types.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/vs/base/common/types.ts b/src/vs/base/common/types.ts index c05da11b423..b41f819ee4d 100644 --- a/src/vs/base/common/types.ts +++ b/src/vs/base/common/types.ts @@ -161,8 +161,18 @@ export function validateConstraint(arg: any, constraint: TypeConstraint | undefi * any additional argument supplied. */ export function create(ctor: Function, ...args: any[]): any { - let obj = Object.create(ctor.prototype); - ctor.apply(obj, args); - - return obj; + if (isNativeClass(ctor)) { + return new (ctor as any)(...args); + } else { + let obj = Object.create(ctor.prototype); + ctor.apply(obj, args); + return obj; + } +} + +// https://stackoverflow.com/a/32235645/1499159 +function isNativeClass(thing): boolean { + return typeof thing === 'function' + && thing.hasOwnProperty('prototype') + && !thing.hasOwnProperty('arguments'); } From ecad367bef5151878e925bcf35ab6dc53bb550e5 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 09:11:20 -0800 Subject: [PATCH 009/207] Strict null auto add --- src/tsconfig.strictNullChecks.json | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 23725549fe4..6d3d5421664 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -272,6 +272,8 @@ "./vs/platform/files/test/files.test.ts", "./vs/platform/history/common/history.ts", "./vs/platform/history/electron-main/historyMainService.ts", + "./vs/platform/history/electron-main/historyStorage.ts", + "./vs/platform/history/test/electron-main/historyStorage.test.ts", "./vs/platform/instantiation/common/descriptors.ts", "./vs/platform/instantiation/common/extensions.ts", "./vs/platform/instantiation/common/graph.ts", @@ -482,8 +484,6 @@ "./vs/workbench/common/theme.ts", "./vs/workbench/common/viewlet.ts", "./vs/workbench/common/views.ts", - "./vs/workbench/electron-browser/resources.ts", - "./vs/workbench/electron-browser/window.ts", "./vs/workbench/contrib/backup/common/backupRestorer.ts", "./vs/workbench/contrib/cli/electron-browser/cli.contribution.ts", "./vs/workbench/contrib/codeEditor/browser/menuPreventer.ts", @@ -635,6 +635,8 @@ "./vs/workbench/contrib/themes/electron-browser/themes.contribution.ts", "./vs/workbench/contrib/url/electron-browser/url.contribution.ts", "./vs/workbench/contrib/webview/electron-browser/webviewProtocols.ts", + "./vs/workbench/electron-browser/resources.ts", + "./vs/workbench/electron-browser/window.ts", "./vs/workbench/services/activity/common/activity.ts", "./vs/workbench/services/backup/common/backup.ts", "./vs/workbench/services/backup/node/backupFileService.ts", @@ -653,9 +655,9 @@ "./vs/workbench/services/decorations/browser/decorationsService.ts", "./vs/workbench/services/decorations/test/browser/decorationsService.test.ts", "./vs/workbench/services/dialogs/electron-browser/dialogService.ts", - "./vs/workbench/services/editor/common/editorService.ts", - "./vs/workbench/services/editor/common/editorGroupsService.ts", "./vs/workbench/services/editor/browser/codeEditorService.ts", + "./vs/workbench/services/editor/common/editorGroupsService.ts", + "./vs/workbench/services/editor/common/editorService.ts", "./vs/workbench/services/extensions/common/extensionHostProtocol.ts", "./vs/workbench/services/extensions/common/extensions.ts", "./vs/workbench/services/extensions/common/extensionsRegistry.ts", @@ -745,4 +747,4 @@ "exclude": [ "./typings/require-monaco.d.ts" ] -} +} \ No newline at end of file From 5076c35a534f9ee03a4fead0ad5b858fcaa260eb Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 09:54:21 -0800 Subject: [PATCH 010/207] Strict null work on mainThread and extHost --- src/tsconfig.strictNullChecks.json | 12 ++++++ .../editor/common/services/resolverService.ts | 2 +- .../mainThreadConfiguration.ts | 2 +- .../api/electron-browser/mainThreadDialogs.ts | 4 +- .../mainThreadDocumentContentProviders.ts | 9 +++-- .../api/electron-browser/mainThreadEditor.ts | 40 ++++++++++--------- .../mainThreadMessageService.ts | 10 ++--- .../electron-browser/mainThreadQuickOpen.ts | 10 ++--- .../api/electron-browser/mainThreadSCM.ts | 14 +++---- .../electron-browser/mainThreadTreeViews.ts | 16 ++++---- src/vs/workbench/api/node/extHost.protocol.ts | 12 +++--- .../workbench/api/node/extHostDecorations.ts | 10 +++-- src/vs/workbench/api/node/extHostDialogs.ts | 8 ++-- .../workbench/api/node/extHostDocumentData.ts | 14 +++---- src/vs/workbench/api/node/extHostWorkspace.ts | 32 +++++++-------- src/vs/workbench/common/views.ts | 2 +- src/vs/workbench/contrib/scm/common/scm.ts | 2 +- ...mainThreadDocumentContentProviders.test.ts | 2 +- 18 files changed, 111 insertions(+), 90 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 6d3d5421664..abd24f54d07 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -403,13 +403,20 @@ "./vs/workbench/api/electron-browser/extHostCustomers.ts", "./vs/workbench/api/electron-browser/mainThreadClipboard.ts", "./vs/workbench/api/electron-browser/mainThreadCommands.ts", + "./vs/workbench/api/electron-browser/mainThreadConfiguration.ts", "./vs/workbench/api/electron-browser/mainThreadDiagnostics.ts", + "./vs/workbench/api/electron-browser/mainThreadDialogs.ts", + "./vs/workbench/api/electron-browser/mainThreadDocumentContentProviders.ts", + "./vs/workbench/api/electron-browser/mainThreadEditor.ts", "./vs/workbench/api/electron-browser/mainThreadErrors.ts", "./vs/workbench/api/electron-browser/mainThreadFileSystem.ts", "./vs/workbench/api/electron-browser/mainThreadFileSystemEventService.ts", "./vs/workbench/api/electron-browser/mainThreadLanguages.ts", "./vs/workbench/api/electron-browser/mainThreadLogService.ts", + "./vs/workbench/api/electron-browser/mainThreadMessageService.ts", "./vs/workbench/api/electron-browser/mainThreadProgress.ts", + "./vs/workbench/api/electron-browser/mainThreadQuickOpen.ts", + "./vs/workbench/api/electron-browser/mainThreadSCM.ts", "./vs/workbench/api/electron-browser/mainThreadStatusBar.ts", "./vs/workbench/api/electron-browser/mainThreadStorage.ts", "./vs/workbench/api/electron-browser/mainThreadTelemetry.ts", @@ -418,7 +425,9 @@ "./vs/workbench/api/electron-browser/mainThreadWorkspace.ts", "./vs/workbench/api/node/extHost.protocol.ts", "./vs/workbench/api/node/extHostClipboard.ts", + "./vs/workbench/api/node/extHostDecorations.ts", "./vs/workbench/api/node/extHostDialogs.ts", + "./vs/workbench/api/node/extHostDocumentData.ts", "./vs/workbench/api/node/extHostExtensionActivator.ts", "./vs/workbench/api/node/extHostHeapService.ts", "./vs/workbench/api/node/extHostLogService.ts", @@ -738,9 +747,12 @@ "./vs/workbench/test/browser/viewlet.test.ts", "./vs/workbench/test/common/editor/editorOptions.test.ts", "./vs/workbench/test/common/notifications.test.ts", + "./vs/workbench/test/electron-browser/api/extHostDocumentData.test.ts", + "./vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts", "./vs/workbench/test/electron-browser/api/extHostTypes.test.ts", "./vs/workbench/test/electron-browser/api/mainThreadCommands.test.ts", "./vs/workbench/test/electron-browser/api/mainThreadDiagnostics.test.ts", + "./vs/workbench/test/electron-browser/api/mainThreadDocumentContentProviders.test.ts", "./vs/workbench/test/electron-browser/api/mock.ts", "./vs/workbench/test/electron-browser/api/testRPCProtocol.ts" ], diff --git a/src/vs/editor/common/services/resolverService.ts b/src/vs/editor/common/services/resolverService.ts index 7cc218bec57..e000629c298 100644 --- a/src/vs/editor/common/services/resolverService.ts +++ b/src/vs/editor/common/services/resolverService.ts @@ -36,7 +36,7 @@ export interface ITextModelContentProvider { /** * Given a resource, return the content of the resource as `ITextModel`. */ - provideTextContent(resource: URI): Promise | null; + provideTextContent(resource: URI): Promise | null; } export interface ITextEditorModel extends IEditorModel { diff --git a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts index 81929b60a66..265994c37dc 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts @@ -34,7 +34,7 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape { } private _getConfigurationData(): IConfigurationInitData { - const configurationData: IConfigurationInitData = { ...this.configurationService.getConfigurationData(), configurationScopes: {} }; + const configurationData: IConfigurationInitData = { ...(this.configurationService.getConfigurationData()!), configurationScopes: {} }; // Send configurations scopes only in development mode. if (!this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment) { configurationData.configurationScopes = getScopes(); diff --git a/src/vs/workbench/api/electron-browser/mainThreadDialogs.ts b/src/vs/workbench/api/electron-browser/mainThreadDialogs.ts index a4d35e062f7..e9ea053a2bd 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDialogs.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDialogs.ts @@ -23,11 +23,11 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape { // } - $showOpenDialog(options: MainThreadDialogOpenOptions): Promise { + $showOpenDialog(options: MainThreadDialogOpenOptions): Promise { return Promise.resolve(this._fileDialogService.showOpenDialog(MainThreadDialogs._convertOpenOptions(options))); } - $showSaveDialog(options: MainThreadDialogSaveOptions): Promise { + $showSaveDialog(options: MainThreadDialogSaveOptions): Promise { return Promise.resolve(this._fileDialogService.showSaveDialog(MainThreadDialogs._convertSaveOptions(options))); } diff --git a/src/vs/workbench/api/electron-browser/mainThreadDocumentContentProviders.ts b/src/vs/workbench/api/electron-browser/mainThreadDocumentContentProviders.ts index 45150b6a9ca..315c05e1b00 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDocumentContentProviders.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDocumentContentProviders.ts @@ -41,7 +41,7 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon $registerTextContentProvider(handle: number, scheme: string): void { const registration = this._textModelResolverService.registerTextModelContentProvider(scheme, { - provideTextContent: (uri: URI): Promise => { + provideTextContent: (uri: URI): Promise => { return this._proxy.$provideTextDocumentContent(handle, uri).then(value => { if (typeof value === 'string') { const firstLineText = value.substr(0, 1 + value.search(/\r?\n/)); @@ -70,8 +70,9 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon } // cancel and dispose an existing update - if (this._pendingUpdate.has(model.id)) { - this._pendingUpdate.get(model.id).cancel(); + const pending = this._pendingUpdate.get(model.id); + if (pending) { + pending.cancel(); } // create and keep update token @@ -86,7 +87,7 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon // ignore this return; } - if (edits.length > 0) { + if (edits && edits.length > 0) { // use the evil-edit as these models show in readonly-editor only model.applyEdits(edits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text))); } diff --git a/src/vs/workbench/api/electron-browser/mainThreadEditor.ts b/src/vs/workbench/api/electron-browser/mainThreadEditor.ts index 38ab78b31c8..a5f9775cb68 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadEditor.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadEditor.ts @@ -24,14 +24,14 @@ export interface IFocusTracker { export class MainThreadTextEditorProperties { - public static readFromEditor(previousProperties: MainThreadTextEditorProperties, model: ITextModel, codeEditor: ICodeEditor): MainThreadTextEditorProperties { + public static readFromEditor(previousProperties: MainThreadTextEditorProperties | null, model: ITextModel, codeEditor: ICodeEditor | null): MainThreadTextEditorProperties { const selections = MainThreadTextEditorProperties._readSelectionsFromCodeEditor(previousProperties, codeEditor); const options = MainThreadTextEditorProperties._readOptionsFromCodeEditor(previousProperties, model, codeEditor); const visibleRanges = MainThreadTextEditorProperties._readVisibleRangesFromCodeEditor(previousProperties, codeEditor); return new MainThreadTextEditorProperties(selections, options, visibleRanges); } - private static _readSelectionsFromCodeEditor(previousProperties: MainThreadTextEditorProperties, codeEditor: ICodeEditor): Selection[] { + private static _readSelectionsFromCodeEditor(previousProperties: MainThreadTextEditorProperties | null, codeEditor: ICodeEditor | null): Selection[] { let result: Selection[] | null = null; if (codeEditor) { result = codeEditor.getSelections(); @@ -45,10 +45,14 @@ export class MainThreadTextEditorProperties { return result; } - private static _readOptionsFromCodeEditor(previousProperties: MainThreadTextEditorProperties, model: ITextModel, codeEditor: ICodeEditor): IResolvedTextEditorConfiguration { + private static _readOptionsFromCodeEditor(previousProperties: MainThreadTextEditorProperties | null, model: ITextModel, codeEditor: ICodeEditor | null): IResolvedTextEditorConfiguration { if (model.isDisposed()) { - // shutdown time - return previousProperties.options; + if (previousProperties) { + // shutdown time + return previousProperties.options; + } else { + throw new Error('No valid properties'); + } } let cursorStyle: TextEditorCursorStyle; @@ -85,7 +89,7 @@ export class MainThreadTextEditorProperties { }; } - private static _readVisibleRangesFromCodeEditor(previousProperties: MainThreadTextEditorProperties, codeEditor: ICodeEditor): Range[] { + private static _readVisibleRangesFromCodeEditor(previousProperties: MainThreadTextEditorProperties | null, codeEditor: ICodeEditor | null): Range[] { if (codeEditor) { return codeEditor.getVisibleRanges(); } @@ -99,7 +103,7 @@ export class MainThreadTextEditorProperties { ) { } - public generateDelta(oldProps: MainThreadTextEditorProperties, selectionChangeSource: string): IEditorPropertiesChangeData { + public generateDelta(oldProps: MainThreadTextEditorProperties | null, selectionChangeSource: string | null): IEditorPropertiesChangeData | null { let delta: IEditorPropertiesChangeData = { options: null, selections: null, @@ -109,7 +113,7 @@ export class MainThreadTextEditorProperties { if (!oldProps || !MainThreadTextEditorProperties._selectionsEqual(oldProps.selections, this.selections)) { delta.selections = { selections: this.selections, - source: selectionChangeSource + source: selectionChangeSource || undefined }; } @@ -179,11 +183,11 @@ export class MainThreadTextEditor { private _model: ITextModel; private _modelService: IModelService; private _modelListeners: IDisposable[]; - private _codeEditor: ICodeEditor; + private _codeEditor: ICodeEditor | null; private _focusTracker: IFocusTracker; private _codeEditorListeners: IDisposable[]; - private _properties: MainThreadTextEditorProperties; + private _properties: MainThreadTextEditorProperties | null; private readonly _onPropertiesChanged: Emitter; constructor( @@ -213,20 +217,20 @@ export class MainThreadTextEditor { } public dispose(): void { - this._model = null; + this._model = null!; this._modelListeners = dispose(this._modelListeners); this._codeEditor = null; this._codeEditorListeners = dispose(this._codeEditorListeners); } - private _updatePropertiesNow(selectionChangeSource: string): void { + private _updatePropertiesNow(selectionChangeSource: string | null): void { this._setProperties( MainThreadTextEditorProperties.readFromEditor(this._properties, this._model, this._codeEditor), selectionChangeSource ); } - private _setProperties(newProperties: MainThreadTextEditorProperties, selectionChangeSource: string): void { + private _setProperties(newProperties: MainThreadTextEditorProperties, selectionChangeSource: string | null): void { const delta = newProperties.generateDelta(this._properties, selectionChangeSource); this._properties = newProperties; if (delta) { @@ -242,15 +246,15 @@ export class MainThreadTextEditor { return this._model; } - public getCodeEditor(): ICodeEditor { + public getCodeEditor(): ICodeEditor | null { return this._codeEditor; } - public hasCodeEditor(codeEditor: ICodeEditor): boolean { + public hasCodeEditor(codeEditor: ICodeEditor | null): boolean { return (this._codeEditor === codeEditor); } - public setCodeEditor(codeEditor: ICodeEditor): void { + public setCodeEditor(codeEditor: ICodeEditor | null): void { if (this.hasCodeEditor(codeEditor)) { // Nothing to do... return; @@ -296,7 +300,7 @@ export class MainThreadTextEditor { return !!this._codeEditor; } - public getProperties(): MainThreadTextEditorProperties { + public getProperties(): MainThreadTextEditorProperties | null { return this._properties; } @@ -312,7 +316,7 @@ export class MainThreadTextEditor { const newSelections = selections.map(Selection.liftSelection); this._setProperties( - new MainThreadTextEditorProperties(newSelections, this._properties.options, this._properties.visibleRanges), + new MainThreadTextEditorProperties(newSelections, this._properties!.options, this._properties!.visibleRanges), null ); } diff --git a/src/vs/workbench/api/electron-browser/mainThreadMessageService.ts b/src/vs/workbench/api/electron-browser/mainThreadMessageService.ts index 52817312213..68cf1ff4c04 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadMessageService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadMessageService.ts @@ -32,7 +32,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape { // } - $showMessage(severity: Severity, message: string, options: MainThreadMessageOptions, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise { + $showMessage(severity: Severity, message: string, options: MainThreadMessageOptions, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise { if (options.modal) { return this._showModalMessage(severity, message, commands); } else { @@ -40,7 +40,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape { } } - private _showMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[], extension: IExtensionDescription): Promise { + private _showMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[], extension: IExtensionDescription | undefined): Promise { return new Promise(resolve => { @@ -50,7 +50,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape { constructor(id: string, label: string, handle: number) { super(id, label, undefined, true, () => { resolve(handle); - return undefined; + return Promise.resolve(); }); } } @@ -67,7 +67,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape { primaryActions.push(new MessageItemAction('_extension_message_handle_' + command.handle, command.title, command.handle)); }); - let source: string; + let source: string | undefined; if (extension) { source = nls.localize('extensionSource', "{0} (Extension)", extension.displayName || extension.name); } @@ -97,7 +97,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape { }); } - private _showModalMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise { + private _showModalMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise { let cancelId: number | undefined = undefined; const buttons = commands.map((command, index) => { diff --git a/src/vs/workbench/api/electron-browser/mainThreadQuickOpen.ts b/src/vs/workbench/api/electron-browser/mainThreadQuickOpen.ts index 580831d2b27..ab2865d0b32 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadQuickOpen.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadQuickOpen.ts @@ -36,7 +36,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape { public dispose(): void { } - $show(instance: number, options: IPickOptions, token: CancellationToken): Promise { + $show(instance: number, options: IPickOptions, token: CancellationToken): Promise { const contents = new Promise((resolve, reject) => { this._items[instance] = { resolve, reject }; }); @@ -72,7 +72,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape { this._items[instance].resolve(items); delete this._items[instance]; } - return undefined; + return Promise.resolve(); } $setError(instance: number, error: Error): Promise { @@ -80,7 +80,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape { this._items[instance].reject(error); delete this._items[instance]; } - return undefined; + return Promise.resolve(); } // ---- input @@ -181,13 +181,13 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape { .filter(handle => handlesToItems.has(handle)) .map(handle => handlesToItems.get(handle)); } else if (param === 'buttons') { - input[param] = params.buttons.map(button => { + input[param] = params.buttons!.map(button => { if (button.handle === -1) { return this._quickInputService.backButton; } const { iconPath, tooltip, handle } = button; return { - iconPath: { + iconPath: iconPath && { dark: URI.revive(iconPath.dark), light: iconPath.light && URI.revive(iconPath.light) }, diff --git a/src/vs/workbench/api/electron-browser/mainThreadSCM.ts b/src/vs/workbench/api/electron-browser/mainThreadSCM.ts index 33588a6084d..667110d3612 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadSCM.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadSCM.ts @@ -21,7 +21,7 @@ class MainThreadSCMResourceGroup implements ISCMResourceGroup { private _onDidSplice = new Emitter>(); readonly onDidSplice = this._onDidSplice.event; - get hideWhenEmpty(): boolean { return this.features.hideWhenEmpty; } + get hideWhenEmpty(): boolean { return !!this.features.hideWhenEmpty; } private _onDidChange = new Emitter(); get onDidChange(): Event { return this._onDidChange.event; } @@ -142,11 +142,11 @@ class MainThreadSCMProvider implements ISCMProvider { this._onDidChange.fire(); if (typeof features.commitTemplate !== 'undefined') { - this._onDidChangeCommitTemplate.fire(this.commitTemplate); + this._onDidChangeCommitTemplate.fire(this.commitTemplate!); } if (typeof features.statusBarCommands !== 'undefined') { - this._onDidChangeStatusBarCommands.fire(this.statusBarCommands); + this._onDidChangeStatusBarCommands.fire(this.statusBarCommands!); } } @@ -202,14 +202,14 @@ class MainThreadSCMProvider implements ISCMProvider { const icon = icons[0]; const iconDark = icons[1] || icon; const decorations = { - icon: icon && URI.parse(icon), - iconDark: iconDark && URI.parse(iconDark), + icon: icon ? URI.parse(icon) : undefined, + iconDark: iconDark ? URI.parse(iconDark) : undefined, tooltip, strikeThrough, faded, source, letter, - color: color && color.id + color: color ? color.id : undefined }; return new MainThreadSCMResource( @@ -241,7 +241,7 @@ class MainThreadSCMProvider implements ISCMProvider { this.groups.splice(this.groups.elements.indexOf(group), 1); } - async getOriginalResource(uri: URI): Promise { + async getOriginalResource(uri: URI): Promise { if (!this.features.hasQuickDiffProvider) { return null; } diff --git a/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts b/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts index c3617f2bb85..84b444bb19e 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts @@ -66,7 +66,7 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie } } - private async reveal(treeView: ITreeView, dataProvider: TreeViewDataProvider, item: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise { + private async reveal(treeView: ITreeView, dataProvider: TreeViewDataProvider, itemIn: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise { options = options ? options : { select: false, focus: false }; const select = isUndefinedOrNull(options.select) ? false : options.select; const focus = isUndefinedOrNull(options.focus) ? false : options.focus; @@ -79,7 +79,7 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie for (const parent of parentChain) { await treeView.expand(parent); } - item = dataProvider.getItem(item.handle); + const item = dataProvider.getItem(itemIn.handle); if (item) { await treeView.reveal(item); if (select) { @@ -91,13 +91,13 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie let itemsToExpand = [item]; for (; itemsToExpand.length > 0 && expand > 0; expand--) { await treeView.expand(itemsToExpand); - itemsToExpand = itemsToExpand.reduce((result, item) => { - item = dataProvider.getItem(item.handle); + itemsToExpand = itemsToExpand.reduce((result, itemValue) => { + const item = dataProvider.getItem(itemValue.handle); if (item && item.children && item.children.length) { result.push(...item.children); } return result; - }, []); + }, [] as ITreeItem[]); } } } @@ -109,7 +109,7 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie this._register(treeView.onDidChangeVisibility(isVisible => this._proxy.$setVisible(treeViewId, isVisible))); } - private getTreeView(treeViewId: string): ITreeView { + private getTreeView(treeViewId: string): ITreeView | null { const viewDescriptor: ITreeViewDescriptor = ViewsRegistry.getView(treeViewId); return viewDescriptor ? viewDescriptor.treeView : null; } @@ -174,7 +174,7 @@ class TreeViewDataProvider implements ITreeViewDataProvider { return itemsToRefresh; } - getItem(treeItemHandle: string): ITreeItem { + getItem(treeItemHandle: string): ITreeItem | undefined { return this.itemsMap.get(treeItemHandle); } @@ -194,7 +194,7 @@ class TreeViewDataProvider implements ITreeViewDataProvider { } private updateTreeItem(current: ITreeItem, treeItem: ITreeItem): void { - treeItem.children = treeItem.children ? treeItem.children : null; + treeItem.children = treeItem.children ? treeItem.children : undefined; if (current) { const properties = distinct([...Object.keys(current), ...Object.keys(treeItem)]); for (const property of properties) { diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 363d37088cf..d16e2fb13dc 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -147,14 +147,14 @@ export interface MainThreadDialogSaveOptions { } export interface MainThreadDiaglogsShape extends IDisposable { - $showOpenDialog(options: MainThreadDialogOpenOptions): Promise; - $showSaveDialog(options: MainThreadDialogSaveOptions): Promise; + $showOpenDialog(options: MainThreadDialogOpenOptions): Promise; + $showSaveDialog(options: MainThreadDialogSaveOptions): Promise; } export interface MainThreadDecorationsShape extends IDisposable { $registerDecorationProvider(handle: number, label: string): void; $unregisterDecorationProvider(handle: number): void; - $onDidChange(handle: number, resources: UriComponents[]): void; + $onDidChange(handle: number, resources: UriComponents[] | null): void; } export interface MainThreadDocumentContentProvidersShape extends IDisposable { @@ -329,7 +329,7 @@ export interface MainThreadMessageOptions { } export interface MainThreadMessageServiceShape extends IDisposable { - $showMessage(severity: Severity, message: string, options: MainThreadMessageOptions, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise; + $showMessage(severity: Severity, message: string, options: MainThreadMessageOptions, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise; } export interface MainThreadOutputServiceShape extends IDisposable { @@ -439,7 +439,7 @@ export interface TransferInputBox extends BaseTransferQuickInput { } export interface MainThreadQuickOpenShape extends IDisposable { - $show(instance: number, options: IPickOptions, token: CancellationToken): Promise; + $show(instance: number, options: IPickOptions, token: CancellationToken): Promise; $setItems(instance: number, items: TransferQuickPickItems[]): Promise; $setError(instance: number, error: Error): Promise; $input(options: vscode.InputBoxOptions, validateInput: boolean, token: CancellationToken): Promise; @@ -505,7 +505,7 @@ export interface ExtHostUrlsShape { } export interface MainThreadWorkspaceShape extends IDisposable { - $startFileSearch(includePattern: string, includeFolder: URI, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise | undefined; + $startFileSearch(includePattern: string | undefined, includeFolder: URI, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise | undefined; $startTextSearch(query: IPatternInfo, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise; $checkExists(includes: string[], token: CancellationToken): Promise; $saveAll(includeUntitled?: boolean): Promise; diff --git a/src/vs/workbench/api/node/extHostDecorations.ts b/src/vs/workbench/api/node/extHostDecorations.ts index 33e787f7dad..3ef24afe445 100644 --- a/src/vs/workbench/api/node/extHostDecorations.ts +++ b/src/vs/workbench/api/node/extHostDecorations.ts @@ -46,16 +46,20 @@ export class ExtHostDecorations implements ExtHostDecorationsShape { const result: DecorationReply = Object.create(null); return Promise.all(requests.map(request => { const { handle, uri, id } = request; - if (!this._provider.has(handle)) { + const entry = this._provider.get(handle); + if (!entry) { // might have been unregistered in the meantime return undefined; } - const { provider, extensionId } = this._provider.get(handle); + const { provider, extensionId } = entry; return Promise.resolve(provider.provideDecoration(URI.revive(uri), token)).then(data => { if (data && data.letter && data.letter.length !== 1) { console.warn(`INVALID decoration from extension '${extensionId.value}'. The 'letter' must be set and be one character, not '${data.letter}'.`); } - result[id] = data && [data.priority, data.bubble, data.title, data.letter, data.color, data.source]; + if (data) { + result[id] = [data.priority, data.bubble, data.title, data.letter, data.color, data.source]; + + } }, err => { console.error(err); }); diff --git a/src/vs/workbench/api/node/extHostDialogs.ts b/src/vs/workbench/api/node/extHostDialogs.ts index 5fb4a0f4ff0..b4223b175a6 100644 --- a/src/vs/workbench/api/node/extHostDialogs.ts +++ b/src/vs/workbench/api/node/extHostDialogs.ts @@ -15,15 +15,15 @@ export class ExtHostDialogs { this._proxy = mainContext.getProxy(MainContext.MainThreadDialogs); } - showOpenDialog(options: vscode.OpenDialogOptions): Promise { + showOpenDialog(options: vscode.OpenDialogOptions): Promise { return this._proxy.$showOpenDialog(options).then(filepaths => { - return filepaths && filepaths.map(URI.revive); + return filepaths ? filepaths.map(URI.revive) : undefined; }); } - showSaveDialog(options: vscode.SaveDialogOptions): Promise { + showSaveDialog(options: vscode.SaveDialogOptions): Promise { return this._proxy.$showSaveDialog(options).then(filepath => { - return filepath && URI.revive(filepath); + return filepath ? URI.revive(filepath) : undefined; }); } } diff --git a/src/vs/workbench/api/node/extHostDocumentData.ts b/src/vs/workbench/api/node/extHostDocumentData.ts index 7d9d6a49155..d659a17e676 100644 --- a/src/vs/workbench/api/node/extHostDocumentData.ts +++ b/src/vs/workbench/api/node/extHostDocumentData.ts @@ -17,7 +17,7 @@ const _modeId2WordDefinition = new Map(); export function setWordDefinitionFor(modeId: string, wordDefinition: RegExp): void { _modeId2WordDefinition.set(modeId, wordDefinition); } -export function getWordDefinitionFor(modeId: string): RegExp { +export function getWordDefinitionFor(modeId: string): RegExp | undefined { return _modeId2WordDefinition.get(modeId); } @@ -131,14 +131,14 @@ export class ExtHostDocumentData extends MirrorTextModel { private _lineAt(lineOrPosition: number | vscode.Position): vscode.TextLine { - let line: number; + let line: number | undefined; if (lineOrPosition instanceof Position) { line = lineOrPosition.line; } else if (typeof lineOrPosition === 'number') { line = lineOrPosition; } - if (line < 0 || line >= this._lines.length) { + if (typeof line !== 'number' || line < 0 || line >= this._lines.length) { throw new Error('Illegal value for `line`'); } @@ -146,7 +146,7 @@ export class ExtHostDocumentData extends MirrorTextModel { if (!result || result.lineNumber !== line || result.text !== this._lines[line]) { const text = this._lines[line]; - const firstNonWhitespaceCharacterIndex = /^(\s*)/.exec(text)[1].length; + const firstNonWhitespaceCharacterIndex = /^(\s*)/.exec(text)![1].length; const range = new Range(line, 0, line, text.length); const rangeIncludingLineBreak = line < this._lines.length - 1 ? new Range(line, 0, line + 1, 0) @@ -170,7 +170,7 @@ export class ExtHostDocumentData extends MirrorTextModel { private _offsetAt(position: vscode.Position): number { position = this._validatePosition(position); this._ensureLineStarts(); - return this._lineStarts.getAccumulatedValue(position.line - 1) + position.character; + return this._lineStarts!.getAccumulatedValue(position.line - 1) + position.character; } private _positionAt(offset: number): vscode.Position { @@ -178,7 +178,7 @@ export class ExtHostDocumentData extends MirrorTextModel { offset = Math.max(0, offset); this._ensureLineStarts(); - let out = this._lineStarts.getIndexOf(offset); + let out = this._lineStarts!.getIndexOf(offset); let lineLength = this._lines[out.index].length; @@ -238,7 +238,7 @@ export class ExtHostDocumentData extends MirrorTextModel { return new Position(line, character); } - private _getWordRangeAtPosition(_position: vscode.Position, regexp?: RegExp): vscode.Range { + private _getWordRangeAtPosition(_position: vscode.Position, regexp?: RegExp): vscode.Range | undefined { let position = this._validatePosition(_position); if (!regexp) { diff --git a/src/vs/workbench/api/node/extHostWorkspace.ts b/src/vs/workbench/api/node/extHostWorkspace.ts index 7175e06d423..4cb7c035cf3 100644 --- a/src/vs/workbench/api/node/extHostWorkspace.ts +++ b/src/vs/workbench/api/node/extHostWorkspace.ts @@ -56,7 +56,7 @@ interface MutableWorkspaceFolder extends vscode.WorkspaceFolder { class ExtHostWorkspaceImpl extends Workspace { - static toExtHostWorkspace(data: IWorkspaceData, previousConfirmedWorkspace?: ExtHostWorkspaceImpl, previousUnconfirmedWorkspace?: ExtHostWorkspaceImpl): { workspace: ExtHostWorkspaceImpl, added: vscode.WorkspaceFolder[], removed: vscode.WorkspaceFolder[] } { + static toExtHostWorkspace(data: IWorkspaceData, previousConfirmedWorkspace?: ExtHostWorkspaceImpl, previousUnconfirmedWorkspace?: ExtHostWorkspaceImpl): { workspace: ExtHostWorkspaceImpl | null, added: vscode.WorkspaceFolder[], removed: vscode.WorkspaceFolder[] } { if (!data) { return { workspace: null, added: [], removed: [] }; } @@ -95,7 +95,7 @@ class ExtHostWorkspaceImpl extends Workspace { return { workspace, added, removed }; } - private static _findFolder(workspace: ExtHostWorkspaceImpl, folderUriToFind: URI): MutableWorkspaceFolder { + private static _findFolder(workspace: ExtHostWorkspaceImpl, folderUriToFind: URI): MutableWorkspaceFolder | undefined { for (let i = 0; i < workspace.folders.length; i++) { const folder = workspace.workspaceFolders[i]; if (isFolderEqual(folder.uri, folderUriToFind)) { @@ -146,7 +146,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { private readonly _proxy: MainThreadWorkspaceShape; private _confirmedWorkspace: ExtHostWorkspaceImpl; - private _unconfirmedWorkspace: ExtHostWorkspaceImpl; + private _unconfirmedWorkspace?: ExtHostWorkspaceImpl; private _messageService: MainThreadMessageServiceShape; @@ -171,7 +171,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { return this._actualWorkspace; } - get name(): string { + get name(): string | undefined { return this._actualWorkspace ? this._actualWorkspace.name : undefined; } @@ -179,7 +179,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { return this._unconfirmedWorkspace || this._confirmedWorkspace; } - getWorkspaceFolders(): vscode.WorkspaceFolder[] { + getWorkspaceFolders(): vscode.WorkspaceFolder[] | undefined { if (!this._actualWorkspace) { return undefined; } @@ -257,14 +257,14 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { return this._actualWorkspace.getWorkspaceFolder(uri, resolveParent); } - resolveWorkspaceFolder(uri: vscode.Uri): vscode.WorkspaceFolder { + resolveWorkspaceFolder(uri: vscode.Uri): vscode.WorkspaceFolder | undefined { if (!this._actualWorkspace) { return undefined; } return this._actualWorkspace.resolveWorkspaceFolder(uri); } - getPath(): string { + getPath(): string | undefined { // this is legacy from the days before having // multi-root and we keep it only alive if there @@ -281,9 +281,9 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { return folders[0].uri.fsPath; } - getRelativePath(pathOrUri: string | vscode.Uri, includeWorkspace?: boolean): string { + getRelativePath(pathOrUri: string | vscode.Uri, includeWorkspace?: boolean): string | undefined { - let path: string; + let path: string | undefined; if (typeof pathOrUri === 'string') { path = pathOrUri; } else if (typeof pathOrUri !== 'undefined') { @@ -349,8 +349,8 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { findFiles(include: string | RelativePattern, exclude: vscode.GlobPattern, maxResults: number, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise { this._logService.trace(`extHostWorkspace#findFiles: fileSearch, extension: ${extensionId.value}, entryPoint: findFiles`); - let includePattern: string; - let includeFolder: URI; + let includePattern: string | undefined; + let includeFolder: URI | undefined; if (include) { if (typeof include === 'string') { includePattern = include; @@ -362,7 +362,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { } } - let excludePatternOrDisregardExcludes: string | false; + let excludePatternOrDisregardExcludes: string | false = false; if (exclude === null) { excludePatternOrDisregardExcludes = false; } else if (exclude) { @@ -381,7 +381,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { .then(data => Array.isArray(data) ? data.map(URI.revive) : []); } - findTextInFiles(query: vscode.TextSearchQuery, options: vscode.FindTextInFilesOptions, callback: (result: vscode.TextSearchResult) => void, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise { + findTextInFiles(query: vscode.TextSearchQuery, options: vscode.FindTextInFilesOptions, callback: (result: vscode.TextSearchResult) => void, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise { this._logService.trace(`extHostWorkspace#findTextInFiles: textSearch, extension: ${extensionId.value}, entryPoint: findTextInFiles`); const requestId = this._requestIdProvider.getNext(); @@ -413,7 +413,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { beforeContext: options.beforeContext, includePattern: options.include && globPatternToString(options.include), - excludePattern: options.exclude && globPatternToString(options.exclude) + excludePattern: options.exclude ? globPatternToString(options.exclude) : undefined }; let isCanceled = false; @@ -424,7 +424,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { } const uri = URI.revive(p.resource); - p.results.forEach(result => { + p.results!.forEach(result => { if (resultIsMatch(result)) { callback({ uri, @@ -471,7 +471,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { return this._proxy.$saveAll(includeUntitled); } - resolveProxy(url: string): Promise { + resolveProxy(url: string): Promise { return this._proxy.$resolveProxy(url); } } diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index 0889e56bd06..2a16b9bd9f6 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -296,7 +296,7 @@ export interface IViewsService { export interface ITreeView extends IDisposable { - dataProvider: ITreeViewDataProvider; + dataProvider: ITreeViewDataProvider | null; showCollapseAllAction: boolean; diff --git a/src/vs/workbench/contrib/scm/common/scm.ts b/src/vs/workbench/contrib/scm/common/scm.ts index 15c29cda4c5..53f10d56b9b 100644 --- a/src/vs/workbench/contrib/scm/common/scm.ts +++ b/src/vs/workbench/contrib/scm/common/scm.ts @@ -68,7 +68,7 @@ export interface ISCMProvider extends IDisposable { readonly statusBarCommands?: Command[]; readonly onDidChange: Event; - getOriginalResource(uri: URI): Promise; + getOriginalResource(uri: URI): Promise; } export const enum InputValidationType { diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadDocumentContentProviders.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadDocumentContentProviders.test.ts index b1a4edd3e85..4fde2d476bf 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadDocumentContentProviders.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadDocumentContentProviders.test.ts @@ -19,7 +19,7 @@ suite('MainThreadDocumentContentProviders', function () { let uri = URI.parse('test:uri'); let model = TextModel.createFromString('1', undefined, undefined, uri); - let providers = new MainThreadDocumentContentProviders(new TestRPCProtocol(), null, null, + let providers = new MainThreadDocumentContentProviders(new TestRPCProtocol(), null!, null!, new class extends mock() { getModel(_uri) { assert.equal(uri.toString(), _uri.toString()); From f078b09648d15686771088961299925b74265afe Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 6 Feb 2019 21:47:03 -0800 Subject: [PATCH 011/207] Strict null check mainThreadSearch --- src/tsconfig.strictNullChecks.json | 1 + src/vs/platform/search/common/search.ts | 4 +-- .../api/electron-browser/mainThreadSearch.ts | 30 +++++++++++++------ 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index abd24f54d07..9e622d856e8 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -417,6 +417,7 @@ "./vs/workbench/api/electron-browser/mainThreadProgress.ts", "./vs/workbench/api/electron-browser/mainThreadQuickOpen.ts", "./vs/workbench/api/electron-browser/mainThreadSCM.ts", + "./vs/workbench/api/electron-browser/mainThreadSearch.ts", "./vs/workbench/api/electron-browser/mainThreadStatusBar.ts", "./vs/workbench/api/electron-browser/mainThreadStorage.ts", "./vs/workbench/api/electron-browser/mainThreadTelemetry.ts", diff --git a/src/vs/platform/search/common/search.ts b/src/vs/platform/search/common/search.ts index 5fc96984e21..09145ea9f93 100644 --- a/src/vs/platform/search/common/search.ts +++ b/src/vs/platform/search/common/search.ts @@ -56,8 +56,8 @@ export const enum SearchProviderType { } export interface ISearchResultProvider { - textSearch(query: ITextQuery, onProgress?: (p: ISearchProgressItem) => void, token?: CancellationToken): Promise; - fileSearch(query: IFileQuery, token?: CancellationToken): Promise; + textSearch(query: ITextQuery, onProgress?: (p: ISearchProgressItem) => void, token?: CancellationToken): Promise; + fileSearch(query: IFileQuery, token?: CancellationToken): Promise; clearCache(cacheKey: string): Promise; } diff --git a/src/vs/workbench/api/electron-browser/mainThreadSearch.ts b/src/vs/workbench/api/electron-browser/mainThreadSearch.ts index c44f4d70e6a..bc4624424f9 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadSearch.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadSearch.ts @@ -50,11 +50,21 @@ export class MainThreadSearch implements MainThreadSearchShape { } $handleFileMatch(handle: number, session, data: UriComponents[]): void { - this._searchProvider.get(handle).handleFindMatch(session, data); + const provider = this._searchProvider.get(handle); + if (!provider) { + throw new Error('Got result for unknown provider'); + } + + provider.handleFindMatch(session, data); } $handleTextMatch(handle: number, session, data: IRawFileMatch2[]): void { - this._searchProvider.get(handle).handleFindMatch(session, data); + const provider = this._searchProvider.get(handle); + if (!provider) { + throw new Error('Got result for unknown provider'); + } + + provider.handleFindMatch(session, data); } $handleTelemetry(eventName: string, data: any): void { @@ -77,7 +87,8 @@ class SearchOperation { addMatch(match: IFileMatch): void { if (this.matches.has(match.resource.toString())) { // Merge with previous IFileMatches - this.matches.get(match.resource.toString()).results.push(...match.results); + // TODO@rob clean up text/file result types + this.matches.get(match.resource.toString())!.results!.push(...match.results!); } else { this.matches.set(match.resource.toString(), match); } @@ -107,15 +118,15 @@ class RemoteSearchProvider implements ISearchResultProvider, IDisposable { dispose(this._registrations); } - fileSearch(query: IFileQuery, token: CancellationToken = CancellationToken.None): Promise { - return this.doSearch(query, null, token); + fileSearch(query: IFileQuery, token: CancellationToken = CancellationToken.None): Promise { + return this.doSearch(query, undefined, token); } - textSearch(query: ITextQuery, onProgress?: (p: ISearchProgressItem) => void, token: CancellationToken = CancellationToken.None): Promise { + textSearch(query: ITextQuery, onProgress?: (p: ISearchProgressItem) => void, token: CancellationToken = CancellationToken.None): Promise { return this.doSearch(query, onProgress, token); } - doSearch(query: ITextQuery | IFileQuery, onProgress?: (p: ISearchProgressItem) => void, token: CancellationToken = CancellationToken.None): Promise { + doSearch(query: ITextQuery | IFileQuery, onProgress?: (p: ISearchProgressItem) => void, token: CancellationToken = CancellationToken.None): Promise { if (isFalsyOrEmpty(query.folderQueries)) { return Promise.resolve(undefined); } @@ -141,12 +152,13 @@ class RemoteSearchProvider implements ISearchResultProvider, IDisposable { } handleFindMatch(session: number, dataOrUri: Array): void { - if (!this._searches.has(session)) { + const searchOp = this._searches.get(session); + + if (!searchOp) { // ignore... return; } - const searchOp = this._searches.get(session); dataOrUri.forEach(result => { if ((result).results) { searchOp.addMatch({ From 5b34b4c65690c27a02bbd67af0c76736d2f53e92 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 7 Feb 2019 21:27:54 +0100 Subject: [PATCH 012/207] add hasWorkspaceFileExtension --- src/vs/code/electron-main/windows.ts | 11 +++++++---- src/vs/platform/workspaces/common/workspaces.ts | 7 +++++++ .../workspaces/electron-main/workspacesMainService.ts | 6 +++--- src/vs/workbench/browser/dnd.ts | 6 +++--- .../workbench/browser/parts/editor/editorWidgets.ts | 5 ++--- src/vs/workbench/contrib/stats/node/workspaceStats.ts | 5 ++--- 6 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 6a7ef247bb8..60fed9a17bf 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { basename, normalize, join, dirname, extname } from 'path'; +import { basename, normalize, join, dirname } from 'path'; import * as fs from 'fs'; import { localize } from 'vs/nls'; import * as arrays from 'vs/base/common/arrays'; @@ -26,7 +26,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWindowsMainService, IOpenConfiguration, IWindowsCountChangedEvent, ICodeWindow, IWindowState as ISingleWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows'; import { IHistoryMainService } from 'vs/platform/history/common/history'; import { IProcessEnvironment, isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; -import { IWorkspacesMainService, IWorkspaceIdentifier, WORKSPACE_FILTER, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesMainService, IWorkspaceIdentifier, WORKSPACE_FILTER, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, hasWorkspaceFileExtension } 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'; @@ -762,6 +762,8 @@ export class WindowsManager implements IWindowsMainService { } private getPathsToOpen(openConfig: IOpenConfiguration): IPathToOpen[] { + debugger; + let windowsToOpen: IPathToOpen[]; let isCommandLineOrAPICall = false; @@ -980,6 +982,7 @@ export class WindowsManager implements IWindowsMainService { // remove trailing slash const uriPath = uri.path; + if (endsWith(uriPath, '/')) { if (uriPath.length > 2) { // only remove if the path has some content @@ -991,7 +994,7 @@ export class WindowsManager implements IWindowsMainService { } // if there's no type hint - if (!typeHint && (extname(uri.path) === WORKSPACE_EXTENSION || options.gotoLineMode)) { + if (!typeHint && (hasWorkspaceFileExtension(uri.path) || options.gotoLineMode)) { typeHint = 'file'; } @@ -1005,7 +1008,7 @@ export class WindowsManager implements IWindowsMainService { remoteAuthority }; } - if (extname(uri.path) === WORKSPACE_EXTENSION && !options.forceOpenWorkspaceAsFile) { + if (hasWorkspaceFileExtension(uri.path) && !options.forceOpenWorkspaceAsFile) { return { workspace: this.workspacesMainService.getWorkspaceIdentifier(uri), remoteAuthority diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index b4559e3f6e8..29aa68c5325 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -8,6 +8,7 @@ import { localize } from 'vs/nls'; import { Event } from 'vs/base/common/event'; import { IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { URI, UriComponents } from 'vs/base/common/uri'; +import { extname } from 'vs/base/common/paths'; export const IWorkspacesMainService = createDecorator('workspacesMainService'); export const IWorkspacesService = createDecorator('workspacesService'); @@ -138,3 +139,9 @@ export type IWorkspaceInitializationPayload = IMultiFolderWorkspaceInitializatio export function isSingleFolderWorkspaceInitializationPayload(obj: any): obj is ISingleFolderWorkspaceInitializationPayload { return isSingleFolderWorkspaceIdentifier((obj.folder as ISingleFolderWorkspaceIdentifier)); } + +const WORKSPACE_SUFFIX = '.' + WORKSPACE_EXTENSION; + +export function hasWorkspaceFileExtension(path: string) { + return extname(path) === WORKSPACE_SUFFIX; +} diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index a9a6242f1d3..e4d66cbac8e 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -3,10 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IWorkspacesMainService, IWorkspaceIdentifier, WORKSPACE_EXTENSION, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesMainService, IWorkspaceIdentifier, hasWorkspaceFileExtension, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; import { isParent } from 'vs/platform/files/common/files'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { join, dirname, extname } from 'path'; +import { join, dirname } from 'path'; import { mkdirp, writeFile, readFile } from 'vs/base/node/pfs'; import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs'; import { isLinux } from 'vs/base/common/platform'; @@ -61,7 +61,7 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain } private isWorkspacePath(path: string): boolean { - return this.isInsideWorkspacesHome(path) || extname(path) === `.${WORKSPACE_EXTENSION}`; + return this.isInsideWorkspacesHome(path) || hasWorkspaceFileExtension(path); } private doResolveWorkspace(path: URI, contents: string): IResolvedWorkspace | null { diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts index 04f21cb6385..739f53af72a 100644 --- a/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { WORKSPACE_EXTENSION, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; -import { extname, basename, normalize } from 'vs/base/common/paths'; +import { hasWorkspaceFileExtension, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; +import { basename, normalize } from 'vs/base/common/paths'; import { IFileService } from 'vs/platform/files/common/files'; import { IWindowsService, IWindowService, IURIToOpen } from 'vs/platform/windows/common/windows'; import { URI } from 'vs/base/common/uri'; @@ -263,7 +263,7 @@ export class ResourcesDropHandler { return Promise.all(fileOnDiskResources.map(fileOnDiskResource => { // Check for Workspace - if (extname(fileOnDiskResource.fsPath) === `.${WORKSPACE_EXTENSION}`) { + if (hasWorkspaceFileExtension(fileOnDiskResource.fsPath)) { workspaceResources.workspaces.push({ uri: fileOnDiskResource, typeHint: 'file' }); return undefined; diff --git a/src/vs/workbench/browser/parts/editor/editorWidgets.ts b/src/vs/workbench/browser/parts/editor/editorWidgets.ts index a59b44c8cd0..781748071a8 100644 --- a/src/vs/workbench/browser/parts/editor/editorWidgets.ts +++ b/src/vs/workbench/browser/parts/editor/editorWidgets.ts @@ -15,8 +15,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IWindowService } from 'vs/platform/windows/common/windows'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { Schemas } from 'vs/base/common/network'; -import { WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces'; -import { extname } from 'vs/base/common/paths'; +import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; import { Disposable, dispose } from 'vs/base/common/lifecycle'; import { localize } from 'vs/nls'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; @@ -139,7 +138,7 @@ export class OpenWorkspaceButtonContribution extends Disposable implements IEdit return false; // we need a model } - if (model.uri.scheme !== Schemas.file || extname(model.uri.fsPath) !== `.${WORKSPACE_EXTENSION}`) { + if (model.uri.scheme !== Schemas.file || hasWorkspaceFileExtension(model.uri.fsPath)) { return false; // we need a local workspace file } diff --git a/src/vs/workbench/contrib/stats/node/workspaceStats.ts b/src/vs/workbench/contrib/stats/node/workspaceStats.ts index 1243fcdf4f2..10ea1691f99 100644 --- a/src/vs/workbench/contrib/stats/node/workspaceStats.ts +++ b/src/vs/workbench/contrib/stats/node/workspaceStats.ts @@ -16,11 +16,10 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { endsWith } from 'vs/base/common/strings'; import { Schemas } from 'vs/base/common/network'; import { INotificationService, Severity, IPromptChoice } from 'vs/platform/notification/common/notification'; -import { WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces'; +import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { joinPath } from 'vs/base/common/resources'; -import { extname } from 'vs/base/common/paths'; import { collectWorkspaceStats, WorkspaceStats as WorkspaceStatsType } from 'vs/base/node/stats'; const SshProtocolMatcher = /^([^@:]+@)?([^:]+):/; @@ -534,7 +533,7 @@ export class WorkspaceStats implements IWorkbenchContribution { // Handle top-level workspace files for local single folder workspace if (state === WorkbenchState.FOLDER && workspace.folders[0].uri.scheme === Schemas.file) { - const workspaceFiles = rootFiles.filter(name => extname(name) === `.${WORKSPACE_EXTENSION}`); + const workspaceFiles = rootFiles.filter(hasWorkspaceFileExtension); if (workspaceFiles.length > 0) { this.doHandleWorkspaceFiles(workspace.folders[0].uri, workspaceFiles); } From 311152c9cdff9102e0e4058704674afb7f777856 Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Thu, 7 Feb 2019 21:44:09 +0100 Subject: [PATCH 013/207] Fixes #68113: LinkedMap has extra keys sometimes --- src/vs/base/common/map.ts | 14 +++++++++ src/vs/base/test/common/map.test.ts | 44 +++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/src/vs/base/common/map.ts b/src/vs/base/common/map.ts index 00b15a28b26..c1ed1d4aa4a 100644 --- a/src/vs/base/common/map.ts +++ b/src/vs/base/common/map.ts @@ -723,9 +723,21 @@ export class LinkedMap { this._tail = undefined; } else if (item === this._head) { + // This can only happend if size === 1 which is handle + // by the case above. + if (!item.next) { + throw new Error('Invalid list'); + } + item.next.previous = undefined; this._head = item.next; } else if (item === this._tail) { + // This can only happend if size === 1 which is handle + // by the case above. + if (!item.previous) { + throw new Error('Invalid list'); + } + item.previous.next = undefined; this._tail = item.previous; } else { @@ -737,6 +749,8 @@ export class LinkedMap { next.previous = previous; previous.next = next; } + item.next = undefined; + item.previous = undefined; } private touch(item: Item, touch: Touch): void { diff --git a/src/vs/base/test/common/map.test.ts b/src/vs/base/test/common/map.test.ts index c179bdb34db..245cccdf776 100644 --- a/src/vs/base/test/common/map.test.ts +++ b/src/vs/base/test/common/map.test.ts @@ -226,6 +226,50 @@ suite('Map', () => { }); }); + test('LinkedMap - delete Head and Tail', function () { + const map = new LinkedMap(); + + assert.equal(map.size, 0); + + map.set('1', 1); + assert.equal(map.size, 1); + map.delete('1'); + assert.equal(map.get('1'), undefined); + assert.equal(map.size, 0); + assert.equal(map.keys().length, 0); + }); + + test('LinkedMap - delete Head', function () { + const map = new LinkedMap(); + + assert.equal(map.size, 0); + + map.set('1', 1); + map.set('2', 2); + assert.equal(map.size, 2); + map.delete('1'); + assert.equal(map.get('2'), 2); + assert.equal(map.size, 1); + assert.equal(map.keys().length, 1); + assert.equal(map.keys()[0], 2); + }); + + test('LinkedMap - delete Tail', function () { + const map = new LinkedMap(); + + assert.equal(map.size, 0); + + map.set('1', 1); + map.set('2', 2); + assert.equal(map.size, 2); + map.delete('2'); + assert.equal(map.get('1'), 1); + assert.equal(map.size, 1); + assert.equal(map.keys().length, 1); + assert.equal(map.keys()[0], 1); + }); + + test('PathIterator', () => { const iter = new PathIterator(); iter.reset('file:///usr/bin/file.txt'); From 0a9e4e3388c79b858b1b5a45207eb96e47728e27 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 10:17:27 -0800 Subject: [PATCH 014/207] Strict null work in extensionEditor --- .../extensions/browser/extensionsViewer.ts | 4 +- .../electron-browser/extensionEditor.ts | 217 +++++++++--------- 2 files changed, 113 insertions(+), 108 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts index 1f022b51b7e..af88fe823fa 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts @@ -35,8 +35,8 @@ export interface IUnknownExtensionTemplateData { export interface IExtensionData { extension: IExtension; hasChildren: boolean; - getChildren: () => Promise; - parent: IExtensionData; + getChildren: () => Promise; + parent: IExtensionData | null; } export class DataSource implements IDataSource { diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts index 46f1a2dc0bd..d591085df81 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts @@ -74,8 +74,13 @@ function removeEmbeddedSVGs(documentContent: string): string { // remove all inline svgs const allSVGs = newDocument.documentElement.querySelectorAll('svg'); - for (let i = 0; i < allSVGs.length; i++) { - allSVGs[i].parentNode.removeChild(allSVGs[i]); + if (allSVGs) { + for (let i = 0; i < allSVGs.length; i++) { + const svg = allSVGs[i]; + if (svg.parentNode) { + svg.parentNode.removeChild(allSVGs[i]); + } + } } return newDocument.documentElement.outerHTML; @@ -97,7 +102,7 @@ class NavBar { } push(id: string, label: string, tooltip: string): void { - const action = new Action(id, label, null, true, () => this._update(id, true)); + const action = new Action(id, label, undefined, true, () => this._update(id, true)); action.tooltip = tooltip; @@ -118,7 +123,7 @@ class NavBar { this._update(this.currentId); } - _update(id: string = this.currentId, focus?: boolean): Promise { + _update(id: string | null = this.currentId, focus?: boolean): Promise { this.currentId = id; this._onChange.fire({ id, focus }); this.actions.forEach(a => a.enabled = a.id !== id); @@ -170,16 +175,16 @@ export class ExtensionEditor extends BaseEditor { private ignoreActionbar: ActionBar; private header: HTMLElement; - private extensionReadme: Cache; - private extensionChangelog: Cache; - private extensionManifest: Cache; - private extensionDependencies: Cache; + private extensionReadme: Cache | null; + private extensionChangelog: Cache | null; + private extensionManifest: Cache | null; + private extensionDependencies: Cache | null; private layoutParticipants: ILayoutParticipant[] = []; private contentDisposables: IDisposable[] = []; private transientDisposables: IDisposable[] = []; private disposables: IDisposable[]; - private activeElement: IActiveElement; + private activeElement: IActiveElement | null; private editorLoadComplete: boolean = false; constructor( @@ -647,7 +652,7 @@ export class ExtensionEditor extends BaseEditor { return this.extensionDependencies.extension; } - get parent(): IExtensionData { + get parent(): IExtensionData | null { return this.extensionDependencies.dependent ? new ExtensionData(this.extensionDependencies.dependent) : null; } @@ -655,8 +660,8 @@ export class ExtensionEditor extends BaseEditor { return this.extensionDependencies.hasDependencies; } - getChildren(): Promise { - return this.extensionDependencies.dependencies ? Promise.resolve(this.extensionDependencies.dependencies.map(d => new ExtensionData(d))) : null; + getChildren(): Promise { + return this.extensionDependencies.dependencies ? Promise.resolve(this.extensionDependencies.dependencies.map(d => new ExtensionData(d))) : Promise.resolve(null); } } @@ -688,11 +693,11 @@ export class ExtensionEditor extends BaseEditor { class ExtensionData implements IExtensionData { readonly extension: IExtension; - readonly parent: IExtensionData; + readonly parent: IExtensionData | null; constructor(extension: IExtension, parent?: IExtensionData) { this.extension = extension; - this.parent = parent; + this.parent = parent || null; } get hasChildren(): boolean { @@ -730,17 +735,17 @@ export class ExtensionEditor extends BaseEditor { } const details = $('details', { open: true, ontoggle: onDetailsToggle }, - $('summary', null, localize('settings', "Settings ({0})", contrib.length)), - $('table', null, - $('tr', null, - $('th', null, localize('setting name', "Name")), - $('th', null, localize('description', "Description")), - $('th', null, localize('default', "Default")) + $('summary', undefined, localize('settings', "Settings ({0})", contrib.length)), + $('table', undefined, + $('tr', undefined, + $('th', undefined, localize('setting name', "Name")), + $('th', undefined, localize('description', "Description")), + $('th', undefined, localize('default', "Default")) ), - ...contrib.map(key => $('tr', null, - $('td', null, $('code', null, key)), - $('td', null, properties[key].description), - $('td', null, $('code', null, `${isUndefined(properties[key].default) ? getDefaultValue(properties[key].type) : properties[key].default}`)) + ...contrib.map(key => $('tr', undefined, + $('td', undefined, $('code', undefined, key)), + $('td', undefined, properties[key].description), + $('td', undefined, $('code', undefined, `${isUndefined(properties[key].default) ? getDefaultValue(properties[key].type) : properties[key].default}`)) )) ) ); @@ -758,15 +763,15 @@ export class ExtensionEditor extends BaseEditor { } const details = $('details', { open: true, ontoggle: onDetailsToggle }, - $('summary', null, localize('debuggers', "Debuggers ({0})", contrib.length)), - $('table', null, - $('tr', null, - $('th', null, localize('debugger name', "Name")), - $('th', null, localize('debugger type', "Type")), + $('summary', undefined, localize('debuggers', "Debuggers ({0})", contrib.length)), + $('table', undefined, + $('tr', undefined, + $('th', undefined, localize('debugger name', "Name")), + $('th', undefined, localize('debugger type', "Type")), ), - ...contrib.map(d => $('tr', null, - $('td', null, d.label), - $('td', null, d.type))) + ...contrib.map(d => $('tr', undefined, + $('td', undefined, d.label!), + $('td', undefined, d.type))) ) ); @@ -778,21 +783,21 @@ export class ExtensionEditor extends BaseEditor { const contributes = manifest.contributes; const contrib = contributes && contributes.viewsContainers || {}; - let viewContainers = <{ id: string, title: string, location: string }[]>Object.keys(contrib).reduce((result, location) => { + let viewContainers = Object.keys(contrib).reduce((result, location) => { let viewContainersForLocation: IViewContainer[] = contrib[location]; result.push(...viewContainersForLocation.map(viewContainer => ({ ...viewContainer, location }))); return result; - }, []); + }, [] as Array<{ id: string, title: string, location: string }>); if (!viewContainers.length) { return false; } const details = $('details', { open: true, ontoggle: onDetailsToggle }, - $('summary', null, localize('viewContainers', "View Containers ({0})", viewContainers.length)), - $('table', null, - $('tr', null, $('th', null, localize('view container id', "ID")), $('th', null, localize('view container title', "Title")), $('th', null, localize('view container location', "Where"))), - ...viewContainers.map(viewContainer => $('tr', null, $('td', null, viewContainer.id), $('td', null, viewContainer.title), $('td', null, viewContainer.location))) + $('summary', undefined, localize('viewContainers', "View Containers ({0})", viewContainers.length)), + $('table', undefined, + $('tr', undefined, $('th', undefined, localize('view container id', "ID")), $('th', undefined, localize('view container title', "Title")), $('th', undefined, localize('view container location', "Where"))), + ...viewContainers.map(viewContainer => $('tr', undefined, $('td', undefined, viewContainer.id), $('td', undefined, viewContainer.title), $('td', undefined, viewContainer.location))) ) ); @@ -804,21 +809,21 @@ export class ExtensionEditor extends BaseEditor { const contributes = manifest.contributes; const contrib = contributes && contributes.views || {}; - let views = <{ id: string, name: string, location: string }[]>Object.keys(contrib).reduce((result, location) => { + let views = Object.keys(contrib).reduce((result, location) => { let viewsForLocation: IView[] = contrib[location]; result.push(...viewsForLocation.map(view => ({ ...view, location }))); return result; - }, []); + }, [] as Array<{ id: string, name: string, location: string }>); if (!views.length) { return false; } const details = $('details', { open: true, ontoggle: onDetailsToggle }, - $('summary', null, localize('views', "Views ({0})", views.length)), - $('table', null, - $('tr', null, $('th', null, localize('view id', "ID")), $('th', null, localize('view name', "Name")), $('th', null, localize('view location', "Where"))), - ...views.map(view => $('tr', null, $('td', null, view.id), $('td', null, view.name), $('td', null, view.location))) + $('summary', undefined, localize('views', "Views ({0})", views.length)), + $('table', undefined, + $('tr', undefined, $('th', undefined, localize('view id', "ID")), $('th', undefined, localize('view name', "Name")), $('th', undefined, localize('view location', "Where"))), + ...views.map(view => $('tr', undefined, $('td', undefined, view.id), $('td', undefined, view.name), $('td', undefined, view.location))) ) ); @@ -835,10 +840,10 @@ export class ExtensionEditor extends BaseEditor { } const details = $('details', { open: true, ontoggle: onDetailsToggle }, - $('summary', null, localize('localizations', "Localizations ({0})", localizations.length)), - $('table', null, - $('tr', null, $('th', null, localize('localizations language id', "Language Id")), $('th', null, localize('localizations language name', "Language Name")), $('th', null, localize('localizations localized language name', "Language Name (Localized)"))), - ...localizations.map(localization => $('tr', null, $('td', null, localization.languageId), $('td', null, localization.languageName), $('td', null, localization.localizedLanguageName))) + $('summary', undefined, localize('localizations', "Localizations ({0})", localizations.length)), + $('table', undefined, + $('tr', undefined, $('th', undefined, localize('localizations language id', "Language Id")), $('th', undefined, localize('localizations language name', "Language Name")), $('th', undefined, localize('localizations localized language name', "Language Name (Localized)"))), + ...localizations.map(localization => $('tr', undefined, $('td', undefined, localization.languageId), $('td', undefined, localization.languageName || ''), $('td', undefined, localization.localizedLanguageName || ''))) ) ); @@ -855,8 +860,8 @@ export class ExtensionEditor extends BaseEditor { } const details = $('details', { open: true, ontoggle: onDetailsToggle }, - $('summary', null, localize('colorThemes', "Color Themes ({0})", contrib.length)), - $('ul', null, ...contrib.map(theme => $('li', null, theme.label))) + $('summary', undefined, localize('colorThemes', "Color Themes ({0})", contrib.length)), + $('ul', undefined, ...contrib.map(theme => $('li', undefined, theme.label))) ); append(container, details); @@ -872,8 +877,8 @@ export class ExtensionEditor extends BaseEditor { } const details = $('details', { open: true, ontoggle: onDetailsToggle }, - $('summary', null, localize('iconThemes', "Icon Themes ({0})", contrib.length)), - $('ul', null, ...contrib.map(theme => $('li', null, theme.label))) + $('summary', undefined, localize('iconThemes', "Icon Themes ({0})", contrib.length)), + $('ul', undefined, ...contrib.map(theme => $('li', undefined, theme.label))) ); append(container, details); @@ -896,26 +901,26 @@ export class ExtensionEditor extends BaseEditor { result.push($('span', { class: 'colorBox', style: 'background-color: ' + Color.Format.CSS.format(color) }, '')); } } - result.push($('code', null, colorReference)); + result.push($('code', undefined, colorReference)); return result; } const details = $('details', { open: true, ontoggle: onDetailsToggle }, - $('summary', null, localize('colors', "Colors ({0})", colors.length)), - $('table', null, - $('tr', null, - $('th', null, localize('colorId', "Id")), - $('th', null, localize('description', "Description")), - $('th', null, localize('defaultDark', "Dark Default")), - $('th', null, localize('defaultLight', "Light Default")), - $('th', null, localize('defaultHC', "High Contrast Default")) + $('summary', undefined, localize('colors', "Colors ({0})", colors.length)), + $('table', undefined, + $('tr', undefined, + $('th', undefined, localize('colorId', "Id")), + $('th', undefined, localize('description', "Description")), + $('th', undefined, localize('defaultDark', "Dark Default")), + $('th', undefined, localize('defaultLight', "Light Default")), + $('th', undefined, localize('defaultHC', "High Contrast Default")) ), - ...colors.map(color => $('tr', null, - $('td', null, $('code', null, color.id)), - $('td', null, color.description), - $('td', null, ...colorPreview(color.defaults.dark)), - $('td', null, ...colorPreview(color.defaults.light)), - $('td', null, ...colorPreview(color.defaults.highContrast)) + ...colors.map(color => $('tr', undefined, + $('td', undefined, $('code', undefined, color.id)), + $('td', undefined, color.description), + $('td', undefined, ...colorPreview(color.defaults.dark)), + $('td', undefined, ...colorPreview(color.defaults.light)), + $('td', undefined, ...colorPreview(color.defaults.highContrast)) )) ) ); @@ -934,15 +939,15 @@ export class ExtensionEditor extends BaseEditor { } const details = $('details', { open: true, ontoggle: onDetailsToggle }, - $('summary', null, localize('JSON Validation', "JSON Validation ({0})", contrib.length)), - $('table', null, - $('tr', null, - $('th', null, localize('fileMatch', "File Match")), - $('th', null, localize('schema', "Schema")) + $('summary', undefined, localize('JSON Validation', "JSON Validation ({0})", contrib.length)), + $('table', undefined, + $('tr', undefined, + $('th', undefined, localize('fileMatch', "File Match")), + $('th', undefined, localize('schema', "Schema")) ), - ...contrib.map(v => $('tr', null, - $('td', null, $('code', null, v.fileMatch)), - $('td', null, v.url) + ...contrib.map(v => $('tr', undefined, + $('td', undefined, $('code', undefined, v.fileMatch)), + $('td', undefined, v.url) )))); append(container, details); @@ -955,8 +960,8 @@ export class ExtensionEditor extends BaseEditor { const commands = rawCommands.map(c => ({ id: c.command, title: c.title, - keybindings: [], - menus: [] + keybindings: [] as ResolvedKeybinding[], + menus: [] as string[] })); const byId = arrays.index(commands, c => c.id); @@ -1008,19 +1013,19 @@ export class ExtensionEditor extends BaseEditor { }; const details = $('details', { open: true, ontoggle: onDetailsToggle }, - $('summary', null, localize('commands', "Commands ({0})", commands.length)), - $('table', null, - $('tr', null, - $('th', null, localize('command name', "Name")), - $('th', null, localize('description', "Description")), - $('th', null, localize('keyboard shortcuts', "Keyboard Shortcuts")), - $('th', null, localize('menuContexts', "Menu Contexts")) + $('summary', undefined, localize('commands', "Commands ({0})", commands.length)), + $('table', undefined, + $('tr', undefined, + $('th', undefined, localize('command name', "Name")), + $('th', undefined, localize('description', "Description")), + $('th', undefined, localize('keyboard shortcuts', "Keyboard Shortcuts")), + $('th', undefined, localize('menuContexts', "Menu Contexts")) ), - ...commands.map(c => $('tr', null, - $('td', null, $('code', null, c.id)), - $('td', null, c.title), - $('td', null, ...c.keybindings.map(keybinding => renderKeybinding(keybinding))), - $('td', null, ...c.menus.map(context => $('code', null, context))) + ...commands.map(c => $('tr', undefined, + $('td', undefined, $('code', undefined, c.id)), + $('td', undefined, c.title), + $('td', undefined, ...c.keybindings.map(keybinding => renderKeybinding(keybinding))), + $('td', undefined, ...c.menus.map(context => $('code', undefined, context))) )) ) ); @@ -1075,21 +1080,21 @@ export class ExtensionEditor extends BaseEditor { } const details = $('details', { open: true, ontoggle: onDetailsToggle }, - $('summary', null, localize('languages', "Languages ({0})", languages.length)), - $('table', null, - $('tr', null, - $('th', null, localize('language id', "ID")), - $('th', null, localize('language name', "Name")), - $('th', null, localize('file extensions', "File Extensions")), - $('th', null, localize('grammar', "Grammar")), - $('th', null, localize('snippets', "Snippets")) + $('summary', undefined, localize('languages', "Languages ({0})", languages.length)), + $('table', undefined, + $('tr', undefined, + $('th', undefined, localize('language id', "ID")), + $('th', undefined, localize('language name', "Name")), + $('th', undefined, localize('file extensions', "File Extensions")), + $('th', undefined, localize('grammar', "Grammar")), + $('th', undefined, localize('snippets', "Snippets")) ), - ...languages.map(l => $('tr', null, - $('td', null, l.id), - $('td', null, l.name), - $('td', null, ...join(l.extensions.map(ext => $('code', null, ext)), ' ')), - $('td', null, document.createTextNode(l.hasGrammar ? '✔︎' : '—')), - $('td', null, document.createTextNode(l.hasSnippets ? '✔︎' : '—')) + ...languages.map(l => $('tr', undefined, + $('td', undefined, l.id), + $('td', undefined, l.name), + $('td', undefined, ...join(l.extensions.map(ext => $('code', undefined, ext)), ' ')), + $('td', undefined, document.createTextNode(l.hasGrammar ? '✔︎' : '—')), + $('td', undefined, document.createTextNode(l.hasSnippets ? '✔︎' : '—')) )) ) ); @@ -1098,8 +1103,8 @@ export class ExtensionEditor extends BaseEditor { return true; } - private resolveKeybinding(rawKeyBinding: IKeyBinding): ResolvedKeybinding { - let key: string; + private resolveKeybinding(rawKeyBinding: IKeyBinding): ResolvedKeybinding | null { + let key: string | undefined; switch (process.platform) { case 'win32': key = rawKeyBinding.win; break; @@ -1154,7 +1159,7 @@ class ShowExtensionEditorFindCommand extends Command { } } - private getExtensionEditor(accessor: ServicesAccessor): ExtensionEditor { + private getExtensionEditor(accessor: ServicesAccessor): ExtensionEditor | null { const activeControl = accessor.get(IEditorService).activeControl as ExtensionEditor; if (activeControl instanceof ExtensionEditor) { return activeControl; From bdd89b3ed37cafe84458229bd754870e3e8e5b53 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 10:24:06 -0800 Subject: [PATCH 015/207] Use undefined instead of null in $ dom creation methods --- .../contrib/preferences/browser/keybindingWidgets.ts | 2 +- .../contrib/preferences/browser/keybindingsEditor.ts | 12 ++++++------ .../contrib/preferences/browser/settingsTree.ts | 10 +++++----- .../contrib/scm/electron-browser/scmViewlet.ts | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts b/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts index 15374d83530..47910fa59fa 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts @@ -224,7 +224,7 @@ export class DefineKeybindingWidget extends Widget { this._domNode.setHeight(DefineKeybindingWidget.HEIGHT); const message = nls.localize('defineKeybinding.initial', "Press desired key combination and then press ENTER."); - dom.append(this._domNode.domNode, dom.$('.message', null, message)); + dom.append(this._domNode.domNode, dom.$('.message', undefined, message)); this._register(attachStylerCallback(this.themeService, { editorWidgetBackground, widgetShadow }, colors => { if (colors.editorWidgetBackground) { diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index 32ceacbb842..0cdaaf7ac93 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -364,8 +364,8 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor private createOpenKeybindingsElement(parent: HTMLElement): void { const openKeybindingsContainer = DOM.append(parent, $('.open-keybindings-container')); - DOM.append(openKeybindingsContainer, $('', null, localize('header-message', "For advanced customizations open and edit"))); - const fileElement = DOM.append(openKeybindingsContainer, $('.file-name', null, localize('keybindings-file-name', "keybindings.json"))); + DOM.append(openKeybindingsContainer, $('', undefined, localize('header-message', "For advanced customizations open and edit"))); + const fileElement = DOM.append(openKeybindingsContainer, $('.file-name', undefined, localize('keybindings-file-name', "keybindings.json"))); fileElement.tabIndex = 0; this._register(DOM.addDisposableListener(fileElement, DOM.EventType.CLICK, () => this.preferencesService.openGlobalKeybindingSettings(true))); this._register(DOM.addDisposableListener(fileElement, DOM.EventType.KEY_UP, e => { @@ -398,10 +398,10 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor keybindingsListHeader.style.lineHeight = '30px'; DOM.append(keybindingsListHeader, $('.header.actions'), - $('.header.command', null, localize('command', "Command")), - $('.header.keybinding', null, localize('keybinding', "Keybinding")), - $('.header.source', null, localize('source', "Source")), - $('.header.when', null, localize('when', "When"))); + $('.header.command', undefined, localize('command', "Command")), + $('.header.keybinding', undefined, localize('keybinding', "Keybinding")), + $('.header.source', undefined, localize('source', "Source")), + $('.header.when', undefined, localize('when', "When"))); } private createList(parent: HTMLElement): void { diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index 2cf8a3ab2c2..f0328a98c34 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -252,7 +252,7 @@ export interface ISettingOverrideClickEvent { export abstract class AbstractSettingRenderer implements ITreeRenderer { /** To override */ - templateId = undefined; + abstract get templateId(): string; static readonly CONTROL_CLASS = 'setting-control-focus-target'; static readonly CONTROL_SELECTOR = '.' + AbstractSettingRenderer.CONTROL_CLASS; @@ -418,15 +418,15 @@ export abstract class AbstractSettingRenderer implements ITreeRenderer { diff --git a/src/vs/workbench/contrib/scm/electron-browser/scmViewlet.ts b/src/vs/workbench/contrib/scm/electron-browser/scmViewlet.ts index 7517fbc261a..5ed9de8e244 100644 --- a/src/vs/workbench/contrib/scm/electron-browser/scmViewlet.ts +++ b/src/vs/workbench/contrib/scm/electron-browser/scmViewlet.ts @@ -782,7 +782,7 @@ export class RepositoryPanel extends ViewletPanel { super.renderHeaderTitle(container, title); addClass(container, 'scm-provider'); - append(container, $('span.type', null, type)); + append(container, $('span.type', undefined, type)); const onContextMenu = Event.map(stop(domEvent(container, 'contextmenu')), e => new StandardMouseEvent(e)); onContextMenu(this.onContextMenu, this, this.disposables); } @@ -1097,7 +1097,7 @@ export class SCMViewlet extends PanelViewlet implements IViewModel, IViewsViewle this.el = parent; addClass(this.el, 'scm-viewlet'); addClass(this.el, 'empty'); - append(parent, $('div.empty-message', null, localize('no open repo', "No source control providers registered."))); + append(parent, $('div.empty-message', undefined, localize('no open repo', "No source control providers registered."))); this.scmService.onDidAddRepository(this.onDidAddRepository, this, this.disposables); this.scmService.onDidRemoveRepository(this.onDidRemoveRepository, this, this.disposables); From ad375c92764b72a1f28f3e1626563e9e41e5c740 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 11:48:23 -0800 Subject: [PATCH 016/207] Strict null work --- src/tsconfig.strictNullChecks.json | 5 +++++ .../files/browser/editors/fileEditorTracker.ts | 2 +- .../contrib/search/browser/searchWidget.ts | 12 ++++++------ .../themes.test.contribution.ts | 17 +++++++++-------- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 9e622d856e8..43e2ec14c54 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -518,8 +518,13 @@ "./vs/workbench/contrib/comments/electron-browser/simpleCommentEditor.ts", "./vs/workbench/contrib/debug/browser/debugANSIHandling.ts", "./vs/workbench/contrib/debug/browser/linkDetector.ts", + "./vs/workbench/contrib/debug/common/debug.ts", "./vs/workbench/contrib/debug/common/debugProtocol.d.ts", + "./vs/workbench/contrib/debug/common/debugSource.ts", + "./vs/workbench/contrib/debug/common/debugUtils.ts", "./vs/workbench/contrib/debug/node/telemetryApp.ts", + "./vs/workbench/contrib/debug/test/common/debugSource.test.ts", + "./vs/workbench/contrib/debug/test/common/debugUtils.test.ts", "./vs/workbench/contrib/debug/test/common/mockDebug.ts", "./vs/workbench/contrib/experiments/electron-browser/experimentalPrompt.ts", "./vs/workbench/contrib/experiments/electron-browser/experiments.contribution.ts", diff --git a/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts b/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts index 5bc167ed371..5b62bd8c09b 100644 --- a/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts +++ b/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts @@ -313,7 +313,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut // to have a size of 2 (1 running load and 1 queued load). const queue = this.modelLoadQueue.queueFor(model.getResource()); if (queue.size <= 1) { - queue.queue(() => model.load().then(null, onUnexpectedError)); + queue.queue(() => model.load().then(undefined, onUnexpectedError)); } } diff --git a/src/vs/workbench/contrib/search/browser/searchWidget.ts b/src/vs/workbench/contrib/search/browser/searchWidget.ts index 3aee389d753..e434db9da78 100644 --- a/src/vs/workbench/contrib/search/browser/searchWidget.ts +++ b/src/vs/workbench/contrib/search/browser/searchWidget.ts @@ -227,7 +227,7 @@ export class SearchWidget extends Widget { } searchInputHasFocus(): boolean { - return this.searchInputBoxFocused.get(); + return !!this.searchInputBoxFocused.get(); } replaceInputHasFocus(): boolean { @@ -264,10 +264,10 @@ export class SearchWidget extends Widget { private renderToggleReplaceButton(parent: HTMLElement): void { const opts: IButtonOptions = { - buttonBackground: null, - buttonBorder: null, - buttonForeground: null, - buttonHoverBackground: null + buttonBackground: undefined, + buttonBorder: undefined, + buttonForeground: undefined, + buttonHoverBackground: undefined }; this.toggleReplaceButton = this._register(new Button(parent, opts)); this.toggleReplaceButton.element.setAttribute('aria-expanded', 'false'); @@ -390,7 +390,7 @@ export class SearchWidget extends Widget { } } - private validateSearchInput(value: string): IMessage { + private validateSearchInput(value: string): IMessage | null { if (value.length === 0) { return null; } diff --git a/src/vs/workbench/contrib/themes/test/electron-browser/themes.test.contribution.ts b/src/vs/workbench/contrib/themes/test/electron-browser/themes.test.contribution.ts index 33140524211..89c17efaa79 100644 --- a/src/vs/workbench/contrib/themes/test/electron-browser/themes.test.contribution.ts +++ b/src/vs/workbench/contrib/themes/test/electron-browser/themes.test.contribution.ts @@ -21,7 +21,7 @@ import { Color } from 'vs/base/common/color'; interface IToken { c: string; t: string; - r: { [themeName: string]: string; }; + r: { [themeName: string]: string | undefined; }; } interface IThemedToken { @@ -48,7 +48,7 @@ class ThemeDocument { for (let i = 0, len = this._theme.tokenColors.length; i < len; i++) { let rule = this._theme.tokenColors[i]; if (!rule.scope) { - this._defaultColor = rule.settings.foreground; + this._defaultColor = rule.settings.foreground!; } } } @@ -124,7 +124,8 @@ class Snapper { private _tokenize(grammar: IGrammar, lines: string[]): IToken[] { let state: StackElement | null = null; - let result: IToken[] = [], resultLen = 0; + let result: IToken[] = []; + let resultLen = 0; for (let i = 0, len = lines.length; i < len; i++) { let line = lines[i]; @@ -144,11 +145,11 @@ class Snapper { c: tokenText, t: tokenScopes, r: { - dark_plus: null, - light_plus: null, - dark_vs: null, - light_vs: null, - hc_black: null, + dark_plus: undefined, + light_plus: undefined, + dark_vs: undefined, + light_vs: undefined, + hc_black: undefined, } }; } From 947238c9776dce41800d7bf532e28bab6762b6e8 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 13:50:36 -0800 Subject: [PATCH 017/207] Allow svgs by default in webviews Fixes #68033 `allowSvgs` was already set as the default value after the webview was created. Due to an unrelated refactoring, the initial default value did not include `allowSvgs` --- .../workbench/contrib/webview/electron-browser/webviewEditor.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewEditor.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewEditor.ts index ed4bcbec2e4..db911b8e5a2 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewEditor.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewEditor.ts @@ -223,6 +223,7 @@ export class WebviewEditor extends BaseWebviewEditor { this._webview = this._instantiationService.createInstance(WebviewElement, this._partService.getContainer(Parts.EDITOR_PART), { + allowSvgs: true, useSameOriginForRoot: false, extensionLocation: input.extensionLocation }); From b5ff5a17fd22e273aa989b1697d40492d6bc244d Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 13:52:26 -0800 Subject: [PATCH 018/207] Strict null work in debug --- src/tsconfig.strictNullChecks.json | 9 ++++++ .../contrib/debug/browser/debugActionItems.ts | 7 +++-- .../debug/browser/debugContentProvider.ts | 10 +++---- .../contrib/debug/browser/exceptionWidget.ts | 6 ++-- .../debug/browser/statusbarColorProvider.ts | 3 ++ .../workbench/contrib/debug/common/debug.ts | 2 +- .../contrib/debug/common/debugSchemas.ts | 2 +- .../contrib/debug/common/debugUtils.ts | 4 +-- .../contrib/debug/common/debugViewModel.ts | 4 +-- .../electron-browser/breakpointWidget.ts | 4 +-- .../debug/electron-browser/rawDebugSession.ts | 23 ++++++++++----- .../contrib/debug/node/debugAdapter.ts | 29 ++++++++++--------- 12 files changed, 63 insertions(+), 40 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 43e2ec14c54..0fea9d867ea 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -517,11 +517,20 @@ "./vs/workbench/contrib/comments/electron-browser/commentService.ts", "./vs/workbench/contrib/comments/electron-browser/simpleCommentEditor.ts", "./vs/workbench/contrib/debug/browser/debugANSIHandling.ts", + "./vs/workbench/contrib/debug/browser/debugActionItems.ts", + "./vs/workbench/contrib/debug/browser/debugContentProvider.ts", + "./vs/workbench/contrib/debug/browser/debugStatus.ts", + "./vs/workbench/contrib/debug/browser/exceptionWidget.ts", "./vs/workbench/contrib/debug/browser/linkDetector.ts", + "./vs/workbench/contrib/debug/browser/statusbarColorProvider.ts", "./vs/workbench/contrib/debug/common/debug.ts", "./vs/workbench/contrib/debug/common/debugProtocol.d.ts", + "./vs/workbench/contrib/debug/common/debugSchemas.ts", "./vs/workbench/contrib/debug/common/debugSource.ts", "./vs/workbench/contrib/debug/common/debugUtils.ts", + "./vs/workbench/contrib/debug/common/debugViewModel.ts", + "./vs/workbench/contrib/debug/electron-browser/rawDebugSession.ts", + "./vs/workbench/contrib/debug/node/debugAdapter.ts", "./vs/workbench/contrib/debug/node/telemetryApp.ts", "./vs/workbench/contrib/debug/test/common/debugSource.test.ts", "./vs/workbench/contrib/debug/test/common/debugUtils.test.ts", diff --git a/src/vs/workbench/contrib/debug/browser/debugActionItems.ts b/src/vs/workbench/contrib/debug/browser/debugActionItems.ts index 07298620ba1..574fec93f5b 100644 --- a/src/vs/workbench/contrib/debug/browser/debugActionItems.ts +++ b/src/vs/workbench/contrib/debug/browser/debugActionItems.ts @@ -31,7 +31,7 @@ export class StartDebugActionItem implements IActionItem { private container: HTMLElement; private start: HTMLElement; private selectBox: SelectBox; - private options: { label: string, handler: (() => boolean) }[]; + private options: { label: string, handler?: (() => boolean) }[]; private toDispose: IDisposable[]; private selected: number; @@ -46,7 +46,7 @@ export class StartDebugActionItem implements IActionItem { @IContextViewService contextViewService: IContextViewService, ) { this.toDispose = []; - this.selectBox = new SelectBox([], -1, contextViewService, null, { ariaLabel: nls.localize('debugLaunchConfigurations', 'Debug Launch Configurations') }); + this.selectBox = new SelectBox([], -1, contextViewService, undefined, { ariaLabel: nls.localize('debugLaunchConfigurations', 'Debug Launch Configurations') }); this.toDispose.push(this.selectBox); this.toDispose.push(attachSelectBoxStyler(this.selectBox, themeService, { selectBackground: SIDE_BAR_BACKGROUND @@ -102,7 +102,8 @@ export class StartDebugActionItem implements IActionItem { } })); this.toDispose.push(this.selectBox.onDidSelect(e => { - const shouldBeSelected = this.options[e.index].handler(); + const target = this.options[e.index]; + const shouldBeSelected = target.handler ? target.handler() : false; if (shouldBeSelected) { this.selected = e.index; } else { diff --git a/src/vs/workbench/contrib/debug/browser/debugContentProvider.ts b/src/vs/workbench/contrib/debug/browser/debugContentProvider.ts index 5909b232d63..37859760d0e 100644 --- a/src/vs/workbench/contrib/debug/browser/debugContentProvider.ts +++ b/src/vs/workbench/contrib/debug/browser/debugContentProvider.ts @@ -52,7 +52,7 @@ export class DebugContentProvider implements IWorkbenchContribution, ITextModelC this.pendingUpdates.forEach(cancellationSource => cancellationSource.dispose()); } - provideTextContent(resource: uri): Promise { + provideTextContent(resource: uri): Promise | null { return this.createOrUpdateContentModel(resource, true); } @@ -69,15 +69,15 @@ export class DebugContentProvider implements IWorkbenchContribution, ITextModelC /** * Create or reload the model content of the given resource. */ - private createOrUpdateContentModel(resource: uri, createIfNotExists: boolean): Promise { + private createOrUpdateContentModel(resource: uri, createIfNotExists: boolean): Promise | null { const model = this.modelService.getModel(resource); if (!model && !createIfNotExists) { // nothing to do - return undefined; + return null; } - let session: IDebugSession; + let session: IDebugSession | undefined; if (resource.query) { const data = Source.getEncodedDebugData(resource); @@ -125,7 +125,7 @@ export class DebugContentProvider implements IWorkbenchContribution, ITextModelC // remove token this.pendingUpdates.delete(model.id); - if (!myToken.token.isCancellationRequested && edits.length > 0) { + if (!myToken.token.isCancellationRequested && edits && edits.length > 0) { // use the evil-edit as these models show in readonly-editor only model.applyEdits(edits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text))); } diff --git a/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts b/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts index 1b971255d7e..7148fa39200 100644 --- a/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts +++ b/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts @@ -24,7 +24,7 @@ export const debugExceptionWidgetBackground = registerColor('debugExceptionWidge export class ExceptionWidget extends ZoneWidget { - private _backgroundColor: Color; + private _backgroundColor?: Color; constructor(editor: ICodeEditor, private exceptionInfo: IExceptionInfo, @IThemeService themeService: IThemeService, @@ -55,7 +55,7 @@ export class ExceptionWidget extends ZoneWidget { protected _applyStyles(): void { if (this.container) { - this.container.style.backgroundColor = this._backgroundColor.toString(); + this.container.style.backgroundColor = this._backgroundColor ? this._backgroundColor.toString() : ''; } super._applyStyles(); } @@ -86,7 +86,7 @@ export class ExceptionWidget extends ZoneWidget { } } - protected _doLayout(heightInPixel: number, widthInPixel: number): void { + protected _doLayout(_heightInPixel: number | undefined, _widthInPixel: number | undefined): void { // Reload the height with respect to the exception text content and relayout it to match the line count. this.container.style.height = 'initial'; diff --git a/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts b/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts index 7ee9bf99083..ad02a131722 100644 --- a/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts +++ b/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts @@ -57,6 +57,9 @@ export class StatusBarColorProvider extends Themable implements IWorkbenchContri super.updateStyles(); const container = this.partService.getContainer(Parts.STATUSBAR_PART); + if (!container) { + return; + } if (isStatusbarInDebugMode(this.debugService)) { addClass(container, 'debugging'); } else { diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index 0e629cd2d1b..7a34a6e28f2 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -461,7 +461,7 @@ export interface ICompound { export interface IDebugAdapter extends IDisposable { readonly onError: Event; - readonly onExit: Event; + readonly onExit: Event; onRequest(callback: (request: DebugProtocol.Request) => void); onEvent(callback: (event: DebugProtocol.Event) => void); startSession(): Promise; diff --git a/src/vs/workbench/contrib/debug/common/debugSchemas.ts b/src/vs/workbench/contrib/debug/common/debugSchemas.ts index 6788b899874..1969ba6b5b9 100644 --- a/src/vs/workbench/contrib/debug/common/debugSchemas.ts +++ b/src/vs/workbench/contrib/debug/common/debugSchemas.ts @@ -195,6 +195,6 @@ export const launchSchema: IJSONSchema = { defaultCompound ] }, - inputs: inputsSchema.definitions.inputs + inputs: inputsSchema.definitions!.inputs } }; diff --git a/src/vs/workbench/contrib/debug/common/debugUtils.ts b/src/vs/workbench/contrib/debug/common/debugUtils.ts index b1b54612c29..fccd81a0add 100644 --- a/src/vs/workbench/contrib/debug/common/debugUtils.ts +++ b/src/vs/workbench/contrib/debug/common/debugUtils.ts @@ -73,10 +73,10 @@ export function getExactExpressionStartAndEnd(lineContent: string, looseStart: n // RFC 2396, Appendix A: https://www.ietf.org/rfc/rfc2396.txt const _schemePattern = /^[a-zA-Z][a-zA-Z0-9\+\-\.]+:/; -export function isUri(s: string) { +export function isUri(s: string | undefined): boolean { // heuristics: a valid uri starts with a scheme and // the scheme has at least 2 characters so that it doesn't look like a drive letter. - return s && s.match(_schemePattern); + return !!(s && s.match(_schemePattern)); } function stringToUri(path: string): string { diff --git a/src/vs/workbench/contrib/debug/common/debugViewModel.ts b/src/vs/workbench/contrib/debug/common/debugViewModel.ts index d65b9d9ae09..8296124dfb9 100644 --- a/src/vs/workbench/contrib/debug/common/debugViewModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugViewModel.ts @@ -58,7 +58,7 @@ export class ViewModel implements IViewModel { this._focusedThread = thread; this._focusedSession = session; - this.loadedScriptsSupportedContextKey.set(session && session.capabilities.supportsLoadedSourcesRequest); + this.loadedScriptsSupportedContextKey.set(session ? !!session.capabilities.supportsLoadedSourcesRequest : false); if (shouldEmitForSession) { this._onDidFocusSession.fire(session); @@ -68,7 +68,7 @@ export class ViewModel implements IViewModel { } } - get onDidFocusSession(): Event { + get onDidFocusSession(): Event { return this._onDidFocusSession.event; } diff --git a/src/vs/workbench/contrib/debug/electron-browser/breakpointWidget.ts b/src/vs/workbench/contrib/debug/electron-browser/breakpointWidget.ts index f2aa24229b2..8998aca5b83 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/breakpointWidget.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/breakpointWidget.ts @@ -53,7 +53,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi private conditionInput = ''; private hitCountInput = ''; private logMessageInput = ''; - private breakpoint: IBreakpoint; + private breakpoint?: IBreakpoint; constructor(editor: ICodeEditor, private lineNumber: number, private context: Context, @IContextViewService private readonly contextViewService: IContextViewService, @@ -102,7 +102,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi } } - private getInputValue(breakpoint: IBreakpoint): string { + private getInputValue(breakpoint: IBreakpoint | undefined): string { switch (this.context) { case Context.LOG_MESSAGE: return breakpoint && breakpoint.logMessage ? breakpoint.logMessage : this.logMessageInput; diff --git a/src/vs/workbench/contrib/debug/electron-browser/rawDebugSession.ts b/src/vs/workbench/contrib/debug/electron-browser/rawDebugSession.ts index 8b28b1564f2..15fac60c1cf 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/rawDebugSession.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/rawDebugSession.ts @@ -64,14 +64,16 @@ export class RawDebugSession { // DA events private readonly _onDidExitAdapter: Emitter; + private debugAdapter: IDebugAdapter | null; constructor( - private debugAdapter: IDebugAdapter, + debugAdapter: IDebugAdapter, dbgr: IDebugger, private telemetryService: ITelemetryService, public customTelemetryService: ITelemetryService, private environmentService: IEnvironmentService ) { + this.debugAdapter = debugAdapter; this._capabilities = Object.create(null); this._readyForBreakpoints = false; this.inShutdown = false; @@ -224,6 +226,9 @@ export class RawDebugSession { * Starts the underlying debug adapter and tracks the session time for telemetry. */ public start(): Promise { + if (!this.debugAdapter) { + return Promise.reject(new Error('no debug adapter')); + } return this.debugAdapter.startSession().then(() => { this.startTime = new Date().getTime(); }, err => { @@ -560,7 +565,7 @@ export class RawDebugSession { let spawnArgs = vscodeArgs.args.map(a => { if ((a.prefix === '--file-uri=' || a.prefix === '--folder-uri=') && !isUri(a.path)) { - return a.path; + return (a.path || ''); } return (a.prefix || '') + (a.path || ''); }); @@ -622,6 +627,10 @@ export class RawDebugSession { private send(command: string, args: any, timeout?: number): Promise { return new Promise((completeDispatch, errorDispatch) => { + if (!this.debugAdapter) { + errorDispatch(new Error('no debug adapter found')); + return; + } this.debugAdapter.sendRequest(command, args, (response: R) => { if (response.success) { completeDispatch(response); @@ -639,7 +648,7 @@ export class RawDebugSession { } const error = errorResponse && errorResponse.body ? errorResponse.body.error : null; - const errorMessage = errorResponse ? errorResponse.message : ''; + const errorMessage = errorResponse ? errorResponse.message || '' : ''; if (error && error.sendTelemetry) { const telemetryMessage = error ? formatPII(error.format, true, error.variables) : errorMessage; @@ -650,7 +659,7 @@ export class RawDebugSession { if (error && error.url) { const label = error.urlLabel ? error.urlLabel : nls.localize('moreInfo', "More Info"); return createErrorWithActions(userMessage, { - actions: [new Action('debug.moreInfo', label, null, true, () => { + actions: [new Action('debug.moreInfo', label, undefined, true, () => { window.open(error.url); return Promise.resolve(null); })] @@ -660,7 +669,7 @@ export class RawDebugSession { return new Error(userMessage); } - private mergeCapabilities(capabilities: DebugProtocol.Capabilities): void { + private mergeCapabilities(capabilities: DebugProtocol.Capabilities | undefined): void { if (capabilities) { this._capabilities = objects.mixin(this._capabilities, capabilities); } @@ -674,11 +683,11 @@ export class RawDebugSession { threadId, allThreadsContinued }, - seq: undefined + seq: undefined! }); } - private telemetryDebugProtocolErrorResponse(telemetryMessage: string) { + private telemetryDebugProtocolErrorResponse(telemetryMessage: string | undefined) { /* __GDPR__ "debugProtocolErrorResponse" : { "error" : { "classification": "CallstackOrException", "purpose": "FeatureInsight" } diff --git a/src/vs/workbench/contrib/debug/node/debugAdapter.ts b/src/vs/workbench/contrib/debug/node/debugAdapter.ts index c6948364d4e..09939841def 100644 --- a/src/vs/workbench/contrib/debug/node/debugAdapter.ts +++ b/src/vs/workbench/contrib/debug/node/debugAdapter.ts @@ -31,7 +31,7 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter { private messageCallback: (message: DebugProtocol.ProtocolMessage) => void; protected readonly _onError: Emitter; - protected readonly _onExit: Emitter; + protected readonly _onExit: Emitter; constructor() { this.sequence = 1; @@ -50,7 +50,7 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter { return this._onError.event; } - get onExit(): Event { + get onExit(): Event { return this._onExit.event; } @@ -255,7 +255,7 @@ export abstract class StreamDebugAdapter extends AbstractDebugAdapter { */ export class SocketDebugAdapter extends StreamDebugAdapter { - private socket: net.Socket; + private socket?: net.Socket; constructor(private adapterServer: IDebugAdapterServer) { super(); @@ -265,8 +265,8 @@ export class SocketDebugAdapter extends StreamDebugAdapter { return new Promise((resolve, reject) => { let connected = false; this.socket = net.createConnection(this.adapterServer.port, this.adapterServer.host || '127.0.0.1', () => { - this.connect(this.socket, this.socket); - resolve(null); + this.connect(this.socket!, this.socket!); + resolve(); connected = true; }); this.socket.on('close', () => { @@ -306,7 +306,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { private serverProcess: cp.ChildProcess; - constructor(private adapterExecutable: IDebugAdapterExecutable, private debugType: string, private outputService?: IOutputService) { + constructor(private adapterExecutable: IDebugAdapterExecutable, private debugType: string, private readonly outputService?: IOutputService) { super(); } @@ -354,7 +354,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { reject(new Error(nls.localize('unableToLaunchDebugAdapter', "Unable to launch debug adapter from '{0}'.", this.adapterExecutable.args[0]))); } this.serverProcess = child; - resolve(null); + resolve(); } else { reject(new Error(nls.localize('unableToLaunchDebugAdapterNoArgs', "Unable to launch debug adapter."))); } @@ -366,7 +366,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { options.cwd = this.adapterExecutable.options.cwd; } this.serverProcess = cp.spawn(this.adapterExecutable.command, this.adapterExecutable.args, options); - resolve(null); + resolve(); } }).then(_ => { this.serverProcess.on('error', err => { @@ -387,13 +387,14 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { this._onError.fire(error); }); - if (this.outputService) { + const outputService = this.outputService; + if (outputService) { const sanitize = (s: string) => s.toString().replace(/\r?\n$/mg, ''); // this.serverProcess.stdout.on('data', (data: string) => { // console.log('%c' + sanitize(data), 'background: #ddd; font-style: italic;'); // }); this.serverProcess.stderr.on('data', (data: string) => { - this.outputService.getChannel(ExtensionsChannelId).append(sanitize(data)); + outputService.getChannel(ExtensionsChannelId).append(sanitize(data)); }); } @@ -431,7 +432,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { } } - private static extract(contribution: IDebuggerContribution, extensionFolderPath: string): IDebuggerContribution { + private static extract(contribution: IDebuggerContribution, extensionFolderPath: string): IDebuggerContribution | undefined { if (!contribution) { return undefined; } @@ -485,7 +486,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { if (ed.contributes) { const debuggers = ed.contributes['debuggers']; if (debuggers && debuggers.length > 0) { - debuggers.filter(dbg => strings.equalsIgnoreCase(dbg.type, debugType)).forEach(dbg => { + debuggers.filter(dbg => typeof dbg.type === 'string' && strings.equalsIgnoreCase(dbg.type, debugType)).forEach(dbg => { // extract relevant attributes and make then absolute where needed const extractedDbg = ExecutableDebugAdapter.extract(dbg, ed.extensionLocation.fsPath); @@ -497,7 +498,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { } // select the right platform - let platformInfo: IPlatformSpecificAdapterContribution; + let platformInfo: IPlatformSpecificAdapterContribution | undefined; if (platform.isWindows && !process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432')) { platformInfo = result.winx86 || result.win || result.windows; } else if (platform.isWindows) { @@ -519,7 +520,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { return { type: 'executable', command: runtime, - args: (runtimeArgs || []).concat([program]).concat(args || []) + args: (runtimeArgs || []).concat(typeof program === 'string' ? [program] : []).concat(args || []) }; } else if (program) { return { From 4573042ac91861b28de55203d44acca1e27fde7b Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Thu, 7 Feb 2019 23:25:05 +0100 Subject: [PATCH 019/207] properly merge debugger contributions --- .../workbench/api/node/extHostDebugService.ts | 5 +-- .../contrib/debug/common/debugUtils.ts | 7 ++- .../debugConfigurationManager.ts | 6 +-- .../debug/electron-browser/debugService.ts | 2 +- .../workbench/contrib/debug/node/debugger.ts | 45 ++++++++++++------- 5 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index a1c246eab34..31a45f7dd27 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -24,7 +24,7 @@ import { getTerminalLauncher, hasChildProcesses, prepareCommand } from 'vs/workb import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/node/variableResolver'; import { ExtHostConfiguration, ExtHostConfigProvider } from './extHostConfiguration'; -import { convertToVSCPaths, convertToDAPaths } from 'vs/workbench/contrib/debug/common/debugUtils'; +import { convertToVSCPaths, convertToDAPaths, isDebuggerMainContribution } from 'vs/workbench/contrib/debug/common/debugUtils'; import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService'; import { IDisposable } from 'vs/base/common/lifecycle'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; @@ -128,8 +128,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { const debuggers = ed.contributes['debuggers']; if (debuggers && debuggers.length > 0) { for (const dbg of debuggers) { - // only debugger contributions with a label, program, or runtime attribute are considered a "defining" debugger contribution - if (dbg.type && (dbg.label || dbg.program || dbg.runtime)) { + if (isDebuggerMainContribution(dbg)) { debugTypes.push(dbg.type); if (dbg.adapterExecutableCommand) { this._aexCommands.set(dbg.type, dbg.adapterExecutableCommand); diff --git a/src/vs/workbench/contrib/debug/common/debugUtils.ts b/src/vs/workbench/contrib/debug/common/debugUtils.ts index fccd81a0add..7bd7849ceb1 100644 --- a/src/vs/workbench/contrib/debug/common/debugUtils.ts +++ b/src/vs/workbench/contrib/debug/common/debugUtils.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { equalsIgnoreCase } from 'vs/base/common/strings'; -import { IConfig } from 'vs/workbench/contrib/debug/common/debug'; +import { IConfig, IDebuggerContribution } from 'vs/workbench/contrib/debug/common/debug'; import { URI as uri } from 'vs/base/common/uri'; import { isAbsolute_posix, isAbsolute_win32 } from 'vs/base/common/paths'; import { deepClone } from 'vs/base/common/objects'; @@ -27,6 +27,11 @@ export function isExtensionHostDebugging(config: IConfig) { return config.type && equalsIgnoreCase(config.type === 'vslsShare' ? (config).adapterProxy.configuration.type : config.type, 'extensionhost'); } +// only a debugger contributions with a label, program, or runtime attribute is considered a "defining" or "main" debugger contribution +export function isDebuggerMainContribution(dbg: IDebuggerContribution) { + return dbg.type && (dbg.label || dbg.program || dbg.runtime); +} + export function getExactExpressionStartAndEnd(lineContent: string, looseStart: number, looseEnd: number): { start: number, end: number } { let matchingExpression: string | undefined = undefined; let startOffset = 0; diff --git a/src/vs/workbench/contrib/debug/electron-browser/debugConfigurationManager.ts b/src/vs/workbench/contrib/debug/electron-browser/debugConfigurationManager.ts index 90d5cbeeeb9..4fda9f76074 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/debugConfigurationManager.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/debugConfigurationManager.ts @@ -249,9 +249,9 @@ export class ConfigurationManager implements IConfigurationManager { }); } - const duplicate = this.getDebugger(rawAdapter.type); - if (duplicate) { - duplicate.merge(rawAdapter, added.description); + const existing = this.getDebugger(rawAdapter.type); + if (existing) { + existing.merge(rawAdapter, added.description); } else { this.debuggers.push(this.instantiationService.createInstance(Debugger, this, rawAdapter, added.description)); } diff --git a/src/vs/workbench/contrib/debug/electron-browser/debugService.ts b/src/vs/workbench/contrib/debug/electron-browser/debugService.ts index 5aac6bdf13c..4828acaa6eb 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/debugService.ts @@ -1016,7 +1016,7 @@ export class DebugService implements IDebugService { //---- telemetry private telemetryDebugSessionStart(root: IWorkspaceFolder, type: string): Promise { - const extension = this.configurationManager.getDebugger(type).extensionDescription; + const extension = this.configurationManager.getDebugger(type).getMainExtensionDescriptor(); /* __GDPR__ "debugSessionStart" : { "type": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, diff --git a/src/vs/workbench/contrib/debug/node/debugger.ts b/src/vs/workbench/contrib/debug/node/debugger.ts index 01f5edd2451..93e37f35d61 100644 --- a/src/vs/workbench/contrib/debug/node/debugger.ts +++ b/src/vs/workbench/contrib/debug/node/debugger.ts @@ -26,19 +26,36 @@ import { getPathFromAmdModule } from 'vs/base/common/amd'; import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; +import { isDebuggerMainContribution } from 'vs/workbench/contrib/debug/common/debugUtils'; export class Debugger implements IDebugger { - private mergedExtensionDescriptions: IExtensionDescription[]; + private debuggerContribution: IDebuggerContribution = {}; + private mergedExtensionDescriptions: IExtensionDescription[] = []; + private mainExtensionDescription: IExtensionDescription | undefined; - constructor(private configurationManager: IConfigurationManager, private debuggerContribution: IDebuggerContribution, public extensionDescription: IExtensionDescription, + constructor(private configurationManager: IConfigurationManager, dbgContribution: IDebuggerContribution, extensionDescription: IExtensionDescription, @IConfigurationService private readonly configurationService: IConfigurationService, @ITextResourcePropertiesService private readonly resourcePropertiesService: ITextResourcePropertiesService, @ICommandService private readonly commandService: ICommandService, @IConfigurationResolverService private readonly configurationResolverService: IConfigurationResolverService, @ITelemetryService private readonly telemetryService: ITelemetryService, ) { - this.mergedExtensionDescriptions = [extensionDescription]; + this.merge(dbgContribution, extensionDescription); + } + + public merge(otherDebuggerContribution: IDebuggerContribution, extensionDescription: IExtensionDescription): void { + + // remember all extensions that are merged for this debugger + this.mergedExtensionDescriptions.push(extensionDescription); + + // merge debugger contributions + objects.mixin(this.debuggerContribution, otherDebuggerContribution, extensionDescription.isBuiltin); + + // remember the extension that has the "main" debugger contribution + if (isDebuggerMainContribution(otherDebuggerContribution)) { + this.mainExtensionDescription = extensionDescription; + } } public createDebugAdapter(session: IDebugSession, outputService: IOutputService): Promise { @@ -129,7 +146,9 @@ export class Debugger implements IDebugger { private inExtHost(): boolean { const debugConfigs = this.configurationService.getValue('debug'); - return debugConfigs.extensionHostDebugAdapter || this.configurationManager.needsToRunInExtHost(this.type) || this.extensionDescription.extensionLocation.scheme !== 'file'; + return debugConfigs.extensionHostDebugAdapter + || this.configurationManager.needsToRunInExtHost(this.type) + || (this.mainExtensionDescription && this.mainExtensionDescription.extensionLocation.scheme !== 'file'); } get label(): string { @@ -152,18 +171,6 @@ export class Debugger implements IDebugger { return this.debuggerContribution.languages; } - merge(secondRawAdapter: IDebuggerContribution, extensionDescription: IExtensionDescription): void { - - // remember all ext descriptions that are the source of this debugger - this.mergedExtensionDescriptions.push(extensionDescription); - - // Give priority to built in debug adapters - if (extensionDescription.isBuiltin) { - this.extensionDescription = extensionDescription; - } - objects.mixin(this.debuggerContribution, secondRawAdapter, extensionDescription.isBuiltin); - } - hasInitialConfiguration(): boolean { return !!this.debuggerContribution.initialConfigurations; } @@ -204,6 +211,10 @@ export class Debugger implements IDebugger { return Promise.resolve(content); } + public getMainExtensionDescriptor(): IExtensionDescription { + return this.mainExtensionDescription || this.mergedExtensionDescriptions[0]; + } + @memoize getCustomTelemetryService(): Promise { if (!this.debuggerContribution.aiKey) { @@ -221,7 +232,7 @@ export class Debugger implements IDebugger { { serverName: 'Debug Telemetry', timeout: 1000 * 60 * 5, - args: [`${this.extensionDescription.publisher}.${this.type}`, JSON.stringify(data), this.debuggerContribution.aiKey], + args: [`${this.getMainExtensionDescriptor().publisher}.${this.type}`, JSON.stringify(data), this.debuggerContribution.aiKey], env: { ELECTRON_RUN_AS_NODE: 1, PIPE_LOGGING: 'true', From c892f9cfe0923cd9aace5d0e4f5b9cb0022a86fd Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 14:08:57 -0800 Subject: [PATCH 020/207] Strict null work --- .../base/parts/quickopen/browser/quickOpenViewer.ts | 2 +- src/vs/base/parts/tree/browser/treeView.ts | 4 ++-- .../extensions/electron-browser/extensionsList.ts | 2 +- .../electron-browser/extensionsWidgets.ts | 13 ++++++++++--- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/vs/base/parts/quickopen/browser/quickOpenViewer.ts b/src/vs/base/parts/quickopen/browser/quickOpenViewer.ts index a6c8e390574..a87b30dbadc 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenViewer.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenViewer.ts @@ -33,7 +33,7 @@ export class DataSource implements IDataSource { hasChildren(tree: ITree, element: any): boolean { const model = this.modelProvider.getModel(); - return model && model === element && model.entries.length > 0; + return !!(model && model === element && model.entries.length > 0); } getChildren(tree: ITree, element: any): Promise { diff --git a/src/vs/base/parts/tree/browser/treeView.ts b/src/vs/base/parts/tree/browser/treeView.ts index fa0a7dcbe2b..5e7e31b7d3e 100644 --- a/src/vs/base/parts/tree/browser/treeView.ts +++ b/src/vs/base/parts/tree/browser/treeView.ts @@ -1286,8 +1286,8 @@ export class TreeView extends HeightMap { element = this.model!.getInput(); position = DOM.getDomNodePagePosition(this.inputItem.element); } else { - let id = this.context.dataSource.getId(this.context.tree, element); - let viewItem = this.items[id]; + const id = this.context.dataSource.getId(this.context.tree, element); + const viewItem = this.items[id!]; position = DOM.getDomNodePagePosition(viewItem.element); } diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsList.ts index 75a817b8b41..60942cd50a7 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsList.ts @@ -34,7 +34,7 @@ export interface ITemplateData { ratings: HTMLElement; author: HTMLElement; description: HTMLElement; - extension: IExtension; + extension: IExtension | null; disposables: IDisposable[]; extensionDisposables: IDisposable[]; actionbar: ActionBar; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts index b5f3b7d5af5..8cf034ebdb5 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts @@ -142,7 +142,7 @@ export class RatingsWidget extends ExtensionWidget { export class RecommendationWidget extends ExtensionWidget { - private element: HTMLElement; + private element?: HTMLElement; private disposables: IDisposable[] = []; constructor( @@ -161,7 +161,7 @@ export class RecommendationWidget extends ExtensionWidget { if (this.element) { this.parent.removeChild(this.element); } - this.element = null; + this.element = undefined; this.disposables = dispose(this.disposables); } @@ -232,6 +232,9 @@ export class RemoteBadgeWidget extends ExtensionWidget { append(this.element, $('span.octicon.octicon-file-symlink-directory')); const applyBadgeStyle = () => { + if (!this.element) { + return; + } const bgColor = this.themeService.getTheme().getColor(STATUS_BAR_HOST_NAME_BACKGROUND); const fgColor = this.workspaceContextService.getWorkbenchState() === WorkbenchState.EMPTY ? this.themeService.getTheme().getColor(STATUS_BAR_NO_FOLDER_FOREGROUND) : this.themeService.getTheme().getColor(STATUS_BAR_FOREGROUND); this.element.style.backgroundColor = bgColor ? bgColor.toString() : ''; @@ -241,7 +244,11 @@ export class RemoteBadgeWidget extends ExtensionWidget { this.themeService.onThemeChange(applyBadgeStyle, this, this.disposables); this.workspaceContextService.onDidChangeWorkbenchState(applyBadgeStyle, this, this.disposables); - const updateTitle = () => this.element.title = localize('remote extension title', "Extension in {0}", this.labelService.getHostLabel()); + const updateTitle = () => { + if (this.element) { + this.element.title = localize('remote extension title', "Extension in {0}", this.labelService.getHostLabel()); + } + }; this.labelService.onDidChangeFormatters(() => updateTitle(), this, this.disposables); updateTitle(); } From 1cd1f81106262c487f233683f32da15f651bd3b5 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 14:26:35 -0800 Subject: [PATCH 021/207] Strict null check extensionHost.ts --- src/tsconfig.strictNullChecks.json | 2 + src/vs/workbench/api/node/extHost.protocol.ts | 12 +++--- .../electron-browser/extensionHost.ts | 42 +++++++++++-------- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 0fea9d867ea..55f71e76197 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -404,6 +404,7 @@ "./vs/workbench/api/electron-browser/mainThreadClipboard.ts", "./vs/workbench/api/electron-browser/mainThreadCommands.ts", "./vs/workbench/api/electron-browser/mainThreadConfiguration.ts", + "./vs/workbench/api/electron-browser/mainThreadConsole.ts", "./vs/workbench/api/electron-browser/mainThreadDiagnostics.ts", "./vs/workbench/api/electron-browser/mainThreadDialogs.ts", "./vs/workbench/api/electron-browser/mainThreadDocumentContentProviders.ts", @@ -686,6 +687,7 @@ "./vs/workbench/services/extensions/common/extensions.ts", "./vs/workbench/services/extensions/common/extensionsRegistry.ts", "./vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts", + "./vs/workbench/services/extensions/electron-browser/extensionHost.ts", "./vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts", "./vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler.ts", "./vs/workbench/services/extensions/electron-browser/runtimeExtensionsInput.ts", diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index d16e2fb13dc..04abd54e92b 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -48,10 +48,10 @@ import { IRemoteConsoleLog } from 'vs/base/node/console'; export interface IEnvironment { isExtensionDevelopmentDebug: boolean; - appRoot: URI; - appSettingsHome: URI; - extensionDevelopmentLocationURI: URI; - extensionTestsPath: string; + appRoot?: URI; + appSettingsHome?: URI; + extensionDevelopmentLocationURI?: URI; + extensionTestsPath?: string; globalStorageHome: URI; } @@ -63,10 +63,10 @@ export interface IWorkspaceData { } export interface IInitData { - commit: string; + commit?: string; parentPid: number; environment: IEnvironment; - workspace: IWorkspaceData; + workspace?: IWorkspaceData; resolvedExtensions: ExtensionIdentifier[]; extensions: IExtensionDescription[]; telemetryInfo: ITelemetryInfo; diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index a898b22b164..3ab15256334 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -39,7 +39,7 @@ import { IExtensionDescription } from 'vs/workbench/services/extensions/common/e export interface IExtensionHostStarter { readonly onCrashed: Event<[number, string]>; - start(): Promise; + start(): Promise | null; getInspectPort(): number; dispose(): void; } @@ -79,15 +79,15 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { private readonly _isExtensionDevTestFromCli: boolean; // State - private _lastExtensionHostError: string; + private _lastExtensionHostError: string | null; private _terminating: boolean; // Resources, in order they get acquired/created when .start() is called: - private _namedPipeServer: Server; + private _namedPipeServer: Server | null; private _inspectPort: number; - private _extensionHostProcess: ChildProcess; - private _extensionHostConnection: Socket; - private _messageProtocol: Promise; + private _extensionHostProcess: ChildProcess | null; + private _extensionHostConnection: Socket | null; + private _messageProtocol: Promise | null; constructor( private readonly _autoStart: boolean, @@ -154,7 +154,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { } } - public start(): Promise { + public start(): Promise | null { if (this._terminating) { // .terminate() was called return null; @@ -180,7 +180,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { // We detach because we have noticed that when the renderer exits, its child processes // (i.e. extension host) are taken down in a brutal fashion by the OS detached: !!isWindows, - execArgv: undefined, + execArgv: undefined as string[] | undefined, silent: true }; @@ -301,7 +301,9 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { this._namedPipeServer = createServer(); this._namedPipeServer.on('error', reject); this._namedPipeServer.listen(pipeName, () => { - this._namedPipeServer.removeListener('error', reject); + if (this._namedPipeServer) { + this._namedPipeServer.removeListener('error', reject); + } resolve(pipeName); }); }); @@ -342,15 +344,19 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { // Wait for the extension host to connect to our named pipe // and wrap the socket in the message passing protocol let handle = setTimeout(() => { - this._namedPipeServer.close(); - this._namedPipeServer = null; + if (this._namedPipeServer) { + this._namedPipeServer.close(); + this._namedPipeServer = null; + } reject('timeout'); }, 60 * 1000); - this._namedPipeServer.on('connection', socket => { + this._namedPipeServer!.on('connection', socket => { clearTimeout(handle); - this._namedPipeServer.close(); - this._namedPipeServer = null; + if (this._namedPipeServer) { + this._namedPipeServer.close(); + this._namedPipeServer = null; + } this._extensionHostConnection = socket; // using a buffered message protocol here because between now @@ -429,8 +435,8 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { extensionTestsPath: this._environmentService.extensionTestsPath, globalStorageHome: URI.file(this._environmentService.globalStorageHome) }, - workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : { - configuration: workspace.configuration, + workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? undefined : { + configuration: workspace.configuration || undefined, folders: workspace.folders, id: workspace.id, name: this._labelService.getWorkspaceLabel(workspace) @@ -509,7 +515,9 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { } // send SIGUSR1 and wait a little the actual port is read from the process stdout which we // scan here: https://github.com/Microsoft/vscode/blob/67ffab8dcd1a6752d8b62bcd13d7020101eef568/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts#L225-L240 - this._extensionHostProcess.kill('SIGUSR1'); + if (this._extensionHostProcess) { + this._extensionHostProcess.kill('SIGUSR1'); + } return timeout(1000); } From 228978ab58e91ae11a92373f9097fcef7a4f7faa Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 14:56:39 -0800 Subject: [PATCH 022/207] Strict null work in mainThreadSave --- .../mainThreadSaveParticipant.ts | 16 ++++----- src/vs/workbench/common/editor.ts | 2 +- .../textfile/common/textFileEditorModel.ts | 24 ++++++------- .../services/textfile/common/textfiles.ts | 4 +-- .../api/mainThreadSaveParticipant.test.ts | 34 +++++++++---------- 5 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts b/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts index 8682ee6a2ed..7a7b720a77b 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts @@ -7,7 +7,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays'; import { IdleValue, sequence } from 'vs/base/common/async'; import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation'; import * as strings from 'vs/base/common/strings'; -import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { trimTrailingWhitespace } from 'vs/editor/common/commands/trimTrailingWhitespaceCommand'; @@ -60,7 +60,7 @@ class TrimWhitespaceParticipant implements ISaveParticipantParticipant { let prevSelection: Selection[] = []; let cursors: Position[] = []; - let editor = findEditor(model, this.codeEditorService); + const editor = findEditor(model, this.codeEditorService); if (editor) { // Find `prevSelection` in any case do ensure a good undo stack when pushing the edit // Collect active cursors in `cursors` only if `isAutoSaved` to avoid having the cursors jump @@ -85,12 +85,12 @@ class TrimWhitespaceParticipant implements ISaveParticipantParticipant { } } -function findEditor(model: ITextModel, codeEditorService: ICodeEditorService): ICodeEditor { - let candidate: ICodeEditor | null = null; +function findEditor(model: ITextModel, codeEditorService: ICodeEditorService): IActiveCodeEditor | null { + let candidate: IActiveCodeEditor | null = null; if (model.isAttachedToEditor()) { for (const editor of codeEditorService.listCodeEditors()) { - if (editor.getModel() === model) { + if (editor.hasModel() && editor.getModel() === model) { if (editor.hasTextFocus()) { return editor; // favour focused editor if there are multiple } @@ -233,7 +233,7 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant { const timeout = this._configurationService.getValue('editor.formatOnSaveTimeout', { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() }); - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { let source = new CancellationTokenSource(); let request = getDocumentFormattingEdits(model, { tabSize, insertSpaces }, source.token); @@ -277,7 +277,7 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant { return [new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn)]; } } - return undefined; + return null; }); } @@ -425,7 +425,7 @@ export class SaveParticipant implements ISaveParticipant { } dispose(): void { - TextFileEditorModel.setSaveParticipant(undefined); + TextFileEditorModel.setSaveParticipant(null); this._saveParticipants.dispose(); } diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 6af7b6dddeb..a9113661957 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -638,7 +638,7 @@ export class EditorModel extends Disposable implements IEditorModel { /** * Causes this model to load returning a promise when loading is completed. */ - load(): Promise { + load(): Promise { return Promise.resolve(this); } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 248ba255f0e..c127e2646f9 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -45,8 +45,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private static saveErrorHandler: ISaveErrorHandler; static setSaveErrorHandler(handler: ISaveErrorHandler): void { TextFileEditorModel.saveErrorHandler = handler; } - private static saveParticipant: ISaveParticipant; - static setSaveParticipant(handler: ISaveParticipant): void { TextFileEditorModel.saveParticipant = handler; } + private static saveParticipant: ISaveParticipant | null; + static setSaveParticipant(handler: ISaveParticipant | null): void { TextFileEditorModel.saveParticipant = handler; } private readonly _onDidContentChange: Emitter = this._register(new Emitter()); get onDidContentChange(): Event { return this._onDidContentChange.event; } @@ -62,9 +62,9 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private bufferSavedVersionId: number; private lastResolvedDiskStat: IFileStat; private blockModelContentChange: boolean; - private autoSaveAfterMillies: number; + private autoSaveAfterMillies?: number; private autoSaveAfterMilliesEnabled: boolean; - private autoSaveDisposable: IDisposable; + private autoSaveDisposable?: IDisposable; private contentChangeEventScheduler: RunOnceScheduler; private orphanedChangeEventScheduler: RunOnceScheduler; private saveSequentializer: SaveSequentializer; @@ -129,7 +129,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private onFileChanges(e: FileChangesEvent): void { let fileEventImpactsModel = false; - let newInOrphanModeGuess: boolean; + let newInOrphanModeGuess: boolean | undefined; // If we are currently orphaned, we check if the model file was added back if (this.inOrphanMode) { @@ -235,7 +235,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil }); } - load(options?: ILoadOptions): Promise { + load(options?: ILoadOptions): Promise { this.logService.trace('load() - enter', this.resource); // It is very important to not reload the model when the model is dirty. @@ -289,7 +289,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil const allowBinary = this.isResolved() /* always allow if we resolved previously */ || (options && options.allowBinary); // Decide on etag - let etag: string; + let etag: string | undefined; if (forceReadFromDisk) { etag = undefined; // reset ETag if we enforce to read from disk } else if (this.lastResolvedDiskStat) { @@ -491,7 +491,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return this.backupFileService.resolveBackupContent(backup).then(backupContent => backupContent, error => null /* ignore errors */); } - protected getOrCreateMode(modeService: IModeService, preferredModeIds: string, firstLineText?: string): ILanguageSelection { + protected getOrCreateMode(modeService: IModeService, preferredModeIds: string | undefined, firstLineText?: string): ILanguageSelection { return modeService.createByFilepathOrFirstLine(this.resource.fsPath, firstLineText); } @@ -914,7 +914,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return this.lastSaveAttemptTime; } - getETag(): string { + getETag(): string | null { return this.lastResolvedDiskStat ? this.lastResolvedDiskStat.etag : null; } @@ -1046,8 +1046,8 @@ interface ISaveOperation { } export class SaveSequentializer { - private _pendingSave: IPendingSave; - private _nextSave: ISaveOperation; + private _pendingSave?: IPendingSave; + private _nextSave?: ISaveOperation; hasPendingSave(versionId?: number): boolean { if (!this._pendingSave) { @@ -1061,7 +1061,7 @@ export class SaveSequentializer { return !!this._pendingSave; } - get pendingSave(): Promise { + get pendingSave(): Promise | undefined { return this._pendingSave ? this._pendingSave.promise : undefined; } diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index a6991132dbc..43d88b808ae 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -236,7 +236,7 @@ export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport hasState(state: ModelState): boolean; - getETag(): string; + getETag(): string | null; updatePreferredEncoding(encoding: string): void; @@ -246,7 +246,7 @@ export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport revert(soft?: boolean): Promise; - createSnapshot(): ITextSnapshot; + createSnapshot(): ITextSnapshot | null; isDirty(): boolean; diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts index 28c4ecf2737..2cc91becc3c 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts @@ -43,31 +43,31 @@ suite('MainThreadSaveParticipant', function () { await model.load(); const configService = new TestConfigurationService(); configService.setUserConfiguration('files', { 'insertFinalNewline': true }); - const participant = new FinalNewLineParticipant(configService, undefined); + const participant = new FinalNewLineParticipant(configService, undefined!); // No new line for empty lines let lineContent = ''; model.textEditorModel.setValue(lineContent); await participant.participate(model, { reason: SaveReason.EXPLICIT }); - assert.equal(snapshotToString(model.createSnapshot()), lineContent); + assert.equal(snapshotToString(model.createSnapshot()!), lineContent); // No new line if last line already empty lineContent = `Hello New Line${model.textEditorModel.getEOL()}`; model.textEditorModel.setValue(lineContent); await participant.participate(model, { reason: SaveReason.EXPLICIT }); - assert.equal(snapshotToString(model.createSnapshot()), lineContent); + assert.equal(snapshotToString(model.createSnapshot()!), lineContent); // New empty line added (single line) lineContent = 'Hello New Line'; model.textEditorModel.setValue(lineContent); await participant.participate(model, { reason: SaveReason.EXPLICIT }); - assert.equal(snapshotToString(model.createSnapshot()), `${lineContent}${model.textEditorModel.getEOL()}`); + assert.equal(snapshotToString(model.createSnapshot()!), `${lineContent}${model.textEditorModel.getEOL()}`); // New empty line added (multi line) lineContent = `Hello New Line${model.textEditorModel.getEOL()}Hello New Line${model.textEditorModel.getEOL()}Hello New Line`; model.textEditorModel.setValue(lineContent); await participant.participate(model, { reason: SaveReason.EXPLICIT }); - assert.equal(snapshotToString(model.createSnapshot()), `${lineContent}${model.textEditorModel.getEOL()}`); + assert.equal(snapshotToString(model.createSnapshot()!), `${lineContent}${model.textEditorModel.getEOL()}`); }); test('trim final new lines', async function () { @@ -76,7 +76,7 @@ suite('MainThreadSaveParticipant', function () { await model.load(); const configService = new TestConfigurationService(); configService.setUserConfiguration('files', { 'trimFinalNewlines': true }); - const participant = new TrimFinalNewLinesParticipant(configService, undefined); + const participant = new TrimFinalNewLinesParticipant(configService, undefined!); const textContent = 'Trim New Line'; const eol = `${model.textEditorModel.getEOL()}`; @@ -84,25 +84,25 @@ suite('MainThreadSaveParticipant', function () { let lineContent = `${textContent}`; model.textEditorModel.setValue(lineContent); await participant.participate(model, { reason: SaveReason.EXPLICIT }); - assert.equal(snapshotToString(model.createSnapshot()), lineContent); + assert.equal(snapshotToString(model.createSnapshot()!), lineContent); // No new line removal if last line is single new line lineContent = `${textContent}${eol}`; model.textEditorModel.setValue(lineContent); await participant.participate(model, { reason: SaveReason.EXPLICIT }); - assert.equal(snapshotToString(model.createSnapshot()), lineContent); + assert.equal(snapshotToString(model.createSnapshot()!), lineContent); // Remove new line (single line with two new lines) lineContent = `${textContent}${eol}${eol}`; model.textEditorModel.setValue(lineContent); await participant.participate(model, { reason: SaveReason.EXPLICIT }); - assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}`); + assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}`); // Remove new lines (multiple lines with multiple new lines) lineContent = `${textContent}${eol}${textContent}${eol}${eol}${eol}`; model.textEditorModel.setValue(lineContent); await participant.participate(model, { reason: SaveReason.EXPLICIT }); - assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}${textContent}${eol}`); + assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}${textContent}${eol}`); }); test('trim final new lines bug#39750', async function () { @@ -111,7 +111,7 @@ suite('MainThreadSaveParticipant', function () { await model.load(); const configService = new TestConfigurationService(); configService.setUserConfiguration('files', { 'trimFinalNewlines': true }); - const participant = new TrimFinalNewLinesParticipant(configService, undefined); + const participant = new TrimFinalNewLinesParticipant(configService, undefined!); const textContent = 'Trim New Line'; // single line @@ -124,12 +124,12 @@ suite('MainThreadSaveParticipant', function () { // undo model.textEditorModel.undo(); - assert.equal(snapshotToString(model.createSnapshot()), `${textContent}`); + assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}`); // trim final new lines should not mess the undo stack await participant.participate(model, { reason: SaveReason.EXPLICIT }); model.textEditorModel.redo(); - assert.equal(snapshotToString(model.createSnapshot()), `${textContent}.`); + assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}.`); }); test('trim final new lines bug#46075', async function () { @@ -138,7 +138,7 @@ suite('MainThreadSaveParticipant', function () { await model.load(); const configService = new TestConfigurationService(); configService.setUserConfiguration('files', { 'trimFinalNewlines': true }); - const participant = new TrimFinalNewLinesParticipant(configService, undefined); + const participant = new TrimFinalNewLinesParticipant(configService, undefined!); const textContent = 'Test'; const eol = `${model.textEditorModel.getEOL()}`; let content = `${textContent}${eol}${eol}`; @@ -150,12 +150,12 @@ suite('MainThreadSaveParticipant', function () { } // confirm trimming - assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}`); + assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}`); // undo should go back to previous content immediately model.textEditorModel.undo(); - assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}${eol}`); + assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}${eol}`); model.textEditorModel.redo(); - assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}`); + assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}`); }); }); From 18ab2129170b38e0a7d750256d75b4f0aa4654ef Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 14:56:55 -0800 Subject: [PATCH 023/207] Strict null work in runtimeExtensionsEditor --- .../electron-browser/runtimeExtensionsEditor.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts index 357adbe4cf0..b1c5250d2a3 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts @@ -98,10 +98,10 @@ export class RuntimeExtensionsEditor extends BaseEditor { public static readonly ID: string = 'workbench.editor.runtimeExtensions'; - private _list: WorkbenchList; + private _list: WorkbenchList | null; private _profileInfo: IExtensionHostProfile; - private _elements: IRuntimeExtension[]; + private _elements: IRuntimeExtension[] | null; private _extensionsDescriptions: IExtensionDescription[]; private _updateSoon: RunOnceScheduler; private _profileSessionState: IContextKey; @@ -299,7 +299,7 @@ export class RuntimeExtensionsEditor extends BaseEditor { toggleClass(data.root, 'odd', index % 2 === 1); - data.name.textContent = element.marketplaceInfo ? element.marketplaceInfo.displayName : element.description.displayName; + data.name.textContent = element.marketplaceInfo ? element.marketplaceInfo.displayName : element.description.displayName || ''; const activationTimes = element.status.activationTimes; let syncTime = activationTimes.codeLoadingTime + activationTimes.activateCallTime; @@ -415,8 +415,8 @@ export class RuntimeExtensionsEditor extends BaseEditor { actions.push(new Separator()); if (e.element.marketplaceInfo) { - actions.push(new Action('runtimeExtensionsEditor.action.disableWorkspace', nls.localize('disable workspace', "Disable (Workspace)"), null, true, () => this._extensionsWorkbenchService.setEnablement(e.element.marketplaceInfo, EnablementState.WorkspaceDisabled))); - actions.push(new Action('runtimeExtensionsEditor.action.disable', nls.localize('disable', "Disable"), null, true, () => this._extensionsWorkbenchService.setEnablement(e.element.marketplaceInfo, EnablementState.Disabled))); + actions.push(new Action('runtimeExtensionsEditor.action.disableWorkspace', nls.localize('disable workspace', "Disable (Workspace)"), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element!.marketplaceInfo, EnablementState.WorkspaceDisabled))); + actions.push(new Action('runtimeExtensionsEditor.action.disable', nls.localize('disable', "Disable"), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element!.marketplaceInfo, EnablementState.Disabled))); actions.push(new Separator()); } const state = this._extensionHostProfileService.state; @@ -440,7 +440,9 @@ export class RuntimeExtensionsEditor extends BaseEditor { } public layout(dimension: Dimension): void { - this._list.layout(dimension.height); + if (this._list) { + this._list.layout(dimension.height); + } } } From 7cd2840710df83b22160c07c3a1616b66750d555 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 15:00:00 -0800 Subject: [PATCH 024/207] Fix failing webview test --- .../contrib/webview/electron-browser/webviewElement.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts index 89ae486f958..d340251efac 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts @@ -248,7 +248,7 @@ export class WebviewElement extends Disposable { ) { super(); this._webview = document.createElement('webview'); - this._webview.setAttribute('partition', this._options.allowSvgs ? 'webview' : `webview${Date.now()}`); + this._webview.setAttribute('partition', `webview${Date.now()}`); this._webview.setAttribute('webpreferences', 'contextIsolation=yes'); From a1c170cd8e7f80f279912f6d4129cf2559fe718e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 8 Feb 2019 01:01:03 +0100 Subject: [PATCH 025/207] Fix #67642 --- .../preferences/browser/preferencesService.ts | 6 +- .../preferences/common/preferencesModels.ts | 60 ++++++++++++------- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/src/vs/workbench/services/preferences/browser/preferencesService.ts b/src/vs/workbench/services/preferences/browser/preferencesService.ts index 56177073387..ca15cd76763 100644 --- a/src/vs/workbench/services/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/services/preferences/browser/preferencesService.ts @@ -35,7 +35,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { GroupDirection, IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { DEFAULT_SETTINGS_EDITOR_SETTING, FOLDER_SETTINGS_PATH, getSettingsTargetName, IPreferencesEditorModel, IPreferencesService, ISetting, ISettingsEditorOptions, SettingsEditorOptions, USE_SPLIT_JSON_SETTING } from 'vs/workbench/services/preferences/common/preferences'; import { DefaultPreferencesEditorInput, KeybindingsEditorInput, PreferencesEditorInput, SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput'; -import { defaultKeybindingsContents, DefaultKeybindingsEditorModel, DefaultSettings, DefaultSettingsEditorModel, Settings2EditorModel, SettingsEditorModel, WorkspaceConfigurationEditorModel } from 'vs/workbench/services/preferences/common/preferencesModels'; +import { defaultKeybindingsContents, DefaultKeybindingsEditorModel, DefaultSettings, DefaultSettingsEditorModel, Settings2EditorModel, SettingsEditorModel, WorkspaceConfigurationEditorModel, DefaultRawSettingsEditorModel } from 'vs/workbench/services/preferences/common/preferencesModels'; const emptyEditableSettingsContent = '{\n}'; @@ -134,9 +134,9 @@ export class PreferencesService extends Disposable implements IPreferencesServic } if (this.defaultSettingsRawResource.toString() === uri.toString()) { - let defaultSettings: DefaultSettings = this.getDefaultSettings(ConfigurationTarget.USER); + const defaultRawSettingsEditorModel = this.instantiationService.createInstance(DefaultRawSettingsEditorModel, this.getDefaultSettings(ConfigurationTarget.USER)); const languageSelection = this.modeService.create('jsonc'); - const model = this._register(this.modelService.createModel(defaultSettings.raw, languageSelection, uri)); + const model = this._register(this.modelService.createModel(defaultRawSettingsEditorModel.content, languageSelection, uri)); return Promise.resolve(model); } diff --git a/src/vs/workbench/services/preferences/common/preferencesModels.ts b/src/vs/workbench/services/preferences/common/preferencesModels.ts index c738a41fc92..fab9317ee52 100644 --- a/src/vs/workbench/services/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/services/preferences/common/preferencesModels.ts @@ -435,8 +435,6 @@ export class WorkspaceConfigurationEditorModel extends SettingsEditorModel { export class DefaultSettings extends Disposable { - private static _RAW: string; - private _allSettingsGroups: ISettingsGroup[]; private _content: string; private _settingsByName: Map; @@ -479,15 +477,7 @@ export class DefaultSettings extends Disposable { return [mostCommonlyUsed, ...settingsGroups]; } - get raw(): string { - if (!DefaultSettings._RAW) { - DefaultSettings._RAW = this.toContent(this.getRegisteredGroups()); - } - - return DefaultSettings._RAW; - } - - private getRegisteredGroups(): ISettingsGroup[] { + getRegisteredGroups(): ISettingsGroup[] { const configurations = Registry.as(Extensions.Configuration).getConfigurations().slice(); const groups = this.removeEmptySettingsGroups(configurations.sort(this.compareConfigurationNodes) .reduce((result, config, index, array) => this.parseConfig(config, result, array), [])); @@ -889,10 +879,6 @@ class SettingsContentBuilder { this._contentByLines = []; } - private offsetIndexToIndex(offsetIdx: number): number { - return offsetIdx - this._rangeOffset; - } - pushLine(...lineText: string[]): void { this._contentByLines.push(...lineText); } @@ -901,11 +887,11 @@ class SettingsContentBuilder { this._contentByLines.push('{'); this._contentByLines.push(''); this._contentByLines.push(''); - const lastSetting = this._pushGroup(settingsGroups); + const lastSetting = this._pushGroup(settingsGroups, ' '); if (lastSetting) { // Strip the comma from the last setting - const lineIdx = this.offsetIndexToIndex(lastSetting.range.endLineNumber); + const lineIdx = lastSetting.range.endLineNumber - this._rangeOffset; const content = this._contentByLines[lineIdx - 2]; this._contentByLines[lineIdx - 2] = content.substring(0, content.length - 1); } @@ -913,8 +899,7 @@ class SettingsContentBuilder { this._contentByLines.push('}'); } - private _pushGroup(group: ISettingsGroup): ISetting { - const indent = ' '; + protected _pushGroup(group: ISettingsGroup, indent: string): ISetting { let lastSetting: ISetting | null = null; const groupStart = this.lineCountWithOffset + 1; for (const section of group.sections) { @@ -979,7 +964,7 @@ class SettingsContentBuilder { `${displayEnum}: ${fixSettingLink(desc)}` : displayEnum; - this._contentByLines.push(` // - ${line}`); + this._contentByLines.push(`${indent}// - ${line}`); setting.descriptionRanges.push({ startLineNumber: this.lineCountWithOffset, startColumn: this.lastLine.indexOf(line) + 1, endLineNumber: this.lineCountWithOffset, endColumn: this.lastLine.length }); }); @@ -1124,6 +1109,41 @@ export function createValidator(prop: IConfigurationPropertySchema): ((value: an }; } +class RawSettingsContentBuilder extends SettingsContentBuilder { + + constructor(private indent: string = '\t') { + super(0); + } + + pushGroup(settingsGroups: ISettingsGroup): void { + this._pushGroup(settingsGroups, this.indent); + } + +} + +export class DefaultRawSettingsEditorModel extends Disposable { + + private _content: string | null = null; + + constructor(private defaultSettings: DefaultSettings) { + super(); + this._register(defaultSettings.onDidChange(() => this._content = null)); + } + + get content(): string { + if (this._content === null) { + const builder = new RawSettingsContentBuilder(); + builder.pushLine('{'); + for (const settingsGroup of this.defaultSettings.getRegisteredGroups()) { + builder.pushGroup(settingsGroup); + } + builder.pushLine('}'); + this._content = builder.getContent(); + } + return this._content; + } +} + function escapeInvisibleChars(enumValue: string): string { return enumValue && enumValue .replace(/\n/g, '\\n') From c460e31c646de2a5b525f8dd50e6b06d452112af Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 8 Feb 2019 01:43:57 +0100 Subject: [PATCH 026/207] fix #67573 --- src/vs/editor/contrib/gotoError/gotoErrorWidget.ts | 3 +++ src/vs/editor/contrib/hover/modesContentHover.ts | 2 +- .../markers/electron-browser/markersTreeViewer.ts | 9 +++++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts index 22e8918aa23..fd3598b5a28 100644 --- a/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts +++ b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts @@ -93,6 +93,9 @@ class MessageWidget { lastLineElement = document.createElement('div'); lastLineElement.innerText = line; this._editor.applyFontInfo(lastLineElement); + if (line === '') { + lastLineElement.style.height = lastLineElement.style.lineHeight; + } this._messageBlock.appendChild(lastLineElement); } if (source || code) { diff --git a/src/vs/editor/contrib/hover/modesContentHover.ts b/src/vs/editor/contrib/hover/modesContentHover.ts index af956cabdfb..1d911e306e9 100644 --- a/src/vs/editor/contrib/hover/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/modesContentHover.ts @@ -473,7 +473,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { const messageElement = dom.append(hoverElement, $('span')); messageElement.style.whiteSpace = 'pre-wrap'; - messageElement.innerText = message.trim(); + messageElement.innerText = message; this._editor.applyFontInfo(messageElement); if (source || code) { diff --git a/src/vs/workbench/contrib/markers/electron-browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/electron-browser/markersTreeViewer.ts index d1632335485..5dc45a8645f 100644 --- a/src/vs/workbench/contrib/markers/electron-browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/electron-browser/markersTreeViewer.ts @@ -90,15 +90,17 @@ const enum TemplateId { export class VirtualDelegate implements IListVirtualDelegate { + static LINE_HEIGHT: number = 22; + constructor(private readonly markersViewState: MarkersViewModel) { } getHeight(element: TreeElement): number { if (element instanceof Marker) { const viewModel = this.markersViewState.getViewModel(element); const noOfLines = !viewModel || viewModel.multiline ? element.lines.length : 1; - return noOfLines * 22; + return noOfLines * VirtualDelegate.LINE_HEIGHT; } - return 22; + return VirtualDelegate.LINE_HEIGHT; } getTemplateId(element: TreeElement): string { @@ -321,6 +323,9 @@ class MarkerWidget extends Disposable { lastLineElement = dom.append(messageContainer, dom.$('.marker-message-line')); const highlightedLabel = new HighlightedLabel(lastLineElement, false); highlightedLabel.set(lines[index], lineMatches[index]); + if (lines[index] === '') { + lastLineElement.style.height = `${VirtualDelegate.LINE_HEIGHT}px`; + } } this.renderDetails(marker, filterData, multiline ? lastLineElement : this.messageAndDetailsContainer); } From e259543b84471270c13e6ea46621b01bf58732d0 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 16:06:01 -0800 Subject: [PATCH 027/207] Split up static webview options and options that can be changed dynamically --- .../electron-browser/extensionEditor.ts | 9 ++-- .../html/electron-browser/htmlPreviewPart.ts | 8 ++-- .../webview/electron-browser/webviewEditor.ts | 9 ++-- .../electron-browser/webviewEditorInput.ts | 2 - .../electron-browser/webviewElement.ts | 47 +++++++++---------- 5 files changed, 36 insertions(+), 39 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts index d591085df81..0e03b0890ce 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts @@ -525,9 +525,12 @@ export class ExtensionEditor extends BaseEditor { .then(renderBody) .then(removeEmbeddedSVGs) .then(body => { - const allowedBadgeProviders = this.extensionsWorkbenchService.allowedBadgeProviders; - const webViewOptions = allowedBadgeProviders.length > 0 ? { allowScripts: false, allowSvgs: false, svgWhiteList: allowedBadgeProviders } : {}; - const wbeviewElement = this.instantiationService.createInstance(WebviewElement, this.partService.getContainer(Parts.EDITOR_PART), webViewOptions); + const wbeviewElement = this.instantiationService.createInstance(WebviewElement, + this.partService.getContainer(Parts.EDITOR_PART), + {}, + { + svgWhiteList: this.extensionsWorkbenchService.allowedBadgeProviders + }); wbeviewElement.mountTo(this.content); const removeLayoutParticipant = arrays.insert(this.layoutParticipants, wbeviewElement); this.contentDisposables.push(toDisposable(removeLayoutParticipant)); diff --git a/src/vs/workbench/contrib/html/electron-browser/htmlPreviewPart.ts b/src/vs/workbench/contrib/html/electron-browser/htmlPreviewPart.ts index fc54e558fff..8f86431edbb 100644 --- a/src/vs/workbench/contrib/html/electron-browser/htmlPreviewPart.ts +++ b/src/vs/workbench/contrib/html/electron-browser/htmlPreviewPart.ts @@ -17,7 +17,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { Dimension } from 'vs/base/browser/dom'; import { BaseWebviewEditor } from 'vs/workbench/contrib/webview/electron-browser/baseWebviewEditor'; -import { WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; +import { WebviewElement, WebviewContentOptions } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -88,7 +88,7 @@ export class HtmlPreviewPart extends BaseWebviewEditor { private get webview(): WebviewElement { if (!this._webview) { - let webviewOptions: WebviewOptions = {}; + let webviewOptions: WebviewContentOptions = {}; if (this.input && this.input instanceof HtmlInput) { webviewOptions = this.input.options; } @@ -96,9 +96,9 @@ export class HtmlPreviewPart extends BaseWebviewEditor { this._webview = this._instantiationService.createInstance(WebviewElement, this._partService.getContainer(Parts.EDITOR_PART), { - ...webviewOptions, useSameOriginForRoot: true - }); + }, + webviewOptions); this._webview.mountTo(this._content); if (this.input && this.input instanceof HtmlInput) { diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewEditor.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewEditor.ts index db911b8e5a2..3db8dc9bd78 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewEditor.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewEditor.ts @@ -183,10 +183,7 @@ export class WebviewEditor extends BaseWebviewEditor { input.claimWebview(this); webview.update(input.html, { allowScripts: input.options.enableScripts, - allowSvgs: true, - useSameOriginForRoot: false, localResourceRoots: input.options.localResourceRoots || this.getDefaultLocalResourceRoots(), - extensionLocation: input.extensionLocation }, !!input.options.retainContextWhenHidden); if (this._webviewContent) { @@ -224,9 +221,9 @@ export class WebviewEditor extends BaseWebviewEditor { this._partService.getContainer(Parts.EDITOR_PART), { allowSvgs: true, - useSameOriginForRoot: false, - extensionLocation: input.extensionLocation - }); + extensionLocation: input.extensionLocation, + }, + {}); this._webview.mountTo(this._webviewContent); input.webview = this._webview; diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewEditorInput.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewEditorInput.ts index d07c498efd5..09ec22e7ae0 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewEditorInput.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewEditorInput.ts @@ -207,8 +207,6 @@ export class WebviewEditorInput extends EditorInput { if (this._webview) { this._webview.options = { allowScripts: this._options.enableScripts, - allowSvgs: true, - useSameOriginForRoot: false, localResourceRoots: this._options.localResourceRoots }; } diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts index d340251efac..79cda62b62d 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts @@ -21,14 +21,17 @@ import { endsWith } from 'vs/base/common/strings'; import { isMacintosh } from 'vs/base/common/platform'; export interface WebviewOptions { - readonly allowScripts?: boolean; readonly allowSvgs?: boolean; - readonly svgWhiteList?: string[]; readonly useSameOriginForRoot?: boolean; - readonly localResourceRoots?: ReadonlyArray; readonly extensionLocation?: URI; } +export interface WebviewContentOptions { + readonly allowScripts?: boolean; + readonly svgWhiteList?: string[]; + readonly localResourceRoots?: ReadonlyArray; +} + interface IKeydownEvent { key: string; keyCode: number; @@ -88,14 +91,10 @@ class SvgBlocker extends Disposable { constructor( webview: Electron.WebviewTag, - private readonly _options: WebviewOptions, + private readonly _options: WebviewContentOptions, ) { super(); - if (this._options.allowSvgs) { - return; - } - let loaded = false; this._register(addDisposableListener(webview, 'did-start-loading', () => { if (loaded) { @@ -134,9 +133,6 @@ class SvgBlocker extends Disposable { } private isAllowedSvg(uri: URI): boolean { - if (this._options.allowSvgs) { - return true; - } if (this._options.svgWhiteList) { return this._options.svgWhiteList.indexOf(uri.authority.toLowerCase()) >= 0; } @@ -239,7 +235,8 @@ export class WebviewElement extends Disposable { constructor( private readonly _styleElement: Element, - private _options: WebviewOptions, + private readonly _options: WebviewOptions, + private _contentOptions: WebviewContentOptions, @IInstantiationService instantiationService: IInstantiationService, @IThemeService private readonly _themeService: IThemeService, @IEnvironmentService environmentService: IEnvironmentService, @@ -276,12 +273,14 @@ export class WebviewElement extends Disposable { new WebviewProtocolProvider( this._webview, this._options.extensionLocation, - () => (this._options.localResourceRoots || []), + () => (this._contentOptions.localResourceRoots || []), environmentService, fileService)); - const svgBlocker = this._register(new SvgBlocker(this._webview, this._options)); - svgBlocker.onDidBlockSvg(() => this.onDidBlockSvg()); + if (!this._options.allowSvgs) { + const svgBlocker = this._register(new SvgBlocker(this._webview, this._contentOptions)); + svgBlocker.onDidBlockSvg(() => this.onDidBlockSvg()); + } this._register(new WebviewKeyboardHandler(this._webview, this._keybindingService)); @@ -397,15 +396,15 @@ export class WebviewElement extends Disposable { this._state = value; } - public set options(value: WebviewOptions) { - if (this._options && areWebviewInputOptionsEqual(value, this._options)) { + public set options(value: WebviewContentOptions) { + if (this._contentOptions && areWebviewInputOptionsEqual(value, this._contentOptions)) { return; } - this._options = value; + this._contentOptions = value; this._send('content', { contents: this._contents, - options: this._options, + options: this._contentOptions, state: this._state }); } @@ -414,20 +413,20 @@ export class WebviewElement extends Disposable { this._contents = value; this._send('content', { contents: value, - options: this._options, + options: this._contentOptions, state: this._state }); } - public update(value: string, options: WebviewOptions, retainContextWhenHidden: boolean) { - if (retainContextWhenHidden && value === this._contents && this._options && areWebviewInputOptionsEqual(options, this._options)) { + public update(value: string, options: WebviewContentOptions, retainContextWhenHidden: boolean) { + if (retainContextWhenHidden && value === this._contents && this._contentOptions && areWebviewInputOptionsEqual(options, this._contentOptions)) { return; } this._contents = value; - this._options = options; + this._contentOptions = options; this._send('content', { contents: this._contents, - options: this._options, + options: this._contentOptions, state: this._state }); } From 1cb2f5500a87146230e60ebb1d944219816aa7c0 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 17:31:03 -0800 Subject: [PATCH 028/207] Support TypeScript's explicit "auto" `quotePreference` Fixes #68185 --- extensions/package.json | 2 +- .../src/features/fileConfigurationManager.ts | 14 +++++++------- .../typescript-language-features/src/utils/api.ts | 1 + extensions/yarn.lock | 8 ++++---- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/extensions/package.json b/extensions/package.json index 0f226217b7c..88394d29642 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": "3.3.1" + "typescript": "3.3.3" }, "scripts": { "postinstall": "node ./postinstall" diff --git a/extensions/typescript-language-features/src/features/fileConfigurationManager.ts b/extensions/typescript-language-features/src/features/fileConfigurationManager.ts index 676e80bafd1..cb06f274215 100644 --- a/extensions/typescript-language-features/src/features/fileConfigurationManager.ts +++ b/extensions/typescript-language-features/src/features/fileConfigurationManager.ts @@ -178,20 +178,20 @@ export default class FileConfigurationManager extends Disposable { document.uri); return { - quotePreference: getQuoteStylePreference(preferences), + quotePreference: this.getQuoteStylePreference(preferences), importModuleSpecifierPreference: getImportModuleSpecifierPreference(preferences), allowTextChangesInNewFiles: document.uri.scheme === 'file', providePrefixAndSuffixTextForRename: true, allowRenameOfImportPath: true, }; } -} -function getQuoteStylePreference(config: vscode.WorkspaceConfiguration) { - switch (config.get('quoteStyle')) { - case 'single': return 'single'; - case 'double': return 'double'; - default: return undefined; + private getQuoteStylePreference(config: vscode.WorkspaceConfiguration) { + switch (config.get('quoteStyle')) { + case 'single': return 'single'; + case 'double': return 'double'; + default: return this.client.apiVersion.gte(API.v333) ? 'auto' : undefined; + } } } diff --git a/extensions/typescript-language-features/src/utils/api.ts b/extensions/typescript-language-features/src/utils/api.ts index 3071afbc4dd..f65069a2424 100644 --- a/extensions/typescript-language-features/src/utils/api.ts +++ b/extensions/typescript-language-features/src/utils/api.ts @@ -34,6 +34,7 @@ export default class API { public static readonly v314 = API.fromSimpleString('3.1.4'); public static readonly v320 = API.fromSimpleString('3.2.0'); public static readonly v330 = API.fromSimpleString('3.3.0'); + public static readonly v333 = API.fromSimpleString('3.3.3'); public static fromVersionString(versionString: string): API { diff --git a/extensions/yarn.lock b/extensions/yarn.lock index faf73e87903..abf61b0ecfa 100644 --- a/extensions/yarn.lock +++ b/extensions/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -typescript@3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.1.tgz#6de14e1db4b8a006ac535e482c8ba018c55f750b" - integrity sha512-cTmIDFW7O0IHbn1DPYjkiebHxwtCMU+eTy30ZtJNBPF9j2O1ITu5XH2YnBeVRKWHqF+3JQwWJv0Q0aUgX8W7IA== +typescript@3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.3.tgz#f1657fc7daa27e1a8930758ace9ae8da31403221" + integrity sha512-Y21Xqe54TBVp+VDSNbuDYdGw0BpoR/Q6wo/+35M8PAU0vipahnyduJWirxxdxjsAkS7hue53x2zp8gz7F05u0A== From 44e4a98091eaee93f1b03bbd13cd1066e926e4a0 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 7 Feb 2019 16:02:14 -0800 Subject: [PATCH 029/207] Fix #68018 - the list.select command should open the element with preserveFocus=false --- src/vs/platform/list/browser/listService.ts | 16 +++++++++++++++- src/vs/workbench/browser/actions/listCommands.ts | 4 ++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 389b713aebf..65095160059 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -655,6 +655,17 @@ export interface IResourceResultsNavigationOptions { openOnFocus: boolean; } +export interface SelectionKeyboardEvent extends KeyboardEvent { + preserveFocus?: boolean; +} + +export function getSelectionKeyboardEvent(typeArg: string, preserveFocus?: boolean): SelectionKeyboardEvent { + const e = new KeyboardEvent(typeArg); + (e).preserveFocus = preserveFocus; + + return e; +} + export class TreeResourceNavigator2 extends Disposable { private readonly _onDidOpenResource = new Emitter>(); @@ -697,10 +708,13 @@ export class TreeResourceNavigator2 extends Disposable { } const isDoubleClick = e.browserEvent.detail === 2; + const preserveFocus = (e.browserEvent instanceof KeyboardEvent && typeof (e.browserEvent).preserveFocus === 'boolean') ? + !!(e.browserEvent).preserveFocus : + !isDoubleClick; if (this.tree.openOnSingleClick || isDoubleClick) { const sideBySide = e.browserEvent instanceof MouseEvent && (e.browserEvent.ctrlKey || e.browserEvent.metaKey || e.browserEvent.altKey); - this.open(!isDoubleClick, isDoubleClick, sideBySide); + this.open(preserveFocus, isDoubleClick, sideBySide); } } diff --git a/src/vs/workbench/browser/actions/listCommands.ts b/src/vs/workbench/browser/actions/listCommands.ts index 2ce44cacbb7..94a19170266 100644 --- a/src/vs/workbench/browser/actions/listCommands.ts +++ b/src/vs/workbench/browser/actions/listCommands.ts @@ -7,7 +7,7 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { List } from 'vs/base/browser/ui/list/listWidget'; -import { WorkbenchListFocusContextKey, IListService, WorkbenchListSupportsMultiSelectContextKey, ListWidget, WorkbenchListHasSelectionOrFocus } from 'vs/platform/list/browser/listService'; +import { WorkbenchListFocusContextKey, IListService, WorkbenchListSupportsMultiSelectContextKey, ListWidget, WorkbenchListHasSelectionOrFocus, getSelectionKeyboardEvent } from 'vs/platform/list/browser/listService'; import { PagedList } from 'vs/base/browser/ui/list/listPaging'; import { range } from 'vs/base/common/arrays'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; @@ -579,7 +579,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ // ObjectTree else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) { const list = focused; - const fakeKeyboardEvent = new KeyboardEvent('keydown'); + const fakeKeyboardEvent = getSelectionKeyboardEvent('keydown', false); list.setSelection(list.getFocus(), fakeKeyboardEvent); list.open(list.getFocus()); } From 0af3142ef8578af7c3662f4dc1fc81d219afce62 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 7 Feb 2019 18:12:14 -0800 Subject: [PATCH 030/207] Fix all findFiles excludes always disregarded --- src/vs/workbench/api/node/extHostWorkspace.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/node/extHostWorkspace.ts b/src/vs/workbench/api/node/extHostWorkspace.ts index 4cb7c035cf3..1a16b50202b 100644 --- a/src/vs/workbench/api/node/extHostWorkspace.ts +++ b/src/vs/workbench/api/node/extHostWorkspace.ts @@ -362,7 +362,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { } } - let excludePatternOrDisregardExcludes: string | false = false; + let excludePatternOrDisregardExcludes: string | false | undefined; if (exclude === null) { excludePatternOrDisregardExcludes = false; } else if (exclude) { From 1c50a87561055485d93a3961160902308497f1e3 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 7 Feb 2019 18:15:23 -0800 Subject: [PATCH 031/207] Fix #68056 - findFiles should not use search.exclude --- src/vs/platform/search/common/search.ts | 4 ++-- src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts | 1 + src/vs/workbench/contrib/search/common/queryBuilder.ts | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/search/common/search.ts b/src/vs/platform/search/common/search.ts index 09145ea9f93..369d036d711 100644 --- a/src/vs/platform/search/common/search.ts +++ b/src/vs/platform/search/common/search.ts @@ -338,9 +338,9 @@ export interface ISearchConfiguration extends IFilesConfiguration { }; } -export function getExcludes(configuration: ISearchConfiguration): glob.IExpression | undefined { +export function getExcludes(configuration: ISearchConfiguration, includeSearchExcludes = true): glob.IExpression | undefined { const fileExcludes = configuration && configuration.files && configuration.files.exclude; - const searchExcludes = configuration && configuration.search && configuration.search.exclude; + const searchExcludes = includeSearchExcludes && configuration && configuration.search && configuration.search.exclude; if (!fileExcludes && !searchExcludes) { return undefined; diff --git a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts index f7eab4f2cf2..91bd9eb6070 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts @@ -124,6 +124,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { { maxResults, disregardExcludeSettings: (excludePatternOrDisregardExcludes === false) || undefined, + disregardSearchExcludeSettings: true, includePattern, _reason: 'startFileSearch' }); diff --git a/src/vs/workbench/contrib/search/common/queryBuilder.ts b/src/vs/workbench/contrib/search/common/queryBuilder.ts index 035215bddeb..5b0b644d105 100644 --- a/src/vs/workbench/contrib/search/common/queryBuilder.ts +++ b/src/vs/workbench/contrib/search/common/queryBuilder.ts @@ -54,6 +54,7 @@ export interface ICommonQueryBuilderOptions { disregardIgnoreFiles?: boolean; disregardGlobalIgnoreFiles?: boolean; disregardExcludeSettings?: boolean; + disregardSearchExcludeSettings?: boolean; ignoreSymlinks?: boolean; } @@ -247,7 +248,7 @@ export class QueryBuilder { private getExcludesForFolder(folderConfig: ISearchConfiguration, options: ICommonQueryBuilderOptions): glob.IExpression | undefined { return options.disregardExcludeSettings ? undefined : - getExcludes(folderConfig); + getExcludes(folderConfig, !options.disregardSearchExcludeSettings); } /** From d0f043db69f3cb795f0e1c72da7c0fe50489f068 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 8 Feb 2019 07:34:50 +0100 Subject: [PATCH 032/207] debt - move jsonValidationExtensionPoint out of services --- build/lib/i18n.resources.json | 8 ++++---- src/tsconfig.strictNullChecks.json | 2 +- .../common/jsonValidationExtensionPoint.ts | 0 .../api/electron-browser/extensionHost.contribution.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) rename src/vs/workbench/{services/jsonschemas => api}/common/jsonValidationExtensionPoint.ts (100%) diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 5adbf22d988..13e5e6bbf29 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -26,6 +26,10 @@ "name": "vs/workbench", "project": "vscode-workbench" }, + { + "name": "vs/workbench/api/common", + "project": "vscode-workbench" + }, { "name": "vs/workbench/contrib/cli", "project": "vscode-workbench" @@ -194,10 +198,6 @@ "name": "vs/workbench/services/extensions", "project": "vscode-workbench" }, - { - "name": "vs/workbench/services/jsonschemas", - "project": "vscode-workbench" - }, { "name": "vs/workbench/services/files", "project": "vscode-workbench" diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 55f71e76197..31500f8b418 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -400,6 +400,7 @@ "./vs/vscode.proposed.d.ts", "./vs/workbench/api/common/configurationExtensionPoint.ts", "./vs/workbench/api/common/menusExtensionPoint.ts", + "./vs/workbench/api/common/jsonValidationExtensionPoint.ts", "./vs/workbench/api/electron-browser/extHostCustomers.ts", "./vs/workbench/api/electron-browser/mainThreadClipboard.ts", "./vs/workbench/api/electron-browser/mainThreadCommands.ts", @@ -706,7 +707,6 @@ "./vs/workbench/services/hash/node/hashService.ts", "./vs/workbench/services/history/common/history.ts", "./vs/workbench/services/history/electron-browser/history.ts", - "./vs/workbench/services/jsonschemas/common/jsonValidationExtensionPoint.ts", "./vs/workbench/services/keybinding/common/keybindingIO.ts", "./vs/workbench/services/keybinding/common/keyboardMapper.ts", "./vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper.ts", diff --git a/src/vs/workbench/services/jsonschemas/common/jsonValidationExtensionPoint.ts b/src/vs/workbench/api/common/jsonValidationExtensionPoint.ts similarity index 100% rename from src/vs/workbench/services/jsonschemas/common/jsonValidationExtensionPoint.ts rename to src/vs/workbench/api/common/jsonValidationExtensionPoint.ts diff --git a/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts b/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts index 3e466d8b5b3..b7aa793a14d 100644 --- a/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts +++ b/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts @@ -9,7 +9,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; // --- other interested parties -import { JSONValidationExtensionPoint } from 'vs/workbench/services/jsonschemas/common/jsonValidationExtensionPoint'; +import { JSONValidationExtensionPoint } from 'vs/workbench/api/common/jsonValidationExtensionPoint'; import { ColorExtensionPoint } from 'vs/workbench/services/themes/common/colorExtensionPoint'; import { LanguageConfigurationFileHandler } from 'vs/workbench/contrib/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint'; From 176b65a4322735f1499b4780e78a549692d48f63 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 8 Feb 2019 07:47:24 +0100 Subject: [PATCH 033/207] debt - make issue service a contrib to the workbench --- build/lib/i18n.resources.json | 4 ++ src/tsconfig.strictNullChecks.json | 2 +- .../electron-browser/issue.contribution.ts | 27 +++++++++ .../issue/electron-browser}/issue.ts | 0 .../issue/electron-browser/issueActions.ts | 60 +++++++++++++++++++ .../issue/electron-browser/issueService.ts} | 3 +- .../electron-browser/actions/helpActions.ts | 53 ---------------- .../electron-browser/shell.contribution.ts | 8 +-- src/vs/workbench/electron-browser/shell.ts | 4 -- .../electron-browser/bulkEditService.ts | 1 - src/vs/workbench/workbench.main.ts | 3 + 11 files changed, 97 insertions(+), 68 deletions(-) create mode 100644 src/vs/workbench/contrib/issue/electron-browser/issue.contribution.ts rename src/vs/workbench/{services/issue/common => contrib/issue/electron-browser}/issue.ts (100%) create mode 100644 src/vs/workbench/contrib/issue/electron-browser/issueActions.ts rename src/vs/workbench/{services/issue/electron-browser/workbenchIssueService.ts => contrib/issue/electron-browser/issueService.ts} (98%) diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 13e5e6bbf29..b395008f581 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -70,6 +70,10 @@ "name": "vs/workbench/contrib/html", "project": "vscode-workbench" }, + { + "name": "vs/workbench/contrib/issue", + "project": "vscode-workbench" + }, { "name": "vs/workbench/contrib/markers", "project": "vscode-workbench" diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 31500f8b418..44fdc958308 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -26,9 +26,9 @@ "./vs/workbench/contrib/execution/**/*", "./vs/workbench/contrib/snippets/**/*.ts", "./vs/workbench/contrib/welcome/**/*.ts", + "./vs/workbench/contrib/issue/**/*", "./vs/workbench/services/commands/**/*", "./vs/workbench/services/files/node/watcher/**/*", - "./vs/workbench/services/issue/**/*", "./vs/workbench/services/themes/**/*.ts" ], "files": [ diff --git a/src/vs/workbench/contrib/issue/electron-browser/issue.contribution.ts b/src/vs/workbench/contrib/issue/electron-browser/issue.contribution.ts new file mode 100644 index 00000000000..4be72478445 --- /dev/null +++ b/src/vs/workbench/contrib/issue/electron-browser/issue.contribution.ts @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Registry } from 'vs/platform/registry/common/platform'; +import * as nls from 'vs/nls'; +import product from 'vs/platform/node/product'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; +import { OpenIssueReporterAction, ReportPerformanceIssueUsingReporterAction, OpenProcessExplorer } from 'vs/workbench/contrib/issue/electron-browser/issueActions'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/electron-browser/issue'; +import { WorkbenchIssueService } from 'vs/workbench/contrib/issue/electron-browser/issueService'; + +const helpCategory = nls.localize('help', "Help"); +const workbenchActionsRegistry = Registry.as(Extensions.WorkbenchActions); + +if (!!product.reportIssueUrl) { + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenIssueReporterAction, OpenIssueReporterAction.ID, OpenIssueReporterAction.LABEL), 'Help: Open Issue Reporter', helpCategory); + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReportPerformanceIssueUsingReporterAction, ReportPerformanceIssueUsingReporterAction.ID, ReportPerformanceIssueUsingReporterAction.LABEL), 'Help: Report Performance Issue', helpCategory); +} + +const developerCategory = nls.localize('developer', "Developer"); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenProcessExplorer, OpenProcessExplorer.ID, OpenProcessExplorer.LABEL), 'Developer: Open Process Explorer', developerCategory); + +registerSingleton(IWorkbenchIssueService, WorkbenchIssueService, true); \ No newline at end of file diff --git a/src/vs/workbench/services/issue/common/issue.ts b/src/vs/workbench/contrib/issue/electron-browser/issue.ts similarity index 100% rename from src/vs/workbench/services/issue/common/issue.ts rename to src/vs/workbench/contrib/issue/electron-browser/issue.ts diff --git a/src/vs/workbench/contrib/issue/electron-browser/issueActions.ts b/src/vs/workbench/contrib/issue/electron-browser/issueActions.ts new file mode 100644 index 00000000000..884189cbaeb --- /dev/null +++ b/src/vs/workbench/contrib/issue/electron-browser/issueActions.ts @@ -0,0 +1,60 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Action } from 'vs/base/common/actions'; +import * as nls from 'vs/nls'; +import { IssueType } from 'vs/platform/issue/common/issue'; +import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/electron-browser/issue'; + +export class OpenIssueReporterAction extends Action { + static readonly ID = 'workbench.action.openIssueReporter'; + static readonly LABEL = nls.localize({ key: 'reportIssueInEnglish', comment: ['Translate this to "Report Issue in English" in all languages please!'] }, "Report Issue"); + + constructor( + id: string, + label: string, + @IWorkbenchIssueService private readonly issueService: IWorkbenchIssueService + ) { + super(id, label); + } + + run(): Promise { + return this.issueService.openReporter().then(() => true); + } +} + +export class OpenProcessExplorer extends Action { + static readonly ID = 'workbench.action.openProcessExplorer'; + static readonly LABEL = nls.localize('openProcessExplorer', "Open Process Explorer"); + + constructor( + id: string, + label: string, + @IWorkbenchIssueService private readonly issueService: IWorkbenchIssueService + ) { + super(id, label); + } + + run(): Promise { + return this.issueService.openProcessExplorer().then(() => true); + } +} + +export class ReportPerformanceIssueUsingReporterAction extends Action { + static readonly ID = 'workbench.action.reportPerformanceIssueUsingReporter'; + static readonly LABEL = nls.localize('reportPerformanceIssue', "Report Performance Issue"); + + constructor( + id: string, + label: string, + @IWorkbenchIssueService private readonly issueService: IWorkbenchIssueService + ) { + super(id, label); + } + + run(): Promise { + return this.issueService.openReporter({ issueType: IssueType.PerformanceIssue }).then(() => true); + } +} diff --git a/src/vs/workbench/services/issue/electron-browser/workbenchIssueService.ts b/src/vs/workbench/contrib/issue/electron-browser/issueService.ts similarity index 98% rename from src/vs/workbench/services/issue/electron-browser/workbenchIssueService.ts rename to src/vs/workbench/contrib/issue/electron-browser/issueService.ts index 80c4ac2f824..708f42373e4 100644 --- a/src/vs/workbench/services/issue/electron-browser/workbenchIssueService.ts +++ b/src/vs/workbench/contrib/issue/electron-browser/issueService.ts @@ -10,7 +10,7 @@ import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { IExtensionManagementService, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { webFrame } from 'electron'; import { assign } from 'vs/base/common/objects'; -import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue'; +import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/electron-browser/issue'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; @@ -98,4 +98,3 @@ function getColor(theme: ITheme, key: string): string | undefined { const color = theme.getColor(key); return color ? color.toString() : undefined; } - diff --git a/src/vs/workbench/electron-browser/actions/helpActions.ts b/src/vs/workbench/electron-browser/actions/helpActions.ts index 009ef59e1b0..07b8f05f223 100644 --- a/src/vs/workbench/electron-browser/actions/helpActions.ts +++ b/src/vs/workbench/electron-browser/actions/helpActions.ts @@ -7,59 +7,6 @@ import { Action } from 'vs/base/common/actions'; import * as nls from 'vs/nls'; import product from 'vs/platform/node/product'; import { isMacintosh, isLinux, language } from 'vs/base/common/platform'; -import { IssueType } from 'vs/platform/issue/common/issue'; -import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue'; - -export class OpenIssueReporterAction extends Action { - static readonly ID = 'workbench.action.openIssueReporter'; - static readonly LABEL = nls.localize({ key: 'reportIssueInEnglish', comment: ['Translate this to "Report Issue in English" in all languages please!'] }, "Report Issue"); - - constructor( - id: string, - label: string, - @IWorkbenchIssueService private readonly issueService: IWorkbenchIssueService - ) { - super(id, label); - } - - run(): Promise { - return this.issueService.openReporter().then(() => true); - } -} - -export class OpenProcessExplorer extends Action { - static readonly ID = 'workbench.action.openProcessExplorer'; - static readonly LABEL = nls.localize('openProcessExplorer', "Open Process Explorer"); - - constructor( - id: string, - label: string, - @IWorkbenchIssueService private readonly issueService: IWorkbenchIssueService - ) { - super(id, label); - } - - run(): Promise { - return this.issueService.openProcessExplorer().then(() => true); - } -} - -export class ReportPerformanceIssueUsingReporterAction extends Action { - static readonly ID = 'workbench.action.reportPerformanceIssueUsingReporter'; - static readonly LABEL = nls.localize('reportPerformanceIssue', "Report Performance Issue"); - - constructor( - id: string, - label: string, - @IWorkbenchIssueService private readonly issueService: IWorkbenchIssueService - ) { - super(id, label); - } - - run(): Promise { - return this.issueService.openReporter({ issueType: IssueType.PerformanceIssue }).then(() => true); - } -} export class KeybindingsReferenceAction extends Action { diff --git a/src/vs/workbench/electron-browser/shell.contribution.ts b/src/vs/workbench/electron-browser/shell.contribution.ts index bc02c150a70..fae520c8721 100644 --- a/src/vs/workbench/electron-browser/shell.contribution.ts +++ b/src/vs/workbench/electron-browser/shell.contribution.ts @@ -5,14 +5,13 @@ import { Registry } from 'vs/platform/registry/common/platform'; import * as nls from 'vs/nls'; -import product from 'vs/platform/node/product'; import * as os from 'os'; import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform'; -import { KeybindingsReferenceAction, OpenDocumentationUrlAction, OpenIntroductoryVideosUrlAction, OpenTipsAndTricksUrlAction, OpenIssueReporterAction, ReportPerformanceIssueUsingReporterAction, OpenProcessExplorer, OpenTwitterUrlAction, OpenRequestFeatureUrlAction, OpenPrivacyStatementUrlAction, OpenLicenseUrlAction } from 'vs/workbench/electron-browser/actions/helpActions'; +import { KeybindingsReferenceAction, OpenDocumentationUrlAction, OpenIntroductoryVideosUrlAction, OpenTipsAndTricksUrlAction, OpenTwitterUrlAction, OpenRequestFeatureUrlAction, OpenPrivacyStatementUrlAction, OpenLicenseUrlAction } from 'vs/workbench/electron-browser/actions/helpActions'; import { ToggleSharedProcessAction, InspectContextKeysAction, ToggleScreencastModeAction } from 'vs/workbench/electron-browser/actions/developerActions'; import { ShowAboutDialogAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, CloseCurrentWindowAction, SwitchWindow, NewWindowAction, QuickSwitchWindow, QuickOpenRecentAction, inRecentFilesPickerContextKey, OpenRecentAction } from 'vs/workbench/electron-browser/actions/windowActions'; import { AddRootFolderAction, GlobalRemoveRootFolderAction, OpenWorkspaceAction, SaveWorkspaceAsAction, OpenWorkspaceConfigFileAction, DuplicateWorkspaceInNewWindowAction, OpenFileFolderAction, OpenFileAction, OpenFolderAction, CloseWorkspaceAction } from 'vs/workbench/browser/actions/workspaceActions'; @@ -70,10 +69,6 @@ if (isMacintosh) { } workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'File: Close Workspace', fileCategory); -if (!!product.reportIssueUrl) { - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenIssueReporterAction, OpenIssueReporterAction.ID, OpenIssueReporterAction.LABEL), 'Help: Open Issue Reporter', helpCategory); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReportPerformanceIssueUsingReporterAction, ReportPerformanceIssueUsingReporterAction.ID, ReportPerformanceIssueUsingReporterAction.LABEL), 'Help: Report Performance Issue', helpCategory); -} if (KeybindingsReferenceAction.AVAILABLE) { workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(KeybindingsReferenceAction, KeybindingsReferenceAction.ID, KeybindingsReferenceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_R) }), 'Help: Keyboard Shortcuts Reference', helpCategory); @@ -142,7 +137,6 @@ const developerCategory = nls.localize('developer', "Developer"); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSharedProcessAction, ToggleSharedProcessAction.ID, ToggleSharedProcessAction.LABEL), 'Developer: Toggle Shared Process', developerCategory); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(InspectContextKeysAction, InspectContextKeysAction.ID, InspectContextKeysAction.LABEL), 'Developer: Inspect Context Keys', developerCategory); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleScreencastModeAction, ToggleScreencastModeAction.ID, ToggleScreencastModeAction.LABEL), 'Developer: Toggle Mouse Clicks', developerCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenProcessExplorer, OpenProcessExplorer.ID, OpenProcessExplorer.LABEL), 'Developer: Open Process Explorer', developerCategory); const recentFilesPickerContext = ContextKeyExpr.and(inQuickOpenContext, ContextKeyExpr.has(inRecentFilesPickerContextKey)); diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index b86a7047898..8af74c27584 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -80,8 +80,6 @@ import { Event, Emitter } from 'vs/base/common/event'; import { WORKBENCH_BACKGROUND } from 'vs/workbench/common/theme'; import { LocalizationsChannelClient } from 'vs/platform/localizations/node/localizationsIpc'; import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; -import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue'; -import { WorkbenchIssueService } from 'vs/workbench/services/issue/electron-browser/workbenchIssueService'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { NotificationService } from 'vs/workbench/services/notification/common/notificationService'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; @@ -389,8 +387,6 @@ export class Shell extends Disposable { serviceCollection.set(ISearchHistoryService, new SyncDescriptor(SearchHistoryService)); - serviceCollection.set(IWorkbenchIssueService, new SyncDescriptor(WorkbenchIssueService)); - serviceCollection.set(ICodeEditorService, new SyncDescriptor(CodeEditorService)); serviceCollection.set(IOpenerService, new SyncDescriptor(OpenerService, undefined, true)); diff --git a/src/vs/workbench/services/bulkEdit/electron-browser/bulkEditService.ts b/src/vs/workbench/services/bulkEdit/electron-browser/bulkEditService.ts index 1183cb36a24..28142311db4 100644 --- a/src/vs/workbench/services/bulkEdit/electron-browser/bulkEditService.ts +++ b/src/vs/workbench/services/bulkEdit/electron-browser/bulkEditService.ts @@ -424,5 +424,4 @@ export class BulkEditService implements IBulkEditService { } } - registerSingleton(IBulkEditService, BulkEditService, true); diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 307396fcf64..c2def5fe958 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -175,4 +175,7 @@ import 'vs/workbench/contrib/outline/electron-browser/outline.contribution'; // Experiments import 'vs/workbench/contrib/experiments/electron-browser/experiments.contribution'; +// Issues +import 'vs/workbench/contrib/issue/electron-browser/issue.contribution'; + //#endregion \ No newline at end of file From 21b0b98264376f9844acecf60a23f808f0fe7428 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 8 Feb 2019 08:12:07 +0100 Subject: [PATCH 034/207] debt - get rid of crash reporter service --- src/tsconfig.strictNullChecks.json | 1 - .../electron-browser/shell.contribution.ts | 15 +++ src/vs/workbench/electron-browser/shell.ts | 7 - src/vs/workbench/electron-browser/window.ts | 46 ++++++- .../electron-browser/crashReporterService.ts | 126 ------------------ .../electron-browser/extensionHost.ts | 4 +- 6 files changed, 57 insertions(+), 142 deletions(-) delete mode 100644 src/vs/workbench/services/crashReporter/electron-browser/crashReporterService.ts diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 44fdc958308..704eadf5a22 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -676,7 +676,6 @@ "./vs/workbench/services/configurationResolver/common/configurationResolverSchema.ts", "./vs/workbench/services/configurationResolver/common/configurationResolverUtils.ts", "./vs/workbench/services/contextview/electron-browser/contextmenuService.ts", - "./vs/workbench/services/crashReporter/electron-browser/crashReporterService.ts", "./vs/workbench/services/decorations/browser/decorations.ts", "./vs/workbench/services/decorations/browser/decorationsService.ts", "./vs/workbench/services/decorations/test/browser/decorationsService.test.ts", diff --git a/src/vs/workbench/electron-browser/shell.contribution.ts b/src/vs/workbench/electron-browser/shell.contribution.ts index fae520c8721..cf31baeca69 100644 --- a/src/vs/workbench/electron-browser/shell.contribution.ts +++ b/src/vs/workbench/electron-browser/shell.contribution.ts @@ -624,3 +624,18 @@ configurationRegistry.registerConfiguration({ } }); +// Configuration: Telemetry +configurationRegistry.registerConfiguration({ + 'id': 'telemetry', + 'order': 110, + title: nls.localize('telemetryConfigurationTitle', "Telemetry"), + 'type': 'object', + 'properties': { + 'telemetry.enableCrashReporter': { + 'type': 'boolean', + 'description': nls.localize('telemetry.enableCrashReporting', "Enable crash reports to be sent to a Microsoft online service. \nThis option requires restart to take effect."), + 'default': true, + 'tags': ['usesOnlineServices'] + } + } +}); \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 8af74c27584..402ebb1e9b6 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -53,7 +53,6 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { WorkbenchModeServiceImpl } from 'vs/workbench/services/mode/common/workbenchModeService'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { ICrashReporterService, NullCrashReporterService, CrashReporterService } from 'vs/workbench/services/crashReporter/electron-browser/crashReporterService'; import { getDelayedChannel, IPCClient } from 'vs/base/parts/ipc/node/ipc'; import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net'; import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/node/extensionManagementIpc'; @@ -319,12 +318,6 @@ export class Shell extends Disposable { serviceCollection.set(ITelemetryService, this.telemetryService); this._register(configurationTelemetry(this.telemetryService, this.configurationService)); - let crashReporterService = NullCrashReporterService; - if (!this.environmentService.disableCrashReporter && product.crashReporter && product.hockeyApp) { - crashReporterService = instantiationService.createInstance(CrashReporterService); - } - serviceCollection.set(ICrashReporterService, crashReporterService); - serviceCollection.set(IDialogService, instantiationService.createInstance(DialogService)); const lifecycleService = instantiationService.createInstance(LifecycleService); diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index c0aff6bd4ba..be8f0488a12 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { URI } from 'vs/base/common/uri'; import * as errors from 'vs/base/common/errors'; -import * as objects from 'vs/base/common/objects'; +import { equals, deepClone, assign } from 'vs/base/common/objects'; import * as DOM from 'vs/base/browser/dom'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IAction, Action } from 'vs/base/common/actions'; @@ -24,7 +24,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import { IResourceInput } from 'vs/platform/editor/common/editor'; import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; import { Themable } from 'vs/workbench/common/theme'; -import { ipcRenderer as ipc, webFrame } from 'electron'; +import { ipcRenderer as ipc, webFrame, crashReporter } from 'electron'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import { IMenuService, MenuId, IMenu, MenuItemAction, ICommandAction } from 'vs/platform/actions/common/actions'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -34,11 +34,13 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { LifecyclePhase, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; import { IIntegrityService } from 'vs/platform/integrity/common/integrity'; -import { AccessibilitySupport, isRootUser, isWindows, isMacintosh } from 'vs/base/common/platform'; +import { AccessibilitySupport, isRootUser, isWindows, isMacintosh, isLinux } from 'vs/base/common/platform'; import product from 'vs/platform/node/product'; +import pkg from 'vs/platform/node/package'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; const TextInputActions: IAction[] = [ new Action('undo', nls.localize('undo', "Undo"), undefined, true, () => Promise.resolve(document.execCommand('undo'))), @@ -79,7 +81,8 @@ export class ElectronWindow extends Themable { @IFileService private readonly fileService: IFileService, @IMenuService private readonly menuService: IMenuService, @ILifecycleService private readonly lifecycleService: ILifecycleService, - @IIntegrityService private readonly integrityService: IIntegrityService + @IIntegrityService private readonly integrityService: IIntegrityService, + @IEnvironmentService private readonly environmentService: IEnvironmentService ) { super(themeService); @@ -297,6 +300,11 @@ export class ElectronWindow extends Themable { // Touchbar menu (if enabled) this.updateTouchbarMenu(); + + // Crash reporter (if enabled) + if (!this.environmentService.disableCrashReporter && product.crashReporter && product.hockeyApp && this.configurationService.getValue('telemetry.enableCrashReporter')) { + this.setupCrashReporter(); + } } private updateTouchbarMenu(): void { @@ -354,12 +362,40 @@ export class ElectronWindow extends Themable { } // Only update if the actions have changed - if (!objects.equals(this.lastInstalledTouchedBar, items)) { + if (!equals(this.lastInstalledTouchedBar, items)) { this.lastInstalledTouchedBar = items; this.windowService.updateTouchBar(items); } } + private setupCrashReporter(): void { + + // base options with product info + const options = { + companyName: product.crashReporter.companyName, + productName: product.crashReporter.productName, + submitURL: isWindows ? product.hockeyApp[`win32-${process.arch}`] : isLinux ? product.hockeyApp[`linux-${process.arch}`] : product.hockeyApp.darwin, + extra: { + vscode_version: pkg.version, + vscode_commit: product.commit + } + }; + + // mixin telemetry info + this.telemetryService.getTelemetryInfo() + .then(info => { + assign(options.extra, { + vscode_sessionId: info.sessionId + }); + + // start crash reporter right here + crashReporter.start(deepClone(options)); + + // start crash reporter in the main process + return this.windowsService.startCrashReporter(options); + }); + } + private onAddFoldersRequest(request: IAddFoldersRequest): void { // Buffer all pending requests diff --git a/src/vs/workbench/services/crashReporter/electron-browser/crashReporterService.ts b/src/vs/workbench/services/crashReporter/electron-browser/crashReporterService.ts deleted file mode 100644 index fc83352b505..00000000000 --- a/src/vs/workbench/services/crashReporter/electron-browser/crashReporterService.ts +++ /dev/null @@ -1,126 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as nls from 'vs/nls'; -import { assign, deepClone } from 'vs/base/common/objects'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { crashReporter } from 'electron'; -import product from 'vs/platform/node/product'; -import pkg from 'vs/platform/node/package'; -import * as os from 'os'; -import { isWindows, isMacintosh, isLinux } from 'vs/base/common/platform'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { Registry } from 'vs/platform/registry/common/platform'; - -export const ICrashReporterService = createDecorator('crashReporterService'); - -export const TELEMETRY_SECTION_ID = 'telemetry'; - -export interface ICrashReporterConfig { - enableCrashReporter: boolean; -} - -const configurationRegistry = Registry.as(Extensions.Configuration); -configurationRegistry.registerConfiguration({ - 'id': TELEMETRY_SECTION_ID, - 'order': 110, - title: nls.localize('telemetryConfigurationTitle', "Telemetry"), - 'type': 'object', - 'properties': { - 'telemetry.enableCrashReporter': { - 'type': 'boolean', - 'description': nls.localize('telemetry.enableCrashReporting', "Enable crash reports to be sent to a Microsoft online service. \nThis option requires restart to take effect."), - 'default': true, - 'tags': ['usesOnlineServices'] - } - } -}); - -export interface ICrashReporterService { - _serviceBrand: any; - getChildProcessStartOptions(processName: string): Electron.CrashReporterStartOptions | undefined; // TODO -} - -export const NullCrashReporterService: ICrashReporterService = { - _serviceBrand: undefined, - getChildProcessStartOptions(processName: string) { return undefined; } -}; - -export class CrashReporterService implements ICrashReporterService { - - _serviceBrand: any; - - private options: Electron.CrashReporterStartOptions; - private isEnabled: boolean; - - constructor( - @ITelemetryService private readonly telemetryService: ITelemetryService, - @IWindowsService private readonly windowsService: IWindowsService, - @IConfigurationService configurationService: IConfigurationService - ) { - const config = configurationService.getValue(TELEMETRY_SECTION_ID); - this.isEnabled = !!config.enableCrashReporter; - - if (this.isEnabled) { - this.startCrashReporter(); - } - } - - private startCrashReporter(): void { - - // base options with product info - this.options = { - companyName: product.crashReporter.companyName, - productName: product.crashReporter.productName, - submitURL: this.getSubmitURL(), - extra: { - vscode_version: pkg.version, - vscode_commit: product.commit - } - }; - - // mixin telemetry info - this.telemetryService.getTelemetryInfo() - .then(info => { - assign(this.options.extra, { - vscode_sessionId: info.sessionId - }); - - // start crash reporter right here - crashReporter.start(deepClone(this.options)); - - // start crash reporter in the main process - return this.windowsService.startCrashReporter(this.options); - }); - } - - private getSubmitURL(): string { - if (isWindows) { - return product.hockeyApp[`win32-${process.arch}`]; - } else if (isMacintosh) { - return product.hockeyApp.darwin; - } else if (isLinux) { - return product.hockeyApp[`linux-${process.arch}`]; - } - throw new Error('Unknown platform'); - } - - getChildProcessStartOptions(name: string): Electron.CrashReporterStartOptions | undefined { - - // Experimental crash reporting support for child processes on Mac only for now - if (this.isEnabled && isMacintosh) { - const childProcessOptions = deepClone(this.options); - (childProcessOptions.extra).processName = name; - childProcessOptions.crashesDirectory = os.tmpdir(); - - return childProcessOptions; - } - - return undefined; - } -} diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index 3ab15256334..7e212550cea 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -34,7 +34,6 @@ import { IWindowService, IWindowsService } from 'vs/platform/windows/common/wind import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IInitData } from 'vs/workbench/api/node/extHost.protocol'; import { MessageType, createMessageOfType, isMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; -import { ICrashReporterService } from 'vs/workbench/services/crashReporter/electron-browser/crashReporterService'; import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; export interface IExtensionHostStarter { @@ -101,7 +100,6 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { @ILifecycleService private readonly _lifecycleService: ILifecycleService, @IEnvironmentService private readonly _environmentService: IEnvironmentService, @ITelemetryService private readonly _telemetryService: ITelemetryService, - @ICrashReporterService private readonly _crashReporterService: ICrashReporterService, @ILogService private readonly _logService: ILogService, @ILabelService private readonly _labelService: ILabelService ) { @@ -196,7 +194,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { } } - const crashReporterOptions = this._crashReporterService.getChildProcessStartOptions('extensionHost'); + const crashReporterOptions = undefined; // TODO@electron pass this in as options to the extension host after verifying this actually works if (crashReporterOptions) { opts.env.CRASH_REPORTER_START_OPTIONS = JSON.stringify(crashReporterOptions); } From ac826e186681dec305433c9322ffd4ad147428e7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 8 Feb 2019 09:09:27 +0100 Subject: [PATCH 035/207] debt - clean up vs/platform a little bit --- src/tsconfig.strictNullChecks.json | 5 ++-- src/vs/editor/contrib/find/findWidget.ts | 2 +- .../editor/contrib/find/simpleFindWidget.ts | 2 +- .../browser/contextScopedHistoryWidget.ts | 21 ++++++++++++---- .../common/contextkeys.ts | 0 src/vs/platform/list/browser/listService.ts | 2 +- .../widget/common/contextScopedWidget.ts | 24 ------------------- .../browser/actions/layoutActions.ts | 2 +- .../contrib/debug/browser/debugCommands.ts | 2 +- .../contrib/debug/electron-browser/repl.ts | 2 +- .../workbench/contrib/files/common/files.ts | 2 +- .../electron-browser/markersPanelActions.ts | 2 +- .../search/browser/patternInputWidget.ts | 2 +- .../contrib/search/browser/searchWidget.ts | 2 +- .../electron-browser/webview.contribution.ts | 2 +- .../electron-browser/shell.contribution.ts | 2 +- .../workbench/electron-browser/workbench.ts | 2 +- tslint.json | 1 + 18 files changed, 33 insertions(+), 44 deletions(-) rename src/vs/platform/{widget => }/browser/contextScopedHistoryWidget.ts (82%) rename src/vs/platform/{workbench => contextkey}/common/contextkeys.ts (100%) delete mode 100644 src/vs/platform/widget/common/contextScopedWidget.ts diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 704eadf5a22..3c37bfd9269 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -229,6 +229,7 @@ "./vs/platform/configuration/test/node/configurationService.test.ts", "./vs/platform/contextkey/browser/contextKeyService.ts", "./vs/platform/contextkey/common/contextkey.ts", + "./vs/platform/contextkey/common/contextkeys.ts", "./vs/platform/contextkey/test/common/contextkey.test.ts", "./vs/platform/contextview/browser/contextMenuHandler.ts", "./vs/platform/contextview/browser/contextMenuService.ts", @@ -381,14 +382,12 @@ "./vs/platform/url/common/urlService.ts", "./vs/platform/url/electron-main/electronUrlListener.ts", "./vs/platform/url/node/urlIpc.ts", - "./vs/platform/widget/browser/contextScopedHistoryWidget.ts", - "./vs/platform/widget/common/contextScopedWidget.ts", + "./vs/platform/browser/contextScopedHistoryWidget.ts", "./vs/platform/windows/common/windows.ts", "./vs/platform/windows/electron-browser/windowService.ts", "./vs/platform/windows/electron-main/windows.ts", "./vs/platform/windows/electron-main/windowsService.ts", "./vs/platform/windows/node/windowsIpc.ts", - "./vs/platform/workbench/common/contextkeys.ts", "./vs/platform/workspace/common/workspace.ts", "./vs/platform/workspace/test/common/testWorkspace.ts", "./vs/platform/workspace/test/common/workspace.test.ts", diff --git a/src/vs/editor/contrib/find/findWidget.ts b/src/vs/editor/contrib/find/findWidget.ts index aab295b7f39..2c5e17df77b 100644 --- a/src/vs/editor/contrib/find/findWidget.ts +++ b/src/vs/editor/contrib/find/findWidget.ts @@ -29,7 +29,7 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { contrastBorder, editorFindMatch, editorFindMatchBorder, editorFindMatchHighlight, editorFindMatchHighlightBorder, editorFindRangeHighlight, editorFindRangeHighlightBorder, editorWidgetBackground, editorWidgetBorder, editorWidgetResizeBorder, errorForeground, inputActiveOptionBorder, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/widget/browser/contextScopedHistoryWidget'; +import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedHistoryWidget'; export interface IFindController { replace(): void; diff --git a/src/vs/editor/contrib/find/simpleFindWidget.ts b/src/vs/editor/contrib/find/simpleFindWidget.ts index 2c014684065..d05a477931e 100644 --- a/src/vs/editor/contrib/find/simpleFindWidget.ts +++ b/src/vs/editor/contrib/find/simpleFindWidget.ts @@ -16,7 +16,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { editorWidgetBackground, inputActiveOptionBorder, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; import { ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { ContextScopedFindInput } from 'vs/platform/widget/browser/contextScopedHistoryWidget'; +import { ContextScopedFindInput } from 'vs/platform/browser/contextScopedHistoryWidget'; const NLS_FIND_INPUT_LABEL = nls.localize('label.find', "Find"); const NLS_FIND_INPUT_PLACEHOLDER = nls.localize('placeholder.find', "Find"); diff --git a/src/vs/platform/widget/browser/contextScopedHistoryWidget.ts b/src/vs/platform/browser/contextScopedHistoryWidget.ts similarity index 82% rename from src/vs/platform/widget/browser/contextScopedHistoryWidget.ts rename to src/vs/platform/browser/contextScopedHistoryWidget.ts index 8d74512c6a1..94d4de658b5 100644 --- a/src/vs/platform/widget/browser/contextScopedHistoryWidget.ts +++ b/src/vs/platform/browser/contextScopedHistoryWidget.ts @@ -3,11 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IContextKeyService, ContextKeyDefinedExpr, ContextKeyExpr, ContextKeyAndExpr, ContextKeyEqualsExpr, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService, ContextKeyDefinedExpr, ContextKeyExpr, ContextKeyAndExpr, ContextKeyEqualsExpr, RawContextKey, IContextKey, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey'; import { HistoryInputBox, IHistoryInputOptions } from 'vs/base/browser/ui/inputbox/inputBox'; import { FindInput, IFindInputOptions } from 'vs/base/browser/ui/findinput/findInput'; import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; -import { IContextScopedWidget, getContextScopedWidget, createWidgetScopedContextKeyService, bindContextScopedWidget } from 'vs/platform/widget/common/contextScopedWidget'; import { IHistoryNavigationWidget } from 'vs/base/browser/history'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; @@ -15,10 +14,24 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; export const HistoryNavigationWidgetContext = 'historyNavigationWidget'; export const HistoryNavigationEnablementContext = 'historyNavigationEnabled'; -export interface IContextScopedHistoryNavigationWidget extends IContextScopedWidget { +function bindContextScopedWidget(contextKeyService: IContextKeyService, widget: IContextScopedWidget, contextKey: string): void { + new RawContextKey(contextKey, widget).bindTo(contextKeyService); +} +function createWidgetScopedContextKeyService(contextKeyService: IContextKeyService, widget: IContextScopedWidget): IContextKeyService { + return contextKeyService.createScoped(widget.target); +} + +function getContextScopedWidget(contextKeyService: IContextKeyService, contextKey: string): T | undefined { + return contextKeyService.getContext(document.activeElement).getValue(contextKey); +} + +interface IContextScopedWidget { + readonly target: IContextKeyServiceTarget; +} + +interface IContextScopedHistoryNavigationWidget extends IContextScopedWidget { historyNavigator: IHistoryNavigationWidget; - } export function createAndBindHistoryNavigationWidgetScopedContextKeyService(contextKeyService: IContextKeyService, widget: IContextScopedHistoryNavigationWidget): { scopedContextKeyService: IContextKeyService, historyNavigationEnablement: IContextKey } { diff --git a/src/vs/platform/workbench/common/contextkeys.ts b/src/vs/platform/contextkey/common/contextkeys.ts similarity index 100% rename from src/vs/platform/workbench/common/contextkeys.ts rename to src/vs/platform/contextkey/common/contextkeys.ts diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 65095160059..aee424a621b 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -24,7 +24,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { Registry } from 'vs/platform/registry/common/platform'; import { attachListStyler, computeStyles, defaultListStyles } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { InputFocusedContextKey } from 'vs/platform/workbench/common/contextkeys'; +import { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys'; import { ObjectTree, IObjectTreeOptions } from 'vs/base/browser/ui/tree/objectTree'; import { ITreeEvent, ITreeRenderer, IAsyncDataSource, IDataSource } from 'vs/base/browser/ui/tree/tree'; import { AsyncDataTree, IAsyncDataTreeOptions } from 'vs/base/browser/ui/tree/asyncDataTree'; diff --git a/src/vs/platform/widget/common/contextScopedWidget.ts b/src/vs/platform/widget/common/contextScopedWidget.ts deleted file mode 100644 index 65ee493f125..00000000000 --- a/src/vs/platform/widget/common/contextScopedWidget.ts +++ /dev/null @@ -1,24 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IContextKeyService, RawContextKey, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey'; - -export function bindContextScopedWidget(contextKeyService: IContextKeyService, widget: IContextScopedWidget, contextKey: string): void { - new RawContextKey(contextKey, widget).bindTo(contextKeyService); -} - -export function createWidgetScopedContextKeyService(contextKeyService: IContextKeyService, widget: IContextScopedWidget): IContextKeyService { - return contextKeyService.createScoped(widget.target); -} - -export function getContextScopedWidget(contextKeyService: IContextKeyService, contextKey: string): T | undefined { - return contextKeyService.getContext(document.activeElement).getValue(contextKey); -} - -export interface IContextScopedWidget { - - readonly target: IContextKeyServiceTarget; - -} \ No newline at end of file diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index e1112d03cbd..082e8abdf2d 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -19,7 +19,7 @@ import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { MenuBarVisibility } from 'vs/platform/windows/common/windows'; import { isWindows, isLinux } from 'vs/base/common/platform'; -import { IsMacContext } from 'vs/platform/workbench/common/contextkeys'; +import { IsMacContext } from 'vs/platform/contextkey/common/contextkeys'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { InEditorZenModeContext } from 'vs/workbench/common/editor'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; diff --git a/src/vs/workbench/contrib/debug/browser/debugCommands.ts b/src/vs/workbench/contrib/debug/browser/debugCommands.ts index 726e1970104..b231d8a4853 100644 --- a/src/vs/workbench/contrib/debug/browser/debugCommands.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCommands.ts @@ -20,7 +20,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { openBreakpointSource } from 'vs/workbench/contrib/debug/browser/breakpointsView'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { InputFocusedContext } from 'vs/platform/workbench/common/contextkeys'; +import { InputFocusedContext } from 'vs/platform/contextkey/common/contextkeys'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { PanelFocusContext } from 'vs/workbench/browser/parts/panel/panelPart'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; diff --git a/src/vs/workbench/contrib/debug/electron-browser/repl.ts b/src/vs/workbench/contrib/debug/electron-browser/repl.ts index b9df4de1e42..2201c867c4a 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/repl.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/repl.ts @@ -35,7 +35,7 @@ import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { IDebugService, REPL_ID, DEBUG_SCHEME, CONTEXT_IN_DEBUG_REPL, IDebugSession, State, IReplElement, IExpressionContainer, IExpression, IReplElementSource } from 'vs/workbench/contrib/debug/common/debug'; import { HistoryNavigator } from 'vs/base/common/history'; import { IHistoryNavigationWidget } from 'vs/base/browser/history'; -import { createAndBindHistoryNavigationWidgetScopedContextKeyService } from 'vs/platform/widget/browser/contextScopedHistoryWidget'; +import { createAndBindHistoryNavigationWidgetScopedContextKeyService } from 'vs/platform/browser/contextScopedHistoryWidget'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { getSimpleCodeEditorWidgetOptions } from 'vs/workbench/contrib/codeEditor/electron-browser/simpleEditorOptions'; import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; diff --git a/src/vs/workbench/contrib/files/common/files.ts b/src/vs/workbench/contrib/files/common/files.ts index 0e1a87939cc..a007c4d655b 100644 --- a/src/vs/workbench/contrib/files/common/files.ts +++ b/src/vs/workbench/contrib/files/common/files.ts @@ -15,7 +15,7 @@ import { Event } from 'vs/base/common/event'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { InputFocusedContextKey } from 'vs/platform/workbench/common/contextkeys'; +import { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys'; import { Registry } from 'vs/platform/registry/common/platform'; import { IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainer } from 'vs/workbench/common/views'; import { Schemas } from 'vs/base/common/network'; diff --git a/src/vs/workbench/contrib/markers/electron-browser/markersPanelActions.ts b/src/vs/workbench/contrib/markers/electron-browser/markersPanelActions.ts index 2d305d300ae..c620c5e6b3f 100644 --- a/src/vs/workbench/contrib/markers/electron-browser/markersPanelActions.ts +++ b/src/vs/workbench/contrib/markers/electron-browser/markersPanelActions.ts @@ -24,7 +24,7 @@ import { badgeBackground, badgeForeground, contrastBorder } from 'vs/platform/th import { localize } from 'vs/nls'; import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ContextScopedHistoryInputBox } from 'vs/platform/widget/browser/contextScopedHistoryWidget'; +import { ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedHistoryWidget'; import { Marker } from 'vs/workbench/contrib/markers/electron-browser/markersModel'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { Event, Emitter } from 'vs/base/common/event'; diff --git a/src/vs/workbench/contrib/search/browser/patternInputWidget.ts b/src/vs/workbench/contrib/search/browser/patternInputWidget.ts index d41815d0459..8886afd04c6 100644 --- a/src/vs/workbench/contrib/search/browser/patternInputWidget.ts +++ b/src/vs/workbench/contrib/search/browser/patternInputWidget.ts @@ -14,7 +14,7 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { Event as CommonEvent, Emitter } from 'vs/base/common/event'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { attachInputBoxStyler, attachCheckboxStyler } from 'vs/platform/theme/common/styler'; -import { ContextScopedHistoryInputBox } from 'vs/platform/widget/browser/contextScopedHistoryWidget'; +import { ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedHistoryWidget'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; export interface IOptions { diff --git a/src/vs/workbench/contrib/search/browser/searchWidget.ts b/src/vs/workbench/contrib/search/browser/searchWidget.ts index e434db9da78..8b7ee3dbafa 100644 --- a/src/vs/workbench/contrib/search/browser/searchWidget.ts +++ b/src/vs/workbench/contrib/search/browser/searchWidget.ts @@ -28,7 +28,7 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co import { ISearchConfigurationProperties } from 'vs/platform/search/common/search'; import { attachFindInputBoxStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/widget/browser/contextScopedHistoryWidget'; +import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedHistoryWidget'; import { appendKeyBindingLabel, isSearchViewFocused } from 'vs/workbench/contrib/search/browser/searchActions'; import * as Constants from 'vs/workbench/contrib/search/common/constants'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; diff --git a/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts b/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts index c186624c3d3..8e2b9e03bc0 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts @@ -20,7 +20,7 @@ import { HideWebViewEditorFindCommand, OpenWebviewDeveloperToolsAction, ReloadWe import { WebviewEditor } from './webviewEditor'; import { WebviewEditorInput } from './webviewEditorInput'; import { IWebviewEditorService, WebviewEditorService } from './webviewEditorService'; -import { InputFocusedContextKey } from 'vs/platform/workbench/common/contextkeys'; +import { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys'; import { isMacintosh } from 'vs/base/common/platform'; (Registry.as(EditorExtensions.Editors)).registerEditor(new EditorDescriptor( diff --git a/src/vs/workbench/electron-browser/shell.contribution.ts b/src/vs/workbench/electron-browser/shell.contribution.ts index cf31baeca69..511a3802324 100644 --- a/src/vs/workbench/electron-browser/shell.contribution.ts +++ b/src/vs/workbench/electron-browser/shell.contribution.ts @@ -21,7 +21,7 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ADD_ROOT_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; -import { IsMacContext } from 'vs/platform/workbench/common/contextkeys'; +import { IsMacContext } from 'vs/platform/contextkey/common/contextkeys'; import { NoEditorsVisibleContext, SingleEditorGroupsContext } from 'vs/workbench/common/editor'; import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index f2977e8dc95..aa5a4e9ad36 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -87,7 +87,7 @@ import { IDecorationsService } from 'vs/workbench/services/decorations/browser/d import { ActivityService } from 'vs/workbench/services/activity/browser/activityService'; import { URI } from 'vs/base/common/uri'; import { IListService, ListService } from 'vs/platform/list/browser/listService'; -import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext } from 'vs/platform/workbench/common/contextkeys'; +import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext } from 'vs/platform/contextkey/common/contextkeys'; import { IViewsService } from 'vs/workbench/common/views'; import { ViewsService } from 'vs/workbench/browser/parts/views/views'; import { INotificationService } from 'vs/platform/notification/common/notification'; diff --git a/tslint.json b/tslint.json index fb3b2dc5a97..100e72fd258 100644 --- a/tslint.json +++ b/tslint.json @@ -337,6 +337,7 @@ "vs/css!./**/*", "**/vs/base/{common,browser}/**", "**/vs/base/parts/*/{common,browser}/**", + "**/vs/platform/{common,browser}/**", "**/vs/platform/*/{common,browser}/**", "**/vs/editor/{common,browser}/**", "**/vs/editor/contrib/**" From 33eef88beee631fed358f964b788c28a0824105b Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 8 Feb 2019 09:13:18 +0100 Subject: [PATCH 036/207] workaround #68095 (#68115) --- .../contrib/files/electron-browser/views/explorerViewer.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/files/electron-browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/electron-browser/views/explorerViewer.ts index cc9213badac..95ee0aa8e66 100644 --- a/src/vs/workbench/contrib/files/electron-browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/electron-browser/views/explorerViewer.ts @@ -470,8 +470,9 @@ export class FileDragAndDrop implements ITreeDragAndDrop { const items = (data as ElementsDragAndDropData).elements; if (!target) { - // Droping onto the empty area. Do not accept if items dragged are already children of the root - if (items.every(i => i.parent && i.parent.isRoot)) { + // Droping onto the empty area. Do not accept if items dragged are already + // children of the root unless we are copying the file + if (!isCopy && items.every(i => i.parent && i.parent.isRoot)) { return false; } From d2c6e376423ecbd3dd7073d73bb9097ef4842b54 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 8 Feb 2019 09:13:25 +0100 Subject: [PATCH 037/207] Unable to copy files across VSCode windows in 1.31 (fixes #68031) (#68104) --- .../files/electron-browser/fileActions.contribution.ts | 2 +- .../contrib/files/electron-browser/views/explorerView.ts | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts index c9be944b28f..b601ff20556 100644 --- a/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts @@ -115,7 +115,7 @@ const PASTE_FILE_ID = 'filesExplorer.paste'; KeybindingsRegistry.registerCommandAndKeybindingRule({ id: PASTE_FILE_ID, weight: KeybindingWeight.WorkbenchContrib + explorerCommandsWeightBonus, - when: ContextKeyExpr.and(FilesExplorerFocusCondition, ExplorerResourceNotReadonlyContext, FileCopiedContext), + when: ContextKeyExpr.and(FilesExplorerFocusCondition, ExplorerResourceNotReadonlyContext), primary: KeyMod.CtrlCmd | KeyCode.KEY_V, handler: pasteFileHandler }); diff --git a/src/vs/workbench/contrib/files/electron-browser/views/explorerView.ts b/src/vs/workbench/contrib/files/electron-browser/views/explorerView.ts index 04251ca5fb9..bff9758fa30 100644 --- a/src/vs/workbench/contrib/files/electron-browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/electron-browser/views/explorerView.ts @@ -45,6 +45,7 @@ import { createFileIconThemableTreeContainerScope } from 'vs/workbench/browser/p import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IAsyncDataTreeViewState } from 'vs/base/browser/ui/tree/asyncDataTree'; import { FuzzyScore } from 'vs/base/common/filters'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; export class ExplorerView extends ViewletPanel { static readonly ID: string = 'workbench.explorer.fileView'; @@ -84,7 +85,8 @@ export class ExplorerView extends ViewletPanel { @IMenuService private readonly menuService: IMenuService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IExplorerService private readonly explorerService: IExplorerService, - @IStorageService private readonly storageService: IStorageService + @IStorageService private readonly storageService: IStorageService, + @IClipboardService private clipboardService: IClipboardService ) { super({ ...(options as IViewletPanelOptions), id: ExplorerView.ID, ariaHeaderLabel: nls.localize('explorerSection', "Files Explorer Section") }, keybindingService, contextMenuService, configurationService); @@ -398,6 +400,9 @@ export class ExplorerView extends ViewletPanel { private onContextMenu(e: ITreeContextMenuEvent): void { const stat = e.element; + // update dynamic contexts + this.fileCopiedContextKey.set(this.clipboardService.hasResources()); + const selection = this.tree.getSelection(); this.contextMenuService.showContextMenu({ getAnchor: () => e.anchor, From 8b1071bcbfbcd9a99353d630fbd954e0cf83cabd Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 8 Feb 2019 10:12:03 +0100 Subject: [PATCH 038/207] use resources#basename instead of path#posix --- .../{electron-browser => browser}/outline.contribution.ts | 0 .../outline/{electron-browser => browser}/outlinePanel.css | 0 .../outline/{electron-browser => browser}/outlinePanel.ts | 6 +++--- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/vs/workbench/contrib/outline/{electron-browser => browser}/outline.contribution.ts (100%) rename src/vs/workbench/contrib/outline/{electron-browser => browser}/outlinePanel.css (100%) rename src/vs/workbench/contrib/outline/{electron-browser => browser}/outlinePanel.ts (99%) diff --git a/src/vs/workbench/contrib/outline/electron-browser/outline.contribution.ts b/src/vs/workbench/contrib/outline/browser/outline.contribution.ts similarity index 100% rename from src/vs/workbench/contrib/outline/electron-browser/outline.contribution.ts rename to src/vs/workbench/contrib/outline/browser/outline.contribution.ts diff --git a/src/vs/workbench/contrib/outline/electron-browser/outlinePanel.css b/src/vs/workbench/contrib/outline/browser/outlinePanel.css similarity index 100% rename from src/vs/workbench/contrib/outline/electron-browser/outlinePanel.css rename to src/vs/workbench/contrib/outline/browser/outlinePanel.css diff --git a/src/vs/workbench/contrib/outline/electron-browser/outlinePanel.ts b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts similarity index 99% rename from src/vs/workbench/contrib/outline/electron-browser/outlinePanel.ts rename to src/vs/workbench/contrib/outline/browser/outlinePanel.ts index 70684ff8365..a6421a616e6 100644 --- a/src/vs/workbench/contrib/outline/electron-browser/outlinePanel.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { posix } from 'path'; import * as dom from 'vs/base/browser/dom'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; @@ -47,6 +46,7 @@ import { FuzzyScore } from 'vs/base/common/filters'; import { OutlineDataSource, OutlineItemComparator, OutlineSortOrder, OutlineVirtualDelegate, OutlineGroupRenderer, OutlineElementRenderer, OutlineItem, OutlineIdentityProvider, OutlineNavigationLabelProvider } from 'vs/editor/contrib/documentSymbols/outlineTree'; import { IDataTreeViewState } from 'vs/base/browser/ui/tree/dataTree'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; +import { basename } from 'vs/base/common/resources'; class RequestState { @@ -433,7 +433,7 @@ export class OutlinePanel extends ViewletPanel { let loadingMessage: IDisposable; if (!oldModel) { loadingMessage = new TimeoutTimer( - () => this._showMessage(localize('loading', "Loading document symbols for '{0}'...", posix.basename(textModel.uri.path))), + () => this._showMessage(localize('loading', "Loading document symbols for '{0}'...", basename(textModel.uri))), 100 ); } @@ -445,7 +445,7 @@ export class OutlinePanel extends ViewletPanel { } if (TreeElement.empty(newModel)) { - return this._showMessage(localize('no-symbols', "No symbols found in document '{0}'", posix.basename(textModel.uri.path))); + return this._showMessage(localize('no-symbols', "No symbols found in document '{0}'", basename(textModel.uri))); } let newSize = TreeElement.size(newModel); From a704dc2818e5ba1cceeb1efba1033f0fdedcf323 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 8 Feb 2019 10:20:29 +0100 Subject: [PATCH 039/207] missing change --- src/vs/workbench/workbench.main.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index c2def5fe958..4acb59e6a74 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -170,7 +170,7 @@ import 'vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay'; import 'vs/workbench/contrib/welcome/page/electron-browser/welcomePage.contribution'; // Outline -import 'vs/workbench/contrib/outline/electron-browser/outline.contribution'; +import 'vs/workbench/contrib/outline/browser/outline.contribution'; // Experiments import 'vs/workbench/contrib/experiments/electron-browser/experiments.contribution'; @@ -178,4 +178,4 @@ import 'vs/workbench/contrib/experiments/electron-browser/experiments.contributi // Issues import 'vs/workbench/contrib/issue/electron-browser/issue.contribution'; -//#endregion \ No newline at end of file +//#endregion From 52d9216a366f67af2cae585313272263a51e3b94 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 8 Feb 2019 10:33:18 +0100 Subject: [PATCH 040/207] debt - use our path/resources util --- .../codeEditor/electron-browser/simpleEditorOptions.ts | 4 ++-- .../comments/electron-browser/simpleCommentEditor.ts | 2 +- .../{electron-browser => browser}/configureSnippets.ts | 8 ++++---- .../{electron-browser => browser}/insertSnippet.ts | 4 ++-- .../snippetCompletionProvider.ts | 4 ++-- .../snippets.contribution.ts | 2 +- .../{electron-browser => browser}/snippetsFile.ts | 4 ++-- .../{electron-browser => browser}/snippetsService.ts | 8 ++++---- .../{electron-browser => browser}/tabCompletion.ts | 8 ++++---- .../{electron-browser => browser}/snippetFile.test.ts | 2 +- .../snippetsRegistry.test.ts | 2 +- .../snippetsRewrite.test.ts | 2 +- .../snippetsService.test.ts | 6 +++--- src/vs/workbench/workbench.main.ts | 10 +++++----- 14 files changed, 33 insertions(+), 33 deletions(-) rename src/vs/workbench/contrib/snippets/{electron-browser => browser}/configureSnippets.ts (97%) rename src/vs/workbench/contrib/snippets/{electron-browser => browser}/insertSnippet.ts (98%) rename src/vs/workbench/contrib/snippets/{electron-browser => browser}/snippetCompletionProvider.ts (98%) rename src/vs/workbench/contrib/snippets/{electron-browser => browser}/snippets.contribution.ts (99%) rename src/vs/workbench/contrib/snippets/{electron-browser => browser}/snippetsFile.ts (98%) rename src/vs/workbench/contrib/snippets/{electron-browser => browser}/snippetsService.ts (98%) rename src/vs/workbench/contrib/snippets/{electron-browser => browser}/tabCompletion.ts (93%) rename src/vs/workbench/contrib/snippets/test/{electron-browser => browser}/snippetFile.test.ts (97%) rename src/vs/workbench/contrib/snippets/test/{electron-browser => browser}/snippetsRegistry.test.ts (99%) rename src/vs/workbench/contrib/snippets/test/{electron-browser => browser}/snippetsRewrite.test.ts (97%) rename src/vs/workbench/contrib/snippets/test/{electron-browser => browser}/snippetsService.test.ts (99%) diff --git a/src/vs/workbench/contrib/codeEditor/electron-browser/simpleEditorOptions.ts b/src/vs/workbench/contrib/codeEditor/electron-browser/simpleEditorOptions.ts index 892a59ae182..7a5ec126f6d 100644 --- a/src/vs/workbench/contrib/codeEditor/electron-browser/simpleEditorOptions.ts +++ b/src/vs/workbench/contrib/codeEditor/electron-browser/simpleEditorOptions.ts @@ -9,7 +9,7 @@ import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2 import { SuggestController } from 'vs/editor/contrib/suggest/suggestController'; import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreventer'; import { SelectionClipboard } from 'vs/workbench/contrib/codeEditor/electron-browser/selectionClipboard'; -import { TabCompletionController } from 'vs/workbench/contrib/snippets/electron-browser/tabCompletion'; +import { TabCompletionController } from 'vs/workbench/contrib/snippets/browser/tabCompletion'; export function getSimpleCodeEditorWidgetOptions(): ICodeEditorWidgetOptions { return { @@ -23,4 +23,4 @@ export function getSimpleCodeEditorWidgetOptions(): ICodeEditorWidgetOptions { TabCompletionController, ] }; -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/comments/electron-browser/simpleCommentEditor.ts b/src/vs/workbench/contrib/comments/electron-browser/simpleCommentEditor.ts index dc695dcddfc..7cfa391293b 100644 --- a/src/vs/workbench/contrib/comments/electron-browser/simpleCommentEditor.ts +++ b/src/vs/workbench/contrib/comments/electron-browser/simpleCommentEditor.ts @@ -16,7 +16,7 @@ import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreve import { ContextMenuController } from 'vs/editor/contrib/contextmenu/contextmenu'; import { SuggestController } from 'vs/editor/contrib/suggest/suggestController'; import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2'; -import { TabCompletionController } from 'vs/workbench/contrib/snippets/electron-browser/tabCompletion'; +import { TabCompletionController } from 'vs/workbench/contrib/snippets/browser/tabCompletion'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { INotificationService } from 'vs/platform/notification/common/notification'; diff --git a/src/vs/workbench/contrib/snippets/electron-browser/configureSnippets.ts b/src/vs/workbench/contrib/snippets/browser/configureSnippets.ts similarity index 97% rename from src/vs/workbench/contrib/snippets/electron-browser/configureSnippets.ts rename to src/vs/workbench/contrib/snippets/browser/configureSnippets.ts index 5c8d2d0fff1..45322bd3c09 100644 --- a/src/vs/workbench/contrib/snippets/electron-browser/configureSnippets.ts +++ b/src/vs/workbench/contrib/snippets/browser/configureSnippets.ts @@ -8,15 +8,15 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IWindowService } from 'vs/platform/windows/common/windows'; -import { join, basename, dirname, extname } from 'path'; +import { join, basename, dirname, extname } from 'vs/base/common/paths'; import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { timeout } from 'vs/base/common/async'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { URI } from 'vs/base/common/uri'; -import { ISnippetsService } from 'vs/workbench/contrib/snippets/electron-browser/snippets.contribution'; +import { ISnippetsService } from 'vs/workbench/contrib/snippets/browser/snippets.contribution'; import { values } from 'vs/base/common/map'; import { IQuickPickItem, IQuickInputService, QuickPickInput } from 'vs/platform/quickinput/common/quickInput'; -import { SnippetSource } from 'vs/workbench/contrib/snippets/electron-browser/snippetsFile'; +import { SnippetSource } from 'vs/workbench/contrib/snippets/browser/snippetsFile'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IFileService } from 'vs/platform/files/common/files'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -78,7 +78,7 @@ async function computePicks(snippetService: ISnippetsService, envService: IEnvir } else { // language snippet - const mode = basename(file.location.fsPath, '.json'); + const mode = basename(file.location.fsPath).replace(/\.json$/, ''); existing.push({ label: basename(file.location.fsPath), description: `(${modeService.getLanguageName(mode)})`, diff --git a/src/vs/workbench/contrib/snippets/electron-browser/insertSnippet.ts b/src/vs/workbench/contrib/snippets/browser/insertSnippet.ts similarity index 98% rename from src/vs/workbench/contrib/snippets/electron-browser/insertSnippet.ts rename to src/vs/workbench/contrib/snippets/browser/insertSnippet.ts index c25feb0f293..dc796e6acb7 100644 --- a/src/vs/workbench/contrib/snippets/electron-browser/insertSnippet.ts +++ b/src/vs/workbench/contrib/snippets/browser/insertSnippet.ts @@ -8,11 +8,11 @@ import { registerEditorAction, ServicesAccessor, EditorAction } from 'vs/editor/ import { IModeService } from 'vs/editor/common/services/modeService'; import { LanguageId } from 'vs/editor/common/modes'; import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { ISnippetsService } from 'vs/workbench/contrib/snippets/electron-browser/snippets.contribution'; +import { ISnippetsService } from 'vs/workbench/contrib/snippets/browser/snippets.contribution'; import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { Snippet, SnippetSource } from 'vs/workbench/contrib/snippets/electron-browser/snippetsFile'; +import { Snippet, SnippetSource } from 'vs/workbench/contrib/snippets/browser/snippetsFile'; import { IQuickPickItem, IQuickInputService, QuickPickInput } from 'vs/platform/quickinput/common/quickInput'; interface ISnippetPick extends IQuickPickItem { diff --git a/src/vs/workbench/contrib/snippets/electron-browser/snippetCompletionProvider.ts b/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts similarity index 98% rename from src/vs/workbench/contrib/snippets/electron-browser/snippetCompletionProvider.ts rename to src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts index 1804c78c6d4..106ca8be945 100644 --- a/src/vs/workbench/contrib/snippets/electron-browser/snippetCompletionProvider.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts @@ -12,8 +12,8 @@ import { CompletionItem, CompletionItemKind, CompletionItemProvider, CompletionL import { IModeService } from 'vs/editor/common/services/modeService'; import { SnippetParser } from 'vs/editor/contrib/snippet/snippetParser'; import { localize } from 'vs/nls'; -import { ISnippetsService } from 'vs/workbench/contrib/snippets/electron-browser/snippets.contribution'; -import { Snippet, SnippetSource } from 'vs/workbench/contrib/snippets/electron-browser/snippetsFile'; +import { ISnippetsService } from 'vs/workbench/contrib/snippets/browser/snippets.contribution'; +import { Snippet, SnippetSource } from 'vs/workbench/contrib/snippets/browser/snippetsFile'; export class SnippetCompletion implements CompletionItem { diff --git a/src/vs/workbench/contrib/snippets/electron-browser/snippets.contribution.ts b/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts similarity index 99% rename from src/vs/workbench/contrib/snippets/electron-browser/snippets.contribution.ts rename to src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts index c8677f3e9f8..7f5324ff6bf 100644 --- a/src/vs/workbench/contrib/snippets/electron-browser/snippets.contribution.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts @@ -9,7 +9,7 @@ import * as JSONContributionRegistry from 'vs/platform/jsonschemas/common/jsonCo import * as nls from 'vs/nls'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { LanguageId } from 'vs/editor/common/modes'; -import { SnippetFile, Snippet } from 'vs/workbench/contrib/snippets/electron-browser/snippetsFile'; +import { SnippetFile, Snippet } from 'vs/workbench/contrib/snippets/browser/snippetsFile'; export const ISnippetsService = createDecorator('snippetService'); diff --git a/src/vs/workbench/contrib/snippets/electron-browser/snippetsFile.ts b/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts similarity index 98% rename from src/vs/workbench/contrib/snippets/electron-browser/snippetsFile.ts rename to src/vs/workbench/contrib/snippets/browser/snippetsFile.ts index 1fbea042c2d..3631253adcf 100644 --- a/src/vs/workbench/contrib/snippets/electron-browser/snippetsFile.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts @@ -7,7 +7,7 @@ import { parse as jsonParse } from 'vs/base/common/json'; import { forEach } from 'vs/base/common/collections'; import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import { localize } from 'vs/nls'; -import { basename, extname } from 'path'; +import { basename, extname } from 'vs/base/common/paths'; import { SnippetParser, Variable, Placeholder, Text } from 'vs/editor/contrib/snippet/snippetParser'; import { KnownSnippetVariableNames } from 'vs/editor/contrib/snippet/snippetVariables'; import { isFalsyOrWhitespace } from 'vs/base/common/strings'; @@ -166,7 +166,7 @@ export class SnippetFile { private _filepathSelect(selector: string, bucket: Snippet[]): void { // for `fooLang.json` files all snippets are accepted - if (selector === basename(this.location.path, '.json')) { + if (selector + '.json' === basename(this.location.path)) { bucket.push(...this.data); } } diff --git a/src/vs/workbench/contrib/snippets/electron-browser/snippetsService.ts b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts similarity index 98% rename from src/vs/workbench/contrib/snippets/electron-browser/snippetsService.ts rename to src/vs/workbench/contrib/snippets/browser/snippetsService.ts index 87a6d143f8d..033852eaa4a 100644 --- a/src/vs/workbench/contrib/snippets/electron-browser/snippetsService.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { basename, extname, join } from 'path'; +import { basename, extname, join } from 'vs/base/common/paths'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { combinedDisposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { values } from 'vs/base/common/map'; @@ -21,8 +21,8 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; import { IWorkspace, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { ISnippetsService } from 'vs/workbench/contrib/snippets/electron-browser/snippets.contribution'; -import { Snippet, SnippetFile, SnippetSource } from 'vs/workbench/contrib/snippets/electron-browser/snippetsFile'; +import { ISnippetsService } from 'vs/workbench/contrib/snippets/browser/snippets.contribution'; +import { Snippet, SnippetFile, SnippetSource } from 'vs/workbench/contrib/snippets/browser/snippetsFile'; import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { languagesExtPoint } from 'vs/workbench/services/mode/common/workbenchModeService'; import { SnippetCompletionProvider } from './snippetCompletionProvider'; @@ -324,7 +324,7 @@ class SnippetsService implements ISnippetsService { const ext = extname(uri.path); const key = uri.toString(); if (source === SnippetSource.User && ext === '.json') { - const langName = basename(uri.path, '.json'); + const langName = basename(uri.path).replace(/\.json/, ''); this._files.set(key, new SnippetFile(source, uri, [langName], undefined, this._fileService)); } else if (ext === '.code-snippets') { this._files.set(key, new SnippetFile(source, uri, undefined, undefined, this._fileService)); diff --git a/src/vs/workbench/contrib/snippets/electron-browser/tabCompletion.ts b/src/vs/workbench/contrib/snippets/browser/tabCompletion.ts similarity index 93% rename from src/vs/workbench/contrib/snippets/electron-browser/tabCompletion.ts rename to src/vs/workbench/contrib/snippets/browser/tabCompletion.ts index 28f171af6b2..33f6bedb330 100644 --- a/src/vs/workbench/contrib/snippets/electron-browser/tabCompletion.ts +++ b/src/vs/workbench/contrib/snippets/browser/tabCompletion.ts @@ -6,8 +6,8 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { RawContextKey, IContextKeyService, ContextKeyExpr, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { ISnippetsService } from 'vs/workbench/contrib/snippets/electron-browser/snippets.contribution'; -import { getNonWhitespacePrefix } from 'vs/workbench/contrib/snippets/electron-browser/snippetsService'; +import { ISnippetsService } from './snippets.contribution'; +import { getNonWhitespacePrefix } from './snippetsService'; import { endsWith } from 'vs/base/common/strings'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import * as editorCommon from 'vs/editor/common/editorCommon'; @@ -17,8 +17,8 @@ import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2 import { showSimpleSuggestions } from 'vs/editor/contrib/suggest/suggest'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { Snippet } from 'vs/workbench/contrib/snippets/electron-browser/snippetsFile'; -import { SnippetCompletion } from 'vs/workbench/contrib/snippets/electron-browser/snippetCompletionProvider'; +import { Snippet } from './snippetsFile'; +import { SnippetCompletion } from './snippetCompletionProvider'; export class TabCompletionController implements editorCommon.IEditorContribution { diff --git a/src/vs/workbench/contrib/snippets/test/electron-browser/snippetFile.test.ts b/src/vs/workbench/contrib/snippets/test/browser/snippetFile.test.ts similarity index 97% rename from src/vs/workbench/contrib/snippets/test/electron-browser/snippetFile.test.ts rename to src/vs/workbench/contrib/snippets/test/browser/snippetFile.test.ts index 2403cdb6634..9de054d0dab 100644 --- a/src/vs/workbench/contrib/snippets/test/electron-browser/snippetFile.test.ts +++ b/src/vs/workbench/contrib/snippets/test/browser/snippetFile.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { SnippetFile, Snippet, SnippetSource } from 'vs/workbench/contrib/snippets/electron-browser/snippetsFile'; +import { SnippetFile, Snippet, SnippetSource } from 'vs/workbench/contrib/snippets/browser/snippetsFile'; import { URI } from 'vs/base/common/uri'; suite('Snippets', function () { diff --git a/src/vs/workbench/contrib/snippets/test/electron-browser/snippetsRegistry.test.ts b/src/vs/workbench/contrib/snippets/test/browser/snippetsRegistry.test.ts similarity index 99% rename from src/vs/workbench/contrib/snippets/test/electron-browser/snippetsRegistry.test.ts rename to src/vs/workbench/contrib/snippets/test/browser/snippetsRegistry.test.ts index ebfe3292282..62d57763e1d 100644 --- a/src/vs/workbench/contrib/snippets/test/electron-browser/snippetsRegistry.test.ts +++ b/src/vs/workbench/contrib/snippets/test/browser/snippetsRegistry.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { getNonWhitespacePrefix } from 'vs/workbench/contrib/snippets/electron-browser/snippetsService'; +import { getNonWhitespacePrefix } from 'vs/workbench/contrib/snippets/browser/snippetsService'; import { Position } from 'vs/editor/common/core/position'; suite('getNonWhitespacePrefix', () => { diff --git a/src/vs/workbench/contrib/snippets/test/electron-browser/snippetsRewrite.test.ts b/src/vs/workbench/contrib/snippets/test/browser/snippetsRewrite.test.ts similarity index 97% rename from src/vs/workbench/contrib/snippets/test/electron-browser/snippetsRewrite.test.ts rename to src/vs/workbench/contrib/snippets/test/browser/snippetsRewrite.test.ts index 9747e16114f..99bde2d2a5a 100644 --- a/src/vs/workbench/contrib/snippets/test/electron-browser/snippetsRewrite.test.ts +++ b/src/vs/workbench/contrib/snippets/test/browser/snippetsRewrite.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { Snippet, SnippetSource } from 'vs/workbench/contrib/snippets/electron-browser/snippetsFile'; +import { Snippet, SnippetSource } from 'vs/workbench/contrib/snippets/browser/snippetsFile'; suite('SnippetRewrite', function () { diff --git a/src/vs/workbench/contrib/snippets/test/electron-browser/snippetsService.test.ts b/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts similarity index 99% rename from src/vs/workbench/contrib/snippets/test/electron-browser/snippetsService.test.ts rename to src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts index d71653bfd19..03915648eb4 100644 --- a/src/vs/workbench/contrib/snippets/test/electron-browser/snippetsService.test.ts +++ b/src/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { SnippetCompletionProvider } from 'vs/workbench/contrib/snippets/electron-browser/snippetCompletionProvider'; +import { SnippetCompletionProvider } from 'vs/workbench/contrib/snippets/browser/snippetCompletionProvider'; import { Position } from 'vs/editor/common/core/position'; import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry'; import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl'; import { TextModel } from 'vs/editor/common/model/textModel'; -import { ISnippetsService } from 'vs/workbench/contrib/snippets/electron-browser/snippets.contribution'; -import { Snippet, SnippetSource } from 'vs/workbench/contrib/snippets/electron-browser/snippetsFile'; +import { ISnippetsService } from 'vs/workbench/contrib/snippets/browser/snippets.contribution'; +import { Snippet, SnippetSource } from 'vs/workbench/contrib/snippets/browser/snippetsFile'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { CompletionContext, CompletionTriggerKind } from 'vs/editor/common/modes'; diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 4acb59e6a74..5f2faf28af7 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -134,11 +134,11 @@ import 'vs/workbench/contrib/codeEditor/electron-browser/codeEditor.contribution import 'vs/workbench/contrib/execution/electron-browser/execution.contribution'; // Snippets -import 'vs/workbench/contrib/snippets/electron-browser/snippets.contribution'; -import 'vs/workbench/contrib/snippets/electron-browser/snippetsService'; -import 'vs/workbench/contrib/snippets/electron-browser/insertSnippet'; -import 'vs/workbench/contrib/snippets/electron-browser/configureSnippets'; -import 'vs/workbench/contrib/snippets/electron-browser/tabCompletion'; +import 'vs/workbench/contrib/snippets/browser/snippets.contribution'; +import 'vs/workbench/contrib/snippets/browser/snippetsService'; +import 'vs/workbench/contrib/snippets/browser/insertSnippet'; +import 'vs/workbench/contrib/snippets/browser/configureSnippets'; +import 'vs/workbench/contrib/snippets/browser/tabCompletion'; // Send a Smile import 'vs/workbench/contrib/feedback/electron-browser/feedback.contribution'; From 94d424aee2e9e7af4bb1edae53c9cd02831624f7 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 8 Feb 2019 10:37:35 +0100 Subject: [PATCH 041/207] Close existing connections when an authority is resolved --- src/vs/code/electron-main/app.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index f451547d241..cb724bb4406 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -682,10 +682,10 @@ export class CodeApplication extends Disposable { constructor(authority: string, host: string, port: number) { this._authority = authority; this._client = connectRemoteAgentManagement(authority, host, port, `main`, isBuilt); - this._disposeRunner = new RunOnceScheduler(() => this._dispose(), 5000); + this._disposeRunner = new RunOnceScheduler(() => this.dispose(), 5000); } - private _dispose(): void { + public dispose(): void { this._disposeRunner.dispose(); connectionPool.delete(this._authority); this._client.then((connection) => { @@ -701,8 +701,12 @@ export class CodeApplication extends Disposable { const resolvedAuthorities = new Map(); ipc.on('vscode:remoteAuthorityResolved', (event: any, data: ResolvedAuthority) => { - this.logService.info('Receieved resolved authority', data.authority); + this.logService.info('Received resolved authority', data.authority); resolvedAuthorities.set(data.authority, data); + // Make sure to close and remove any existing connections + if (connectionPool.has(data.authority)) { + connectionPool.get(data.authority).dispose(); + } }); const resolveAuthority = (authority: string): ResolvedAuthority | null => { From 4c6741b2ad33e23562770e76db61b665d02b1f8a Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 8 Feb 2019 11:26:32 +0100 Subject: [PATCH 042/207] expandOnlyOnTwistieClick per element related to #62127 --- src/vs/base/browser/ui/tree/abstractTree.ts | 16 ++++++++++++---- src/vs/base/browser/ui/tree/asyncDataTree.ts | 7 ++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index ca9bf9d311e..711ae180384 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -712,7 +712,7 @@ export interface IAbstractTreeOptions extends IAbstractTr readonly dnd?: ITreeDragAndDrop; readonly autoExpandSingleChildren?: boolean; readonly keyboardNavigationEventFilter?: IKeyboardNavigationEventFilter; - readonly expandOnlyOnTwistieClick?: boolean; + readonly expandOnlyOnTwistieClick?: boolean | ((e: T) => boolean); } function dfs(node: ITreeNode, fn: (node: ITreeNode) => void): void { @@ -825,7 +825,15 @@ class TreeNodeListMouseController extends MouseController< return super.onPointer(e); } - if (this.tree.expandOnlyOnTwistieClick && !onTwistie) { + let expandOnlyOnTwistieClick = false; + + if (typeof this.tree.expandOnlyOnTwistieClick === 'function') { + expandOnlyOnTwistieClick = this.tree.expandOnlyOnTwistieClick(node.element); + } else { + expandOnlyOnTwistieClick = !!this.tree.expandOnlyOnTwistieClick; + } + + if (expandOnlyOnTwistieClick && !onTwistie) { return super.onPointer(e); } @@ -834,7 +842,7 @@ class TreeNodeListMouseController extends MouseController< const recursive = e.browserEvent.altKey; model.setCollapsed(location, undefined, recursive); - if (this.tree.expandOnlyOnTwistieClick && onTwistie) { + if (expandOnlyOnTwistieClick && onTwistie) { return; } @@ -952,7 +960,7 @@ export abstract class AbstractTree implements IDisposable // Options TODO@joao expose options only, not Optional<> get openOnSingleClick(): boolean { return typeof this._options.openOnSingleClick === 'undefined' ? true : this._options.openOnSingleClick; } - get expandOnlyOnTwistieClick(): boolean { return typeof this._options.expandOnlyOnTwistieClick === 'undefined' ? false : this._options.expandOnlyOnTwistieClick; } + get expandOnlyOnTwistieClick(): boolean | ((e: T) => boolean) { return typeof this._options.expandOnlyOnTwistieClick === 'undefined' ? false : this._options.expandOnlyOnTwistieClick; } get onDidDispose(): Event { return this.view.onDidDispose; } diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index 98c194d5e6d..84b2fa3c308 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -217,7 +217,12 @@ function asObjectTreeOptions(options?: IAsyncDataTreeOpt return options.keyboardNavigationLabelProvider!.getKeyboardNavigationLabel(e.element as T); } }, - sorter: undefined + sorter: undefined, + expandOnlyOnTwistieClick: typeof options.expandOnlyOnTwistieClick === 'undefined' ? undefined : ( + typeof options.expandOnlyOnTwistieClick !== 'function' ? options.expandOnlyOnTwistieClick : ( + e => (options.expandOnlyOnTwistieClick as ((e: T) => boolean))(e.element as T) + ) + ) }; } From 935561a4343c094e28a8788bc56563fdbe6b2706 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 8 Feb 2019 11:34:00 +0100 Subject: [PATCH 043/207] Fix strict null check --- src/vs/code/electron-main/app.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index cb724bb4406..2fe419d5fd7 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -705,7 +705,7 @@ export class CodeApplication extends Disposable { resolvedAuthorities.set(data.authority, data); // Make sure to close and remove any existing connections if (connectionPool.has(data.authority)) { - connectionPool.get(data.authority).dispose(); + connectionPool.get(data.authority)!.dispose(); } }); From b909133b22f1d1a1b1780f91488bf08cb3d66004 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 24 Jan 2019 12:20:04 +0100 Subject: [PATCH 044/207] Add support for api:none in IExtensionManifest --- src/vs/platform/extensions/common/extensions.ts | 1 + src/vs/workbench/api/node/extHost.api.impl.ts | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts index 1fc3e1913be..cb8566333b3 100644 --- a/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -158,6 +158,7 @@ export interface IExtensionManifest { readonly repository?: { url: string; }; readonly bugs?: { url: string; }; readonly enableProposedApi?: boolean; + readonly api?: string; } export const enum ExtensionType { diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 7373f1f92d4..2b6cd0333da 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -851,7 +851,7 @@ class Extension implements vscode.Extension { public id: string; public extensionPath: string; - public packageJSON: any; + public packageJSON: IExtensionDescription; constructor(extensionService: ExtHostExtensionService, description: IExtensionDescription) { this._extensionService = extensionService; @@ -866,6 +866,9 @@ class Extension implements vscode.Extension { } get exports(): T { + if (this.packageJSON.api === 'none') { + return undefined; + } return this._extensionService.getExtensionExports(this._identifier); } From 340f01e30b6b9ecbeeeba60d1587390c62c7fa2e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 8 Feb 2019 11:46:58 +0100 Subject: [PATCH 045/207] fix null reference issue with destructuring --- src/vs/workbench/services/textMate/electron-browser/TMSyntax.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/textMate/electron-browser/TMSyntax.ts b/src/vs/workbench/services/textMate/electron-browser/TMSyntax.ts index 3142782ef07..7248d076a02 100644 --- a/src/vs/workbench/services/textMate/electron-browser/TMSyntax.ts +++ b/src/vs/workbench/services/textMate/electron-browser/TMSyntax.ts @@ -257,7 +257,7 @@ export class TextMateService extends Disposable implements ITextMateService { let injections: string[] = []; for (let i = 1; i <= scopeParts.length; i++) { const subScopeName = scopeParts.slice(0, i).join('.'); - injections = [...injections, ...this._injections[subScopeName]]; + injections = [...injections, ...(this._injections[subScopeName] || [])]; } return injections; } From 8fad1eec756d42b9fd757ea6170d0a7e37d91ca7 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 8 Feb 2019 11:49:06 +0100 Subject: [PATCH 046/207] use new getAllPropertyNames-util instead of for-in-loop --- src/vs/base/common/types.ts | 14 ++++++++++++++ src/vs/base/common/worker/simpleWorker.ts | 5 +++-- .../editor/common/services/editorSimpleWorker.ts | 5 +++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/vs/base/common/types.ts b/src/vs/base/common/types.ts index b41f819ee4d..bddf6b764f2 100644 --- a/src/vs/base/common/types.ts +++ b/src/vs/base/common/types.ts @@ -176,3 +176,17 @@ function isNativeClass(thing): boolean { && thing.hasOwnProperty('prototype') && !thing.hasOwnProperty('arguments'); } + +/** + * + * + */ +export function getAllPropertyNames(obj: object): string[] { + let res: string[] = []; + let proto = Object.getPrototypeOf(obj); + while (Object.prototype !== proto) { + res = res.concat(Object.getOwnPropertyNames(proto)); + proto = Object.getPrototypeOf(proto); + } + return res; +} diff --git a/src/vs/base/common/worker/simpleWorker.ts b/src/vs/base/common/worker/simpleWorker.ts index fc6db66a8e4..fa19fff26e9 100644 --- a/src/vs/base/common/worker/simpleWorker.ts +++ b/src/vs/base/common/worker/simpleWorker.ts @@ -6,6 +6,7 @@ import { transformErrorForSerialization } from 'vs/base/common/errors'; import { Disposable } from 'vs/base/common/lifecycle'; import { isWeb } from 'vs/base/common/platform'; +import { getAllPropertyNames } from 'vs/base/common/types'; const INITIALIZE = '$initialize'; @@ -324,7 +325,7 @@ export class SimpleWorkerServer { if (this._requestHandler) { // static request handler let methods: string[] = []; - for (let prop in this._requestHandler) { + for (const prop of getAllPropertyNames(this._requestHandler)) { if (typeof this._requestHandler[prop] === 'function') { methods.push(prop); } @@ -360,7 +361,7 @@ export class SimpleWorkerServer { } let methods: string[] = []; - for (let prop in this._requestHandler) { + for (const prop of getAllPropertyNames(this._requestHandler)) { if (typeof this._requestHandler[prop] === 'function') { methods.push(prop); } diff --git a/src/vs/editor/common/services/editorSimpleWorker.ts b/src/vs/editor/common/services/editorSimpleWorker.ts index ed3a564f52e..4ef83f744a7 100644 --- a/src/vs/editor/common/services/editorSimpleWorker.ts +++ b/src/vs/editor/common/services/editorSimpleWorker.ts @@ -22,6 +22,7 @@ import { ILinkComputerTarget, computeLinks } from 'vs/editor/common/modes/linkCo import { BasicInplaceReplace } from 'vs/editor/common/modes/supports/inplaceReplaceSupport'; import { IDiffComputationResult } from 'vs/editor/common/services/editorWorkerService'; import { createMonacoBaseAPI } from 'vs/editor/common/standalone/standaloneBase'; +import { getAllPropertyNames } from 'vs/base/common/types'; export interface IMirrorModel { readonly uri: URI; @@ -599,7 +600,7 @@ export abstract class BaseEditorSimpleWorker { this._foreignModule = this._foreignModuleFactory(ctx, createData); // static foreing module let methods: string[] = []; - for (let prop in this._foreignModule) { + for (const prop of getAllPropertyNames(this._foreignModule)) { if (typeof this._foreignModule[prop] === 'function') { methods.push(prop); } @@ -612,7 +613,7 @@ export abstract class BaseEditorSimpleWorker { this._foreignModule = foreignModule.create(ctx, createData); let methods: string[] = []; - for (let prop in this._foreignModule) { + for (const prop of getAllPropertyNames(this._foreignModule)) { if (typeof this._foreignModule[prop] === 'function') { methods.push(prop); } From 9b669a0c71544049728ac7bf3aaf19d667eb0916 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 28 Jan 2019 17:07:41 +0100 Subject: [PATCH 047/207] Remove extensions with dependency loops as soon as possible --- .../api/node/extHostExtensionActivator.ts | 21 +--- .../electron-browser/extensionService.ts | 14 ++- .../node/extensionDescriptionRegistry.ts | 117 +++++++++++++++++- 3 files changed, 128 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/api/node/extHostExtensionActivator.ts b/src/vs/workbench/api/node/extHostExtensionActivator.ts index a21a307e7b9..102fd5bedce 100644 --- a/src/vs/workbench/api/node/extHostExtensionActivator.ts +++ b/src/vs/workbench/api/node/extHostExtensionActivator.ts @@ -231,7 +231,7 @@ export class ExtensionsActivator { return NO_OP_VOID_PROMISE; } let activateExtensions = this._registry.getExtensionDescriptionsForActivationEvent(activationEvent); - return this._activateExtensions(activateExtensions, reason, 0).then(() => { + return this._activateExtensions(activateExtensions, reason).then(() => { this._alreadyActivatedEvents[activationEvent] = true; }); } @@ -242,7 +242,7 @@ export class ExtensionsActivator { throw new Error('Extension `' + extensionId + '` is not known'); } - return this._activateExtensions([desc], reason, 0); + return this._activateExtensions([desc], reason); } /** @@ -295,7 +295,7 @@ export class ExtensionsActivator { } } - private _activateExtensions(extensionDescriptions: IExtensionDescription[], reason: ExtensionActivationReason, recursionLevel: number): Promise { + private _activateExtensions(extensionDescriptions: IExtensionDescription[], reason: ExtensionActivationReason): Promise { // console.log(recursionLevel, '_activateExtensions: ', extensionDescriptions.map(p => p.id)); if (extensionDescriptions.length === 0) { return Promise.resolve(undefined); @@ -306,17 +306,6 @@ export class ExtensionsActivator { return Promise.resolve(undefined); } - if (recursionLevel > 10) { - // More than 10 dependencies deep => most likely a dependency loop - for (let i = 0, len = extensionDescriptions.length; i < len; i++) { - // Error condition 3: dependency loop - this._host.showMessage(Severity.Error, nls.localize('failedDep2', "Extension '{0}' failed to activate. Reason: more than 10 levels of dependencies (most likely a dependency loop).", extensionDescriptions[i].identifier.value)); - const error = new Error('More than 10 levels of dependencies (most likely a dependency loop)'); - this._activatedExtensions.set(ExtensionIdentifier.toKey(extensionDescriptions[i].identifier), new FailedExtension(error)); - } - return Promise.resolve(undefined); - } - let greenMap: { [id: string]: IExtensionDescription; } = Object.create(null), red: IExtensionDescription[] = []; @@ -342,8 +331,8 @@ export class ExtensionsActivator { return Promise.all(green.map((p) => this._activateExtension(p, reason))).then(_ => undefined); } - return this._activateExtensions(green, reason, recursionLevel + 1).then(_ => { - return this._activateExtensions(red, reason, recursionLevel + 1); + return this._activateExtensions(green, reason).then(_ => { + return this._activateExtensions(red, reason); }); } diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 801b69f39a2..306aa82dc67 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -227,7 +227,11 @@ export class ExtensionService extends Disposable implements IExtensionService { } // Update the local registry - this._registry.deltaExtensions(toAdd, toRemove.map(e => e.identifier)); + const result = this._registry.deltaExtensions(toAdd, toRemove.map(e => e.identifier)); + toRemove = toRemove.concat(result.removedDueToLooping); + if (result.removedDueToLooping.length > 0) { + this._logOrShowMessage(Severity.Error, nls.localize('looping', "The following extensions contain dependency loops and have been disabled: {0}", result.removedDueToLooping.map(e => `'${e.identifier.value}'`).join(', '))); + } // Update extension points this._rehandleExtensionPoints(([]).concat(toAdd).concat(toRemove)); @@ -625,12 +629,16 @@ export class ExtensionService extends Disposable implements IExtensionService { const enabledExtensions = await this._getRuntimeExtensions(extensions); this._handleExtensionPoints(enabledExtensions); - extensionHost.start(enabledExtensions.map(extension => extension.identifier)); + extensionHost.start(enabledExtensions.map(extension => extension.identifier).filter(id => this._registry.containsExtension(id))); this._releaseBarrier(); } private _handleExtensionPoints(allExtensions: IExtensionDescription[]): void { - this._registry = new ExtensionDescriptionRegistry(allExtensions); + this._registry = new ExtensionDescriptionRegistry([]); + const result = this._registry.deltaExtensions(allExtensions, []); + if (result.removedDueToLooping.length > 0) { + this._logOrShowMessage(Severity.Error, nls.localize('looping', "The following extensions contain dependency loops and have been disabled: {0}", result.removedDueToLooping.map(e => `'${e.identifier.value}'`).join(', '))); + } let availableExtensions = this._registry.getAllExtensionDescriptions(); let extensionPoints = ExtensionsRegistry.getExtensionPoints(); diff --git a/src/vs/workbench/services/extensions/node/extensionDescriptionRegistry.ts b/src/vs/workbench/services/extensions/node/extensionDescriptionRegistry.ts index 3eddf8c90ed..c4182d11adf 100644 --- a/src/vs/workbench/services/extensions/node/extensionDescriptionRegistry.ts +++ b/src/vs/workbench/services/extensions/node/extensionDescriptionRegistry.ts @@ -7,6 +7,12 @@ import { IExtensionDescription } from 'vs/workbench/services/extensions/common/e import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { Emitter } from 'vs/base/common/event'; +export class DeltaExtensionsResult { + constructor( + public readonly removedDueToLooping: IExtensionDescription[] + ) { } +} + export class ExtensionDescriptionRegistry { private readonly _onDidChange = new Emitter(); public readonly onDidChange = this._onDidChange.event; @@ -60,19 +66,120 @@ export class ExtensionDescriptionRegistry { this._onDidChange.fire(undefined); } - public deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]) { - this._extensionDescriptions = this._extensionDescriptions.concat(toAdd); - const toRemoveSet = new Set(); - toRemove.forEach(extensionId => toRemoveSet.add(ExtensionIdentifier.toKey(extensionId))); - this._extensionDescriptions = this._extensionDescriptions.filter(extension => !toRemoveSet.has(ExtensionIdentifier.toKey(extension.identifier))); + public deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): DeltaExtensionsResult { + if (toAdd.length > 0) { + this._extensionDescriptions = this._extensionDescriptions.concat(toAdd); + } + + // Immediately remove looping extensions! + const looping = ExtensionDescriptionRegistry._findLoopingExtensions(this._extensionDescriptions); + toRemove = toRemove.concat(looping.map(ext => ext.identifier)); + + if (toRemove.length > 0) { + const toRemoveSet = new Set(); + toRemove.forEach(extensionId => toRemoveSet.add(ExtensionIdentifier.toKey(extensionId))); + this._extensionDescriptions = this._extensionDescriptions.filter(extension => !toRemoveSet.has(ExtensionIdentifier.toKey(extension.identifier))); + } + this._initialize(); this._onDidChange.fire(undefined); + return new DeltaExtensionsResult(looping); + } + + private static _findLoopingExtensions(extensionDescriptions: IExtensionDescription[]): IExtensionDescription[] { + const G = new class { + + private _arcs = new Map(); + private _nodesSet = new Set(); + private _nodesArr: string[] = []; + + addNode(id: string): void { + if (!this._nodesSet.has(id)) { + this._nodesSet.add(id); + this._nodesArr.push(id); + } + } + + addArc(from: string, to: string): void { + this.addNode(from); + this.addNode(to); + if (this._arcs.has(from)) { + this._arcs.get(from).push(to); + } else { + this._arcs.set(from, [to]); + } + } + + getArcs(id: string): string[] { + if (this._arcs.has(id)) { + return this._arcs.get(id); + } + return []; + } + + hasOnlyGoodArcs(id: string, good: Set): boolean { + const dependencies = G.getArcs(id); + for (let i = 0; i < dependencies.length; i++) { + if (!good.has(dependencies[i])) { + return false; + } + } + return true; + } + + getNodes(): string[] { + return this._nodesArr; + } + }; + + let descs = new Map(); + for (let extensionDescription of extensionDescriptions) { + const extensionId = ExtensionIdentifier.toKey(extensionDescription.identifier); + descs.set(extensionId, extensionDescription); + if (extensionDescription.extensionDependencies) { + for (let _depId of extensionDescription.extensionDependencies) { + const depId = ExtensionIdentifier.toKey(_depId); + G.addArc(extensionId, depId); + } + } + } + + // initialize with all extensions with no dependencies. + let good = new Set(); + G.getNodes().filter(id => G.getArcs(id).length === 0).forEach(id => good.add(id)); + + // all other extensions will be processed below. + let nodes = G.getNodes().filter(id => !good.has(id)); + + let madeProgress: boolean; + do { + madeProgress = false; + + // find one extension which has only good deps + for (let i = 0; i < nodes.length; i++) { + const id = nodes[i]; + + if (G.hasOnlyGoodArcs(id, good)) { + nodes.splice(i, 1); + i--; + good.add(id); + madeProgress = true; + } + } + } while (madeProgress); + + // The remaining nodes are bad and have loops + return nodes.map(id => descs.get(id)); } public containsActivationEvent(activationEvent: string): boolean { return this._activationMap.has(activationEvent); } + public containsExtension(extensionId: ExtensionIdentifier): boolean { + return this._extensionsMap.has(ExtensionIdentifier.toKey(extensionId)); + } + public getExtensionDescriptionsForActivationEvent(activationEvent: string): IExtensionDescription[] { const extensions = this._activationMap.get(activationEvent); return extensions ? extensions.slice(0) : []; From 2ba52db77aaabc9d98be76b59d3e44559e1a69d3 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Tue, 29 Jan 2019 00:41:06 +0100 Subject: [PATCH 048/207] Reroute activation for hosted extensions --- .../mainThreadExtensionService.ts | 3 + src/vs/workbench/api/node/extHost.protocol.ts | 4 +- .../api/node/extHostExtensionActivator.ts | 104 +++++++++++------- .../api/node/extHostExtensionService.ts | 29 +++-- .../electron-browser/extensionHost.ts | 1 + .../extensionHostProcessManager.ts | 2 +- .../electron-browser/extensionService.ts | 10 ++ .../node/extensionDescriptionRegistry.ts | 6 +- 8 files changed, 106 insertions(+), 53 deletions(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadExtensionService.ts b/src/vs/workbench/api/electron-browser/mainThreadExtensionService.ts index 03f10d6cd55..f7b315c0357 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadExtensionService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadExtensionService.ts @@ -31,6 +31,9 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha $localShowMessage(severity: Severity, msg: string): void { this._extensionService._logOrShowMessage(severity, msg); } + $activateExtension(extensionId: ExtensionIdentifier, activationEvent: string): Promise { + return this._extensionService._activateById(extensionId, activationEvent); + } $onWillActivateExtension(extensionId: ExtensionIdentifier): void { this._extensionService._onWillActivateExtension(extensionId); } diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 04abd54e92b..925871aefc4 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -68,6 +68,7 @@ export interface IInitData { environment: IEnvironment; workspace?: IWorkspaceData; resolvedExtensions: ExtensionIdentifier[]; + hostExtensions: ExtensionIdentifier[]; extensions: IExtensionDescription[]; telemetryInfo: ITelemetryInfo; logLevel: LogLevel; @@ -546,6 +547,7 @@ export interface MainThreadTaskShape extends IDisposable { export interface MainThreadExtensionServiceShape extends IDisposable { $localShowMessage(severity: Severity, msg: string): void; + $activateExtension(extensionId: ExtensionIdentifier, activationEvent: string): Promise; $onWillActivateExtension(extensionId: ExtensionIdentifier): void; $onDidActivateExtension(extensionId: ExtensionIdentifier, startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationEvent: string): void; $onExtensionActivationFailed(extensionId: ExtensionIdentifier): void; @@ -749,7 +751,7 @@ export interface ExtHostExtensionServiceShape { $resolveAuthority(remoteAuthority: string): Promise; $startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise; $activateByEvent(activationEvent: string): Promise; - $activate(extensionId: ExtensionIdentifier, activationEvent: string): Promise; + $activate(extensionId: ExtensionIdentifier, activationEvent: string): Promise; $deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise; diff --git a/src/vs/workbench/api/node/extHostExtensionActivator.ts b/src/vs/workbench/api/node/extHostExtensionActivator.ts index 102fd5bedce..b6f50845288 100644 --- a/src/vs/workbench/api/node/extHostExtensionActivator.ts +++ b/src/vs/workbench/api/node/extHostExtensionActivator.ts @@ -6,7 +6,6 @@ import * as nls from 'vs/nls'; import { IDisposable } from 'vs/base/common/lifecycle'; import Severity from 'vs/base/common/severity'; -import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; @@ -161,6 +160,12 @@ export class EmptyExtension extends ActivatedExtension { } } +export class HostExtension extends ActivatedExtension { + constructor() { + super(false, null, ExtensionActivationTimes.NONE, { activate: undefined, deactivate: undefined }, undefined, []); + } +} + export class FailedExtension extends ActivatedExtension { constructor(activationError: Error) { super(true, activationError, ExtensionActivationTimes.NONE, { activate: undefined, deactivate: undefined }, undefined, []); @@ -170,7 +175,7 @@ export class FailedExtension extends ActivatedExtension { export interface IExtensionsActivatorHost { showMessage(severity: Severity, message: string): void; - actualActivateExtension(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): Promise; + actualActivateExtension(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise; } export class ExtensionActivatedByEvent { @@ -192,6 +197,7 @@ export class ExtensionsActivator { private readonly _registry: ExtensionDescriptionRegistry; private readonly _resolvedExtensionsSet: Set; + private readonly _hostExtensionsMap: Map; private readonly _host: IExtensionsActivatorHost; private readonly _activatingExtensions: Map>; private readonly _activatedExtensions: Map; @@ -200,10 +206,12 @@ export class ExtensionsActivator { */ private readonly _alreadyActivatedEvents: { [activationEvent: string]: boolean; }; - constructor(registry: ExtensionDescriptionRegistry, resolvedExtensions: ExtensionIdentifier[], host: IExtensionsActivatorHost) { + constructor(registry: ExtensionDescriptionRegistry, resolvedExtensions: ExtensionIdentifier[], hostExtensions: ExtensionIdentifier[], host: IExtensionsActivatorHost) { this._registry = registry; this._resolvedExtensionsSet = new Set(); resolvedExtensions.forEach((extensionId) => this._resolvedExtensionsSet.add(ExtensionIdentifier.toKey(extensionId))); + this._hostExtensionsMap = new Map(); + hostExtensions.forEach((extensionId) => this._hostExtensionsMap.set(ExtensionIdentifier.toKey(extensionId), extensionId)); this._host = host; this._activatingExtensions = new Map>(); this._activatedExtensions = new Map(); @@ -231,7 +239,7 @@ export class ExtensionsActivator { return NO_OP_VOID_PROMISE; } let activateExtensions = this._registry.getExtensionDescriptionsForActivationEvent(activationEvent); - return this._activateExtensions(activateExtensions, reason).then(() => { + return this._activateExtensions(activateExtensions.map(e => e.identifier), reason).then(() => { this._alreadyActivatedEvents[activationEvent] = true; }); } @@ -242,14 +250,20 @@ export class ExtensionsActivator { throw new Error('Extension `' + extensionId + '` is not known'); } - return this._activateExtensions([desc], reason); + return this._activateExtensions([desc.identifier], reason); } /** * Handle semantics related to dependencies for `currentExtension`. * semantics: `redExtensions` must wait for `greenExtensions`. */ - private _handleActivateRequest(currentExtension: IExtensionDescription, greenExtensions: { [id: string]: IExtensionDescription; }, redExtensions: IExtensionDescription[]): void { + private _handleActivateRequest(currentExtensionId: ExtensionIdentifier, greenExtensions: { [id: string]: ExtensionIdentifier; }, redExtensions: ExtensionIdentifier[]): void { + if (this._hostExtensionsMap.has(ExtensionIdentifier.toKey(currentExtensionId))) { + greenExtensions[ExtensionIdentifier.toKey(currentExtensionId)] = currentExtensionId; + return; + } + + const currentExtension = this._registry.getExtensionDescription(currentExtensionId)!; let depIds = (typeof currentExtension.extensionDependencies === 'undefined' ? [] : currentExtension.extensionDependencies); let currentExtensionGetsGreenLight = true; @@ -261,61 +275,71 @@ export class ExtensionsActivator { continue; } - const depDesc = this._registry.getExtensionDescription(depId); + const dep = this._activatedExtensions.get(ExtensionIdentifier.toKey(depId)); + if (dep && !dep.activationFailed) { + // the dependency is already activated OK + continue; + } - if (!depDesc) { - // Error condition 1: unknown dependency - this._host.showMessage(Severity.Error, nls.localize('unknownDep', "Cannot activate extension '{0}' because it depends on extension '{1}', which is not installed or disabled. Please install or enable '{1}' and reload the window.", currentExtension.displayName || currentExtension.identifier.value, depId)); - const error = new Error(`Unknown dependency '${depId}'`); + if (dep && dep.activationFailed) { + // Error condition 2: a dependency has already failed activation + this._host.showMessage(Severity.Error, nls.localize('failedDep1', "Cannot activate extension '{0}' because it depends on extension '{1}', which failed to activate.", currentExtension.displayName || currentExtension.identifier.value, depId)); + const error = new Error(`Dependency ${depId} failed to activate`); + (error).detail = dep.activationFailedError; this._activatedExtensions.set(ExtensionIdentifier.toKey(currentExtension.identifier), new FailedExtension(error)); return; } - const dep = this._activatedExtensions.get(ExtensionIdentifier.toKey(depId)); - if (dep) { - if (dep.activationFailed) { - // Error condition 2: a dependency has already failed activation - this._host.showMessage(Severity.Error, nls.localize('failedDep1', "Cannot activate extension '{0}' because it depends on extension '{1}', which failed to activate.", currentExtension.displayName || currentExtension.identifier.value, depId)); - const error = new Error(`Dependency ${depId} failed to activate`); - (error).detail = dep.activationFailedError; - this._activatedExtensions.set(ExtensionIdentifier.toKey(currentExtension.identifier), new FailedExtension(error)); - return; - } - } else { + if (this._hostExtensionsMap.has(ExtensionIdentifier.toKey(depId))) { // must first wait for the dependency to activate currentExtensionGetsGreenLight = false; - greenExtensions[ExtensionIdentifier.toKey(depId)] = depDesc; + greenExtensions[ExtensionIdentifier.toKey(depId)] = this._hostExtensionsMap.get(ExtensionIdentifier.toKey(depId))!; + continue; } + + const depDesc = this._registry.getExtensionDescription(depId); + if (depDesc) { + // must first wait for the dependency to activate + currentExtensionGetsGreenLight = false; + greenExtensions[ExtensionIdentifier.toKey(depId)] = depDesc.identifier; + continue; + } + + // Error condition 1: unknown dependency + this._host.showMessage(Severity.Error, nls.localize('unknownDep', "Cannot activate extension '{0}' because it depends on extension '{1}', which is not installed or disabled. Please install or enable '{1}' and reload the window.", currentExtension.displayName || currentExtension.identifier.value, depId)); + const error = new Error(`Unknown dependency '${depId}'`); + this._activatedExtensions.set(ExtensionIdentifier.toKey(currentExtension.identifier), new FailedExtension(error)); + return; } if (currentExtensionGetsGreenLight) { - greenExtensions[ExtensionIdentifier.toKey(currentExtension.identifier)] = currentExtension; + greenExtensions[ExtensionIdentifier.toKey(currentExtension.identifier)] = currentExtensionId; } else { - redExtensions.push(currentExtension); + redExtensions.push(currentExtensionId); } } - private _activateExtensions(extensionDescriptions: IExtensionDescription[], reason: ExtensionActivationReason): Promise { - // console.log(recursionLevel, '_activateExtensions: ', extensionDescriptions.map(p => p.id)); - if (extensionDescriptions.length === 0) { + private _activateExtensions(extensionIds: ExtensionIdentifier[], reason: ExtensionActivationReason): Promise { + // console.log('_activateExtensions: ', extensionIds.map(p => p.value)); + if (extensionIds.length === 0) { return Promise.resolve(undefined); } - extensionDescriptions = extensionDescriptions.filter((p) => !this._activatedExtensions.has(ExtensionIdentifier.toKey(p.identifier))); - if (extensionDescriptions.length === 0) { + extensionIds = extensionIds.filter((p) => !this._activatedExtensions.has(ExtensionIdentifier.toKey(p))); + if (extensionIds.length === 0) { return Promise.resolve(undefined); } - let greenMap: { [id: string]: IExtensionDescription; } = Object.create(null), - red: IExtensionDescription[] = []; + let greenMap: { [id: string]: ExtensionIdentifier; } = Object.create(null), + red: ExtensionIdentifier[] = []; - for (let i = 0, len = extensionDescriptions.length; i < len; i++) { - this._handleActivateRequest(extensionDescriptions[i], greenMap, red); + for (let i = 0, len = extensionIds.length; i < len; i++) { + this._handleActivateRequest(extensionIds[i], greenMap, red); } // Make sure no red is also green for (let i = 0, len = red.length; i < len; i++) { - const redExtensionKey = ExtensionIdentifier.toKey(red[i].identifier); + const redExtensionKey = ExtensionIdentifier.toKey(red[i]); if (greenMap[redExtensionKey]) { delete greenMap[redExtensionKey]; } @@ -336,8 +360,8 @@ export class ExtensionsActivator { }); } - private _activateExtension(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): Promise { - const extensionKey = ExtensionIdentifier.toKey(extensionDescription.identifier); + private _activateExtension(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise { + const extensionKey = ExtensionIdentifier.toKey(extensionId); if (this._activatedExtensions.has(extensionKey)) { return Promise.resolve(undefined); @@ -348,9 +372,9 @@ export class ExtensionsActivator { return currentlyActivatingExtension; } - const newlyActivatingExtension = this._host.actualActivateExtension(extensionDescription, reason).then(undefined, (err) => { - this._host.showMessage(Severity.Error, nls.localize('activationError', "Activating extension '{0}' failed: {1}.", extensionDescription.identifier.value, err.message)); - console.error('Activating extension `' + extensionDescription.identifier.value + '` failed: ', err.message); + const newlyActivatingExtension = this._host.actualActivateExtension(extensionId, reason).then(undefined, (err) => { + this._host.showMessage(Severity.Error, nls.localize('activationError', "Activating extension '{0}' failed: {1}.", extensionId.value, err.message)); + console.error('Activating extension `' + extensionId.value + '` failed: ', err.message); console.log('Here is the error stack: ', err.stack); // Treat the extension as being empty return new FailedExtension(err); diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index 1f4a1e100b0..82228a9ec5e 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -15,7 +15,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { createApiFactory, initializeExtensionApi, IExtensionApiFactory } from 'vs/workbench/api/node/extHost.api.impl'; import { ExtHostExtensionServiceShape, IEnvironment, IInitData, IMainContext, IWorkspaceData, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape } from 'vs/workbench/api/node/extHost.protocol'; import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration'; -import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionContext, IExtensionMemento, IExtensionModule } from 'vs/workbench/api/node/extHostExtensionActivator'; +import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionContext, IExtensionMemento, IExtensionModule, HostExtension } from 'vs/workbench/api/node/extHostExtensionActivator'; import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService'; import { ExtHostStorage } from 'vs/workbench/api/node/extHostStorage'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; @@ -192,7 +192,11 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { this._registry = new ExtensionDescriptionRegistry(initData.extensions); this._storage = new ExtHostStorage(this._extHostContext); this._storagePath = new ExtensionStoragePath(initData.workspace, initData.environment); - this._activator = new ExtensionsActivator(this._registry, initData.resolvedExtensions, { + + const hostExtensions = new Set(); + initData.hostExtensions.forEach((extensionId) => hostExtensions.add(ExtensionIdentifier.toKey(extensionId))); + + this._activator = new ExtensionsActivator(this._registry, initData.resolvedExtensions, initData.hostExtensions, { showMessage: (severity: Severity, message: string): void => { this._mainThreadExtensionsProxy.$localShowMessage(severity, message); @@ -208,7 +212,13 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { } }, - actualActivateExtension: (extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): Promise => { + actualActivateExtension: async (extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise => { + if (hostExtensions.has(ExtensionIdentifier.toKey(extensionId))) { + let activationEvent = (reason instanceof ExtensionActivatedByEvent ? reason.activationEvent : null); + await this._mainThreadExtensionsProxy.$activateExtension(extensionId, activationEvent); + return new HostExtension(); + } + const extensionDescription = this._registry.getExtensionDescription(extensionId); return this._activateExtension(extensionDescription, reason); } }); @@ -666,11 +676,14 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { ); } - public $activate(extensionId: ExtensionIdentifier, activationEvent: string): Promise { - return ( - this._barrier.wait() - .then(_ => this._activateById(extensionId, new ExtensionActivatedByEvent(false, activationEvent))) - ); + public async $activate(extensionId: ExtensionIdentifier, activationEvent: string): Promise { + await this._barrier.wait(); + if (!this._registry.getExtensionDescription(extensionId)) { + // unknown extension => ignore + return false; + } + await this._activateById(extensionId, new ExtensionActivatedByEvent(false, activationEvent)); + return true; } public async $deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise { diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index 7e212550cea..34e7cbf0a57 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -440,6 +440,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { name: this._labelService.getWorkspaceLabel(workspace) }, resolvedExtensions: [], + hostExtensions: [], extensions: extensionDescriptions, telemetryInfo, logLevel: this._logService.getLevel(), diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHostProcessManager.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHostProcessManager.ts index 8329209bdd5..17316e8db3f 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHostProcessManager.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHostProcessManager.ts @@ -199,7 +199,7 @@ export class ExtensionHostProcessManager extends Disposable { return this._extensionHostProcessRPCProtocol.getProxy(ExtHostContext.ExtHostExtensionService); } - public activate(extension: ExtensionIdentifier, activationEvent: string): Promise { + public activate(extension: ExtensionIdentifier, activationEvent: string): Promise { return this._extensionHostProcessProxy.then((proxy) => { return proxy.value.$activate(extension, activationEvent); }); diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 306aa82dc67..02e23141003 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -823,6 +823,16 @@ export class ExtensionService extends Disposable implements IExtensionService { } } + public async _activateById(extensionId: ExtensionIdentifier, activationEvent: string): Promise { + const results = await Promise.all( + this._extensionHostProcessManagers.map(manager => manager.activate(extensionId, activationEvent)) + ); + const activated = results.some(e => e); + if (!activated) { + throw new Error(`Unknown extension ${extensionId.value}`); + } + } + public _onWillActivateExtension(extensionId: ExtensionIdentifier): void { this._extensionHostActiveExtensions.set(ExtensionIdentifier.toKey(extensionId), extensionId); } diff --git a/src/vs/workbench/services/extensions/node/extensionDescriptionRegistry.ts b/src/vs/workbench/services/extensions/node/extensionDescriptionRegistry.ts index c4182d11adf..6ad4cac017d 100644 --- a/src/vs/workbench/services/extensions/node/extensionDescriptionRegistry.ts +++ b/src/vs/workbench/services/extensions/node/extensionDescriptionRegistry.ts @@ -104,7 +104,7 @@ export class ExtensionDescriptionRegistry { this.addNode(from); this.addNode(to); if (this._arcs.has(from)) { - this._arcs.get(from).push(to); + this._arcs.get(from)!.push(to); } else { this._arcs.set(from, [to]); } @@ -112,7 +112,7 @@ export class ExtensionDescriptionRegistry { getArcs(id: string): string[] { if (this._arcs.has(id)) { - return this._arcs.get(id); + return this._arcs.get(id)!; } return []; } @@ -169,7 +169,7 @@ export class ExtensionDescriptionRegistry { } while (madeProgress); // The remaining nodes are bad and have loops - return nodes.map(id => descs.get(id)); + return nodes.map(id => descs.get(id)!); } public containsActivationEvent(activationEvent: string): boolean { From 86fcbadd3048a4562cc2f621fe01907b42fbd491 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 8 Feb 2019 12:07:22 +0100 Subject: [PATCH 049/207] fix Event#once --- src/vs/base/common/event.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index 1a77679c4ff..4438fa3db74 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -27,8 +27,8 @@ export namespace Event { return (listener, thisArgs = null, disposables?) => { // we need this, in case the event fires during the listener call let didFire = false; - - const result = event(e => { + let result: IDisposable; + result = event(e => { if (didFire) { return; } else if (result) { From 8d9ef1c975feba0e9e0be10c9d09732ef53ac43b Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 8 Feb 2019 12:12:27 +0100 Subject: [PATCH 050/207] add es5ClassCompat-vehicle --- src/vs/workbench/api/node/extHostTypes.ts | 57 +++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index 950d8cee119..166bbba1b98 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -16,6 +16,18 @@ import { generateUuid } from 'vs/base/common/uuid'; import * as vscode from 'vscode'; +function es5ClassCompat(target: Function): any { + ///@ts-ignore + function _() { return Reflect.construct(target, arguments, this.constructor); } + Object.defineProperty(_, 'name', Object.getOwnPropertyDescriptor(target, 'name')); + ///@ts-ignore + Object.setPrototypeOf(_, target); + ///@ts-ignore + Object.setPrototypeOf(_.prototype, target.prototype); + return _; +} + +@es5ClassCompat export class Disposable { static from(...inDisposables: { dispose(): any }[]): Disposable { @@ -46,6 +58,7 @@ export class Disposable { } } +@es5ClassCompat export class Position { static Min(...positions: Position[]): Position { @@ -217,6 +230,7 @@ export class Position { } } +@es5ClassCompat export class Range { static isRange(thing: any): thing is vscode.Range { @@ -351,6 +365,7 @@ export class Range { } } +@es5ClassCompat export class Selection extends Range { static isSelection(thing: any): thing is Selection { @@ -421,6 +436,7 @@ export enum EndOfLine { CRLF = 2 } +@es5ClassCompat export class TextEdit { static isTextEdit(thing: any): thing is TextEdit { @@ -524,6 +540,7 @@ export interface IFileTextEdit { edit: TextEdit; } +@es5ClassCompat export class WorkspaceEdit implements vscode.WorkspaceEdit { private _edits = new Array(); @@ -627,6 +644,7 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit { } } +@es5ClassCompat export class SnippetString { static isSnippetString(thing: any): thing is SnippetString { @@ -720,6 +738,7 @@ export enum DiagnosticSeverity { Error = 0 } +@es5ClassCompat export class Location { static isLocation(thing: any): thing is Location { @@ -758,6 +777,7 @@ export class Location { } } +@es5ClassCompat export class DiagnosticRelatedInformation { static is(thing: any): thing is DiagnosticRelatedInformation { @@ -791,6 +811,7 @@ export class DiagnosticRelatedInformation { } } +@es5ClassCompat export class Diagnostic { range: Range; @@ -835,6 +856,7 @@ export class Diagnostic { } } +@es5ClassCompat export class Hover { public contents: vscode.MarkdownString[] | vscode.MarkedString[]; @@ -864,6 +886,7 @@ export enum DocumentHighlightKind { Write = 2 } +@es5ClassCompat export class DocumentHighlight { range: Range; @@ -911,6 +934,7 @@ export enum SymbolKind { TypeParameter = 25 } +@es5ClassCompat export class SymbolInformation { static validate(candidate: SymbolInformation): void { @@ -954,6 +978,7 @@ export class SymbolInformation { } } +@es5ClassCompat export class DocumentSymbol { static validate(candidate: DocumentSymbol): void { @@ -993,6 +1018,7 @@ export enum CodeActionTrigger { Manual = 2, } +@es5ClassCompat export class CodeAction { title: string; @@ -1011,6 +1037,7 @@ export class CodeAction { } +@es5ClassCompat export class CodeActionKind { private static readonly sep = '.'; @@ -1041,6 +1068,7 @@ export class CodeActionKind { } } +@es5ClassCompat export class SelectionRangeKind { private static readonly _sep = '.'; @@ -1060,6 +1088,7 @@ export class SelectionRangeKind { } } +@es5ClassCompat export class SelectionRange { kind: SelectionRangeKind; @@ -1072,6 +1101,7 @@ export class SelectionRange { } +@es5ClassCompat export class CodeLens { range: Range; @@ -1088,6 +1118,7 @@ export class CodeLens { } } +@es5ClassCompat export class MarkdownString { value: string; @@ -1118,6 +1149,7 @@ export class MarkdownString { } } +@es5ClassCompat export class ParameterInformation { label: string | [number, number]; @@ -1129,6 +1161,7 @@ export class ParameterInformation { } } +@es5ClassCompat export class SignatureInformation { label: string; @@ -1142,6 +1175,7 @@ export class SignatureInformation { } } +@es5ClassCompat export class SignatureHelp { signatures: SignatureInformation[]; @@ -1198,6 +1232,7 @@ export enum CompletionItemKind { TypeParameter = 24 } +@es5ClassCompat export class CompletionItem implements vscode.CompletionItem { label: string; @@ -1235,6 +1270,7 @@ export class CompletionItem implements vscode.CompletionItem { } } +@es5ClassCompat export class CompletionList { isIncomplete?: boolean; @@ -1324,6 +1360,7 @@ export namespace TextEditorSelectionChangeKind { } } +@es5ClassCompat export class DocumentLink { range: Range; @@ -1342,6 +1379,7 @@ export class DocumentLink { } } +@es5ClassCompat export class Color { readonly red: number; readonly green: number; @@ -1358,6 +1396,7 @@ export class Color { export type IColorFormat = string | { opaque: string, transparent: string }; +@es5ClassCompat export class ColorInformation { range: Range; @@ -1375,6 +1414,7 @@ export class ColorInformation { } } +@es5ClassCompat export class ColorPresentation { label: string; textEdit?: TextEdit; @@ -1416,6 +1456,7 @@ export enum TaskPanelKind { New = 3 } +@es5ClassCompat export class TaskGroup implements vscode.TaskGroup { private _id: string; @@ -1458,6 +1499,7 @@ export class TaskGroup implements vscode.TaskGroup { } } +@es5ClassCompat export class ProcessExecution implements vscode.ProcessExecution { private _process: string; @@ -1530,6 +1572,7 @@ export class ProcessExecution implements vscode.ProcessExecution { } } +@es5ClassCompat export class ShellExecution implements vscode.ShellExecution { private _commandLine: string; @@ -1626,6 +1669,7 @@ export enum TaskScope { Workspace = 2 } +@es5ClassCompat export class Task implements vscode.Task { private static ProcessType: string = 'process'; @@ -1858,6 +1902,7 @@ export enum ProgressLocation { Notification = 15 } +@es5ClassCompat export class TreeItem { label?: string | vscode.TreeItemLabel; @@ -1885,6 +1930,7 @@ export enum TreeItemCollapsibleState { Expanded = 2 } +@es5ClassCompat export class ThemeIcon { static readonly File = new ThemeIcon('file'); @@ -1897,6 +1943,7 @@ export class ThemeIcon { } } +@es5ClassCompat export class ThemeColor { id: string; constructor(id: string) { @@ -1912,6 +1959,7 @@ export enum ConfigurationTarget { WorkspaceFolder = 3 } +@es5ClassCompat export class RelativePattern implements IRelativePattern { base: string; baseFolder?: URI; @@ -1944,6 +1992,7 @@ export class RelativePattern implements IRelativePattern { } } +@es5ClassCompat export class Breakpoint { private _id: string | undefined; @@ -1974,6 +2023,7 @@ export class Breakpoint { } } +@es5ClassCompat export class SourceBreakpoint extends Breakpoint { readonly location: Location; @@ -1986,6 +2036,7 @@ export class SourceBreakpoint extends Breakpoint { } } +@es5ClassCompat export class FunctionBreakpoint extends Breakpoint { readonly functionName: string; @@ -1998,6 +2049,7 @@ export class FunctionBreakpoint extends Breakpoint { } } +@es5ClassCompat export class DebugAdapterExecutable implements vscode.DebugAdapterExecutable { readonly command: string; readonly args: string[]; @@ -2010,6 +2062,7 @@ export class DebugAdapterExecutable implements vscode.DebugAdapterExecutable { } } +@es5ClassCompat export class DebugAdapterServer implements vscode.DebugAdapterServer { readonly port: number; readonly host?: string; @@ -2021,6 +2074,7 @@ export class DebugAdapterServer implements vscode.DebugAdapterServer { } /* +@es5ClassCompat export class DebugAdapterImplementation implements vscode.DebugAdapterImplementation { readonly implementation: any; @@ -2048,6 +2102,7 @@ export enum FileChangeType { Deleted = 3, } +@es5ClassCompat export class FileSystemError extends Error { static FileExists(messageOrUri?: string | URI): FileSystemError { @@ -2090,6 +2145,7 @@ export class FileSystemError extends Error { //#region folding api +@es5ClassCompat export class FoldingRange { start: number; @@ -2125,6 +2181,7 @@ export enum CommentThreadCollapsibleState { Expanded = 1 } +@es5ClassCompat export class QuickInputButtons { static readonly Back: vscode.QuickInputButton = { iconPath: 'back.svg' }; From 7afc9b836dd873954f3744764824ad8369b1b38e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 8 Feb 2019 12:17:22 +0100 Subject: [PATCH 051/207] Fix #67658 --- .../markers/electron-browser/markersPanel.ts | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/markers/electron-browser/markersPanel.ts b/src/vs/workbench/contrib/markers/electron-browser/markersPanel.ts index ff973cff879..f05d660102b 100644 --- a/src/vs/workbench/contrib/markers/electron-browser/markersPanel.ts +++ b/src/vs/workbench/contrib/markers/electron-browser/markersPanel.ts @@ -413,10 +413,29 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { } private createListeners(): void { - const onModelChange = Event.debounce(this.markersWorkbenchService.markersModel.onDidChange, (uris, uri) => { if (!uris) { uris = []; } uris.push(uri); return uris; }, 0); + const onModelOrActiveEditorChanged = Event.debounce(Event.any(this.markersWorkbenchService.markersModel.onDidChange, Event.map(this.editorService.onDidActiveEditorChange, () => true)), (result, e) => { + if (!result) { + result = { + resources: [], + activeEditorChanged: false + }; + } + if (e === true) { + result.activeEditorChanged = true; + } else { + result.resources.push(e); + } + return result; + }, 0); - this._register(onModelChange(this.onDidChangeModel, this)); - this._register(this.editorService.onDidActiveEditorChange(this.onActiveEditorChanged, this)); + this._register(onModelOrActiveEditorChanged(({ resources, activeEditorChanged }) => { + if (resources) { + this.onDidChangeModel(resources); + } + if (activeEditorChanged) { + this.onActiveEditorChanged(); + } + }, this)); this._register(this.tree.onDidChangeSelection(() => this.onSelected())); this._register(this.filterAction.onDidChange((event: IMarkersFilterActionChangeEvent) => { if (event.filterText || event.useFilesExclude) { From 17c51e9dbeeceb9c704ff885852d8967e468533d Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 8 Feb 2019 12:09:58 +0100 Subject: [PATCH 052/207] fixes #68161 --- src/vs/base/browser/ui/list/listWidget.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 1d2c65d40d2..e4c9599601b 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -369,6 +369,7 @@ class TypeLabelController implements IDisposable { .filter(e => !isInputElement(e.target as HTMLElement)) .map(event => new StandardKeyboardEvent(event)) .filter(this.keyboardNavigationLabelProvider.mightProducePrintableCharacter ? e => this.keyboardNavigationLabelProvider.mightProducePrintableCharacter!(e) : e => mightProducePrintableCharacter(e)) + .forEach(e => { e.stopPropagation(); e.preventDefault(); }) .map(event => event.browserEvent.key) .event; From 43d68b608d7d25dac59ca70af3c7efd3863768bb Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 8 Feb 2019 12:26:27 +0100 Subject: [PATCH 053/207] fixes #68054 --- src/vs/base/browser/ui/list/listWidget.ts | 29 ++++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index e4c9599601b..87f3b6b1ede 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -508,6 +508,7 @@ export class MouseController implements IDisposable { private multipleSelectionSupport: boolean; readonly multipleSelectionController: IMultipleSelectionController; private openController: IOpenController; + private mouseSupport: boolean; private disposables: IDisposable[] = []; constructor(protected list: List) { @@ -518,15 +519,19 @@ export class MouseController implements IDisposable { } this.openController = list.options.openController || DefaultOpenController; + this.mouseSupport = typeof list.options.mouseSupport === 'undefined' || !!list.options.mouseSupport; + + if (this.mouseSupport) { + list.onMouseDown(this.onMouseDown, this, this.disposables); + list.onContextMenu(this.onContextMenu, this, this.disposables); + list.onMouseDblClick(this.onDoubleClick, this, this.disposables); + list.onTouchStart(this.onMouseDown, this, this.disposables); + Gesture.addTarget(list.getHTMLElement()); + } - list.onMouseDown(this.onMouseDown, this, this.disposables); - list.onContextMenu(this.onContextMenu, this, this.disposables); list.onMouseClick(this.onPointer, this, this.disposables); list.onMouseMiddleClick(this.onPointer, this, this.disposables); - list.onMouseDblClick(this.onDoubleClick, this, this.disposables); - list.onTouchStart(this.onMouseDown, this, this.disposables); list.onTap(this.onPointer, this, this.disposables); - Gesture.addTarget(list.getHTMLElement()); } protected isSelectionSingleChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean { @@ -561,6 +566,10 @@ export class MouseController implements IDisposable { } protected onPointer(e: IListMouseEvent): void { + if (!this.mouseSupport) { + return; + } + if (isInputElement(e.browserEvent.target as HTMLElement)) { return; } @@ -1069,11 +1078,6 @@ export class List implements ISpliceable, IDisposable { private spliceable: ISpliceable; private styleElement: HTMLStyleElement; private styleController: IStyleController; - private mouseController: MouseController | undefined; - - get multipleSelectionController(): IMultipleSelectionController { - return (this.mouseController && this.mouseController.multipleSelectionController) || DefaultMultipleSelectionContoller; - } private _onDidUpdateOptions = new Emitter>(); readonly onDidUpdateOptions = this._onDidUpdateOptions.event; @@ -1218,10 +1222,7 @@ export class List implements ISpliceable, IDisposable { this.disposables.push(controller); } - if (typeof _options.mouseSupport === 'boolean' ? _options.mouseSupport : true) { - this.mouseController = this.createMouseController(_options); - this.disposables.push(this.mouseController); - } + this.disposables.push(this.createMouseController(_options)); this.onFocusChange(this._onFocusChange, this, this.disposables); this.onSelectionChange(this._onSelectionChange, this, this.disposables); From 04271d109111b06b51653d3637db2c46dee57a95 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Fri, 8 Feb 2019 12:31:02 +0100 Subject: [PATCH 054/207] Add alternate dialog --- .../platform/contextkey/common/contextkeys.ts | 3 + src/vs/platform/label/common/label.ts | 2 +- .../fileActions.contribution.ts | 3 +- .../files/electron-browser/fileActions.ts | 5 +- .../electron-browser/shell.contribution.ts | 32 +- .../workbench/electron-browser/workbench.ts | 12 +- .../dialogs/electron-browser/dialogService.ts | 37 +- .../electron-browser/remoteFileDialog.ts | 319 ++++++++++++++++++ .../services/dialogs/media/dark/accept.svg | 1 + .../services/dialogs/media/dark/cancel.svg | 1 + .../services/dialogs/media/light/accept.svg | 1 + .../services/dialogs/media/light/cancel.svg | 1 + .../services/label/common/labelService.ts | 20 +- .../textfile/common/textFileService.ts | 9 +- 14 files changed, 415 insertions(+), 31 deletions(-) create mode 100644 src/vs/workbench/services/dialogs/electron-browser/remoteFileDialog.ts create mode 100644 src/vs/workbench/services/dialogs/media/dark/accept.svg create mode 100644 src/vs/workbench/services/dialogs/media/dark/cancel.svg create mode 100644 src/vs/workbench/services/dialogs/media/light/accept.svg create mode 100644 src/vs/workbench/services/dialogs/media/light/cancel.svg diff --git a/src/vs/platform/contextkey/common/contextkeys.ts b/src/vs/platform/contextkey/common/contextkeys.ts index 94b03a0ce93..6697e0d989b 100644 --- a/src/vs/platform/contextkey/common/contextkeys.ts +++ b/src/vs/platform/contextkey/common/contextkeys.ts @@ -11,3 +11,6 @@ export const InputFocusedContext = new RawContextKey(InputFocusedContex export const IsMacContext = new RawContextKey('isMac', isMacintosh); export const IsLinuxContext = new RawContextKey('isLinux', isLinux); export const IsWindowsContext = new RawContextKey('isWindows', isWindows); + +export const SupportsWorkspacesContext = new RawContextKey('supportsWorkspaces', true); +export const SupportsOpenFileFolderContext = new RawContextKey('supportsOpenFileFolder', isMacintosh); diff --git a/src/vs/platform/label/common/label.ts b/src/vs/platform/label/common/label.ts index 4bd34446d4f..87746ef28af 100644 --- a/src/vs/platform/label/common/label.ts +++ b/src/vs/platform/label/common/label.ts @@ -19,7 +19,7 @@ export interface ILabelService { * If relative is passed returns a label relative to the workspace root that the uri belongs to. * If noPrefix is passed does not tildify the label and also does not prepand the root name for relative labels in a multi root scenario. */ - getUriLabel(resource: URI, options?: { relative?: boolean, noPrefix?: boolean }): string; + getUriLabel(resource: URI, options?: { relative?: boolean, noPrefix?: boolean, endWithSeparator?: boolean }): string; getWorkspaceLabel(workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IWorkspace), options?: { verbose: boolean }): string; getHostLabel(): string; registerFormatter(formatter: ResourceLabelFormatter): IDisposable; diff --git a/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts index b601ff20556..1d6e6e45001 100644 --- a/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/electron-browser/fileActions.contribution.ts @@ -23,6 +23,7 @@ import { ResourceContextKey } from 'vs/workbench/common/resources'; import { WorkbenchListDoubleSelection } from 'vs/platform/list/browser/listService'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; +import { SupportsWorkspacesContext } from 'vs/platform/contextkey/common/contextkeys'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; // Contribute Global Actions @@ -478,7 +479,7 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { id: ADD_ROOT_FOLDER_COMMAND_ID, title: ADD_ROOT_FOLDER_LABEL }, - when: ContextKeyExpr.and(ExplorerRootContext) + when: ContextKeyExpr.and(ExplorerRootContext, SupportsWorkspacesContext) }); MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { diff --git a/src/vs/workbench/contrib/files/electron-browser/fileActions.ts b/src/vs/workbench/contrib/files/electron-browser/fileActions.ts index bd8c77fd5a0..1d61e4c585a 100644 --- a/src/vs/workbench/contrib/files/electron-browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/electron-browser/fileActions.ts @@ -46,6 +46,7 @@ import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; import { ExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; import { onUnexpectedError } from 'vs/base/common/errors'; import { sequence } from 'vs/base/common/async'; +import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; export const NEW_FILE_COMMAND_ID = 'explorer.newFile'; export const NEW_FILE_LABEL = nls.localize('newFile', "New File"); @@ -874,8 +875,8 @@ export class ShowOpenedFileInNewWindow extends Action { } public run(): Promise { - const fileResource = toResource(this.editorService.activeEditor, { supportSideBySide: true, filter: Schemas.file /* todo@remote */ }); - if (fileResource) { + const fileResource = toResource(this.editorService.activeEditor, { supportSideBySide: true }); + if (fileResource && (fileResource.scheme === Schemas.file || fileResource.scheme === REMOTE_HOST_SCHEME)) { this.windowService.openWindow([{ uri: fileResource, typeHint: 'file' }], { forceNewWindow: true, forceOpenWorkspaceAsFile: true }); } else { this.notificationService.info(nls.localize('openFileToShowInNewWindow', "Open a file first to open in new window")); diff --git a/src/vs/workbench/electron-browser/shell.contribution.ts b/src/vs/workbench/electron-browser/shell.contribution.ts index 511a3802324..d7445124b53 100644 --- a/src/vs/workbench/electron-browser/shell.contribution.ts +++ b/src/vs/workbench/electron-browser/shell.contribution.ts @@ -21,7 +21,7 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ADD_ROOT_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; -import { IsMacContext } from 'vs/platform/contextkey/common/contextkeys'; +import { SupportsOpenFileFolderContext, SupportsWorkspacesContext, IsMacContext } from 'vs/platform/contextkey/common/contextkeys'; import { NoEditorsVisibleContext, SingleEditorGroupsContext } from 'vs/workbench/common/editor'; import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; @@ -61,12 +61,9 @@ workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(Switch workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(QuickSwitchWindow, QuickSwitchWindow.ID, QuickSwitchWindow.LABEL), 'Quick Switch Window...'); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenRecentAction, QuickOpenRecentAction.ID, QuickOpenRecentAction.LABEL), 'File: Quick Open Recent...', fileCategory); -if (isMacintosh) { - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open...', fileCategory); -} else { - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', fileCategory); - workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'File: Open Folder...', fileCategory); -} +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open...', fileCategory, SupportsOpenFileFolderContext); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', fileCategory, SupportsOpenFileFolderContext.toNegated()); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'File: Open Folder...', fileCategory, SupportsOpenFileFolderContext.toNegated()); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'File: Close Workspace', fileCategory); @@ -115,10 +112,10 @@ workbenchActionsRegistry.registerWorkbenchAction( workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleFullScreenAction, ToggleFullScreenAction.ID, ToggleFullScreenAction.LABEL, { primary: KeyCode.F11, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_F } }), 'View: Toggle Full Screen', viewCategory); const workspacesCategory = nls.localize('workspaces', "Workspaces"); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL), 'Workspaces: Add Folder to Workspace...', workspacesCategory); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL), 'Workspaces: Add Folder to Workspace...', workspacesCategory, SupportsWorkspacesContext); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRemoveRootFolderAction, GlobalRemoveRootFolderAction.ID, GlobalRemoveRootFolderAction.LABEL), 'Workspaces: Remove Folder from Workspace...', workspacesCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceAction, OpenWorkspaceAction.ID, OpenWorkspaceAction.LABEL), 'Workspaces: Open Workspace...', workspacesCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SaveWorkspaceAsAction, SaveWorkspaceAsAction.ID, SaveWorkspaceAsAction.LABEL), 'Workspaces: Save Workspace As...', workspacesCategory); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceAction, OpenWorkspaceAction.ID, OpenWorkspaceAction.LABEL), 'Workspaces: Open Workspace...', workspacesCategory, SupportsWorkspacesContext); +workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SaveWorkspaceAsAction, SaveWorkspaceAsAction.ID, SaveWorkspaceAsAction.LABEL), 'Workspaces: Save Workspace As...', workspacesCategory, SupportsWorkspacesContext); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(DuplicateWorkspaceInNewWindowAction, DuplicateWorkspaceInNewWindowAction.ID, DuplicateWorkspaceInNewWindowAction.LABEL), 'Workspaces: Duplicate Workspace in New Window', workspacesCategory); CommandsRegistry.registerCommand(OpenWorkspaceConfigFileAction.ID, serviceAccessor => { @@ -178,7 +175,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { title: nls.localize({ key: 'miOpenFile', comment: ['&& denotes a mnemonic'] }, "&&Open File...") }, order: 1, - when: IsMacContext.toNegated() + when: SupportsOpenFileFolderContext.toNegated() }); MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { @@ -188,7 +185,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { title: nls.localize({ key: 'miOpenFolder', comment: ['&& denotes a mnemonic'] }, "Open &&Folder...") }, order: 2, - when: IsMacContext.toNegated() + when: SupportsOpenFileFolderContext.toNegated() }); MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { @@ -198,7 +195,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { title: nls.localize({ key: 'miOpen', comment: ['&& denotes a mnemonic'] }, "&&Open...") }, order: 1, - when: IsMacContext + when: SupportsOpenFileFolderContext }); MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { @@ -207,7 +204,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { id: OpenWorkspaceAction.ID, title: nls.localize({ key: 'miOpenWorkspace', comment: ['&& denotes a mnemonic'] }, "Open Wor&&kspace...") }, - order: 3 + order: 3, + when: SupportsWorkspacesContext }); MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { @@ -234,7 +232,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { id: ADD_ROOT_FOLDER_COMMAND_ID, title: nls.localize({ key: 'miAddFolderToWorkspace', comment: ['&& denotes a mnemonic'] }, "A&&dd Folder to Workspace...") }, - order: 1 + order: 1, + when: SupportsWorkspacesContext }); MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { @@ -243,7 +242,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { id: SaveWorkspaceAsAction.ID, title: nls.localize('miSaveWorkspaceAs', "Save Workspace As...") }, - order: 2 + order: 2, + when: SupportsWorkspacesContext }); MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index aa5a4e9ad36..3b279295ead 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -87,7 +87,7 @@ import { IDecorationsService } from 'vs/workbench/services/decorations/browser/d import { ActivityService } from 'vs/workbench/services/activity/browser/activityService'; import { URI } from 'vs/base/common/uri'; import { IListService, ListService } from 'vs/platform/list/browser/listService'; -import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext } from 'vs/platform/contextkey/common/contextkeys'; +import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, SupportsOpenFileFolderContext, SupportsWorkspacesContext } from 'vs/platform/contextkey/common/contextkeys'; import { IViewsService } from 'vs/workbench/common/views'; import { ViewsService } from 'vs/workbench/browser/parts/views/views'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -109,7 +109,7 @@ import { ContextViewService } from 'vs/platform/contextview/browser/contextViewS import { WorkbenchThemeService } from 'vs/workbench/services/themes/electron-browser/workbenchThemeService'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { FileDialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService'; +import { RemoteFileDialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService'; import { LogStorageAction } from 'vs/platform/storage/node/storageService'; import { Sizing, Direction, Grid, View } from 'vs/base/browser/ui/grid/grid'; import { IEditor } from 'vs/editor/common/editorCommon'; @@ -425,7 +425,7 @@ export class Workbench extends Disposable implements IPartService { serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService)); // File Dialogs - serviceCollection.set(IFileDialogService, new SyncDescriptor(FileDialogService)); + serviceCollection.set(IFileDialogService, new SyncDescriptor(RemoteFileDialogService)); // Backup File Service if (this.workbenchParams.configuration.backupPath) { @@ -627,6 +627,12 @@ export class Workbench extends Disposable implements IPartService { IsMacContext.bindTo(this.contextKeyService); IsLinuxContext.bindTo(this.contextKeyService); IsWindowsContext.bindTo(this.contextKeyService); + const supportsOpenFileFolderContextKey = SupportsOpenFileFolderContext.bindTo(this.contextKeyService); + const supportsWorkspacesContextKey = SupportsWorkspacesContext.bindTo(this.contextKeyService); + if (this.windowService.getConfiguration().remoteAuthority) { + supportsOpenFileFolderContextKey.set(true); + supportsWorkspacesContextKey.set(false); + } const sidebarVisibleContextRaw = new RawContextKey('sidebarVisible', false); this.sideBarVisibleContext = sidebarVisibleContextRaw.bindTo(this.contextKeyService); diff --git a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts index f34d75f6120..4e3c58dac66 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts @@ -15,9 +15,12 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/ import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { URI } from 'vs/base/common/uri'; +import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { Schemas } from 'vs/base/common/network'; import * as resources from 'vs/base/common/resources'; import { isParent } from 'vs/platform/files/common/files'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { RemoteFileDialog } from 'vs/workbench/services/dialogs/electron-browser/remoteFileDialog'; interface IMassagedMessageBoxOptions { @@ -160,7 +163,8 @@ export class FileDialogService implements IFileDialogService { @IWindowService private readonly windowService: IWindowService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IHistoryService private readonly historyService: IHistoryService, - @IEnvironmentService private readonly environmentService: IEnvironmentService + @IEnvironmentService private readonly environmentService: IEnvironmentService, + @IInstantiationService private readonly instantiationService: IInstantiationService, ) { } defaultFilePath(schemeFilter: string): URI | undefined { @@ -273,6 +277,11 @@ export class FileDialogService implements IFileDialogService { }); } + public showSaveRemoteDialog(options: ISaveDialogOptions): Promise { + const remoteFileDialog = this.instantiationService.createInstance(RemoteFileDialog); + return remoteFileDialog.showSaveDialog(options); + } + showOpenDialog(options: IOpenDialogOptions): Promise { const defaultUri = options.defaultUri; if (defaultUri && defaultUri.scheme !== Schemas.file) { @@ -303,6 +312,32 @@ export class FileDialogService implements IFileDialogService { return this.windowService.showOpenDialog(newOptions).then(result => result ? result.map(URI.file) : undefined); } + + public showOpenRemoteDialog(options: IOpenDialogOptions): Promise { + const remoteFileDialog = this.instantiationService.createInstance(RemoteFileDialog); + return remoteFileDialog.showOpenDialog(options); + } +} + +export class RemoteFileDialogService extends FileDialogService { + + constructor( + @IWindowService windowService: IWindowService, + @IWorkspaceContextService contextService: IWorkspaceContextService, + @IHistoryService historyService: IHistoryService, + @IEnvironmentService environmentService: IEnvironmentService, + @IInstantiationService instantiationService: IInstantiationService, + ) { + super(windowService, contextService, historyService, environmentService, instantiationService); + } + + public showSaveDialog(options: ISaveDialogOptions): Promise { + const defaultUri = options.defaultUri; + if (defaultUri && defaultUri.scheme === REMOTE_HOST_SCHEME) { + return this.showSaveRemoteDialog(options); + } + return super.showSaveDialog(options); + } } function isUntitledWorkspace(path: string, environmentService: IEnvironmentService): boolean { diff --git a/src/vs/workbench/services/dialogs/electron-browser/remoteFileDialog.ts b/src/vs/workbench/services/dialogs/electron-browser/remoteFileDialog.ts new file mode 100644 index 00000000000..bfd6b0d74e6 --- /dev/null +++ b/src/vs/workbench/services/dialogs/electron-browser/remoteFileDialog.ts @@ -0,0 +1,319 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import * as resources from 'vs/base/common/resources'; +import { RemoteFileService } from 'vs/workbench/services/files/electron-browser/remoteFileService'; +import { IFileService } from 'vs/platform/files/common/files'; +import { IQuickInputService, IQuickPickItem, IQuickPick } from 'vs/platform/quickinput/common/quickInput'; +import { URI } from 'vs/base/common/uri'; +import { isWindows } from 'vs/base/common/platform'; +import { ISaveDialogOptions, IOpenDialogOptions } from 'vs/platform/dialogs/common/dialogs'; +import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; +import { IWindowService } from 'vs/platform/windows/common/windows'; +import { ILabelService } from 'vs/platform/label/common/label'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { INotificationService } from 'vs/platform/notification/common/notification'; + +interface FileQuickPickItem extends IQuickPickItem { + uri: URI; + isFolder: boolean; +} + +// Reference: https://en.wikipedia.org/wiki/Filename +const INVALID_FILE_CHARS = isWindows ? /[\\/:\*\?"<>\|]/g : /[\\/]/g; +const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])$/i; + +export class RemoteFileDialog { + + private acceptButton = { iconPath: this.getIcons('accept.svg'), tooltip: 'Select' }; + private cancelButton = { iconPath: this.getIcons('cancel.svg'), tooltip: 'Cancel' }; + private currentFolder: URI; + private filePickBox: IQuickPick; + private allowFileSelection: boolean; + private allowFolderSelection: boolean; + private remoteAuthority: string; + + constructor( + @IFileService private readonly remoteFileService: RemoteFileService, + @IQuickInputService private readonly quickInputService: IQuickInputService, + @IWindowService private readonly windowService: IWindowService, + @ILabelService private readonly labelService: ILabelService, + @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, + @IEditorService private readonly editorService: IEditorService, + @INotificationService private readonly notificationService: INotificationService, + ) { + this.remoteAuthority = this.windowService.getConfiguration().remoteAuthority; + } + + public async showOpenDialog(options: IOpenDialogOptions = {}): Promise { + if (!this.remoteAuthority) { + this.notificationService.info(nls.localize('remoteFileDialog.notConnectedToRemote', 'Not connected to a remote.')); + return Promise.resolve(undefined); + } + const defaultUri = options.defaultUri ? options.defaultUri : URI.from({ scheme: REMOTE_HOST_SCHEME, authority: this.remoteAuthority, path: '/' }); + const title = nls.localize('remoteFileDialog.openTitle', 'Open File or Folder'); + return this.pickResource({ title, defaultUri, canSelectFiles: true, canSelectFolders: true }).then(async fileFolderUri => { + if (fileFolderUri) { + const stat = await this.remoteFileService.resolveFile(fileFolderUri); + if (stat.isDirectory) { + return this.windowService.openWindow([{ uri: fileFolderUri, typeHint: 'folder' }]); + } else { + return this.editorService.openEditor({ resource: fileFolderUri }).then(() => { + return Promise.resolve(undefined); + }); + } + } + return Promise.resolve(undefined); + }); + } + + public showSaveDialog(options: ISaveDialogOptions): Promise { + if (!this.remoteAuthority) { + this.notificationService.info(nls.localize('remoteFileDialog.notConnectedToRemote', 'Not connected to a remote.')); + return Promise.resolve(undefined); + } + const defaultUri = options.defaultUri ? options.defaultUri : URI.from({ scheme: REMOTE_HOST_SCHEME, authority: this.remoteAuthority, path: '/' }); + return new Promise((resolve) => { + let saveNameBox = this.quickInputService.createInputBox(); + saveNameBox.title = options.title; + saveNameBox.placeholder = nls.localize('remoteFileDialog.saveTitle', 'Enter the new name of the file'); + saveNameBox.value = ''; + saveNameBox.totalSteps = 2; + saveNameBox.step = 1; + saveNameBox.onDidChangeValue(v => { + saveNameBox.validationMessage = this.isValidBaseName(v) ? void 0 : nls.localize('remoteFileDialog.error.invalidfilename', 'Not a valid file name'); + }); + saveNameBox.onDidAccept(_ => { + const name = saveNameBox.value; + if (this.isValidBaseName(name)) { + saveNameBox.hide(); + this.pickResource({ defaultUri: defaultUri, canSelectFolders: true, title: nls.localize('remoteFileDialogerror.titleFolderPage', 'Folder for \'{0}\'', name) }, { step: 2, totalSteps: 2 }).then(folderUri => { + if (folderUri) { + resolve(this.remoteUriFrom(this.remotePathJoin(folderUri, name))); + } else { + resolve(undefined); + } + saveNameBox.dispose(); + }); + } + }); + saveNameBox.show(); + }); + } + + private remoteUriFrom(path: string): URI { + return URI.from({ scheme: REMOTE_HOST_SCHEME, authority: this.remoteAuthority, path }); + } + + private remotePathJoin(firstPart: URI, secondPart: string): string { + return this.labelService.getUriLabel(resources.joinPath(firstPart, secondPart)); + } + + private async pickResource(options: IOpenDialogOptions, multiOpts?: { step: number; totalSteps: number; }): Promise { + this.allowFolderSelection = !!options.canSelectFolders; + this.allowFileSelection = !!options.canSelectFiles; + const defaultUri = options.defaultUri; + let homedir = defaultUri && defaultUri.scheme === REMOTE_HOST_SCHEME ? defaultUri : this.workspaceContextService.getWorkspace().folders[0].uri; + + return new Promise((resolve) => { + this.filePickBox = this.quickInputService.createQuickPick(); + if (multiOpts) { + this.filePickBox.totalSteps = multiOpts.totalSteps; + this.filePickBox.step = multiOpts.step; + } + + let isResolved = false; + let isAcceptHandled = false; + + this.currentFolder = homedir; + this.filePickBox.buttons = [this.acceptButton, this.cancelButton]; + this.filePickBox.onDidTriggerButton(button => { + if (button === this.acceptButton) { + resolve(this.currentFolder); + isResolved = true; + } + this.filePickBox.hide(); + }); + this.filePickBox.title = options.title; + this.filePickBox.placeholder = this.labelService.getUriLabel(this.currentFolder, { endWithSeparator: true }); + this.filePickBox.items = []; + this.filePickBox.onDidAccept(_ => { + if (isAcceptHandled || this.filePickBox.busy) { + return; + } + isAcceptHandled = true; + if (this.filePickBox.activeItems.length === 0) { + if (this.allowFolderSelection) { + resolve(this.currentFolder); + isResolved = true; + this.filePickBox.hide(); + } + } else if (this.filePickBox.activeItems.length === 1) { + const item = this.filePickBox.selectedItems[0]; + if (item) { + if (!item.isFolder) { + resolve(item.uri); + isResolved = true; + this.filePickBox.hide(); + } else { + this.updateItems(item.uri); + } + } + } + }); + this.filePickBox.onDidChangeActive(i => { + isAcceptHandled = false; + }); + + let to: NodeJS.Timer | undefined; + this.filePickBox.onDidChangeValue(value => { + if (to) { + clearTimeout(to); + } + if (this.endsWithSlash(value)) { + to = undefined; + this.onValueChange(); + } else { + to = setTimeout(this.onValueChange, 300); + } + }); + this.filePickBox.onDidHide(() => { + if (!isResolved) { + resolve(undefined); + } + this.filePickBox.dispose(); + }); + + this.filePickBox.show(); + this.updateItems(homedir); + }); + } + + private async onValueChange() { + if (this.filePickBox) { + let fullPath = this.remoteUriFrom(this.filePickBox.value); + let stat = await this.remoteFileService.resolveFile(fullPath); + if (!stat.isDirectory && this.allowFileSelection) { + this.updateItems(resources.dirname(fullPath)); + this.filePickBox.value = resources.basename(fullPath); + } else if (stat.isDirectory) { + this.updateItems(fullPath); + } + } + } + + private updateItems(newFolder: URI) { + this.currentFolder = newFolder; + this.filePickBox.placeholder = this.labelService.getUriLabel(newFolder, { endWithSeparator: true }); + this.filePickBox.value = ''; + this.filePickBox.busy = true; + this.createItems(this.currentFolder).then(items => { + this.filePickBox.items = items; + if (this.allowFolderSelection) { + this.filePickBox.activeItems = []; + } + this.filePickBox.busy = false; + }); + } + + private isValidBaseName(name: string): boolean { + if (!name || name.length === 0 || /^\s+$/.test(name)) { + return false; // require a name that is not just whitespace + } + + INVALID_FILE_CHARS.lastIndex = 0; // the holy grail of software development + if (INVALID_FILE_CHARS.test(name)) { + return false; // check for certain invalid file characters + } + + if (isWindows && WINDOWS_FORBIDDEN_NAMES.test(name)) { + return false; // check for certain invalid file names + } + + if (name === '.' || name === '..') { + return false; // check for reserved values + } + + if (isWindows && name[name.length - 1] === '.') { + return false; // Windows: file cannot end with a "." + } + + if (isWindows && name.length !== name.trim().length) { + return false; // Windows: file cannot end with a whitespace + } + + return true; + } + + private endsWithSlash(s: string) { + return /[\/\\]$/.test(s); + } + + private basenameWithTrailingSlash(fullPath: URI): string { + const child = this.labelService.getUriLabel(fullPath, { endWithSeparator: true }); + const parent = this.labelService.getUriLabel(resources.dirname(fullPath), { endWithSeparator: true }); + return child.substring(parent.length); + } + + private createBackItem(currFolder: URI): FileQuickPickItem | null { + const parentFolder = resources.dirname(currFolder); + if (!resources.isEqual(currFolder, parentFolder)) { + return { label: '..', uri: resources.dirname(currFolder), isFolder: true }; + } + return null; + } + + private async createItems(currentFolder: URI): Promise { + const result: FileQuickPickItem[] = []; + + const backDir = this.createBackItem(currentFolder); + if (backDir) { + result.push(backDir); + } + try { + const fileNames = await this.remoteFileService.readFolder(currentFolder); + const items = await Promise.all(fileNames.map(fileName => this.createItem(fileName, currentFolder))); + for (let item of items) { + if (item) { + result.push(item); + } + } + } catch (e) { + // ignore + console.log(e); + } + return result.sort((i1, i2) => { + if (i1.isFolder !== i2.isFolder) { + return i1.isFolder ? -1 : 1; + } + return i1.label.localeCompare(i2.label); + }); + } + + private async createItem(filename: string, parent: URI): Promise { + let fullPath = resources.joinPath(parent, filename); + try { + const stat = await this.remoteFileService.resolveFile(fullPath); + if (stat.isDirectory) { + filename = this.basenameWithTrailingSlash(fullPath); + return { label: filename, uri: fullPath, isFolder: true }; + } else if (!stat.isDirectory && this.allowFileSelection) { + return { label: filename, uri: fullPath, isFolder: false }; + } + return null; + } catch (e) { + return null; + } + } + + private getIcons(name: string): { light: URI, dark: URI } { + return { + light: URI.parse(require.toUrl(`vs/workbench/services/dialogs/media/light/${name}`)), + dark: URI.parse(require.toUrl(`vs/workbench/services/dialogs/media/dark/${name}`)) + }; + } +} \ No newline at end of file diff --git a/src/vs/workbench/services/dialogs/media/dark/accept.svg b/src/vs/workbench/services/dialogs/media/dark/accept.svg new file mode 100644 index 00000000000..c225b2f597f --- /dev/null +++ b/src/vs/workbench/services/dialogs/media/dark/accept.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/services/dialogs/media/dark/cancel.svg b/src/vs/workbench/services/dialogs/media/dark/cancel.svg new file mode 100644 index 00000000000..751e89b3b02 --- /dev/null +++ b/src/vs/workbench/services/dialogs/media/dark/cancel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/services/dialogs/media/light/accept.svg b/src/vs/workbench/services/dialogs/media/light/accept.svg new file mode 100644 index 00000000000..d45df06edf8 --- /dev/null +++ b/src/vs/workbench/services/dialogs/media/light/accept.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/services/dialogs/media/light/cancel.svg b/src/vs/workbench/services/dialogs/media/light/cancel.svg new file mode 100644 index 00000000000..fde34404d4e --- /dev/null +++ b/src/vs/workbench/services/dialogs/media/light/cancel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/services/label/common/labelService.ts b/src/vs/workbench/services/label/common/labelService.ts index d92d21679ac..5cabc34cee5 100644 --- a/src/vs/workbench/services/label/common/labelService.ts +++ b/src/vs/workbench/services/label/common/labelService.ts @@ -14,7 +14,7 @@ import { IWorkspaceContextService, IWorkspace } from 'vs/platform/workspace/comm import { isEqual, basenameOrAuthority, isEqualOrParent, basename, joinPath, dirname } from 'vs/base/common/resources'; import { isLinux, isWindows } from 'vs/base/common/platform'; import { tildify, getPathLabel } from 'vs/base/common/labels'; -import { ltrim } from 'vs/base/common/strings'; +import { ltrim, endsWith } from 'vs/base/common/strings'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, WORKSPACE_EXTENSION, toWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { Schemas } from 'vs/base/common/network'; import { IWindowService } from 'vs/platform/windows/common/windows'; @@ -130,12 +130,14 @@ export class LabelService implements ILabelService { return bestResult ? bestResult.formatting : undefined; } - getUriLabel(resource: URI, options: { relative?: boolean, noPrefix?: boolean } = {}): string { + getUriLabel(resource: URI, options: { relative?: boolean, noPrefix?: boolean, endWithSeparator?: boolean } = {}): string { const formatting = this.findFormatting(resource); if (!formatting) { return getPathLabel(resource.path, this.environmentService, options.relative ? this.contextService : undefined); } + let label: string; + if (options.relative) { const baseResource = this.contextService && this.contextService.getWorkspaceFolder(resource); if (baseResource) { @@ -153,11 +155,13 @@ export class LabelService implements ILabelService { relativeLabel = relativeLabel ? (rootName + ' • ' + relativeLabel) : rootName; // always show root basename if there are multiple } - return relativeLabel; + label = relativeLabel; } + } else { + label = this.formatUri(resource, formatting, options.noPrefix); } - return this.formatUri(resource, formatting, options.noPrefix); + return options.endWithSeparator ? this.appendSeparatorIfMissing(label, formatting) : label; } getWorkspaceLabel(workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IWorkspace), options?: { verbose: boolean }): string { @@ -247,4 +251,12 @@ export class LabelService implements ILabelService { return label.replace(sepRegexp, formatting.separator); } + + private appendSeparatorIfMissing(label: string, formatting: ResourceLabelFormatting): string { + let appendedLabel = label; + if (!endsWith(label, formatting.separator)) { + appendedLabel += formatting.separator; + } + return appendedLabel; + } } diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index 1b8e23675a7..2a85b26c188 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -32,6 +32,7 @@ import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/text import { IModelService } from 'vs/editor/common/services/modelService'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { isEqualOrParent, isEqual, joinPath, dirname } from 'vs/base/common/resources'; +import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; export interface IBackupResult { didBackup: boolean; @@ -434,7 +435,8 @@ export abstract class TextFileService extends Disposable implements ITextFileSer // Untitled with associated file path don't need to prompt if (this.untitledEditorService.hasAssociatedFilePath(untitled)) { - targetUri = untitled.with({ scheme: Schemas.file }); + const authority = this.windowService.getConfiguration().remoteAuthority; + targetUri = authority ? untitled.with({ scheme: REMOTE_HOST_SCHEME, authority }) : untitled.with({ scheme: Schemas.file }); } // Otherwise ask user @@ -616,7 +618,8 @@ export abstract class TextFileService extends Disposable implements ITextFileSer private suggestFileName(untitledResource: URI): URI { const untitledFileName = this.untitledEditorService.suggestFileName(untitledResource); - const schemeFilter = Schemas.file; + const remoteAuthority = this.windowService.getConfiguration().remoteAuthority; + const schemeFilter = remoteAuthority ? REMOTE_HOST_SCHEME : Schemas.file; const lastActiveFile = this.historyService.getLastActiveFile(schemeFilter); if (lastActiveFile) { @@ -629,7 +632,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer return joinPath(lastActiveFolder, untitledFileName); } - return URI.file(untitledFileName); + return schemeFilter === Schemas.file ? URI.file(untitledFileName) : URI.from({ scheme: schemeFilter, authority: remoteAuthority, path: untitledFileName }); } revert(resource: URI, options?: IRevertOptions): Promise { From b95e51b7979841c992da64ffa7738025f8180695 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 8 Feb 2019 12:32:30 +0100 Subject: [PATCH 055/207] tree: disable list aria roles related to #67156 --- src/vs/base/browser/ui/list/listView.ts | 15 ++++++++++++--- src/vs/base/browser/ui/list/listWidget.ts | 1 + src/vs/base/browser/ui/tree/abstractTree.ts | 3 ++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index 7cf3f8ec9b3..7b60e1ab46b 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -49,6 +49,7 @@ export interface IListViewOptions { readonly supportDynamicHeights?: boolean; readonly mouseSupport?: boolean; readonly horizontalScrolling?: boolean; + readonly disableAriaRoles?: boolean; } const DefaultOptions = { @@ -63,7 +64,8 @@ const DefaultOptions = { onDragOver() { return false; }, drop() { } }, - horizontalScrolling: false + horizontalScrolling: false, + disableAriaRoles: false }; export class ElementsDragAndDropData implements IDragAndDropData { @@ -165,6 +167,7 @@ export class ListView implements ISpliceable, IDisposable { private setRowLineHeight: boolean; private supportDynamicHeights: boolean; private horizontalScrolling: boolean; + private disableAriaRoles: boolean; private scrollWidth: number | undefined; private canUseTranslate3d: boolean | undefined = undefined; @@ -221,6 +224,8 @@ export class ListView implements ISpliceable, IDisposable { this.horizontalScrolling = getOrDefault(options, o => o.horizontalScrolling, DefaultOptions.horizontalScrolling); DOM.toggleClass(this.domNode, 'horizontal-scrolling', this.horizontalScrolling); + this.disableAriaRoles = getOrDefault(options, o => o.disableAriaRoles, DefaultOptions.disableAriaRoles); + this.rowsContainer = document.createElement('div'); this.rowsContainer.className = 'monaco-list-rows'; Gesture.addTarget(this.rowsContainer); @@ -595,8 +600,12 @@ export class ListView implements ISpliceable, IDisposable { item.row!.domNode!.setAttribute('data-index', `${index}`); item.row!.domNode!.setAttribute('data-last-element', index === this.length - 1 ? 'true' : 'false'); - item.row!.domNode!.setAttribute('aria-setsize', `${this.length}`); - item.row!.domNode!.setAttribute('aria-posinset', `${index + 1}`); + + if (!this.disableAriaRoles) { + item.row!.domNode!.setAttribute('aria-setsize', `${this.length}`); + item.row!.domNode!.setAttribute('aria-posinset', `${index + 1}`); + } + DOM.toggleClass(item.row!.domNode!, 'drop-target', item.dropTarget); } diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 87f3b6b1ede..fe2471d11d1 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -818,6 +818,7 @@ export interface IListOptions extends IListStyles { readonly supportDynamicHeights?: boolean; readonly mouseSupport?: boolean; readonly horizontalScrolling?: boolean; + readonly disableAriaRoles?: boolean; } export interface IListStyles { diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 711ae180384..745aa45ba9f 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -150,7 +150,8 @@ function asListOptions(modelProvider: () => ITreeModel Date: Fri, 8 Feb 2019 12:46:27 +0100 Subject: [PATCH 056/207] "fix" types#constraint check --- src/vs/base/common/types.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vs/base/common/types.ts b/src/vs/base/common/types.ts index bddf6b764f2..ad873be97b1 100644 --- a/src/vs/base/common/types.ts +++ b/src/vs/base/common/types.ts @@ -143,8 +143,12 @@ export function validateConstraint(arg: any, constraint: TypeConstraint | undefi throw new Error(`argument does not match constraint: typeof ${constraint}`); } } else if (isFunction(constraint)) { - if (arg instanceof constraint) { - return; + try { + if (arg instanceof constraint) { + return; + } + } catch{ + // ignore } if (!isUndefinedOrNull(arg) && arg.constructor === constraint) { return; From 92eedf890c66994783e785b00321189d70e55228 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 8 Feb 2019 12:58:42 +0100 Subject: [PATCH 057/207] open workspace button in every window --- src/vs/workbench/browser/parts/editor/editorWidgets.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/editor/editorWidgets.ts b/src/vs/workbench/browser/parts/editor/editorWidgets.ts index 781748071a8..dfa93b7c447 100644 --- a/src/vs/workbench/browser/parts/editor/editorWidgets.ts +++ b/src/vs/workbench/browser/parts/editor/editorWidgets.ts @@ -138,7 +138,7 @@ export class OpenWorkspaceButtonContribution extends Disposable implements IEdit return false; // we need a model } - if (model.uri.scheme !== Schemas.file || hasWorkspaceFileExtension(model.uri.fsPath)) { + if (model.uri.scheme !== Schemas.file || !hasWorkspaceFileExtension(model.uri.fsPath)) { return false; // we need a local workspace file } From d5e86e798fc7136bc808cdc23866621a3c4b7f80 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 8 Feb 2019 13:56:33 +0100 Subject: [PATCH 058/207] Fix #62127 --- .../workbench/contrib/markers/electron-browser/markersPanel.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/markers/electron-browser/markersPanel.ts b/src/vs/workbench/contrib/markers/electron-browser/markersPanel.ts index f05d660102b..b3d35c26455 100644 --- a/src/vs/workbench/contrib/markers/electron-browser/markersPanel.ts +++ b/src/vs/workbench/contrib/markers/electron-browser/markersPanel.ts @@ -336,7 +336,8 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { filter: this.filter, accessibilityProvider, identityProvider, - dnd: new ResourceDragAndDrop(this.instantiationService) + dnd: new ResourceDragAndDrop(this.instantiationService), + expandOnlyOnTwistieClick: (e: TreeElement) => e instanceof Marker && e.relatedInformation.length > 0 } ) as any as WorkbenchObjectTree; From 641adcca86fef8bbb6b050bddbcd0f4ce329b374 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Fri, 8 Feb 2019 13:56:05 +0100 Subject: [PATCH 059/207] Fix strict null from dialog change --- .../dialogs/electron-browser/dialogService.ts | 2 +- .../electron-browser/remoteFileDialog.ts | 42 ++++++++++--------- .../electron-browser/remoteFileService.ts | 2 +- .../services/label/common/labelService.ts | 36 ++++++++-------- 4 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts index 4e3c58dac66..4b80e39c48a 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts @@ -331,7 +331,7 @@ export class RemoteFileDialogService extends FileDialogService { super(windowService, contextService, historyService, environmentService, instantiationService); } - public showSaveDialog(options: ISaveDialogOptions): Promise { + public showSaveDialog(options: ISaveDialogOptions): Promise { const defaultUri = options.defaultUri; if (defaultUri && defaultUri.scheme === REMOTE_HOST_SCHEME) { return this.showSaveRemoteDialog(options); diff --git a/src/vs/workbench/services/dialogs/electron-browser/remoteFileDialog.ts b/src/vs/workbench/services/dialogs/electron-browser/remoteFileDialog.ts index bfd6b0d74e6..cb03268fdc2 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/remoteFileDialog.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/remoteFileDialog.ts @@ -35,7 +35,7 @@ export class RemoteFileDialog { private filePickBox: IQuickPick; private allowFileSelection: boolean; private allowFolderSelection: boolean; - private remoteAuthority: string; + private remoteAuthority: string | undefined; constructor( @IFileService private readonly remoteFileService: RemoteFileService, @@ -49,10 +49,10 @@ export class RemoteFileDialog { this.remoteAuthority = this.windowService.getConfiguration().remoteAuthority; } - public async showOpenDialog(options: IOpenDialogOptions = {}): Promise { + public async showOpenDialog(options: IOpenDialogOptions = {}): Promise { if (!this.remoteAuthority) { this.notificationService.info(nls.localize('remoteFileDialog.notConnectedToRemote', 'Not connected to a remote.')); - return Promise.resolve(undefined); + return Promise.resolve(); } const defaultUri = options.defaultUri ? options.defaultUri : URI.from({ scheme: REMOTE_HOST_SCHEME, authority: this.remoteAuthority, path: '/' }); const title = nls.localize('remoteFileDialog.openTitle', 'Open File or Folder'); @@ -63,11 +63,11 @@ export class RemoteFileDialog { return this.windowService.openWindow([{ uri: fileFolderUri, typeHint: 'folder' }]); } else { return this.editorService.openEditor({ resource: fileFolderUri }).then(() => { - return Promise.resolve(undefined); + return Promise.resolve(); }); } } - return Promise.resolve(undefined); + return Promise.resolve(); }); } @@ -206,18 +206,20 @@ export class RemoteFileDialog { } } - private updateItems(newFolder: URI) { - this.currentFolder = newFolder; - this.filePickBox.placeholder = this.labelService.getUriLabel(newFolder, { endWithSeparator: true }); - this.filePickBox.value = ''; - this.filePickBox.busy = true; - this.createItems(this.currentFolder).then(items => { - this.filePickBox.items = items; - if (this.allowFolderSelection) { - this.filePickBox.activeItems = []; - } - this.filePickBox.busy = false; - }); + private updateItems(newFolder: URI | null) { + if (newFolder) { + this.currentFolder = newFolder; + this.filePickBox.placeholder = this.labelService.getUriLabel(newFolder, { endWithSeparator: true }); + this.filePickBox.value = ''; + this.filePickBox.busy = true; + this.createItems(this.currentFolder).then(items => { + this.filePickBox.items = items; + if (this.allowFolderSelection) { + this.filePickBox.activeItems = []; + } + this.filePickBox.busy = false; + }); + } } private isValidBaseName(name: string): boolean { @@ -255,14 +257,14 @@ export class RemoteFileDialog { private basenameWithTrailingSlash(fullPath: URI): string { const child = this.labelService.getUriLabel(fullPath, { endWithSeparator: true }); - const parent = this.labelService.getUriLabel(resources.dirname(fullPath), { endWithSeparator: true }); + const parent = this.labelService.getUriLabel(resources.dirname(fullPath)!, { endWithSeparator: true }); return child.substring(parent.length); } private createBackItem(currFolder: URI): FileQuickPickItem | null { - const parentFolder = resources.dirname(currFolder); + const parentFolder = resources.dirname(currFolder)!; if (!resources.isEqual(currFolder, parentFolder)) { - return { label: '..', uri: resources.dirname(currFolder), isFolder: true }; + return { label: '..', uri: resources.dirname(currFolder)!, isFolder: true }; } return null; } diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index 784c2f3880e..e73018103bc 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -213,7 +213,7 @@ export class RemoteFileService extends FileService { return resource.scheme === Schemas.file || this._provider.has(resource.scheme); } - private _tryParseFileOperationResult(err: any): FileOperationResult { + private _tryParseFileOperationResult(err: any): FileOperationResult | undefined { if (!(err instanceof Error)) { return undefined; } diff --git a/src/vs/workbench/services/label/common/labelService.ts b/src/vs/workbench/services/label/common/labelService.ts index 5cabc34cee5..51e39703916 100644 --- a/src/vs/workbench/services/label/common/labelService.ts +++ b/src/vs/workbench/services/label/common/labelService.ts @@ -136,27 +136,25 @@ export class LabelService implements ILabelService { return getPathLabel(resource.path, this.environmentService, options.relative ? this.contextService : undefined); } - let label: string; + let label: string | undefined; + const baseResource = this.contextService && this.contextService.getWorkspaceFolder(resource); - if (options.relative) { - const baseResource = this.contextService && this.contextService.getWorkspaceFolder(resource); - if (baseResource) { - let relativeLabel: string; - if (isEqual(baseResource.uri, resource, !isLinux)) { - relativeLabel = ''; // no label if resources are identical - } else { - const baseResourceLabel = this.formatUri(baseResource.uri, formatting, options.noPrefix); - relativeLabel = ltrim(this.formatUri(resource, formatting, options.noPrefix).substring(baseResourceLabel.length), formatting.separator); - } - - const hasMultipleRoots = this.contextService.getWorkspace().folders.length > 1; - if (hasMultipleRoots && !options.noPrefix) { - const rootName = (baseResource && baseResource.name) ? baseResource.name : basenameOrAuthority(baseResource.uri); - relativeLabel = relativeLabel ? (rootName + ' • ' + relativeLabel) : rootName; // always show root basename if there are multiple - } - - label = relativeLabel; + if (options.relative && baseResource) { + let relativeLabel: string; + if (isEqual(baseResource.uri, resource, !isLinux)) { + relativeLabel = ''; // no label if resources are identical + } else { + const baseResourceLabel = this.formatUri(baseResource.uri, formatting, options.noPrefix); + relativeLabel = ltrim(this.formatUri(resource, formatting, options.noPrefix).substring(baseResourceLabel.length), formatting.separator); } + + const hasMultipleRoots = this.contextService.getWorkspace().folders.length > 1; + if (hasMultipleRoots && !options.noPrefix) { + const rootName = (baseResource && baseResource.name) ? baseResource.name : basenameOrAuthority(baseResource.uri); + relativeLabel = relativeLabel ? (rootName + ' • ' + relativeLabel) : rootName; // always show root basename if there are multiple + } + + label = relativeLabel; } else { label = this.formatUri(resource, formatting, options.noPrefix); } From aa7439e3046c5737df33caf20a2d020e831cb92c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 8 Feb 2019 14:43:19 +0100 Subject: [PATCH 060/207] update distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ef3bb7814f7..908f250e6be 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.32.0", - "distro": "310c6547347fcd3b799dc67e048b7e010339211f", + "distro": "7b752ca3a77088fd367b62bfcce2e437c99030b7", "author": { "name": "Microsoft Corporation" }, From 9f7bd1ba681600fc33f6971955a022aaee245fc8 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Fri, 8 Feb 2019 15:05:07 +0100 Subject: [PATCH 061/207] Remove dialogService.ts from strict null since it now depends on non strict null checked files --- src/tsconfig.strictNullChecks.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 3c37bfd9269..a7d6fde6f4f 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -678,7 +678,6 @@ "./vs/workbench/services/decorations/browser/decorations.ts", "./vs/workbench/services/decorations/browser/decorationsService.ts", "./vs/workbench/services/decorations/test/browser/decorationsService.test.ts", - "./vs/workbench/services/dialogs/electron-browser/dialogService.ts", "./vs/workbench/services/editor/browser/codeEditorService.ts", "./vs/workbench/services/editor/common/editorGroupsService.ts", "./vs/workbench/services/editor/common/editorService.ts", From 815063890bd4b9b901215a78cafb8d59942bcb44 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 8 Feb 2019 15:20:00 +0100 Subject: [PATCH 062/207] fix monaco build --- build/lib/standalone.js | 6 ++---- build/lib/standalone.ts | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/build/lib/standalone.js b/build/lib/standalone.js index cf921e7401c..63e16442d53 100644 --- a/build/lib/standalone.js +++ b/build/lib/standalone.js @@ -27,7 +27,7 @@ function writeFile(filePath, contents) { fs.writeFileSync(filePath, contents); } function extractEditor(options) { - const tsConfig = JSON.parse(fs.readFileSync(path.join(options.sourcesRoot, 'tsconfig.json')).toString()); + const tsConfig = JSON.parse(fs.readFileSync(path.join(options.sourcesRoot, 'tsconfig.monaco.json')).toString()); let compilerOptions; if (tsConfig.extends) { compilerOptions = Object.assign({}, require(path.join(options.sourcesRoot, tsConfig.extends)).compilerOptions, tsConfig.compilerOptions); @@ -36,13 +36,11 @@ function extractEditor(options) { compilerOptions = tsConfig.compilerOptions; } tsConfig.compilerOptions = compilerOptions; + compilerOptions.noEmit = false; compilerOptions.noUnusedLocals = false; compilerOptions.preserveConstEnums = false; compilerOptions.declaration = false; compilerOptions.moduleResolution = ts.ModuleResolutionKind.Classic; - delete compilerOptions.types; - delete tsConfig.extends; - tsConfig.exclude = []; options.compilerOptions = compilerOptions; let result = tss.shake(options); for (let fileName in result) { diff --git a/build/lib/standalone.ts b/build/lib/standalone.ts index b7b0fee295f..dfd3c99fe91 100644 --- a/build/lib/standalone.ts +++ b/build/lib/standalone.ts @@ -31,7 +31,7 @@ function writeFile(filePath: string, contents: Buffer | string): void { } export function extractEditor(options: tss.ITreeShakingOptions & { destRoot: string }): void { - const tsConfig = JSON.parse(fs.readFileSync(path.join(options.sourcesRoot, 'tsconfig.json')).toString()); + const tsConfig = JSON.parse(fs.readFileSync(path.join(options.sourcesRoot, 'tsconfig.monaco.json')).toString()); let compilerOptions: { [key: string]: any }; if (tsConfig.extends) { compilerOptions = Object.assign({}, require(path.join(options.sourcesRoot, tsConfig.extends)).compilerOptions, tsConfig.compilerOptions); @@ -40,14 +40,12 @@ export function extractEditor(options: tss.ITreeShakingOptions & { destRoot: str } tsConfig.compilerOptions = compilerOptions; + compilerOptions.noEmit = false; compilerOptions.noUnusedLocals = false; compilerOptions.preserveConstEnums = false; compilerOptions.declaration = false; compilerOptions.moduleResolution = ts.ModuleResolutionKind.Classic; - delete compilerOptions.types; - delete tsConfig.extends; - tsConfig.exclude = []; options.compilerOptions = compilerOptions; From 51305a66472d3e6cbe0355d4e631fda32cc1a934 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 8 Feb 2019 12:47:46 +0100 Subject: [PATCH 063/207] Remove syncExtensions from ResolvedAuthority --- build/lib/i18n.resources.json | 4 ++++ src/vs/code/electron-main/app.ts | 2 +- .../remote/common/remoteAuthorityResolver.ts | 1 - src/vs/workbench/electron-browser/shell.ts | 2 +- .../node/multiExtensionManagement.ts | 18 ++++++++++-------- .../extensionHostProcessManager.ts | 3 +-- .../node/remoteAgentEnvironmentChannel.ts | 4 +++- .../services/remote/node/remoteAgentService.ts | 1 + 8 files changed, 21 insertions(+), 14 deletions(-) rename src/vs/{platform => workbench/services}/extensionManagement/node/multiExtensionManagement.ts (94%) diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index b395008f581..6193ef287a3 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -202,6 +202,10 @@ "name": "vs/workbench/services/extensions", "project": "vscode-workbench" }, + { + "name": "vs/workbench/services/extensionManagement", + "project": "vscode-workbench" + }, { "name": "vs/workbench/services/files", "project": "vscode-workbench" diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 2fe419d5fd7..02729fd6138 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -720,7 +720,7 @@ export class CodeApplication extends Disposable { } else { const [host, strPort] = authority.split(':'); const port = parseInt(strPort, 10); - return { authority, host, port, syncExtensions: false }; + return { authority, host, port }; } }; diff --git a/src/vs/platform/remote/common/remoteAuthorityResolver.ts b/src/vs/platform/remote/common/remoteAuthorityResolver.ts index 9b87bb77a80..e507dd1c165 100644 --- a/src/vs/platform/remote/common/remoteAuthorityResolver.ts +++ b/src/vs/platform/remote/common/remoteAuthorityResolver.ts @@ -11,7 +11,6 @@ export interface ResolvedAuthority { readonly authority: string; readonly host: string; readonly port: number; - readonly syncExtensions: boolean; readonly debugListenPort?: number; readonly debugConnectPort?: number; } diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 402ebb1e9b6..30a43711c8b 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -98,7 +98,7 @@ import { IDownloadService } from 'vs/platform/download/common/download'; import { DownloadService } from 'vs/platform/download/node/downloadService'; import { DownloadServiceChannel } from 'vs/platform/download/node/downloadIpc'; import { TextResourcePropertiesService } from 'vs/workbench/services/textfile/electron-browser/textResourcePropertiesService'; -import { MultiExtensionManagementService } from 'vs/platform/extensionManagement/node/multiExtensionManagement'; +import { MultiExtensionManagementService } from 'vs/workbench/services/extensionManagement/node/multiExtensionManagement'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-browser/remoteAuthorityResolverService'; import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService'; diff --git a/src/vs/platform/extensionManagement/node/multiExtensionManagement.ts b/src/vs/workbench/services/extensionManagement/node/multiExtensionManagement.ts similarity index 94% rename from src/vs/platform/extensionManagement/node/multiExtensionManagement.ts rename to src/vs/workbench/services/extensionManagement/node/multiExtensionManagement.ts index f5764c324d9..8545d95f5a8 100644 --- a/src/vs/platform/extensionManagement/node/multiExtensionManagement.ts +++ b/src/vs/workbench/services/extensionManagement/node/multiExtensionManagement.ts @@ -14,7 +14,7 @@ import { URI } from 'vs/base/common/uri'; import { Disposable } from 'vs/base/common/lifecycle'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { IRemoteAuthorityResolverService, ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/node/remoteAgentService'; import { getManifest } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; import { ILogService } from 'vs/platform/log/common/log'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; @@ -36,7 +36,7 @@ export class MultiExtensionManagementService extends Disposable implements IExte @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IRemoteAuthorityResolverService private readonly remoteAuthorityResolverService: IRemoteAuthorityResolverService, + @IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService, @ILogService private readonly logService: ILogService ) { super(); @@ -199,14 +199,16 @@ export class MultiExtensionManagementService extends Disposable implements IExte return this.extensionManagementServerService.getExtensionManagementServer(extension.location); } - private _remoteAuthorityResolverPromise: Promise; - private hasToSyncExtensions(): Promise { + private async hasToSyncExtensions(): Promise { if (!this.extensionManagementServerService.remoteExtensionManagementServer) { - return Promise.resolve(false); + return false; } - if (!this._remoteAuthorityResolverPromise) { - this._remoteAuthorityResolverPromise = this.remoteAuthorityResolverService.resolveAuthority(this.extensionManagementServerService.remoteExtensionManagementServer.authority); + const connection = this.remoteAgentService.getConnection(); + if (!connection) { + return false; } - return this._remoteAuthorityResolverPromise.then(({ syncExtensions }) => !!syncExtensions); + + const remoteEnv = await connection.getEnvironment(); + return remoteEnv.syncExtensions; } } \ No newline at end of file diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHostProcessManager.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHostProcessManager.ts index 17316e8db3f..277ad1cbd42 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHostProcessManager.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHostProcessManager.ts @@ -249,8 +249,7 @@ export class ExtensionHostProcessManager extends Disposable { return Promise.resolve({ authority: remoteAuthority, host: pieces[0], - port: parseInt(pieces[1], 10), - syncExtensions: false + port: parseInt(pieces[1], 10) }); } return this._extensionHostProcessProxy.then(proxy => proxy.value.$resolveAuthority(remoteAuthority)); diff --git a/src/vs/workbench/services/remote/node/remoteAgentEnvironmentChannel.ts b/src/vs/workbench/services/remote/node/remoteAgentEnvironmentChannel.ts index d9ae2e0d561..8ed6173c312 100644 --- a/src/vs/workbench/services/remote/node/remoteAgentEnvironmentChannel.ts +++ b/src/vs/workbench/services/remote/node/remoteAgentEnvironmentChannel.ts @@ -19,6 +19,7 @@ export interface IRemoteAgentEnvironmentDTO { globalStorageHome: UriComponents; extensions: IExtensionDescription[]; os: OperatingSystem; + syncExtensions: boolean; } export class RemoteExtensionEnvironmentChannelClient { @@ -37,7 +38,8 @@ export class RemoteExtensionEnvironmentChannelClient { extensionHostLogsPath: URI.revive(data.extensionHostLogsPath), globalStorageHome: URI.revive(data.globalStorageHome), extensions: data.extensions.map(ext => { (ext).extensionLocation = URI.revive(ext.extensionLocation); return ext; }), - os: data.os + os: data.os, + syncExtensions: data.syncExtensions }; }); } diff --git a/src/vs/workbench/services/remote/node/remoteAgentService.ts b/src/vs/workbench/services/remote/node/remoteAgentService.ts index c9acd0e18d1..66fa9f4bf6a 100644 --- a/src/vs/workbench/services/remote/node/remoteAgentService.ts +++ b/src/vs/workbench/services/remote/node/remoteAgentService.ts @@ -24,6 +24,7 @@ export interface IRemoteAgentEnvironment { globalStorageHome: URI; extensions: IExtensionDescription[]; os: OperatingSystem; + syncExtensions: boolean; } export interface IRemoteAgentService { From 709bf352b12de8284683bef94cb5984129bfc776 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 8 Feb 2019 15:27:07 +0100 Subject: [PATCH 064/207] Fix strict null check --- src/tsconfig.strictNullChecks.json | 2 +- .../extensionManagement/node/multiExtensionManagement.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index a7d6fde6f4f..3b090e0b718 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -261,7 +261,6 @@ "./vs/platform/extensionManagement/node/extensionManagementService.ts", "./vs/platform/extensionManagement/node/extensionManagementUtil.ts", "./vs/platform/extensionManagement/node/extensionsManifestCache.ts", - "./vs/platform/extensionManagement/node/multiExtensionManagement.ts", "./vs/platform/extensionManagement/test/electron-browser/extensionManagement.test.ts", "./vs/platform/extensions/common/extensionHost.ts", "./vs/platform/extensions/common/extensions.ts", @@ -681,6 +680,7 @@ "./vs/workbench/services/editor/browser/codeEditorService.ts", "./vs/workbench/services/editor/common/editorGroupsService.ts", "./vs/workbench/services/editor/common/editorService.ts", + "./vs/workbench/services/extensionManagement/node/multiExtensionManagement.ts", "./vs/workbench/services/extensions/common/extensionHostProtocol.ts", "./vs/workbench/services/extensions/common/extensions.ts", "./vs/workbench/services/extensions/common/extensionsRegistry.ts", diff --git a/src/vs/workbench/services/extensionManagement/node/multiExtensionManagement.ts b/src/vs/workbench/services/extensionManagement/node/multiExtensionManagement.ts index 8545d95f5a8..d9297d67d42 100644 --- a/src/vs/workbench/services/extensionManagement/node/multiExtensionManagement.ts +++ b/src/vs/workbench/services/extensionManagement/node/multiExtensionManagement.ts @@ -209,6 +209,10 @@ export class MultiExtensionManagementService extends Disposable implements IExte } const remoteEnv = await connection.getEnvironment(); + if (!remoteEnv) { + return false; + } + return remoteEnv.syncExtensions; } } \ No newline at end of file From 8bd8c6f688af008ecfea1d563d38760cbb923ea2 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 8 Feb 2019 15:30:43 +0100 Subject: [PATCH 065/207] strict null trouble --- src/vs/workbench/api/node/extHostTypes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index 166bbba1b98..26553bf2a32 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -19,7 +19,7 @@ import * as vscode from 'vscode'; function es5ClassCompat(target: Function): any { ///@ts-ignore function _() { return Reflect.construct(target, arguments, this.constructor); } - Object.defineProperty(_, 'name', Object.getOwnPropertyDescriptor(target, 'name')); + Object.defineProperty(_, 'name', Object.getOwnPropertyDescriptor(target, 'name')!); ///@ts-ignore Object.setPrototypeOf(_, target); ///@ts-ignore From 0a61bab1a27aa58d8c3fcb16423c1ed4747d58d7 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 8 Feb 2019 15:36:13 +0100 Subject: [PATCH 066/207] Format settings.json --- .vscode/settings.json | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 2cb6c48fce4..af8b3803709 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -42,13 +42,19 @@ "emmet.excludeLanguages": [], "typescript.preferences.importModuleSpecifier": "non-relative", "typescript.preferences.quoteStyle": "single", - "json.schemas": [{ - "fileMatch": [ "cgmanifest.json" ], - "url": "./.vscode/cgmanifest.schema.json" - }, { - "fileMatch": [ "cglicenses.json" ], - "url": "./.vscode/cglicenses.schema.json" - } -], -"git.ignoreLimitWarning": true -} + "json.schemas": [ + { + "fileMatch": [ + "cgmanifest.json" + ], + "url": "./.vscode/cgmanifest.schema.json" + }, + { + "fileMatch": [ + "cglicenses.json" + ], + "url": "./.vscode/cglicenses.schema.json" + } + ], + "git.ignoreLimitWarning": true +} \ No newline at end of file From 7d38cdcb515358a3706f4115ea21cb3effcab679 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 8 Feb 2019 15:55:19 +0100 Subject: [PATCH 067/207] Render more task names --- build/gulpfile.extensions.js | 14 ++++++++---- build/lib/compilation.js | 8 +++++-- build/lib/compilation.ts | 8 +++++-- build/lib/util.js | 41 ++++++++++++++++++++------------- build/lib/util.ts | 44 ++++++++++++++++++++++-------------- 5 files changed, 73 insertions(+), 42 deletions(-) diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index 3a780a22e8d..a7a47522152 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -100,18 +100,20 @@ const tasks = compilations.map(function (tsconfigFile) { const srcOpts = { cwd: path.dirname(__dirname), base: srcBase }; - const cleanTask = () => util.primraf(out); + const cleanTask = util.rimraf(out); - const compileTask = util.task.series(cleanTask, () => { + const compileTask_ = () => { const pipeline = createPipeline(false, true); const input = gulp.src(src, srcOpts); return input .pipe(pipeline()) .pipe(gulp.dest(out)); - }); + }; + compileTask_.displayName = `compile-extension-${name}`; + const compileTask = util.task.series(cleanTask, compileTask_); - const watchTask = util.task.series(cleanTask, () => { + const watchTask_ = () => { const pipeline = createPipeline(false); const input = gulp.src(src, srcOpts); const watchInput = watcher(src, srcOpts); @@ -119,7 +121,9 @@ const tasks = compilations.map(function (tsconfigFile) { return watchInput .pipe(util.incremental(pipeline, input)) .pipe(gulp.dest(out)); - }); + }; + watchTask_.displayName = `watch-extension-${name}`; + const watchTask = util.task.series(cleanTask, watchTask_); const compileBuildTask = util.task.series(cleanTask, () => { const pipeline = createPipeline(true, true); diff --git a/build/lib/compilation.js b/build/lib/compilation.js index 592a5d087ce..4f183bc512d 100644 --- a/build/lib/compilation.js +++ b/build/lib/compilation.js @@ -78,7 +78,7 @@ const typesDts = [ '!node_modules/@types/uglify-js/**/*', ]; function compileTask(src, out, build) { - return function () { + const result = function () { const compile = createCompile(src, build, true); const srcPipe = es.merge(gulp.src(`${src}/**`, { base: `${src}` }), gulp.src(typesDts)); let generator = new MonacoGenerator(false); @@ -90,10 +90,12 @@ function compileTask(src, out, build) { .pipe(compile()) .pipe(gulp.dest(out)); }; + result.displayName = `compile-task-${out}${build ? '-build' : ''}`; + return result; } exports.compileTask = compileTask; function watchTask(out, build) { - return function () { + const result = function () { const compile = createCompile('src', build); const src = es.merge(gulp.src('src/**', { base: 'src' }), gulp.src(typesDts)); const watchSrc = watch('src/**', { base: 'src' }); @@ -104,6 +106,8 @@ function watchTask(out, build) { .pipe(util.incremental(compile, src, true)) .pipe(gulp.dest(out)); }; + result.displayName = `watch-task-${out}${build ? '-build' : ''}`; + return result; } exports.watchTask = watchTask; const REPO_SRC_FOLDER = path.join(__dirname, '../../src'); diff --git a/build/lib/compilation.ts b/build/lib/compilation.ts index b431a134f6c..60f65ebe381 100644 --- a/build/lib/compilation.ts +++ b/build/lib/compilation.ts @@ -90,7 +90,7 @@ const typesDts = [ export function compileTask(src: string, out: string, build: boolean): () => NodeJS.ReadWriteStream { - return function () { + const result = function () { const compile = createCompile(src, build, true); const srcPipe = es.merge( @@ -108,11 +108,13 @@ export function compileTask(src: string, out: string, build: boolean): () => Nod .pipe(compile()) .pipe(gulp.dest(out)); }; + result.displayName = `compile-task-${out}${build ? '-build' : ''}`; + return result; } export function watchTask(out: string, build: boolean): () => NodeJS.ReadWriteStream { - return function () { + const result = function () { const compile = createCompile('src', build); const src = es.merge( @@ -129,6 +131,8 @@ export function watchTask(out: string, build: boolean): () => NodeJS.ReadWriteSt .pipe(util.incremental(compile, src, true)) .pipe(gulp.dest(out)); }; + result.displayName = `watch-task-${out}${build ? '-build' : ''}`; + return result; } const REPO_SRC_FOLDER = path.join(__dirname, '../../src'); diff --git a/build/lib/util.js b/build/lib/util.js index b6228ad4cf9..10d4493e78b 100644 --- a/build/lib/util.js +++ b/build/lib/util.js @@ -14,6 +14,8 @@ const fs = require("fs"); const _rimraf = require("rimraf"); const git = require("./git"); const VinylFile = require("vinyl"); +const fancyLog = require("fancy-log"); +const ansiColors = require("ansi-colors"); const NoCancellationToken = { isCancellationRequested: () => false }; function incremental(streamProvider, initial, supportsCancellation) { const input = es.through(); @@ -180,24 +182,10 @@ function rimraf(dir) { return cb(err); }); }; - return cb => retry(cb); + retry.displayName = `clean-${path.basename(dir)}`; + return retry; } exports.rimraf = rimraf; -/** - * Like rimraf (with 5 retries), but with a promise instead of a callback. - */ -function primraf(dir) { - const fn = rimraf(dir); - return new Promise((resolve, reject) => { - fn((err) => { - if (err) { - return reject(err); - } - resolve(); - }); - }); -} -exports.primraf = primraf; var task; (function (task_1) { function _isPromise(p) { @@ -206,7 +194,28 @@ var task; } return false; } + function _renderTime(time) { + if (time < 1000) { + return `${time.toFixed(2)} ms`; + } + let seconds = time / 1000; + if (seconds < 60) { + return `${seconds.toFixed(1)} s`; + } + let minutes = Math.floor(seconds / 60); + seconds -= minutes * 60; + return `${minutes} m and ${seconds} s`; + } async function _execute(task) { + const name = task.displayName || task.name || ``; + fancyLog('Starting', ansiColors.cyan(name), '...'); + const startTime = process.hrtime(); + await _doExecute(task); + const elapsedArr = process.hrtime(startTime); + const elapsedNanoseconds = (elapsedArr[0] * 1e9 + elapsedArr[1]); + fancyLog(`Finished`, ansiColors.cyan(name), 'after', ansiColors.green(_renderTime(elapsedNanoseconds / 1e6))); + } + async function _doExecute(task) { // Always invoke as if it were a callback task return new Promise((resolve, reject) => { if (task.length === 1) { diff --git a/build/lib/util.ts b/build/lib/util.ts index 42d3aba2fee..0df157feb54 100644 --- a/build/lib/util.ts +++ b/build/lib/util.ts @@ -17,6 +17,8 @@ import * as git from './git'; import * as VinylFile from 'vinyl'; import { ThroughStream } from 'through'; import * as sm from 'source-map'; +import * as fancyLog from 'fancy-log'; +import * as ansiColors from 'ansi-colors'; export interface ICancellationToken { isCancellationRequested(): boolean; @@ -233,23 +235,8 @@ export function rimraf(dir: string): (cb: any) => void { return cb(err); }); }; - - return cb => retry(cb); -} - -/** - * Like rimraf (with 5 retries), but with a promise instead of a callback. - */ -export function primraf(dir: string): Promise { - const fn = rimraf(dir); - return new Promise((resolve, reject) => { - fn((err: any) => { - if (err) { - return reject(err); - } - resolve(); - }); - }); + retry.displayName = `clean-${path.basename(dir)}`; + return retry; } export type PromiseTask = () => Promise; @@ -266,7 +253,30 @@ export namespace task { return false; } + function _renderTime(time: number): string { + if (time < 1000) { + return `${time.toFixed(2)} ms`; + } + let seconds = time / 1000; + if (seconds < 60) { + return `${seconds.toFixed(1)} s`; + } + let minutes = Math.floor(seconds / 60); + seconds -= minutes * 60; + return `${minutes} m and ${seconds} s`; + } + async function _execute(task: Task): Promise { + const name = (task).displayName || task.name || ``; + fancyLog('Starting', ansiColors.cyan(name), '...'); + const startTime = process.hrtime(); + await _doExecute(task); + const elapsedArr = process.hrtime(startTime); + const elapsedNanoseconds = (elapsedArr[0] * 1e9 + elapsedArr[1]); + fancyLog(`Finished`, ansiColors.cyan(name), 'after', ansiColors.green(_renderTime(elapsedNanoseconds / 1e6))); + } + + async function _doExecute(task: Task): Promise { // Always invoke as if it were a callback task return new Promise((resolve, reject) => { if (task.length === 1) { From af76bbacd4253d3bd507139db277990d51a075f7 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 8 Feb 2019 16:04:38 +0100 Subject: [PATCH 068/207] Even more task names --- build/gulpfile.extensions.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index a7a47522152..458d0c0e4db 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -101,6 +101,7 @@ const tasks = compilations.map(function (tsconfigFile) { const srcOpts = { cwd: path.dirname(__dirname), base: srcBase }; const cleanTask = util.rimraf(out); + cleanTask.displayName = `clean-extension-${name}`; const compileTask_ = () => { const pipeline = createPipeline(false, true); @@ -125,14 +126,16 @@ const tasks = compilations.map(function (tsconfigFile) { watchTask_.displayName = `watch-extension-${name}`; const watchTask = util.task.series(cleanTask, watchTask_); - const compileBuildTask = util.task.series(cleanTask, () => { + const compileBuildTask_ = () => { const pipeline = createPipeline(true, true); const input = gulp.src(src, srcOpts); return input .pipe(pipeline()) .pipe(gulp.dest(out)); - }); + }; + compileBuildTask_.displayName = `compile-build-extension-${name}`; + const compileBuildTask = util.task.series(cleanTask, compileBuildTask_); // Tasks gulp.task('compile-extension:' + name, compileTask); From 4d8bb9298128ffc4f9e0daf8d98f28650a71038b Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 8 Feb 2019 16:03:01 +0100 Subject: [PATCH 069/207] use fileservice to decide which editor inputs are openable --- .../browser/parts/editor/editorWidgets.ts | 13 +++++++++---- .../contrib/files/electron-browser/fileActions.ts | 14 +++++++++----- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorWidgets.ts b/src/vs/workbench/browser/parts/editor/editorWidgets.ts index dfa93b7c447..0b2a66006e6 100644 --- a/src/vs/workbench/browser/parts/editor/editorWidgets.ts +++ b/src/vs/workbench/browser/parts/editor/editorWidgets.ts @@ -14,12 +14,12 @@ import { buttonBackground, buttonForeground, editorBackground, editorForeground, import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { Schemas } from 'vs/base/common/network'; import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; import { Disposable, dispose } from 'vs/base/common/lifecycle'; import { localize } from 'vs/nls'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { isEqual } from 'vs/base/common/resources'; +import { IFileService } from 'vs/platform/files/common/files'; export class FloatingClickWidget extends Widget implements IOverlayWidget { @@ -107,7 +107,8 @@ export class OpenWorkspaceButtonContribution extends Disposable implements IEdit private editor: ICodeEditor, @IInstantiationService private readonly instantiationService: IInstantiationService, @IWindowService private readonly windowService: IWindowService, - @IWorkspaceContextService private readonly contextService: IWorkspaceContextService + @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, + @IFileService private readonly fileService: IFileService ) { super(); @@ -138,8 +139,12 @@ export class OpenWorkspaceButtonContribution extends Disposable implements IEdit return false; // we need a model } - if (model.uri.scheme !== Schemas.file || !hasWorkspaceFileExtension(model.uri.fsPath)) { - return false; // we need a local workspace file + if (!hasWorkspaceFileExtension(model.uri.fsPath)) { + return false; // we need a workspace file + } + + if (!this.fileService.canHandleResource(model.uri)) { + return false; // needs to be backed by a file service } if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { diff --git a/src/vs/workbench/contrib/files/electron-browser/fileActions.ts b/src/vs/workbench/contrib/files/electron-browser/fileActions.ts index 1d61e4c585a..664f2ab2073 100644 --- a/src/vs/workbench/contrib/files/electron-browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/electron-browser/fileActions.ts @@ -46,7 +46,6 @@ import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; import { ExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; import { onUnexpectedError } from 'vs/base/common/errors'; import { sequence } from 'vs/base/common/async'; -import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; export const NEW_FILE_COMMAND_ID = 'explorer.newFile'; export const NEW_FILE_LABEL = nls.localize('newFile', "New File"); @@ -869,17 +868,22 @@ export class ShowOpenedFileInNewWindow extends Action { label: string, @IEditorService private readonly editorService: IEditorService, @IWindowService private readonly windowService: IWindowService, - @INotificationService private readonly notificationService: INotificationService + @INotificationService private readonly notificationService: INotificationService, + @IFileService private readonly fileService: IFileService ) { super(id, label); } public run(): Promise { const fileResource = toResource(this.editorService.activeEditor, { supportSideBySide: true }); - if (fileResource && (fileResource.scheme === Schemas.file || fileResource.scheme === REMOTE_HOST_SCHEME)) { - this.windowService.openWindow([{ uri: fileResource, typeHint: 'file' }], { forceNewWindow: true, forceOpenWorkspaceAsFile: true }); + if (fileResource) { + if (this.fileService.canHandleResource(fileResource)) { + this.windowService.openWindow([{ uri: fileResource, typeHint: 'file' }], { forceNewWindow: true, forceOpenWorkspaceAsFile: true }); + } else { + this.notificationService.info(nls.localize('openFileToShowInNewWindow.unsupportedschema', "The active editor must contain an openable resource.")); + } } else { - this.notificationService.info(nls.localize('openFileToShowInNewWindow', "Open a file first to open in new window")); + this.notificationService.info(nls.localize('openFileToShowInNewWindow.nofile', "Open a file first to open in new window")); } return Promise.resolve(true); From 153a897c06a9cb0355c6b637d7bb9c5c8e4cf143 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 8 Feb 2019 16:26:39 +0100 Subject: [PATCH 070/207] avoid tsconfig-warning and just copy `lib.webworker.importscripts.d.ts` --- src/tsconfig.json | 3 +-- src/typings/lib.webworker.importscripts.d.ts | 23 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 src/typings/lib.webworker.importscripts.d.ts diff --git a/src/tsconfig.json b/src/tsconfig.json index 2458f614ce1..72ae60789f9 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -9,8 +9,7 @@ "lib": [ "dom", "es5", - "es2015.iterable", - "webworker.importscripts" + "es2015.iterable" ] }, "include": [ diff --git a/src/typings/lib.webworker.importscripts.d.ts b/src/typings/lib.webworker.importscripts.d.ts new file mode 100644 index 00000000000..e84f717c9a4 --- /dev/null +++ b/src/typings/lib.webworker.importscripts.d.ts @@ -0,0 +1,23 @@ +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + + + + +///////////////////////////// +/// WorkerGlobalScope APIs +///////////////////////////// +// These are only available in a Web Worker +declare function importScripts(...urls: string[]): void; From 8c3bf7a8b7fcaed20a0e447e6ed88819e7af05c0 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 8 Feb 2019 16:31:04 +0100 Subject: [PATCH 071/207] fixes #68240 --- src/vs/base/browser/ui/list/listView.ts | 36 ++++++++++++++------ src/vs/base/browser/ui/list/listWidget.ts | 26 ++++---------- src/vs/base/browser/ui/tree/abstractTree.ts | 11 ++++-- src/vs/base/browser/ui/tree/asyncDataTree.ts | 3 +- 4 files changed, 41 insertions(+), 35 deletions(-) diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index 7b60e1ab46b..73ca98dabcf 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -41,6 +41,11 @@ export interface IListViewDragAndDrop extends IListDragAndDrop { getDragElements(element: T): T[]; } +export interface IAriaSetProvider { + getSetSize(element: T, index: number, listLength: number): number; + getPosInSet(element: T, index: number): number; +} + export interface IListViewOptions { readonly dnd?: IListViewDragAndDrop; readonly useShadows?: boolean; @@ -49,7 +54,7 @@ export interface IListViewOptions { readonly supportDynamicHeights?: boolean; readonly mouseSupport?: boolean; readonly horizontalScrolling?: boolean; - readonly disableAriaRoles?: boolean; + readonly ariaSetProvider?: IAriaSetProvider; } const DefaultOptions = { @@ -64,8 +69,7 @@ const DefaultOptions = { onDragOver() { return false; }, drop() { } }, - horizontalScrolling: false, - disableAriaRoles: false + horizontalScrolling: false }; export class ElementsDragAndDropData implements IDragAndDropData { @@ -144,6 +148,9 @@ function equalsDragFeedback(f1: number[] | undefined, f2: number[] | undefined): export class ListView implements ISpliceable, IDisposable { + private static InstanceCount = 0; + readonly domId = `list_id_${++ListView.InstanceCount}`; + readonly domNode: HTMLElement; private items: IItem[]; @@ -167,7 +174,7 @@ export class ListView implements ISpliceable, IDisposable { private setRowLineHeight: boolean; private supportDynamicHeights: boolean; private horizontalScrolling: boolean; - private disableAriaRoles: boolean; + private ariaSetProvider: IAriaSetProvider; private scrollWidth: number | undefined; private canUseTranslate3d: boolean | undefined = undefined; @@ -198,7 +205,7 @@ export class ListView implements ISpliceable, IDisposable { container: HTMLElement, private virtualDelegate: IListVirtualDelegate, renderers: IListRenderer[], - options: IListViewOptions = DefaultOptions + options: IListViewOptions = DefaultOptions as IListViewOptions ) { if (options.horizontalScrolling && options.supportDynamicHeights) { throw new Error('Horizontal scrolling and dynamic heights not supported simultaneously'); @@ -219,12 +226,16 @@ export class ListView implements ISpliceable, IDisposable { this.domNode = document.createElement('div'); this.domNode.className = 'monaco-list'; + + DOM.addClass(this.domNode, this.domId); + this.domNode.tabIndex = 0; + DOM.toggleClass(this.domNode, 'mouse-support', typeof options.mouseSupport === 'boolean' ? options.mouseSupport : true); this.horizontalScrolling = getOrDefault(options, o => o.horizontalScrolling, DefaultOptions.horizontalScrolling); DOM.toggleClass(this.domNode, 'horizontal-scrolling', this.horizontalScrolling); - this.disableAriaRoles = getOrDefault(options, o => o.disableAriaRoles, DefaultOptions.disableAriaRoles); + this.ariaSetProvider = options.ariaSetProvider || { getSetSize: (e, i, length) => length, getPosInSet: (_, index) => index + 1 }; this.rowsContainer = document.createElement('div'); this.rowsContainer.className = 'monaco-list-rows'; @@ -533,6 +544,7 @@ export class ListView implements ISpliceable, IDisposable { if (!item.row) { item.row = this.cache.alloc(item.templateId); + item.row!.domNode!.setAttribute('role', 'treeitem'); } if (!item.row.domNode!.parentElement) { @@ -600,11 +612,9 @@ export class ListView implements ISpliceable, IDisposable { item.row!.domNode!.setAttribute('data-index', `${index}`); item.row!.domNode!.setAttribute('data-last-element', index === this.length - 1 ? 'true' : 'false'); - - if (!this.disableAriaRoles) { - item.row!.domNode!.setAttribute('aria-setsize', `${this.length}`); - item.row!.domNode!.setAttribute('aria-posinset', `${index + 1}`); - } + item.row!.domNode!.setAttribute('aria-setsize', String(this.ariaSetProvider.getSetSize(item.element, index, this.length))); + item.row!.domNode!.setAttribute('aria-posinset', String(this.ariaSetProvider.getPosInSet(item.element, index))); + item.row!.domNode!.setAttribute('id', this.getElementDomId(index)); DOM.toggleClass(item.row!.domNode!, 'drop-target', item.dropTarget); } @@ -1083,6 +1093,10 @@ export class ListView implements ISpliceable, IDisposable { return nextToLastItem.row.domNode; } + getElementDomId(index: number): string { + return `${this.domId}_${index}`; + } + // Dispose dispose() { diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index fe2471d11d1..a342692f5c8 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -17,7 +17,7 @@ import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardE import { Event, Emitter, EventBufferer } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; import { IListVirtualDelegate, IListRenderer, IListEvent, IListContextMenuEvent, IListMouseEvent, IListTouchEvent, IListGestureEvent, IIdentityProvider, IKeyboardNavigationLabelProvider, IListDragAndDrop, IListDragOverReaction, ListAriaRootRole } from './list'; -import { ListView, IListViewOptions, IListViewDragAndDrop } from './listView'; +import { ListView, IListViewOptions, IListViewDragAndDrop, IAriaSetProvider } from './listView'; import { Color } from 'vs/base/common/color'; import { mixin } from 'vs/base/common/objects'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; @@ -179,16 +179,12 @@ class Trait implements ISpliceable, IDisposable { class FocusTrait extends Trait { - constructor( - private getDomId: (index: number) => string - ) { + constructor() { super('focused'); } renderIndex(index: number, container: HTMLElement): void { super.renderIndex(index, container); - container.setAttribute('role', 'treeitem'); - container.setAttribute('id', this.getDomId(index)); if (this.contains(index)) { container.setAttribute('aria-selected', 'true'); @@ -818,7 +814,7 @@ export interface IListOptions extends IListStyles { readonly supportDynamicHeights?: boolean; readonly mouseSupport?: boolean; readonly horizontalScrolling?: boolean; - readonly disableAriaRoles?: boolean; + readonly ariaSetProvider?: IAriaSetProvider; } export interface IListStyles { @@ -1069,9 +1065,6 @@ export interface IListOptionsUpdate { export class List implements ISpliceable, IDisposable { - private static InstanceCount = 0; - private idPrefix = `list_id_${++List.InstanceCount}`; - private focus: Trait; private selection: Trait; private eventBufferer = new EventBufferer(); @@ -1167,7 +1160,7 @@ export class List implements ISpliceable, IDisposable { renderers: IListRenderer[], private _options: IListOptions = DefaultOptions ) { - this.focus = new FocusTrait(i => this.getElementDomId(i)); + this.focus = new FocusTrait(); this.selection = new Trait('selected'); mixin(_options, defaultStyles, false); @@ -1193,12 +1186,9 @@ export class List implements ISpliceable, IDisposable { this.view.domNode.setAttribute('role', _options.ariaRole); } - DOM.addClass(this.view.domNode, this.idPrefix); - this.view.domNode.tabIndex = 0; - this.styleElement = DOM.createStyleSheet(this.view.domNode); - this.styleController = _options.styleController || new DefaultStyleController(this.styleElement, this.idPrefix); + this.styleController = _options.styleController || new DefaultStyleController(this.styleElement, this.view.domId); this.spliceable = new CombinedSpliceable([ new TraitSpliceable(this.focus, this.view, _options.identityProvider), @@ -1528,10 +1518,6 @@ export class List implements ISpliceable, IDisposable { return Math.abs((scrollTop - elementTop) / m); } - private getElementDomId(index: number): string { - return `${this.idPrefix}_${index}`; - } - isDOMFocused(): boolean { return this.view.domNode === document.activeElement; } @@ -1572,7 +1558,7 @@ export class List implements ISpliceable, IDisposable { const focus = this.focus.get(); if (focus.length > 0) { - this.view.domNode.setAttribute('aria-activedescendant', this.getElementDomId(focus[0])); + this.view.domNode.setAttribute('aria-activedescendant', this.view.getElementDomId(focus[0])); } else { this.view.domNode.removeAttribute('aria-activedescendant'); } diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 745aa45ba9f..7c94ff8e627 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -151,7 +151,14 @@ function asListOptions(modelProvider: () => ITreeModel implements IListRenderer(options?: IAsyncDataTreeOpt typeof options.expandOnlyOnTwistieClick !== 'function' ? options.expandOnlyOnTwistieClick : ( e => (options.expandOnlyOnTwistieClick as ((e: T) => boolean))(e.element as T) ) - ) + ), + ariaSetProvider: undefined }; } From b6da3af518c5f55ddcfd2e18573fb2261f215e42 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 8 Feb 2019 16:58:51 +0100 Subject: [PATCH 072/207] make sure to gc-track commands of code lens objects --- .../electron-browser/mainThreadLanguageFeatures.ts | 12 ++++++++++-- src/vs/workbench/api/node/extHost.protocol.ts | 6 +++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts index f3307626193..9dfc7c5cf97 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts @@ -124,13 +124,21 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha const provider = { provideCodeLenses: (model: ITextModel, token: CancellationToken): modes.ICodeLensSymbol[] | Promise => { return this._proxy.$provideCodeLenses(handle, model.uri, token).then(dto => { - if (dto) { dto.forEach(obj => this._heapService.trackObject(obj)); } + if (dto) { + dto.forEach(obj => { + this._heapService.trackObject(obj); + this._heapService.trackObject(obj.command); + }); + } return dto; }); }, resolveCodeLens: (model: ITextModel, codeLens: modes.ICodeLensSymbol, token: CancellationToken): modes.ICodeLensSymbol | Promise => { return this._proxy.$resolveCodeLens(handle, model.uri, codeLens, token).then(obj => { - this._heapService.trackObject(obj); + if (obj) { + this._heapService.trackObject(obj); + this._heapService.trackObject(obj.command); + } return obj; }); } diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 925871aefc4..3dc5bb08a89 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -882,7 +882,11 @@ export interface CodeActionDto { export type LinkDto = ObjectIdentifier & modes.ILink; -export type CodeLensDto = ObjectIdentifier & modes.ICodeLensSymbol; +export interface CodeLensDto extends ObjectIdentifier { + range: IRange; + id?: string; + command?: CommandDto; +} export interface ExtHostLanguageFeaturesShape { $provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise; From 2422c987f44339ad4b6f9227ffbbf1e358d8a3d6 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 8 Feb 2019 17:49:44 +0100 Subject: [PATCH 073/207] make vscode.Uri.parse throw when scheme is missing, #66802 --- .../workbench/services/extensions/node/extensionHostMain.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/extensions/node/extensionHostMain.ts b/src/vs/workbench/services/extensions/node/extensionHostMain.ts index ec9cd8be9e4..94ce5f596df 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostMain.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostMain.ts @@ -7,7 +7,7 @@ import { timeout } from 'vs/base/common/async'; import * as errors from 'vs/base/common/errors'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Counter } from 'vs/base/common/numbers'; -import { URI, setUriThrowOnMissingScheme } from 'vs/base/common/uri'; +import { URI } from 'vs/base/common/uri'; import { IURITransformer } from 'vs/base/common/uriIpc'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/node/ipc'; import { IEnvironment, IInitData, MainContext, MainThreadConsoleShape } from 'vs/workbench/api/node/extHost.protocol'; @@ -20,7 +20,7 @@ import { RPCProtocol } from 'vs/workbench/services/extensions/node/rpcProtocol'; // we don't (yet) throw when extensions parse // uris that have no scheme -setUriThrowOnMissingScheme(false); +// setUriThrowOnMissingScheme(false); const nativeExit = process.exit.bind(process); function patchProcess(allowExit: boolean) { From c110d84460b3e45842a8fe753562341003595e1d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 8 Feb 2019 18:03:56 +0100 Subject: [PATCH 074/207] fix integration test --- .../src/test/workspaceSymbolProvider.test.ts | 2 +- .../vscode-api-tests/src/singlefolder-tests/workspace.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts b/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts index d19b6611699..e74d3b592bc 100644 --- a/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts +++ b/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts @@ -38,7 +38,7 @@ suite('markdown.WorkspaceSymbolProvider', () => { const fileNameCount = 10; const files: vscode.TextDocument[] = []; for (let i = 0; i < fileNameCount; ++i) { - const testFileName = vscode.Uri.parse(`test${i}.md`); + const testFileName = vscode.Uri.file(`test${i}.md`); files.push(new InMemoryDocument(testFileName, `# common\nabc\n## header${i}`)); } diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts index e5cf2bd12a4..a950e90504b 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts @@ -568,7 +568,7 @@ suite('workspace-namespace', () => { test('applyEdit should fail when editing renamed from resource', async () => { const resource = await createRandomFile(); - const newResource = vscode.Uri.parse(resource.fsPath + '.1'); + const newResource = vscode.Uri.file(resource.fsPath + '.1'); const edit = new vscode.WorkspaceEdit(); edit.renameFile(resource, newResource); edit.insert(resource, new vscode.Position(0, 0), ''); From fdf21ccad7d2ecf7d345bf638f34fa3d703eae90 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 8 Feb 2019 16:56:28 -0800 Subject: [PATCH 075/207] vscode-xterm@3.12.0-beta3 Fixes #67933 --- package.json | 4 ++-- yarn.lock | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 908f250e6be..1f252eb0cab 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "vscode-ripgrep": "^1.2.5", "vscode-sqlite3": "4.0.7", "vscode-textmate": "^4.0.1", - "vscode-xterm": "3.12.0-beta2", + "vscode-xterm": "3.12.0-beta3", "winreg": "^1.2.4", "yauzl": "^2.9.1", "yazl": "^2.4.3" @@ -150,4 +150,4 @@ "windows-mutex": "0.2.1", "windows-process-tree": "0.2.3" } -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index 4a5b178d8c4..9a934e15461 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9442,10 +9442,10 @@ vscode-uri@^1.0.6: resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.6.tgz#6b8f141b0bbc44ad7b07e94f82f168ac7608ad4d" integrity sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww== -vscode-xterm@3.12.0-beta2: - version "3.12.0-beta2" - resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.12.0-beta2.tgz#fbbf6d1926e0628d4e0b85b1bfdefa2b0bf40df6" - integrity sha512-NhLYyJXjwLXXzn+NYEOkAtTxbdbAGkjztabE2Vy8j4fXXOwHHHg6KurMCbL7bd8BOEMIPrTIw6zLhzfexs5Vhw== +vscode-xterm@3.12.0-beta3: + version "3.12.0-beta3" + resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.12.0-beta3.tgz#d642d249fe01615dbe1ab4d11b333c1d52b65ee8" + integrity sha512-rR9EmZjVJiQZ39Q4msSzZcwLzMQPzmxdjvr6uJogo3ht3+cEFnZbtJ8cHKYpU7gkKnj+l56d5uC3pbmt3MB/Nw== vso-node-api@6.1.2-preview: version "6.1.2-preview" From fdc710af64c74335e330b5cd98a5f60d5b188caa Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 17:56:21 -0800 Subject: [PATCH 076/207] Strict null work for main thread debug, tasks, and output --- src/tsconfig.strictNullChecks.json | 2 + .../mainThreadDebugService.ts | 24 ++++++--- .../mainThreadOutputService.ts | 16 +++--- .../api/electron-browser/mainThreadTask.ts | 53 ++++++++++--------- src/vs/workbench/api/node/extHost.protocol.ts | 14 ++--- .../workbench/api/node/extHostDebugService.ts | 2 +- src/vs/workbench/api/shared/tasks.ts | 10 ++-- .../workbench/contrib/debug/common/debug.ts | 4 +- .../debugConfigurationManager.ts | 2 +- .../debug/electron-browser/debugService.ts | 2 +- .../contrib/tasks/common/taskService.ts | 2 +- .../workbench/contrib/tasks/common/tasks.ts | 2 +- .../electron-browser/task.contribution.ts | 2 +- 13 files changed, 76 insertions(+), 59 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 3b090e0b718..e14e51c576e 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -404,6 +404,7 @@ "./vs/workbench/api/electron-browser/mainThreadCommands.ts", "./vs/workbench/api/electron-browser/mainThreadConfiguration.ts", "./vs/workbench/api/electron-browser/mainThreadConsole.ts", + "./vs/workbench/api/electron-browser/mainThreadDebugService.ts", "./vs/workbench/api/electron-browser/mainThreadDiagnostics.ts", "./vs/workbench/api/electron-browser/mainThreadDialogs.ts", "./vs/workbench/api/electron-browser/mainThreadDocumentContentProviders.ts", @@ -414,6 +415,7 @@ "./vs/workbench/api/electron-browser/mainThreadLanguages.ts", "./vs/workbench/api/electron-browser/mainThreadLogService.ts", "./vs/workbench/api/electron-browser/mainThreadMessageService.ts", + "./vs/workbench/api/electron-browser/mainThreadOutputService.ts", "./vs/workbench/api/electron-browser/mainThreadProgress.ts", "./vs/workbench/api/electron-browser/mainThreadQuickOpen.ts", "./vs/workbench/api/electron-browser/mainThreadSCM.ts", diff --git a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts index 287c7320573..80b8a12bc42 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts @@ -141,13 +141,13 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb this.debugService.addFunctionBreakpoint(dto.functionName, dto.id); } } - return undefined; + return Promise.resolve(); } public $unregisterBreakpoints(breakpointIds: string[], functionBreakpointIds: string[]): Promise { breakpointIds.forEach(id => this.debugService.removeBreakpoints(id)); functionBreakpointIds.forEach(id => this.debugService.removeFunctionBreakpoints(id)); - return undefined; + return Promise.resolve(); } @@ -259,20 +259,32 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb } public $acceptDAMessage(handle: number, message: DebugProtocol.ProtocolMessage) { - this._debugAdapters.get(handle).acceptMessage(convertToVSCPaths(message, false)); + this.getDebugAdapter(handle).acceptMessage(convertToVSCPaths(message, false)); } + public $acceptDAError(handle: number, name: string, message: string, stack: string) { - this._debugAdapters.get(handle).fireError(handle, new Error(`${name}: ${message}\n${stack}`)); + this.getDebugAdapter(handle).fireError(handle, new Error(`${name}: ${message}\n${stack}`)); } public $acceptDAExit(handle: number, code: number, signal: string) { - this._debugAdapters.get(handle).fireExit(handle, code, signal); + this.getDebugAdapter(handle).fireExit(handle, code, signal); + } + + private getDebugAdapter(handle: number): ExtensionHostDebugAdapter { + const adapter = this._debugAdapters.get(handle); + if (!adapter) { + throw new Error('Invalid debug adapter'); + } + return adapter; } // dto helpers - getSessionDto(session: IDebugSession): IDebugSessionDto { + getSessionDto(session: undefined): undefined; + getSessionDto(session: IDebugSession): IDebugSessionDto; + getSessionDto(session: IDebugSession | undefined): IDebugSessionDto | undefined; + getSessionDto(session: IDebugSession | undefined): IDebugSessionDto | undefined { if (session) { const sessionID = session.getId(); if (this._sessions.has(sessionID)) { diff --git a/src/vs/workbench/api/electron-browser/mainThreadOutputService.ts b/src/vs/workbench/api/electron-browser/mainThreadOutputService.ts index 6318bbd9559..7f9f642dafd 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadOutputService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadOutputService.ts @@ -38,7 +38,7 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut const setVisibleChannel = () => { const panel = this._panelService.getActivePanel(); - const visibleChannel: IOutputChannel = panel && panel.getId() === OUTPUT_PANEL_ID ? this._outputService.getActiveChannel() : null; + const visibleChannel: IOutputChannel | null = panel && panel.getId() === OUTPUT_PANEL_ID ? this._outputService.getActiveChannel() : null; this._proxy.$setVisibleChannel(visibleChannel ? visibleChannel.id : null); }; this._register(Event.any(this._outputService.onActiveOutputChannel, this._panelService.onDidPanelOpen, this._panelService.onDidPanelClose)(() => setVisibleChannel())); @@ -47,12 +47,12 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut public $register(label: string, log: boolean, file?: UriComponents): Promise { const id = 'extension-output-#' + (MainThreadOutputService._idPool++); - Registry.as(Extensions.OutputChannels).registerChannel({ id, label, file: file ? URI.revive(file) : null, log }); + Registry.as(Extensions.OutputChannels).registerChannel({ id, label, file: file ? URI.revive(file) : undefined, log }); this._register(toDisposable(() => this.$dispose(id))); return Promise.resolve(id); } - public $append(channelId: string, value: string): Promise { + public $append(channelId: string, value: string): Promise | undefined { const channel = this._getChannel(channelId); if (channel) { channel.append(value); @@ -60,7 +60,7 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut return undefined; } - public $update(channelId: string): Promise { + public $update(channelId: string): Promise | undefined { const channel = this._getChannel(channelId); if (channel) { channel.update(); @@ -68,7 +68,7 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut return undefined; } - public $clear(channelId: string, till: number): Promise { + public $clear(channelId: string, till: number): Promise | undefined { const channel = this._getChannel(channelId); if (channel) { channel.clear(till); @@ -76,7 +76,7 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut return undefined; } - public $reveal(channelId: string, preserveFocus: boolean): Promise { + public $reveal(channelId: string, preserveFocus: boolean): Promise | undefined { const channel = this._getChannel(channelId); if (channel) { this._outputService.showChannel(channel.id, preserveFocus); @@ -84,7 +84,7 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut return undefined; } - public $close(channelId: string): Promise { + public $close(channelId: string): Promise | undefined { const panel = this._panelService.getActivePanel(); if (panel && panel.getId() === OUTPUT_PANEL_ID && channelId === this._outputService.getActiveChannel().id) { this._partService.setPanelHidden(true); @@ -93,7 +93,7 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut return undefined; } - public $dispose(channelId: string): Promise { + public $dispose(channelId: string): Promise | undefined { const channel = this._getChannel(channelId); if (channel) { channel.dispose(); diff --git a/src/vs/workbench/api/electron-browser/mainThreadTask.ts b/src/vs/workbench/api/electron-browser/mainThreadTask.ts index 37231f85b42..8637ce0dcad 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadTask.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadTask.ts @@ -74,7 +74,7 @@ namespace TaskDefinitionDTO { delete result._key; return result; } - export function to(value: TaskDefinitionDTO, executeOnly: boolean): KeyedTaskIdentifier { + export function to(value: TaskDefinitionDTO, executeOnly: boolean): KeyedTaskIdentifier | undefined { let result = TaskDefinition.createTaskIdentifier(value, console); if (result === undefined && executeOnly) { result = { @@ -87,13 +87,13 @@ namespace TaskDefinitionDTO { } namespace TaskPresentationOptionsDTO { - export function from(value: PresentationOptions): TaskPresentationOptionsDTO { + export function from(value: PresentationOptions | undefined): TaskPresentationOptionsDTO | undefined { if (value === undefined || value === null) { return undefined; } return Objects.assign(Object.create(null), value); } - export function to(value: TaskPresentationOptionsDTO): PresentationOptions { + export function to(value: TaskPresentationOptionsDTO | undefined): PresentationOptions { if (value === undefined || value === null) { return PresentationOptions.defaults; } @@ -102,13 +102,13 @@ namespace TaskPresentationOptionsDTO { } namespace RunOptionsDTO { - export function from(value: RunOptions): RunOptionsDTO { + export function from(value: RunOptions): RunOptionsDTO | undefined { if (value === undefined || value === null) { return undefined; } return Objects.assign(Object.create(null), value); } - export function to(value: RunOptionsDTO): RunOptions { + export function to(value: RunOptionsDTO | undefined): RunOptions { if (value === undefined || value === null) { return RunOptions.defaults; } @@ -117,7 +117,7 @@ namespace RunOptionsDTO { } namespace ProcessExecutionOptionsDTO { - export function from(value: CommandOptions): ProcessExecutionOptionsDTO { + export function from(value: CommandOptions): ProcessExecutionOptionsDTO | undefined { if (value === undefined || value === null) { return undefined; } @@ -126,7 +126,7 @@ namespace ProcessExecutionOptionsDTO { env: value.env }; } - export function to(value: ProcessExecutionOptionsDTO): CommandOptions { + export function to(value: ProcessExecutionOptionsDTO | undefined): CommandOptions { if (value === undefined || value === null) { return CommandOptions.defaults; } @@ -167,7 +167,7 @@ namespace ProcessExecutionDTO { } namespace ShellExecutionOptionsDTO { - export function from(value: CommandOptions): ShellExecutionOptionsDTO { + export function from(value: CommandOptions): ShellExecutionOptionsDTO | undefined { if (value === undefined || value === null) { return undefined; } @@ -182,7 +182,7 @@ namespace ShellExecutionOptionsDTO { } return result; } - export function to(value: ShellExecutionOptionsDTO): CommandOptions { + export function to(value: ShellExecutionOptionsDTO): CommandOptions | undefined { if (value === undefined || value === null) { return undefined; } @@ -257,7 +257,7 @@ namespace TaskSourceDTO { } export function to(value: TaskSourceDTO, workspace: IWorkspaceContextService): ExtensionTaskSource { let scope: TaskScope; - let workspaceFolder: IWorkspaceFolder; + let workspaceFolder: IWorkspaceFolder | undefined; if ((value.scope === undefined) || ((typeof value.scope === 'number') && (value.scope !== TaskScope.Global))) { if (workspace.getWorkspace().folders.length === 0) { scope = TaskScope.Global; @@ -270,9 +270,9 @@ namespace TaskSourceDTO { scope = value.scope; } else { scope = TaskScope.Folder; - workspaceFolder = workspace.getWorkspaceFolder(URI.revive(value.scope)); + workspaceFolder = workspace.getWorkspaceFolder(URI.revive(value.scope)) || undefined; } - let result: ExtensionTaskSource = { + const result: ExtensionTaskSource = { kind: TaskSourceKind.Extension, label: value.label, extension: value.extensionId, @@ -291,7 +291,7 @@ namespace TaskHandleDTO { } namespace TaskDTO { - export function from(task: Task): TaskDTO { + export function from(task: Task): TaskDTO | undefined { if (task === undefined || task === null || (!CustomTask.is(task) && !ContributedTask.is(task))) { return undefined; } @@ -327,16 +327,19 @@ namespace TaskDTO { return result; } - export function to(task: TaskDTO, workspace: IWorkspaceContextService, executeOnly: boolean): ContributedTask { + export function to(task: TaskDTO, workspace: IWorkspaceContextService, executeOnly: boolean): ContributedTask | undefined { if (typeof task.name !== 'string') { return undefined; } - let command: CommandConfiguration; - if (ShellExecutionDTO.is(task.execution)) { - command = ShellExecutionDTO.to(task.execution); - } else if (ProcessExecutionDTO.is(task.execution)) { - command = ProcessExecutionDTO.to(task.execution); + let command: CommandConfiguration | undefined; + if (task.execution) { + if (ShellExecutionDTO.is(task.execution)) { + command = ShellExecutionDTO.to(task.execution); + } else if (ProcessExecutionDTO.is(task.execution)) { + command = ProcessExecutionDTO.to(task.execution); + } } + if (!command) { return undefined; } @@ -371,7 +374,7 @@ namespace TaskFilterDTO { export function from(value: TaskFilter): TaskFilterDTO { return value; } - export function to(value: TaskFilterDTO): TaskFilter { + export function to(value: TaskFilterDTO | undefined): TaskFilter | undefined { return value; } } @@ -392,13 +395,13 @@ export class MainThreadTask implements MainThreadTaskShape { this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTask); this._providers = new Map(); this._taskService.onDidStateChange((event: TaskEvent) => { - let task = event.__task; + const task = event.__task!; if (event.kind === TaskEventKind.Start) { this._proxy.$onDidStartTask(TaskExecutionDTO.from(task.getTaskExecution())); } else if (event.kind === TaskEventKind.ProcessStarted) { - this._proxy.$onDidStartTaskProcess(TaskProcessStartedDTO.from(task.getTaskExecution(), event.processId)); + this._proxy.$onDidStartTaskProcess(TaskProcessStartedDTO.from(task.getTaskExecution(), event.processId!)); } else if (event.kind === TaskEventKind.ProcessEnded) { - this._proxy.$onDidEndTaskProcess(TaskProcessEndedDTO.from(task.getTaskExecution(), event.exitCode)); + this._proxy.$onDidEndTaskProcess(TaskProcessEndedDTO.from(task.getTaskExecution(), event.exitCode!)); } else if (event.kind === TaskEventKind.End) { this._proxy.$OnDidEndTask(TaskExecutionDTO.from(task.getTaskExecution())); } @@ -534,8 +537,8 @@ export class MainThreadTask implements MainThreadTaskShape { }); return new Promise((resolve, reject) => { this._configurationResolverService.resolveWithInteraction(workspaceFolder, partiallyResolvedVars, 'tasks').then(resolvedVars => { - let result = { - process: undefined as string, + let result: ResolvedVariables = { + process: undefined, variables: new Map() }; for (let i = 0; i < partiallyResolvedVars.length; i++) { diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 3dc5bb08a89..3664541f73f 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -335,12 +335,12 @@ export interface MainThreadMessageServiceShape extends IDisposable { export interface MainThreadOutputServiceShape extends IDisposable { $register(label: string, log: boolean, file?: UriComponents): Promise; - $append(channelId: string, value: string): Promise; - $update(channelId: string): Promise; - $clear(channelId: string, till: number): Promise; - $reveal(channelId: string, preserveFocus: boolean): Promise; - $close(channelId: string): Promise; - $dispose(channelId: string): Promise; + $append(channelId: string, value: string): Promise | undefined; + $update(channelId: string): Promise | undefined; + $clear(channelId: string, till: number): Promise | undefined; + $reveal(channelId: string, preserveFocus: boolean): Promise | undefined; + $close(channelId: string): Promise | undefined; + $dispose(channelId: string): Promise | undefined; } export interface MainThreadProgressShape extends IDisposable { @@ -1036,7 +1036,7 @@ export interface ExtHostDebugServiceShape { $provideDebugAdapter(handle: number, session: IDebugSessionDto): Promise; $acceptDebugSessionStarted(session: IDebugSessionDto): void; $acceptDebugSessionTerminated(session: IDebugSessionDto): void; - $acceptDebugSessionActiveChanged(session: IDebugSessionDto): void; + $acceptDebugSessionActiveChanged(session: IDebugSessionDto | undefined): void; $acceptDebugSessionCustomEvent(session: IDebugSessionDto, event: any): void; $acceptBreakpointsDelta(delta: IBreakpointsDeltaDto): void; } diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index 31a45f7dd27..c8b50085a15 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -601,7 +601,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } } - public $acceptDebugSessionActiveChanged(sessionDto: IDebugSessionDto): void { + public $acceptDebugSessionActiveChanged(sessionDto: IDebugSessionDto | undefined): void { this._activeDebugSession = sessionDto ? this.getSession(sessionDto) : undefined; this._onDidChangeActiveDebugSession.fire(this._activeDebugSession); diff --git a/src/vs/workbench/api/shared/tasks.ts b/src/vs/workbench/api/shared/tasks.ts index 0a1d3b6535b..e260f14f1f5 100644 --- a/src/vs/workbench/api/shared/tasks.ts +++ b/src/vs/workbench/api/shared/tasks.ts @@ -79,16 +79,16 @@ export interface TaskHandleDTO { export interface TaskDTO { _id: string; - name: string; - execution: ProcessExecutionDTO | ShellExecutionDTO; + name?: string; + execution?: ProcessExecutionDTO | ShellExecutionDTO; definition: TaskDefinitionDTO; - isBackground: boolean; + isBackground?: boolean; source: TaskSourceDTO; group?: string; - presentationOptions: TaskPresentationOptionsDTO; + presentationOptions?: TaskPresentationOptionsDTO; problemMatchers: string[]; hasDefinedMatchers: boolean; - runOptions: RunOptionsDTO; + runOptions?: RunOptionsDTO; } export interface TaskSetDTO { diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index 7a34a6e28f2..5b88039697f 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -586,7 +586,7 @@ export interface IConfigurationManager { getLaunches(): ReadonlyArray; - getLaunch(workspaceUri: uri): ILaunch | undefined; + getLaunch(workspaceUri: uri | undefined): ILaunch | undefined; /** * Allows to register on change of selected debug configuration. @@ -784,7 +784,7 @@ export interface IDebugService { * Returns true if the start debugging was successfull. For compound launches, all configurations have to start successfuly for it to return success. * On errors the startDebugging will throw an error, however some error and cancelations are handled and in that case will simply return false. */ - startDebugging(launch: ILaunch, configOrName?: IConfig | string, noDebug?: boolean): Promise; + startDebugging(launch: ILaunch | undefined, configOrName?: IConfig | string, noDebug?: boolean): Promise; /** * Restarts a session or creates a new one if there is no active session. diff --git a/src/vs/workbench/contrib/debug/electron-browser/debugConfigurationManager.ts b/src/vs/workbench/contrib/debug/electron-browser/debugConfigurationManager.ts index 4fda9f76074..2503788ccb6 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/debugConfigurationManager.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/debugConfigurationManager.ts @@ -337,7 +337,7 @@ export class ConfigurationManager implements IConfigurationManager { return this.launches; } - public getLaunch(workspaceUri: uri): ILaunch { + public getLaunch(workspaceUri: uri | undefined): ILaunch { if (!uri.isUri(workspaceUri)) { return undefined; } diff --git a/src/vs/workbench/contrib/debug/electron-browser/debugService.ts b/src/vs/workbench/contrib/debug/electron-browser/debugService.ts index 4828acaa6eb..d8ce6c42a77 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/debugService.ts @@ -255,7 +255,7 @@ export class DebugService implements IDebugService { * main entry point * properly manages compounds, checks for errors and handles the initializing state. */ - startDebugging(launch: ILaunch, configOrName?: IConfig | string, noDebug = false, unresolvedConfig?: IConfig, ): Promise { + startDebugging(launch: ILaunch | undefined, configOrName?: IConfig | string, noDebug = false, unresolvedConfig?: IConfig, ): Promise { this.startInitializingState(); // make sure to save all files and that the configuration is up to date diff --git a/src/vs/workbench/contrib/tasks/common/taskService.ts b/src/vs/workbench/contrib/tasks/common/taskService.ts index 48cc70b770c..8e24623e7eb 100644 --- a/src/vs/workbench/contrib/tasks/common/taskService.ts +++ b/src/vs/workbench/contrib/tasks/common/taskService.ts @@ -57,7 +57,7 @@ export interface ITaskService { configureAction(): Action; build(): Promise; runTest(): Promise; - run(task: Task, options?: ProblemMatcherRunOptions): Promise; + run(task: Task | undefined, options?: ProblemMatcherRunOptions): Promise; inTerminal(): boolean; isActive(): Promise; getActiveTasks(): Promise; diff --git a/src/vs/workbench/contrib/tasks/common/tasks.ts b/src/vs/workbench/contrib/tasks/common/tasks.ts index 1b6177ee838..46612113bb6 100644 --- a/src/vs/workbench/contrib/tasks/common/tasks.ts +++ b/src/vs/workbench/contrib/tasks/common/tasks.ts @@ -350,7 +350,7 @@ export interface WorkspaceTaskSource extends BaseTaskSource { export interface ExtensionTaskSource extends BaseTaskSource { readonly kind: 'extension'; - readonly extension: string; + readonly extension?: string; readonly scope: TaskScope; readonly workspaceFolder: IWorkspaceFolder | undefined; } diff --git a/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts index 641dccb3fdb..1260acdd106 100644 --- a/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts @@ -852,7 +852,7 @@ class TaskService extends Disposable implements ITaskService { }); } - public run(task: Task, options?: ProblemMatcherRunOptions): Promise { + public run(task: Task | undefined, options?: ProblemMatcherRunOptions): Promise { return this.getGroupedTasks().then((grouped) => { if (!task) { throw new TaskError(Severity.Info, nls.localize('TaskServer.noTask', 'Requested task {0} to execute not found.', task.configurationProperties.name), TaskErrors.TaskNotFound); From 40c4d2b7433a86ac16f792ece0405122a2892c0a Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 21:25:44 -0800 Subject: [PATCH 077/207] Strict null check work for extHostTypes --- src/vs/editor/common/modes.ts | 2 +- .../wordHighlighter/wordHighlighter.ts | 2 +- src/vs/monaco.d.ts | 2 +- src/vs/workbench/api/node/extHost.api.impl.ts | 12 ++-- .../workbench/api/node/extHostDiagnostics.ts | 9 +-- .../workbench/api/node/extHostTextEditors.ts | 2 +- .../api/node/extHostTypeConverters.ts | 71 +++++++++++-------- src/vs/workbench/api/node/extHostTypes.ts | 18 ++--- 8 files changed, 65 insertions(+), 53 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 4bad77f0289..d04c849653a 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -667,7 +667,7 @@ export interface DocumentHighlight { /** * The highlight kind, default is [text](#DocumentHighlightKind.Text). */ - kind: DocumentHighlightKind; + kind?: DocumentHighlightKind; } /** * The document highlight provider interface defines the contract between extensions and diff --git a/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts b/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts index 036f26483fb..2215346fca3 100644 --- a/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts +++ b/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts @@ -415,7 +415,7 @@ class WordHighlighter { this._hasWordHighlights.set(this.hasDecorations()); } - private static _getDecorationOptions(kind: DocumentHighlightKind): ModelDecorationOptions { + private static _getDecorationOptions(kind: DocumentHighlightKind | undefined): ModelDecorationOptions { if (kind === DocumentHighlightKind.Write) { return this._WRITE_OPTIONS; } else if (kind === DocumentHighlightKind.Text) { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 35793ae2e20..18a83b0c2b4 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4968,7 +4968,7 @@ declare namespace monaco.languages { /** * The highlight kind, default is [text](#DocumentHighlightKind.Text). */ - kind: DocumentHighlightKind; + kind?: DocumentHighlightKind; } /** diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 2b6cd0333da..ef5ac86ac9b 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -219,7 +219,7 @@ export function createApiFactory( }); }, registerDiffInformationCommand: proposedApiFunction(extension, (id: string, callback: (diff: vscode.LineChange[], ...args: any[]) => any, thisArg?: any): vscode.Disposable => { - return extHostCommands.registerCommand(true, id, async (...args: any[]) => { + return extHostCommands.registerCommand(true, id, async (...args: any[]): Promise => { let activeTextEditor = extHostEditors.getActiveTextEditor(); if (!activeTextEditor) { console.warn('Cannot execute ' + id + ' because there is no active text editor.'); @@ -242,9 +242,9 @@ export function createApiFactory( const env: typeof vscode.env = Object.freeze({ get machineId() { return initData.telemetryInfo.machineId; }, get sessionId() { return initData.telemetryInfo.sessionId; }, - get language() { return platform.language; }, + get language() { return platform.language!; }, get appName() { return product.nameLong; }, - get appRoot() { return initData.environment.appRoot.fsPath; }, + get appRoot() { return initData.environment.appRoot!.fsPath; }, get logLevel() { checkProposedApiEnabled(extension); return typeConverters.LogLevel.to(extHostLogService.getLevel()); @@ -263,8 +263,8 @@ export function createApiFactory( // namespace: extensions const extensions: typeof vscode.extensions = { - getExtension(extensionId: string): Extension { - let desc = extensionRegistry.getExtensionDescription(extensionId); + getExtension(extensionId: string): Extension | undefined { + const desc = extensionRegistry.getExtensionDescription(extensionId); if (desc) { return new Extension(extensionService, desc); } @@ -443,7 +443,7 @@ export function createApiFactory( return extHostMessageService.showMessage(extension, Severity.Error, message, first, rest); }, showQuickPick(items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken): any { - return extHostQuickOpen.showQuickPick(items, extension.enableProposedApi, options, token); + return extHostQuickOpen.showQuickPick(items, !!extension.enableProposedApi, options, token); }, showWorkspaceFolderPick(options: vscode.WorkspaceFolderPickOptions) { return extHostQuickOpen.showWorkspaceFolderPick(options); diff --git a/src/vs/workbench/api/node/extHostDiagnostics.ts b/src/vs/workbench/api/node/extHostDiagnostics.ts index 3fdf6edf07e..229ea037c4d 100644 --- a/src/vs/workbench/api/node/extHostDiagnostics.ts +++ b/src/vs/workbench/api/node/extHostDiagnostics.ts @@ -60,7 +60,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection { // the actual implementation for #set this._checkDisposed(); - let toSync: vscode.Uri[]; + let toSync: vscode.Uri[] = []; let hasChanged = true; if (first instanceof URI) { @@ -81,7 +81,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection { } else if (Array.isArray(first)) { // update many rows toSync = []; - let lastUri: vscode.Uri; + let lastUri: vscode.Uri | undefined; // ensure stable-sort mergeSort(first, DiagnosticCollection._compareIndexedTuplesByUri); @@ -255,7 +255,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape { this._proxy = mainContext.getProxy(MainContext.MainThreadDiagnostics); } - createDiagnosticCollection(name: string): vscode.DiagnosticCollection { + createDiagnosticCollection(name?: string): vscode.DiagnosticCollection { let { _collections, _proxy, _onDidChangeDiagnostics } = this; let owner: string; if (!name) { @@ -272,7 +272,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape { const result = new class extends DiagnosticCollection { constructor() { - super(name, owner, ExtHostDiagnostics._maxDiagnosticsPerFile, _proxy, _onDidChangeDiagnostics); + super(name!, owner, ExtHostDiagnostics._maxDiagnosticsPerFile, _proxy, _onDidChangeDiagnostics); _collections.set(owner, this); } dispose() { @@ -286,6 +286,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape { getDiagnostics(resource: vscode.Uri): vscode.Diagnostic[]; getDiagnostics(): [vscode.Uri, vscode.Diagnostic[]][]; + getDiagnostics(resource?: vscode.Uri): vscode.Diagnostic[] | [vscode.Uri, vscode.Diagnostic[]][]; getDiagnostics(resource?: vscode.Uri): vscode.Diagnostic[] | [vscode.Uri, vscode.Diagnostic[]][] { if (resource) { return this._getDiagnostics(resource); diff --git a/src/vs/workbench/api/node/extHostTextEditors.ts b/src/vs/workbench/api/node/extHostTextEditors.ts index 7843bd63662..8889172ad67 100644 --- a/src/vs/workbench/api/node/extHostTextEditors.ts +++ b/src/vs/workbench/api/node/extHostTextEditors.ts @@ -42,7 +42,7 @@ export class ExtHostEditors implements ExtHostEditorsShape { this._extHostDocumentsAndEditors.onDidChangeActiveTextEditor(e => this._onDidChangeActiveTextEditor.fire(e)); } - getActiveTextEditor(): ExtHostTextEditor { + getActiveTextEditor(): ExtHostTextEditor | undefined { return this._extHostDocumentsAndEditors.activeEditor(); } diff --git a/src/vs/workbench/api/node/extHostTypeConverters.ts b/src/vs/workbench/api/node/extHostTypeConverters.ts index 3cc5c1cb05b..61e6846831b 100644 --- a/src/vs/workbench/api/node/extHostTypeConverters.ts +++ b/src/vs/workbench/api/node/extHostTypeConverters.ts @@ -28,6 +28,7 @@ import * as marked from 'vs/base/common/marked/marked'; import { parse } from 'vs/base/common/marshalling'; import { cloneAndChange } from 'vs/base/common/objects'; import { LogLevel as _MainLogLevel } from 'vs/platform/log/common/log'; +import { coalesce } from 'vs/base/common/arrays'; export interface PositionLike { line: number; @@ -64,7 +65,10 @@ export namespace Selection { } export namespace Range { - export function from(range: RangeLike): IRange { + export function from(range: undefined): undefined; + export function from(range: RangeLike): IRange; + export function from(range: RangeLike | undefined): IRange | undefined; + export function from(range: RangeLike | undefined): IRange | undefined { if (!range) { return undefined; } @@ -77,7 +81,10 @@ export namespace Range { }; } - export function to(range: IRange): types.Range { + export function to(range: undefined): types.Range; + export function to(range: IRange): types.Range; + export function to(range: IRange | undefined): types.Range | undefined; + export function to(range: IRange | undefined): types.Range | undefined { if (!range) { return undefined; } @@ -96,7 +103,7 @@ export namespace Position { } export namespace DiagnosticTag { - export function from(value: vscode.DiagnosticTag): MarkerTag { + export function from(value: vscode.DiagnosticTag): MarkerTag | undefined { switch (value) { case types.DiagnosticTag.Unnecessary: return MarkerTag.Unnecessary; @@ -114,7 +121,7 @@ export namespace Diagnostic { code: isString(value.code) || isNumber(value.code) ? String(value.code) : undefined, severity: DiagnosticSeverity.from(value.severity), relatedInformation: value.relatedInformation && value.relatedInformation.map(DiagnosticRelatedInformation.from), - tags: Array.isArray(value.tags) ? value.tags.map(DiagnosticTag.from) : undefined, + tags: Array.isArray(value.tags) ? coalesce(value.tags.map(DiagnosticTag.from)) : undefined, }; } } @@ -175,7 +182,7 @@ export namespace ViewColumn { return ACTIVE_GROUP; // default is always the active group } - export function to(position?: EditorViewColumn): vscode.ViewColumn { + export function to(position?: EditorViewColumn): vscode.ViewColumn | undefined { if (typeof position === 'number' && position >= 0) { return position + 1; // adjust to index (ViewColumn.ONE => 1) } @@ -226,13 +233,15 @@ export namespace MarkdownString { } // extract uris into a separate object - res.uris = Object.create(null); + const resUris: { [href: string]: UriComponents } = Object.create(null); + res.uris = resUris; + let renderer = new marked.Renderer(); renderer.image = renderer.link = (href: string): string => { try { let uri = URI.parse(href, true); - uri = uri.with({ query: _uriMassage(uri.query, res.uris) }); - res.uris[href] = uri; + uri = uri.with({ query: _uriMassage(uri.query, resUris) }); + resUris[href] = uri; } catch (e) { // ignore } @@ -284,10 +293,12 @@ export namespace MarkdownString { export function fromRangeOrRangeWithMessage(ranges: vscode.Range[] | vscode.DecorationOptions[]): IDecorationOptions[] { if (isDecorationOptionsArr(ranges)) { - return ranges.map(r => { + return ranges.map((r): IDecorationOptions => { return { range: Range.from(r.range), - hoverMessage: Array.isArray(r.hoverMessage) ? MarkdownString.fromMany(r.hoverMessage) : r.hoverMessage && MarkdownString.from(r.hoverMessage), + hoverMessage: Array.isArray(r.hoverMessage) + ? MarkdownString.fromMany(r.hoverMessage) + : (r.hoverMessage ? MarkdownString.from(r.hoverMessage) : undefined), renderOptions: /* URI vs Uri */r.renderOptions }; }); @@ -318,7 +329,7 @@ export namespace ThemableDecorationAttachmentRenderOptions { } return { contentText: options.contentText, - contentIconPath: pathOrURIToURI(options.contentIconPath), + contentIconPath: options.contentIconPath ? pathOrURIToURI(options.contentIconPath) : undefined, border: options.border, borderColor: options.borderColor, fontStyle: options.fontStyle, @@ -357,11 +368,11 @@ export namespace ThemableDecorationRenderOptions { color: options.color, opacity: options.opacity, letterSpacing: options.letterSpacing, - gutterIconPath: pathOrURIToURI(options.gutterIconPath), + gutterIconPath: options.gutterIconPath ? pathOrURIToURI(options.gutterIconPath) : undefined, gutterIconSize: options.gutterIconSize, overviewRulerColor: options.overviewRulerColor, - before: ThemableDecorationAttachmentRenderOptions.from(options.before), - after: ThemableDecorationAttachmentRenderOptions.from(options.after), + before: options.before ? ThemableDecorationAttachmentRenderOptions.from(options.before) : undefined, + after: options.after ? ThemableDecorationAttachmentRenderOptions.from(options.after) : undefined, }; } } @@ -388,10 +399,10 @@ export namespace DecorationRenderOptions { export function from(options: vscode.DecorationRenderOptions): IDecorationRenderOptions { return { isWholeLine: options.isWholeLine, - rangeBehavior: DecorationRangeBehavior.from(options.rangeBehavior), + rangeBehavior: options.rangeBehavior ? DecorationRangeBehavior.from(options.rangeBehavior) : undefined, overviewRulerLane: options.overviewRulerLane, - light: ThemableDecorationRenderOptions.from(options.light), - dark: ThemableDecorationRenderOptions.from(options.dark), + light: options.light ? ThemableDecorationRenderOptions.from(options.light) : undefined, + dark: options.dark ? ThemableDecorationRenderOptions.from(options.dark) : undefined, backgroundColor: options.backgroundColor, outline: options.outline, @@ -411,11 +422,11 @@ export namespace DecorationRenderOptions { color: options.color, opacity: options.opacity, letterSpacing: options.letterSpacing, - gutterIconPath: pathOrURIToURI(options.gutterIconPath), + gutterIconPath: options.gutterIconPath ? pathOrURIToURI(options.gutterIconPath) : undefined, gutterIconSize: options.gutterIconSize, overviewRulerColor: options.overviewRulerColor, - before: ThemableDecorationAttachmentRenderOptions.from(options.before), - after: ThemableDecorationAttachmentRenderOptions.from(options.after), + before: options.before ? ThemableDecorationAttachmentRenderOptions.from(options.before) : undefined, + after: options.after ? ThemableDecorationAttachmentRenderOptions.from(options.after) : undefined, }; } } @@ -432,7 +443,7 @@ export namespace TextEdit { export function to(edit: modes.TextEdit): types.TextEdit { const result = new types.TextEdit(Range.to(edit.range), edit.text); - result.newEol = EndOfLine.to(edit.eol); + result.newEol = typeof edit.eol === 'undefined' ? undefined : EndOfLine.to(edit.eol); return result; } } @@ -724,9 +735,9 @@ export namespace CompletionItem { result.preselect = suggestion.preselect; result.commitCharacters = suggestion.commitCharacters; result.range = Range.to(suggestion.range); - result.keepWhitespace = Boolean(suggestion.insertTextRules & modes.CompletionItemInsertTextRule.KeepWhitespace); + result.keepWhitespace = typeof suggestion.insertTextRules === 'undefined' ? false : Boolean(suggestion.insertTextRules & modes.CompletionItemInsertTextRule.KeepWhitespace); // 'inserText'-logic - if (suggestion.insertTextRules & modes.CompletionItemInsertTextRule.InsertAsSnippet) { + if (typeof suggestion.insertTextRules !== 'undefined' && suggestion.insertTextRules & modes.CompletionItemInsertTextRule.InsertAsSnippet) { result.insertText = new types.SnippetString(suggestion.insertText); } else { result.insertText = suggestion.insertText; @@ -742,7 +753,7 @@ export namespace ParameterInformation { export function from(info: types.ParameterInformation): modes.ParameterInformation { return { label: info.label, - documentation: MarkdownString.fromStrict(info.documentation) + documentation: info.documentation ? MarkdownString.fromStrict(info.documentation) : undefined }; } export function to(info: modes.ParameterInformation): types.ParameterInformation { @@ -758,7 +769,7 @@ export namespace SignatureInformation { export function from(info: types.SignatureInformation): modes.SignatureInformation { return { label: info.label, - documentation: MarkdownString.fromStrict(info.documentation), + documentation: info.documentation ? MarkdownString.fromStrict(info.documentation) : undefined, parameters: info.parameters && info.parameters.map(ParameterInformation.from) }; } @@ -877,7 +888,7 @@ export namespace TextDocumentSaveReason { export namespace EndOfLine { - export function from(eol: vscode.EndOfLine): EndOfLineSequence { + export function from(eol: vscode.EndOfLine): EndOfLineSequence | undefined { if (eol === types.EndOfLine.CRLF) { return EndOfLineSequence.CRLF; } else if (eol === types.EndOfLine.LF) { @@ -886,7 +897,7 @@ export namespace EndOfLine { return undefined; } - export function to(eol: EndOfLineSequence): vscode.EndOfLine { + export function to(eol: EndOfLineSequence): vscode.EndOfLine | undefined { if (eol === EndOfLineSequence.CRLF) { return types.EndOfLine.CRLF; } else if (eol === EndOfLineSequence.LF) { @@ -897,7 +908,7 @@ export namespace EndOfLine { } export namespace ProgressLocation { - export function from(loc: vscode.ProgressLocation): MainProgressLocation { + export function from(loc: vscode.ProgressLocation): MainProgressLocation | undefined { switch (loc) { case types.ProgressLocation.SourceControl: return MainProgressLocation.Scm; case types.ProgressLocation.Window: return MainProgressLocation.Window; @@ -935,7 +946,7 @@ export namespace FoldingRangeKind { export namespace TextEditorOptions { - export function from(options?: vscode.TextDocumentShowOptions): ITextEditorOptions { + export function from(options?: vscode.TextDocumentShowOptions): ITextEditorOptions | undefined { if (options) { return { pinned: typeof options.preview === 'boolean' ? !options.preview : undefined, @@ -975,7 +986,7 @@ export namespace GlobPattern { export namespace LanguageSelector { - export function from(selector: vscode.DocumentSelector): languageSelector.LanguageSelector { + export function from(selector: vscode.DocumentSelector): languageSelector.LanguageSelector | undefined { if (!selector) { return undefined; } else if (Array.isArray(selector)) { diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index 950d8cee119..1e6a66f3096 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -1166,8 +1166,8 @@ export enum CompletionTriggerKind { } export interface CompletionContext { - triggerKind: CompletionTriggerKind; - triggerCharacter: string; + readonly triggerKind: CompletionTriggerKind; + readonly triggerCharacter?: string; } export enum CompletionItemKind { @@ -1202,15 +1202,15 @@ export class CompletionItem implements vscode.CompletionItem { label: string; kind: CompletionItemKind | undefined; - detail: string; - documentation: string | MarkdownString; - sortText: string; - filterText: string; - preselect: boolean; + detail?: string; + documentation?: string | MarkdownString; + sortText?: string; + filterText?: string; + preselect?: boolean; insertText: string | SnippetString; keepWhitespace?: boolean; range: Range; - commitCharacters: string[]; + commitCharacters?: string[]; textEdit: TextEdit; additionalTextEdits: TextEdit[]; command: vscode.Command; @@ -1314,7 +1314,7 @@ export enum DecorationRangeBehavior { } export namespace TextEditorSelectionChangeKind { - export function fromValue(s: string) { + export function fromValue(s: string | undefined) { switch (s) { case 'keyboard': return TextEditorSelectionChangeKind.Keyboard; case 'mouse': return TextEditorSelectionChangeKind.Mouse; From ec0a503c6ee281a9b9af94986da5db80af63641e Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Feb 2019 21:26:16 -0800 Subject: [PATCH 078/207] Strict null work for terminalActions --- .../terminal/electron-browser/terminalActions.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalActions.ts index 67965756849..a54c1b7758d 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalActions.ts @@ -137,7 +137,7 @@ export class QuickKillTerminalAction extends Action { if (instance) { instance.dispose(true); } - return Promise.resolve(timeout(50)).then(result => this.quickOpenService.show(TERMINAL_PICKER_PREFIX, null)); + return Promise.resolve(timeout(50)).then(result => this.quickOpenService.show(TERMINAL_PICKER_PREFIX, undefined)); } } @@ -291,7 +291,7 @@ export class SendSequenceTerminalCommand extends Command { const workspaceContextService = accessor.get(IWorkspaceContextService); const historyService = accessor.get(IHistoryService); const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(Schemas.file); - const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) : null; + const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) || undefined : undefined; const resolvedText = configurationResolverService.resolve(lastActiveWorkspaceRoot, args.text); terminalInstance.sendText(resolvedText, false); } @@ -324,7 +324,7 @@ export class CreateNewTerminalAction extends Action { } } - let instancePromise: Promise; + let instancePromise: Promise; if (folders.length <= 1) { // Allow terminal service to handle the path when there is only a // single root @@ -651,7 +651,7 @@ export class RunSelectedTextInTerminalAction extends Action { return Promise.resolve(undefined); } let editor = this.codeEditorService.getFocusedCodeEditor(); - if (!editor) { + if (!editor || !editor.hasModel()) { return Promise.resolve(undefined); } let selection = editor.getSelection(); @@ -687,7 +687,7 @@ export class RunActiveFileInTerminalAction extends Action { return Promise.resolve(undefined); } const editor = this.codeEditorService.getActiveCodeEditor(); - if (!editor) { + if (!editor || !editor.hasModel()) { return Promise.resolve(undefined); } const uri = editor.getModel().uri; @@ -1050,7 +1050,7 @@ export class QuickOpenTermAction extends Action { } public run(): Promise { - return this.quickOpenService.show(TERMINAL_PICKER_PREFIX, null); + return this.quickOpenService.show(TERMINAL_PICKER_PREFIX, undefined); } } @@ -1071,7 +1071,7 @@ export class RenameTerminalQuickOpenAction extends RenameTerminalAction { super.run(this.terminal) // This timeout is needed to make sure the previous quickOpen has time to close before we show the next one .then(() => timeout(50)) - .then(result => this.quickOpenService.show(TERMINAL_PICKER_PREFIX, null)); + .then(result => this.quickOpenService.show(TERMINAL_PICKER_PREFIX, undefined)); return Promise.resolve(null); } } From 980eb3e504e96a62ee062e37c7c3691f865a5551 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 8 Feb 2019 17:15:58 -0800 Subject: [PATCH 079/207] Strict null work in debug --- .../workbench/contrib/debug/common/debug.ts | 10 +++---- .../contrib/debug/common/debugModel.ts | 26 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index 5b88039697f..d1d5e2ba2fe 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -244,7 +244,7 @@ export interface IThread extends ITreeElement { /** * Information about the exception if an 'exception' stopped event raised and DA supports the 'exceptionInfo' request, otherwise null. */ - readonly exceptionInfo: Promise; + readonly exceptionInfo: Promise; /** * Gets the callstack if it has already been received from the debug @@ -321,7 +321,7 @@ export interface IBaseBreakpoint extends IEnablement { readonly hitCondition: string; readonly logMessage: string; readonly verified: boolean; - readonly idFromAdapter: number; + readonly idFromAdapter: number | undefined; } export interface IBreakpoint extends IBaseBreakpoint { @@ -330,7 +330,7 @@ export interface IBreakpoint extends IBaseBreakpoint { readonly endLineNumber?: number; readonly column: number; readonly endColumn?: number; - readonly message: string; + readonly message?: string; readonly adapterData: any; } @@ -346,7 +346,7 @@ export interface IExceptionBreakpoint extends IEnablement { export interface IExceptionInfo { readonly id?: string; readonly description?: string; - readonly breakMode: string; + readonly breakMode: string | null; readonly details?: DebugProtocol.ExceptionDetails; } @@ -394,7 +394,7 @@ export interface IDebugModel extends ITreeElement { onDidChangeBreakpoints: Event; onDidChangeCallStack: Event; - onDidChangeWatchExpressions: Event; + onDidChangeWatchExpressions: Event; } /** diff --git a/src/vs/workbench/contrib/debug/common/debugModel.ts b/src/vs/workbench/contrib/debug/common/debugModel.ts index 35172eda586..54afae5c265 100644 --- a/src/vs/workbench/contrib/debug/common/debugModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugModel.ts @@ -95,7 +95,7 @@ export class ExpressionContainer implements IExpressionContainer { public valueChanged: boolean; private _value: string; - protected children: Promise; + protected children?: Promise; constructor( protected session: IDebugSession, @@ -187,7 +187,7 @@ export class ExpressionContainer implements IExpressionContainer { set value(value: string) { this._value = value; - this.valueChanged = ExpressionContainer.allValues.get(this.getId()) && + this.valueChanged = !!ExpressionContainer.allValues.get(this.getId()) && ExpressionContainer.allValues.get(this.getId()) !== Expression.DEFAULT_VALUE && ExpressionContainer.allValues.get(this.getId()) !== value; ExpressionContainer.allValues.set(this.getId(), value); } @@ -259,7 +259,7 @@ export class Variable extends ExpressionContainer implements IExpression { namedVariables: number, indexedVariables: number, public presentationHint: DebugProtocol.VariablePresentationHint, - public type: string | null = null, + public type: string | undefined = undefined, public available = true, startOfVariables = 0 ) { @@ -308,7 +308,7 @@ export class Scope extends ExpressionContainer implements IScope { export class StackFrame implements IStackFrame { - private scopes: Promise; + private scopes: Promise | null; constructor( public thread: IThread, @@ -367,7 +367,7 @@ export class StackFrame implements IStackFrame { } const scopesContainingRange = scopes.filter(scope => scope.range && Range.containsRange(scope.range, range)) - .sort((first, second) => (first.range.endLineNumber - first.range.startLineNumber) - (second.range.endLineNumber - second.range.startLineNumber)); + .sort((first, second) => (first.range!.endLineNumber - first.range!.startLineNumber) - (second.range!.endLineNumber - second.range!.startLineNumber)); return scopesContainingRange.length ? scopesContainingRange : scopes; }); } @@ -564,7 +564,7 @@ export class BaseBreakpoint extends Enablement implements IBaseBreakpoint { return data ? data.verified : true; } - get idFromAdapter(): number { + get idFromAdapter(): number | undefined { const data = this.getSessionData(); return data ? data.id : undefined; } @@ -617,7 +617,7 @@ export class Breakpoint extends BaseBreakpoint implements IBreakpoint { return data && typeof data.column === 'number' && typeof this._column === 'number' ? data.column : this._column; } - get message(): string { + get message(): string | undefined { const data = this.getSessionData(); if (!data) { return undefined; @@ -634,12 +634,12 @@ export class Breakpoint extends BaseBreakpoint implements IBreakpoint { return data && data.source && data.source.adapterData ? data.source.adapterData : this._adapterData; } - get endLineNumber(): number { + get endLineNumber(): number | undefined { const data = this.getSessionData(); return data ? data.endLine : undefined; } - get endColumn(): number { + get endColumn(): number | undefined { const data = this.getSessionData(); return data ? data.endColumn : undefined; } @@ -743,9 +743,9 @@ export class DebugModel implements IDebugModel { private toDispose: lifecycle.IDisposable[]; private schedulers = new Map(); private breakpointsSessionId: string; - private readonly _onDidChangeBreakpoints: Emitter; + private readonly _onDidChangeBreakpoints: Emitter; private readonly _onDidChangeCallStack: Emitter; - private readonly _onDidChangeWatchExpressions: Emitter; + private readonly _onDidChangeWatchExpressions: Emitter; constructor( private breakpoints: Breakpoint[], @@ -797,7 +797,7 @@ export class DebugModel implements IDebugModel { return this._onDidChangeCallStack.event; } - get onDidChangeWatchExpressions(): Event { + get onDidChangeWatchExpressions(): Event { return this._onDidChangeWatchExpressions.event; } @@ -830,7 +830,7 @@ export class DebugModel implements IDebugModel { }, 420)); } - this.schedulers.get(thread.getId()).schedule(); + this.schedulers.get(thread.getId())!.schedule(); this._onDidChangeCallStack.fire(); }); } From 1adf6b94f138e6f3c20a8c0e6b94387dfa2d3cf6 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Fri, 8 Feb 2019 17:28:05 -0800 Subject: [PATCH 080/207] Fix Microsoft/vscode-pull-request-github#895. Relayout comment view zone when width changes. --- .../contrib/comments/electron-browser/commentThreadWidget.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/comments/electron-browser/commentThreadWidget.ts b/src/vs/workbench/contrib/comments/electron-browser/commentThreadWidget.ts index c288cd08cc9..98ef671fa2e 100644 --- a/src/vs/workbench/contrib/comments/electron-browser/commentThreadWidget.ts +++ b/src/vs/workbench/contrib/comments/electron-browser/commentThreadWidget.ts @@ -293,6 +293,10 @@ export class ReviewZoneWidget extends ZoneWidget { } } + protected _onWidth(widthInPixel: number): void { + this._commentEditor.layout({ height: (this._commentEditor.hasWidgetFocus() ? 5 : 1) * 18, width: widthInPixel - 54 /* margin 20px * 10 + scrollbar 14px*/ }); + } + protected _doLayout(heightInPixel: number, widthInPixel: number): void { this._commentEditor.layout({ height: (this._commentEditor.hasWidgetFocus() ? 5 : 1) * 18, width: widthInPixel - 54 /* margin 20px * 10 + scrollbar 14px*/ }); } From 58fb98d4814222277d981b53add9cd00ab0bf408 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Fri, 8 Feb 2019 17:28:38 -0800 Subject: [PATCH 081/207] Dispose commen widget properly. --- .../contrib/comments/electron-browser/commentThreadWidget.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/comments/electron-browser/commentThreadWidget.ts b/src/vs/workbench/contrib/comments/electron-browser/commentThreadWidget.ts index 98ef671fa2e..e7fbb504a5e 100644 --- a/src/vs/workbench/contrib/comments/electron-browser/commentThreadWidget.ts +++ b/src/vs/workbench/contrib/comments/electron-browser/commentThreadWidget.ts @@ -358,6 +358,7 @@ export class ReviewZoneWidget extends ZoneWidget { } } else { this.dispose(); + return; } } From 0ca33fc320235115d5e64092f8186444cd7ec4c1 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sat, 9 Feb 2019 09:48:38 +0100 Subject: [PATCH 082/207] fix #67882 --- .../services/history/electron-browser/history.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/history/electron-browser/history.ts b/src/vs/workbench/services/history/electron-browser/history.ts index c9fdaa454ad..845c6a2e909 100644 --- a/src/vs/workbench/services/history/electron-browser/history.ts +++ b/src/vs/workbench/services/history/electron-browser/history.ts @@ -281,7 +281,17 @@ export class HistoryService extends Disposable implements IHistoryService { } if (lastClosedFile) { - this.editorService.openEditor({ resource: lastClosedFile.resource, options: { pinned: true, index: lastClosedFile.index } }); + this.editorService.openEditor({ resource: lastClosedFile.resource, options: { pinned: true, index: lastClosedFile.index } }).then(editor => { + + // Fix for https://github.com/Microsoft/vscode/issues/67882 + // If opening of the editor fails, make sure to try the next one + // but make sure to remove this one from the list to prevent + // endless loops. + if (!editor) { + this.recentlyClosedFiles.pop(); + this.reopenLastClosedEditor(); + } + }); } } From 5efe35145e792bc6337433f8061353256f804c93 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sat, 9 Feb 2019 15:34:34 +0100 Subject: [PATCH 083/207] fix #67946 --- .../common/editor/untitledEditorModel.ts | 10 ++- .../textfile/common/textFileService.ts | 66 +++++++++++++++---- .../electron-browser/textFileService.ts | 13 +++- .../workbench/test/workbenchTestServices.ts | 6 +- 4 files changed, 76 insertions(+), 19 deletions(-) diff --git a/src/vs/workbench/common/editor/untitledEditorModel.ts b/src/vs/workbench/common/editor/untitledEditorModel.ts index 54817b0a6b4..70cfc8c48e0 100644 --- a/src/vs/workbench/common/editor/untitledEditorModel.ts +++ b/src/vs/workbench/common/editor/untitledEditorModel.ts @@ -38,7 +38,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin constructor( private modeId: string, private resource: URI, - private hasAssociatedFilePath: boolean, + private _hasAssociatedFilePath: boolean, private initialValue: string, private preferredEncoding: string, @IModeService modeService: IModeService, @@ -56,6 +56,10 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin this.registerListeners(); } + get hasAssociatedFilePath(): boolean { + return this._hasAssociatedFilePath; + } + protected getOrCreateMode(modeService: IModeService, modeId: string, firstLineText?: string): ILanguageSelection { if (!modeId || modeId === PLAINTEXT_MODE_ID) { return modeService.createByFilepathOrFirstLine(this.resource.fsPath, firstLineText); // lookup mode via resource path if the provided modeId is unspecific @@ -145,7 +149,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin const hasBackup = !!backupTextBufferFactory; // untitled associated to file path are dirty right away as well as untitled with content - this.setDirty(this.hasAssociatedFilePath || hasBackup); + this.setDirty(this._hasAssociatedFilePath || hasBackup); let untitledContents: ITextBufferFactory; if (backupTextBufferFactory) { @@ -182,7 +186,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin // mark the untitled editor as non-dirty once its content becomes empty and we do // not have an associated path set. we never want dirty indicator in that case. - if (!this.hasAssociatedFilePath && this.textEditorModel.getLineCount() === 1 && this.textEditorModel.getLineContent(1) === '') { + if (!this._hasAssociatedFilePath && this.textEditorModel.getLineCount() === 1 && this.textEditorModel.getLineContent(1) === '') { this.setDirty(false); } diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index 2a85b26c188..6f135af2307 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -103,6 +103,8 @@ export abstract class TextFileService extends Disposable implements ITextFileSer abstract confirmSave(resources?: URI[]): Promise; + abstract confirmOverwrite(resource: URI): Promise; + private registerListeners(): void { // Lifecycle @@ -435,8 +437,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer // Untitled with associated file path don't need to prompt if (this.untitledEditorService.hasAssociatedFilePath(untitled)) { - const authority = this.windowService.getConfiguration().remoteAuthority; - targetUri = authority ? untitled.with({ scheme: REMOTE_HOST_SCHEME, authority }) : untitled.with({ scheme: Schemas.file }); + targetUri = this.untitledToAssociatedFileResource(untitled); } // Otherwise ask user @@ -473,6 +474,12 @@ export abstract class TextFileService extends Disposable implements ITextFileSer }); } + private untitledToAssociatedFileResource(untitled: URI): URI { + const authority = this.windowService.getConfiguration().remoteAuthority; + + return authority ? untitled.with({ scheme: REMOTE_HOST_SCHEME, authority }) : untitled.with({ scheme: Schemas.file }); + } + private doSaveAllFiles(resources?: URI[], options: ISaveOptions = Object.create(null)): Promise { const dirtyFileModels = this.getDirtyFileModels(Array.isArray(resources) ? resources : undefined /* Save All */) .filter(model => { @@ -560,7 +567,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer modelPromise = this.untitledEditorService.loadOrCreate({ resource }); } - return modelPromise.then(model => { + return modelPromise.then(model => { // We have a model: Use it (can be null e.g. if this file is binary and not a text file or was never opened before) if (model) { @@ -568,8 +575,13 @@ export abstract class TextFileService extends Disposable implements ITextFileSer } // Otherwise we can only copy - return this.fileService.copyFile(resource, target); - }).then(() => { + return this.fileService.copyFile(resource, target).then(() => true); + }).then(result => { + + // Return early if the operation was not running + if (!result) { + return target; + } // Revert the source return this.revert(resource).then(() => { @@ -580,30 +592,56 @@ export abstract class TextFileService extends Disposable implements ITextFileSer }); } - private doSaveTextFileAs(sourceModel: ITextFileEditorModel | UntitledEditorModel, resource: URI, target: URI, options?: ISaveOptions): Promise { + private doSaveTextFileAs(sourceModel: ITextFileEditorModel | UntitledEditorModel, resource: URI, target: URI, options?: ISaveOptions): Promise { let targetModelResolver: Promise; + let targetExists: boolean = false; // Prefer an existing model if it is already loaded for the given target resource const targetModel = this.models.get(target); if (targetModel && targetModel.isResolved()) { targetModelResolver = Promise.resolve(targetModel); + targetExists = true; } // Otherwise create the target file empty if it does not exist already and resolve it from there else { - targetModelResolver = this.fileService.resolveFile(target).then(stat => stat, () => null).then(stat => stat || this.fileService.updateContent(target, '')).then(stat => { - return this.models.loadOrCreate(target); - }); + targetModelResolver = this.fileService.existsFile(target).then(exists => { + targetExists = exists; + + // create target model adhoc if file does not exist yet + if (!targetExists) { + return this.fileService.updateContent(target, ''); + } + + return undefined; + }).then(() => this.models.loadOrCreate(target)); } return targetModelResolver.then(targetModel => { - // take over encoding and model value from source model - targetModel.updatePreferredEncoding(sourceModel.getEncoding()); - this.modelService.updateModel(targetModel.textEditorModel, createTextBufferFactoryFromSnapshot(sourceModel.createSnapshot())); + // Confirm to overwrite if we have an untitled file with associated file where + // the file actually exists on disk and we are instructed to save to that file + // path. This can happen if the file was created after the untitled file was opened. + // See https://github.com/Microsoft/vscode/issues/67946 + let confirmWrite: Promise; + if (sourceModel instanceof UntitledEditorModel && sourceModel.hasAssociatedFilePath && targetExists && isEqual(target, this.untitledToAssociatedFileResource(sourceModel.getResource()))) { + confirmWrite = this.confirmOverwrite(target); + } else { + confirmWrite = Promise.resolve(true); + } - // save model - return targetModel.save(options); + return confirmWrite.then(write => { + if (!write) { + return false; + } + + // take over encoding and model value from source model + targetModel.updatePreferredEncoding(sourceModel.getEncoding()); + this.modelService.updateModel(targetModel.textEditorModel, createTextBufferFactoryFromSnapshot(sourceModel.createSnapshot())); + + // save model + return targetModel.save(options).then(() => true); + }); }, error => { // binary model: delete the file and run the operation again diff --git a/src/vs/workbench/services/textfile/electron-browser/textFileService.ts b/src/vs/workbench/services/textfile/electron-browser/textFileService.ts index ad1f19a9500..51d4869b322 100644 --- a/src/vs/workbench/services/textfile/electron-browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/textFileService.ts @@ -26,7 +26,7 @@ import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IModelService } from 'vs/editor/common/services/modelService'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; -import { getConfirmMessage, IDialogService, ISaveDialogOptions, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { getConfirmMessage, IDialogService, ISaveDialogOptions, IFileDialogService, IConfirmation } from 'vs/platform/dialogs/common/dialogs'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { coalesce } from 'vs/base/common/arrays'; @@ -103,6 +103,17 @@ export class TextFileService extends AbstractTextFileService { }); } + confirmOverwrite(resource: URI): Promise { + const confirm: IConfirmation = { + message: nls.localize('confirmOverwrite', "'{0}' already exists. Do you want to replace it?", paths.basename(resource.fsPath)), + detail: nls.localize('irreversible', "A file or folder with the same name already exists in the folder {0}. Replacing it will overwrite its current contents.", paths.basename(paths.dirname(resource.fsPath))), + primaryButton: nls.localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), + type: 'warning' + }; + + return this.dialogService.confirm(confirm).then(result => result.confirmed); + } + promptForPath(resource: URI, defaultUri: URI): Promise { // Help user to find a name for the file by opening it first diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 8e51ba0bc7f..0e13742ee46 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -236,6 +236,10 @@ export class TestTextFileService extends TextFileService { return Promise.resolve(this.confirmResult); } + public confirmOverwrite(_resource: URI): Promise { + return Promise.resolve(true); + } + public onFilesConfigurationChange(configuration: any): void { super.onFilesConfigurationChange(configuration); } @@ -799,7 +803,7 @@ export class TestFileService implements IFileService { } existsFile(_resource: URI): Promise { - throw new Error('not implemented'); + return Promise.resolve(true); } resolveContent(resource: URI, _options?: IResolveContentOptions): Promise { From 63e72bb218b32a2af1bb5f97b9891539ccad1fe7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sat, 9 Feb 2019 16:44:57 +0100 Subject: [PATCH 084/207] debt - move broadcast to workbench --- src/tsconfig.strictNullChecks.json | 2 +- src/vs/workbench/api/electron-browser/mainThreadConsole.ts | 2 +- src/vs/workbench/contrib/debug/electron-browser/debugService.ts | 2 +- .../contrib/splash/electron-browser/partsSplash.contribution.ts | 2 +- src/vs/workbench/electron-browser/shell.ts | 2 +- .../services}/broadcast/electron-browser/broadcastService.ts | 0 .../services/extensions/electron-browser/extensionHost.ts | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename src/vs/{platform => workbench/services}/broadcast/electron-browser/broadcastService.ts (100%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index e14e51c576e..1edc3c85e06 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -213,7 +213,6 @@ "./vs/platform/actions/test/common/menuService.test.ts", "./vs/platform/backup/common/backup.ts", "./vs/platform/backup/electron-main/backupMainService.ts", - "./vs/platform/broadcast/electron-browser/broadcastService.ts", "./vs/platform/clipboard/common/clipboardService.ts", "./vs/platform/clipboard/electron-browser/clipboardService.ts", "./vs/platform/commands/common/commands.ts", @@ -666,6 +665,7 @@ "./vs/workbench/services/activity/common/activity.ts", "./vs/workbench/services/backup/common/backup.ts", "./vs/workbench/services/backup/node/backupFileService.ts", + "./vs/workbench/services/broadcast/electron-browser/broadcastService.ts", "./vs/workbench/services/bulkEdit/electron-browser/bulkEditService.ts", "./vs/workbench/services/configuration/common/configuration.ts", "./vs/workbench/services/configuration/common/configurationModels.ts", diff --git a/src/vs/workbench/api/electron-browser/mainThreadConsole.ts b/src/vs/workbench/api/electron-browser/mainThreadConsole.ts index 0f4e37223aa..be1aa913a83 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadConsole.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadConsole.ts @@ -9,7 +9,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IRemoteConsoleLog, log, parse } from 'vs/base/node/console'; import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/electron-browser/extensionHost'; import { IWindowsService } from 'vs/platform/windows/common/windows'; -import { IBroadcastService } from 'vs/platform/broadcast/electron-browser/broadcastService'; +import { IBroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService'; import { EXTENSION_LOG_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost'; @extHostNamedCustomer(MainContext.MainThreadConsole) diff --git a/src/vs/workbench/contrib/debug/electron-browser/debugService.ts b/src/vs/workbench/contrib/debug/electron-browser/debugService.ts index d8ce6c42a77..aa51759e4ce 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/debugService.ts @@ -34,7 +34,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL, EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost'; -import { IBroadcastService } from 'vs/platform/broadcast/electron-browser/broadcastService'; +import { IBroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService'; import { IRemoteConsoleLog, parse, getFirstFrame } from 'vs/base/node/console'; import { TaskEvent, TaskEventKind, TaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; diff --git a/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts b/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts index 018ac5b635d..cae6bc95caa 100644 --- a/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts +++ b/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts @@ -8,7 +8,7 @@ import { getTotalHeight, getTotalWidth } from 'vs/base/browser/dom'; import { Color } from 'vs/base/common/color'; import { Event } from 'vs/base/common/event'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; -import { IBroadcastService } from 'vs/platform/broadcast/electron-browser/broadcastService'; +import { IBroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 30a43711c8b..96060f4ad7f 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -69,7 +69,7 @@ import { registerThemingParticipant, ITheme, ICssStyleCollector, HIGH_CONTRAST } import { foreground, selectionBackground, focusBorder, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listHighlightForeground, inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry'; import { TextMateService } from 'vs/workbench/services/textMate/electron-browser/TMSyntax'; import { ITextMateService } from 'vs/workbench/services/textMate/electron-browser/textMateService'; -import { IBroadcastService, BroadcastService } from 'vs/platform/broadcast/electron-browser/broadcastService'; +import { IBroadcastService, BroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService'; import { HashService } from 'vs/workbench/services/hash/node/hashService'; import { IHashService } from 'vs/workbench/services/hash/common/hashService'; import { ILogService } from 'vs/platform/log/common/log'; diff --git a/src/vs/platform/broadcast/electron-browser/broadcastService.ts b/src/vs/workbench/services/broadcast/electron-browser/broadcastService.ts similarity index 100% rename from src/vs/platform/broadcast/electron-browser/broadcastService.ts rename to src/vs/workbench/services/broadcast/electron-browser/broadcastService.ts diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index 34e7cbf0a57..d821bce3686 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -21,7 +21,7 @@ import { IRemoteConsoleLog, log, parse } from 'vs/base/node/console'; import { findFreePort, randomPort } from 'vs/base/node/ports'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/node/ipc'; import { Protocol, generateRandomPipeName, BufferedProtocol } from 'vs/base/parts/ipc/node/ipc.net'; -import { IBroadcast, IBroadcastService } from 'vs/platform/broadcast/electron-browser/broadcastService'; +import { IBroadcast, IBroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL, EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost'; import { ILabelService } from 'vs/platform/label/common/label'; From 06ccc3a5153edfe18139171b424c436a3f780416 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sat, 9 Feb 2019 16:49:44 +0100 Subject: [PATCH 085/207] debt - move integrity service to workbench --- build/lib/i18n.resources.json | 4 ++++ src/tsconfig.strictNullChecks.json | 4 ++-- .../workbench/contrib/feedback/electron-browser/feedback.ts | 2 +- src/vs/workbench/electron-browser/shell.ts | 4 ++-- src/vs/workbench/electron-browser/window.ts | 2 +- .../services}/integrity/common/integrity.ts | 0 .../services}/integrity/node/integrityServiceImpl.ts | 2 +- 7 files changed, 11 insertions(+), 7 deletions(-) rename src/vs/{platform => workbench/services}/integrity/common/integrity.ts (100%) rename src/vs/{platform => workbench/services}/integrity/node/integrityServiceImpl.ts (98%) diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 6193ef287a3..7343be25ea2 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -210,6 +210,10 @@ "name": "vs/workbench/services/files", "project": "vscode-workbench" }, + { + "name": "vs/workbench/services/integrity", + "project": "vscode-workbench" + }, { "name": "vs/workbench/services/keybinding", "project": "vscode-workbench" diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 1edc3c85e06..4e861eac5cc 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -283,8 +283,6 @@ "./vs/platform/instantiation/test/common/graph.test.ts", "./vs/platform/instantiation/test/common/instantiationService.test.ts", "./vs/platform/instantiation/test/common/instantiationServiceMock.ts", - "./vs/platform/integrity/common/integrity.ts", - "./vs/platform/integrity/node/integrityServiceImpl.ts", "./vs/platform/issue/common/issue.ts", "./vs/platform/issue/electron-main/issueService.ts", "./vs/platform/issue/node/issueIpc.ts", @@ -706,6 +704,8 @@ "./vs/workbench/services/hash/node/hashService.ts", "./vs/workbench/services/history/common/history.ts", "./vs/workbench/services/history/electron-browser/history.ts", + "./vs/workbench/services/integrity/common/integrity.ts", + "./vs/workbench/services/integrity/node/integrityServiceImpl.ts", "./vs/workbench/services/keybinding/common/keybindingIO.ts", "./vs/workbench/services/keybinding/common/keyboardMapper.ts", "./vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper.ts", diff --git a/src/vs/workbench/contrib/feedback/electron-browser/feedback.ts b/src/vs/workbench/contrib/feedback/electron-browser/feedback.ts index 5d3f0f1f67b..11051ef1722 100644 --- a/src/vs/workbench/contrib/feedback/electron-browser/feedback.ts +++ b/src/vs/workbench/contrib/feedback/electron-browser/feedback.ts @@ -11,7 +11,7 @@ import { IContextViewService } from 'vs/platform/contextview/browser/contextView import product from 'vs/platform/node/product'; import * as dom from 'vs/base/browser/dom'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IIntegrityService } from 'vs/platform/integrity/common/integrity'; +import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { attachButtonStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; import { editorWidgetBackground, widgetShadow, inputBorder, inputForeground, inputBackground, inputActiveOptionBorder, editorBackground, buttonBackground, contrastBorder, darken } from 'vs/platform/theme/common/colorRegistry'; diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 96060f4ad7f..02380f32f81 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -34,8 +34,8 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { CodeEditorService } from 'vs/workbench/services/editor/browser/codeEditorService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { IntegrityServiceImpl } from 'vs/platform/integrity/node/integrityServiceImpl'; -import { IIntegrityService } from 'vs/platform/integrity/common/integrity'; +import { IntegrityServiceImpl } from 'vs/workbench/services/integrity/node/integrityServiceImpl'; +import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity'; import { EditorWorkerServiceImpl } from 'vs/editor/common/services/editorWorkerServiceImpl'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; import { ExtensionService } from 'vs/workbench/services/extensions/electron-browser/extensionService'; diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index be8f0488a12..1f243734b82 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -33,7 +33,7 @@ import { RunOnceScheduler } from 'vs/base/common/async'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { LifecyclePhase, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; -import { IIntegrityService } from 'vs/platform/integrity/common/integrity'; +import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity'; import { AccessibilitySupport, isRootUser, isWindows, isMacintosh, isLinux } from 'vs/base/common/platform'; import product from 'vs/platform/node/product'; import pkg from 'vs/platform/node/package'; diff --git a/src/vs/platform/integrity/common/integrity.ts b/src/vs/workbench/services/integrity/common/integrity.ts similarity index 100% rename from src/vs/platform/integrity/common/integrity.ts rename to src/vs/workbench/services/integrity/common/integrity.ts diff --git a/src/vs/platform/integrity/node/integrityServiceImpl.ts b/src/vs/workbench/services/integrity/node/integrityServiceImpl.ts similarity index 98% rename from src/vs/platform/integrity/node/integrityServiceImpl.ts rename to src/vs/workbench/services/integrity/node/integrityServiceImpl.ts index 25970d2f57f..699851ed92d 100644 --- a/src/vs/platform/integrity/node/integrityServiceImpl.ts +++ b/src/vs/workbench/services/integrity/node/integrityServiceImpl.ts @@ -8,7 +8,7 @@ import * as crypto from 'crypto'; import * as fs from 'fs'; import Severity from 'vs/base/common/severity'; import { URI } from 'vs/base/common/uri'; -import { ChecksumPair, IIntegrityService, IntegrityTestResult } from 'vs/platform/integrity/common/integrity'; +import { ChecksumPair, IIntegrityService, IntegrityTestResult } from 'vs/workbench/services/integrity/common/integrity'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import product from 'vs/platform/node/product'; import { INotificationService } from 'vs/platform/notification/common/notification'; From b49a05b5a5855d4f29d85a2b379d336c2f0bffdd Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sat, 9 Feb 2019 16:51:44 +0100 Subject: [PATCH 086/207] debt - move minimalTranslations to where it is used --- src/tsconfig.strictNullChecks.json | 2 +- .../electron-browser/localizations.contribution.ts | 2 +- .../localizations/electron-browser}/minimalTranslations.ts | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/vs/{platform/node => workbench/contrib/localizations/electron-browser}/minimalTranslations.ts (100%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 4e861eac5cc..04625436fc9 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -317,7 +317,6 @@ "./vs/platform/menubar/electron-main/menubar.ts", "./vs/platform/menubar/electron-main/menubarService.ts", "./vs/platform/menubar/node/menubarIpc.ts", - "./vs/platform/node/minimalTranslations.ts", "./vs/platform/node/package.ts", "./vs/platform/node/product.ts", "./vs/platform/node/test/zip.test.ts", @@ -559,6 +558,7 @@ "./vs/workbench/contrib/files/electron-browser/views/explorerDecorationsProvider.ts", "./vs/workbench/contrib/localizations/electron-browser/localizations.contribution.ts", "./vs/workbench/contrib/localizations/electron-browser/localizationsActions.ts", + "./vs/workbench/contrib/localizations/electron-browser/minimalTranslations.ts", "./vs/workbench/contrib/logs/common/logConstants.ts", "./vs/workbench/contrib/logs/electron-browser/logs.contribution.ts", "./vs/workbench/contrib/logs/electron-browser/logsActions.ts", diff --git a/src/vs/workbench/contrib/localizations/electron-browser/localizations.contribution.ts b/src/vs/workbench/contrib/localizations/electron-browser/localizations.contribution.ts index 5f18522d574..304da769429 100644 --- a/src/vs/workbench/contrib/localizations/electron-browser/localizations.contribution.ts +++ b/src/vs/workbench/contrib/localizations/electron-browser/localizations.contribution.ts @@ -26,7 +26,7 @@ import { IWindowsService } from 'vs/platform/windows/common/windows'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { VIEWLET_ID as EXTENSIONS_VIEWLET_ID, IExtensionsViewlet } from 'vs/workbench/contrib/extensions/common/extensions'; -import { minimumTranslatedStrings } from 'vs/platform/node/minimalTranslations'; +import { minimumTranslatedStrings } from 'vs/workbench/contrib/localizations/electron-browser/minimalTranslations'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { CancellationToken } from 'vs/base/common/cancellation'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; diff --git a/src/vs/platform/node/minimalTranslations.ts b/src/vs/workbench/contrib/localizations/electron-browser/minimalTranslations.ts similarity index 100% rename from src/vs/platform/node/minimalTranslations.ts rename to src/vs/workbench/contrib/localizations/electron-browser/minimalTranslations.ts From 31e7084fe91252c2f24e045d47af1348d5be482e Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sat, 9 Feb 2019 16:56:59 +0100 Subject: [PATCH 087/207] debt - move outputAppender to where it is used --- src/tsconfig.strictNullChecks.json | 2 +- src/vs/workbench/api/node/extHostOutputService.ts | 2 +- .../workbench/contrib/output/electron-browser/outputServices.ts | 2 +- .../contrib}/output/node/outputAppender.ts | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename src/vs/{platform => workbench/contrib}/output/node/outputAppender.ts (100%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 04625436fc9..d901a39cd84 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -324,7 +324,6 @@ "./vs/platform/notification/common/notification.ts", "./vs/platform/notification/test/common/testNotificationService.ts", "./vs/platform/opener/common/opener.ts", - "./vs/platform/output/node/outputAppender.ts", "./vs/platform/progress/common/progress.ts", "./vs/platform/quickOpen/common/quickOpen.ts", "./vs/platform/quickinput/common/quickInput.ts", @@ -573,6 +572,7 @@ "./vs/workbench/contrib/output/common/output.ts", "./vs/workbench/contrib/output/common/outputLinkComputer.ts", "./vs/workbench/contrib/output/common/outputLinkProvider.ts", + "./vs/workbench/contrib/output/node/outputAppender.ts", "./vs/workbench/contrib/performance/electron-browser/startupTimings.ts", "./vs/workbench/contrib/preferences/browser/settingsWidgets.ts", "./vs/workbench/contrib/preferences/common/smartSnippetInserter.ts", diff --git a/src/vs/workbench/api/node/extHostOutputService.ts b/src/vs/workbench/api/node/extHostOutputService.ts index a72e053e94d..201ff12c9f2 100644 --- a/src/vs/workbench/api/node/extHostOutputService.ts +++ b/src/vs/workbench/api/node/extHostOutputService.ts @@ -7,7 +7,7 @@ import { MainContext, MainThreadOutputServiceShape, IMainContext, ExtHostOutputS import * as vscode from 'vscode'; import { URI } from 'vs/base/common/uri'; import { posix } from 'path'; -import { OutputAppender } from 'vs/platform/output/node/outputAppender'; +import { OutputAppender } from 'vs/workbench/contrib/output/node/outputAppender'; import { toLocalISOString } from 'vs/base/common/date'; import { Event, Emitter } from 'vs/base/common/event'; import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; diff --git a/src/vs/workbench/contrib/output/electron-browser/outputServices.ts b/src/vs/workbench/contrib/output/electron-browser/outputServices.ts index 6a9a65811a8..b18649d3cf1 100644 --- a/src/vs/workbench/contrib/output/electron-browser/outputServices.ts +++ b/src/vs/workbench/contrib/output/electron-browser/outputServices.ts @@ -37,7 +37,7 @@ import { binarySearch } from 'vs/base/common/arrays'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { OutputAppender } from 'vs/platform/output/node/outputAppender'; +import { OutputAppender } from 'vs/workbench/contrib/output/node/outputAppender'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { isNumber } from 'vs/base/common/types'; diff --git a/src/vs/platform/output/node/outputAppender.ts b/src/vs/workbench/contrib/output/node/outputAppender.ts similarity index 100% rename from src/vs/platform/output/node/outputAppender.ts rename to src/vs/workbench/contrib/output/node/outputAppender.ts From 7c1fe9a7d6eaa6b3bbfddb740996c4bb867e6385 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Sat, 9 Feb 2019 17:02:31 +0100 Subject: [PATCH 088/207] debt - move search out of platform --- src/tsconfig.strictNullChecks.json | 8 ++++---- src/vs/workbench/api/electron-browser/mainThreadSearch.ts | 2 +- .../workbench/api/electron-browser/mainThreadWorkspace.ts | 2 +- src/vs/workbench/api/node/extHost.protocol.ts | 2 +- src/vs/workbench/api/node/extHostSearch.fileIndex.ts | 2 +- src/vs/workbench/api/node/extHostSearch.ts | 2 +- src/vs/workbench/api/node/extHostWorkspace.ts | 2 +- .../workbench/contrib/search/browser/openFileHandler.ts | 2 +- src/vs/workbench/contrib/search/browser/searchActions.ts | 2 +- .../workbench/contrib/search/browser/searchResultsView.ts | 2 +- src/vs/workbench/contrib/search/browser/searchView.ts | 2 +- src/vs/workbench/contrib/search/browser/searchWidget.ts | 2 +- src/vs/workbench/contrib/search/common/queryBuilder.ts | 2 +- src/vs/workbench/contrib/search/common/search.ts | 2 +- src/vs/workbench/contrib/search/common/searchModel.ts | 4 ++-- .../search/electron-browser/search.contribution.ts | 2 +- .../contrib/search/test/browser/openFileHandler.test.ts | 2 +- .../contrib/search/test/browser/searchActions.test.ts | 2 +- .../contrib/search/test/browser/searchViewlet.test.ts | 2 +- .../contrib/search/test/common/queryBuilder.test.ts | 2 +- .../contrib/search/test/common/searchModel.test.ts | 2 +- .../contrib/search/test/common/searchResult.test.ts | 2 +- src/vs/workbench/electron-browser/shell.ts | 2 +- .../services/history/electron-browser/history.ts | 2 +- .../services}/search/common/replace.ts | 2 +- .../services}/search/common/search.ts | 0 src/vs/workbench/services/search/common/searchHelpers.ts | 2 +- src/vs/workbench/services/search/node/fileSearch.ts | 2 +- .../workbench/services/search/node/fileSearchManager.ts | 2 +- src/vs/workbench/services/search/node/rawSearchService.ts | 2 +- .../workbench/services/search/node/ripgrepFileSearch.ts | 2 +- .../workbench/services/search/node/ripgrepSearchUtils.ts | 2 +- .../services/search/node/ripgrepTextSearchEngine.ts | 2 +- src/vs/workbench/services/search/node/search.ts | 2 +- .../services/search/node/searchHistoryService.ts | 2 +- src/vs/workbench/services/search/node/searchIpc.ts | 2 +- src/vs/workbench/services/search/node/searchService.ts | 2 +- .../workbench/services/search/node/textSearchAdapter.ts | 2 +- .../workbench/services/search/node/textSearchManager.ts | 2 +- .../services}/search/test/common/replace.test.ts | 2 +- .../services}/search/test/common/search.test.ts | 2 +- .../services/search/test/common/searchHelpers.test.ts | 2 +- .../services/search/test/node/rawSearchService.test.ts | 2 +- src/vs/workbench/services/search/test/node/search.test.ts | 2 +- .../search/test/node/textSearch.integrationTest.ts | 2 +- .../services/search/test/node/textSearchManager.test.ts | 2 +- .../test/electron-browser/api/extHostSearch.test.ts | 2 +- .../electron-browser/quickopen.perf.integrationTest.ts | 2 +- .../electron-browser/textsearch.perf.integrationTest.ts | 2 +- 49 files changed, 52 insertions(+), 52 deletions(-) rename src/vs/{platform => workbench/services}/search/common/replace.ts (98%) rename src/vs/{platform => workbench/services}/search/common/search.ts (100%) rename src/vs/{platform => workbench/services}/search/test/common/replace.test.ts (99%) rename src/vs/{platform => workbench/services}/search/test/common/search.test.ts (98%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index d901a39cd84..a2f5b68454b 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -338,10 +338,6 @@ "./vs/platform/request/electron-main/requestService.ts", "./vs/platform/request/node/request.ts", "./vs/platform/request/node/requestService.ts", - "./vs/platform/search/common/replace.ts", - "./vs/platform/search/common/search.ts", - "./vs/platform/search/test/common/replace.test.ts", - "./vs/platform/search/test/common/search.test.ts", "./vs/platform/state/common/state.ts", "./vs/platform/state/node/stateService.ts", "./vs/platform/statusbar/common/statusbar.ts", @@ -730,6 +726,8 @@ "./vs/workbench/services/remote/node/remoteAgentEnvironmentChannel.ts", "./vs/workbench/services/remote/node/remoteAgentService.ts", "./vs/workbench/services/search/common/searchHelpers.ts", + "./vs/workbench/services/search/common/replace.ts", + "./vs/workbench/services/search/common/search.ts", "./vs/workbench/services/search/node/fileSearch.ts", "./vs/workbench/services/search/node/fileSearchManager.ts", "./vs/workbench/services/search/node/rawSearchService.ts", @@ -749,6 +747,8 @@ "./vs/workbench/services/search/test/node/search.test.ts", "./vs/workbench/services/search/test/node/textSearch.integrationTest.ts", "./vs/workbench/services/search/test/node/textSearchManager.test.ts", + "./vs/workbench/services/search/test/common/replace.test.ts", + "./vs/workbench/services/search/test/common/search.test.ts", "./vs/workbench/services/textMate/electron-browser/TMGrammars.ts", "./vs/workbench/services/textMate/electron-browser/TMHelper.ts", "./vs/workbench/services/textMate/electron-browser/TMSyntax.ts", diff --git a/src/vs/workbench/api/electron-browser/mainThreadSearch.ts b/src/vs/workbench/api/electron-browser/mainThreadSearch.ts index bc4624424f9..e4e99dcf661 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadSearch.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadSearch.ts @@ -7,7 +7,7 @@ import { isFalsyOrEmpty } from 'vs/base/common/arrays'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { values } from 'vs/base/common/map'; import { URI, UriComponents } from 'vs/base/common/uri'; -import { IFileMatch, IRawFileMatch2, ISearchComplete, ISearchCompleteStats, ISearchProgressItem, ISearchResultProvider, ISearchService, QueryType, SearchProviderType, ITextQuery, IFileQuery } from 'vs/platform/search/common/search'; +import { IFileMatch, IRawFileMatch2, ISearchComplete, ISearchCompleteStats, ISearchProgressItem, ISearchResultProvider, ISearchService, QueryType, SearchProviderType, ITextQuery, IFileQuery } from 'vs/workbench/services/search/common/search'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; import { ExtHostContext, ExtHostSearchShape, IExtHostContext, MainContext, MainThreadSearchShape } from '../node/extHost.protocol'; diff --git a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts index 91bd9eb6070..1f675e2748b 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts @@ -12,7 +12,7 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ILabelService } from 'vs/platform/label/common/label'; -import { IFileMatch, IPatternInfo, ISearchProgressItem, ISearchService } from 'vs/platform/search/common/search'; +import { IFileMatch, IPatternInfo, ISearchProgressItem, ISearchService } from 'vs/workbench/services/search/common/search'; import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 3664541f73f..fc3280e1a91 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -25,7 +25,7 @@ import { ResourceLabelFormatter } from 'vs/platform/label/common/label'; import { LogLevel } from 'vs/platform/log/common/log'; import { IMarkerData } from 'vs/platform/markers/common/markers'; import { IPickOptions, IQuickInputButton, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; -import { IPatternInfo, IRawFileMatch2, IRawQuery, IRawTextQuery, ISearchCompleteStats } from 'vs/platform/search/common/search'; +import { IPatternInfo, IRawFileMatch2, IRawQuery, IRawTextQuery, ISearchCompleteStats } from 'vs/workbench/services/search/common/search'; import { StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar'; import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; import { ThemeColor } from 'vs/platform/theme/common/themeService'; diff --git a/src/vs/workbench/api/node/extHostSearch.fileIndex.ts b/src/vs/workbench/api/node/extHostSearch.fileIndex.ts index d0ed46e8e2a..6e104cd310e 100644 --- a/src/vs/workbench/api/node/extHostSearch.fileIndex.ts +++ b/src/vs/workbench/api/node/extHostSearch.fileIndex.ts @@ -14,7 +14,7 @@ import { StopWatch } from 'vs/base/common/stopwatch'; import * as strings from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { compareItemsByScore, IItemAccessor, prepareQuery, ScorerCache } from 'vs/base/parts/quickopen/common/quickOpenScorer'; -import { ICachedSearchStats, IFileIndexProviderStats, IFileMatch, IFileQuery, IFileSearchStats, IFolderQuery, ISearchCompleteStats } from 'vs/platform/search/common/search'; +import { ICachedSearchStats, IFileIndexProviderStats, IFileMatch, IFileQuery, IFileSearchStats, IFolderQuery, ISearchCompleteStats } from 'vs/workbench/services/search/common/search'; import { IDirectoryEntry, IDirectoryTree, IInternalFileMatch } from 'vs/workbench/services/search/node/fileSearchManager'; import { QueryGlobTester, resolvePatternsForProvider } from 'vs/workbench/services/search/node/search'; import * as vscode from 'vscode'; diff --git a/src/vs/workbench/api/node/extHostSearch.ts b/src/vs/workbench/api/node/extHostSearch.ts index 53ff6f41386..80559688fb1 100644 --- a/src/vs/workbench/api/node/extHostSearch.ts +++ b/src/vs/workbench/api/node/extHostSearch.ts @@ -8,7 +8,7 @@ import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; import * as extfs from 'vs/base/node/extfs'; import { ILogService } from 'vs/platform/log/common/log'; -import { IFileQuery, IFolderQuery, IRawFileQuery, IRawQuery, IRawTextQuery, ISearchCompleteStats, ITextQuery } from 'vs/platform/search/common/search'; +import { IFileQuery, IFolderQuery, IRawFileQuery, IRawQuery, IRawTextQuery, ISearchCompleteStats, ITextQuery } from 'vs/workbench/services/search/common/search'; import { FileIndexSearchManager } from 'vs/workbench/api/node/extHostSearch.fileIndex'; import { FileSearchManager } from 'vs/workbench/services/search/node/fileSearchManager'; import { SearchService } from 'vs/workbench/services/search/node/rawSearchService'; diff --git a/src/vs/workbench/api/node/extHostWorkspace.ts b/src/vs/workbench/api/node/extHostWorkspace.ts index 1a16b50202b..7026471a079 100644 --- a/src/vs/workbench/api/node/extHostWorkspace.ts +++ b/src/vs/workbench/api/node/extHostWorkspace.ts @@ -17,7 +17,7 @@ import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { ILogService } from 'vs/platform/log/common/log'; import { Severity } from 'vs/platform/notification/common/notification'; -import { IRawFileMatch2, resultIsMatch } from 'vs/platform/search/common/search'; +import { IRawFileMatch2, resultIsMatch } from 'vs/workbench/services/search/common/search'; import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { Range, RelativePattern } from 'vs/workbench/api/node/extHostTypes'; import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder'; diff --git a/src/vs/workbench/contrib/search/browser/openFileHandler.ts b/src/vs/workbench/contrib/search/browser/openFileHandler.ts index 0434fc1c196..e03cc673b30 100644 --- a/src/vs/workbench/contrib/search/browser/openFileHandler.ts +++ b/src/vs/workbench/contrib/search/browser/openFileHandler.ts @@ -23,7 +23,7 @@ import { EditorInput, IWorkbenchEditorConfiguration } from 'vs/workbench/common/ import { IResourceInput } from 'vs/platform/editor/common/editor'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ISearchService, IFileSearchStats, IFileQuery, ISearchComplete } from 'vs/platform/search/common/search'; +import { ISearchService, IFileSearchStats, IFileQuery, ISearchComplete } from 'vs/workbench/services/search/common/search'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IRange } from 'vs/editor/common/core/range'; diff --git a/src/vs/workbench/contrib/search/browser/searchActions.ts b/src/vs/workbench/contrib/search/browser/searchActions.ts index 6e9c0f5e71e..e1bd450dac3 100644 --- a/src/vs/workbench/contrib/search/browser/searchActions.ts +++ b/src/vs/workbench/contrib/search/browser/searchActions.ts @@ -21,7 +21,7 @@ import { IEditorOptions } from 'vs/platform/editor/common/editor'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { WorkbenchObjectTree } from 'vs/platform/list/browser/listService'; -import { ISearchConfiguration, ISearchHistoryService, VIEW_ID } from 'vs/platform/search/common/search'; +import { ISearchConfiguration, ISearchHistoryService, VIEW_ID } from 'vs/workbench/services/search/common/search'; import { SearchView } from 'vs/workbench/contrib/search/browser/searchView'; import * as Constants from 'vs/workbench/contrib/search/common/constants'; import { IReplaceService } from 'vs/workbench/contrib/search/common/replace'; diff --git a/src/vs/workbench/contrib/search/browser/searchResultsView.ts b/src/vs/workbench/contrib/search/browser/searchResultsView.ts index fb053f632e8..aa275dc8c4d 100644 --- a/src/vs/workbench/contrib/search/browser/searchResultsView.ts +++ b/src/vs/workbench/contrib/search/browser/searchResultsView.ts @@ -18,7 +18,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { FileKind } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILabelService } from 'vs/platform/label/common/label'; -import { ISearchConfigurationProperties } from 'vs/platform/search/common/search'; +import { ISearchConfigurationProperties } from 'vs/workbench/services/search/common/search'; import { attachBadgeStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index a9ff441ccdf..b3620be6d97 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -36,7 +36,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { TreeResourceNavigator2, WorkbenchObjectTree } from 'vs/platform/list/browser/listService'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IProgressService } from 'vs/platform/progress/common/progress'; -import { IPatternInfo, ISearchComplete, ISearchConfiguration, ISearchConfigurationProperties, ISearchHistoryService, ISearchHistoryValues, ITextQuery, SearchErrorCode, VIEW_ID } from 'vs/platform/search/common/search'; +import { IPatternInfo, ISearchComplete, ISearchConfiguration, ISearchConfigurationProperties, ISearchHistoryService, ISearchHistoryValues, ITextQuery, SearchErrorCode, VIEW_ID } from 'vs/workbench/services/search/common/search'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { diffInserted, diffInsertedOutline, diffRemoved, diffRemovedOutline, editorFindMatchHighlight, editorFindMatchHighlightBorder, listActiveSelectionForeground } from 'vs/platform/theme/common/colorRegistry'; diff --git a/src/vs/workbench/contrib/search/browser/searchWidget.ts b/src/vs/workbench/contrib/search/browser/searchWidget.ts index 8b7ee3dbafa..068651eb2f6 100644 --- a/src/vs/workbench/contrib/search/browser/searchWidget.ts +++ b/src/vs/workbench/contrib/search/browser/searchWidget.ts @@ -25,7 +25,7 @@ import { ContextKeyExpr, IContextKey, IContextKeyService } from 'vs/platform/con import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { ISearchConfigurationProperties } from 'vs/platform/search/common/search'; +import { ISearchConfigurationProperties } from 'vs/workbench/services/search/common/search'; import { attachFindInputBoxStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedHistoryWidget'; diff --git a/src/vs/workbench/contrib/search/common/queryBuilder.ts b/src/vs/workbench/contrib/search/common/queryBuilder.ts index 5b0b644d105..f5c6ec5222b 100644 --- a/src/vs/workbench/contrib/search/common/queryBuilder.ts +++ b/src/vs/workbench/contrib/search/common/queryBuilder.ts @@ -16,7 +16,7 @@ import { isMultilineRegexSource } from 'vs/editor/common/model/textModelSearch'; import * as nls from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { getExcludes, ICommonQueryProps, IFileQuery, IFolderQuery, IPatternInfo, ISearchConfiguration, ITextQuery, ITextSearchPreviewOptions, pathIncludedInQuery, QueryType } from 'vs/platform/search/common/search'; +import { getExcludes, ICommonQueryProps, IFileQuery, IFolderQuery, IPatternInfo, ISearchConfiguration, ITextQuery, ITextSearchPreviewOptions, pathIncludedInQuery, QueryType } from 'vs/workbench/services/search/common/search'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; /** diff --git a/src/vs/workbench/contrib/search/common/search.ts b/src/vs/workbench/contrib/search/common/search.ts index 09bc26d9b9d..0e56ed9e0ba 100644 --- a/src/vs/workbench/contrib/search/common/search.ts +++ b/src/vs/workbench/contrib/search/common/search.ts @@ -5,7 +5,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { ISearchConfiguration, ISearchConfigurationProperties } from 'vs/platform/search/common/search'; +import { ISearchConfiguration, ISearchConfigurationProperties } from 'vs/workbench/services/search/common/search'; import { SymbolKind, Location, ProviderResult } from 'vs/editor/common/modes'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { URI } from 'vs/base/common/uri'; diff --git a/src/vs/workbench/contrib/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index 1e020ef4531..3a98f141ab1 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -19,8 +19,8 @@ import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { IModelService } from 'vs/editor/common/services/modelService'; import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IProgressRunner } from 'vs/platform/progress/common/progress'; -import { ReplacePattern } from 'vs/platform/search/common/replace'; -import { IFileMatch, IPatternInfo, ISearchComplete, ISearchProgressItem, ISearchService, ITextQuery, ITextSearchPreviewOptions, ITextSearchMatch, ITextSearchStats, resultIsMatch, ISearchRange, OneLineRange } from 'vs/platform/search/common/search'; +import { ReplacePattern } from 'vs/workbench/services/search/common/replace'; +import { IFileMatch, IPatternInfo, ISearchComplete, ISearchProgressItem, ISearchService, ITextQuery, ITextSearchPreviewOptions, ITextSearchMatch, ITextSearchStats, resultIsMatch, ISearchRange, OneLineRange } from 'vs/workbench/services/search/common/search'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { overviewRulerFindMatchForeground } from 'vs/platform/theme/common/colorRegistry'; import { themeColorFromId } from 'vs/platform/theme/common/themeService'; diff --git a/src/vs/workbench/contrib/search/electron-browser/search.contribution.ts b/src/vs/workbench/contrib/search/electron-browser/search.contribution.ts index 8f8d622cb86..aea7c75f20e 100644 --- a/src/vs/workbench/contrib/search/electron-browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/electron-browser/search.contribution.ts @@ -32,7 +32,7 @@ import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IListService, WorkbenchListFocusContextKey, WorkbenchObjectTree } from 'vs/platform/list/browser/listService'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { Registry } from 'vs/platform/registry/common/platform'; -import { ISearchConfigurationProperties, VIEW_ID, ISearchConfiguration } from 'vs/platform/search/common/search'; +import { ISearchConfigurationProperties, VIEW_ID, ISearchConfiguration } from 'vs/workbench/services/search/common/search'; import { defaultQuickOpenContextKey } from 'vs/workbench/browser/parts/quickopen/quickopen'; import { Extensions as QuickOpenExtensions, IQuickOpenRegistry, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; diff --git a/src/vs/workbench/contrib/search/test/browser/openFileHandler.test.ts b/src/vs/workbench/contrib/search/test/browser/openFileHandler.test.ts index 97eebd7be8e..d6887d88e82 100644 --- a/src/vs/workbench/contrib/search/test/browser/openFileHandler.test.ts +++ b/src/vs/workbench/contrib/search/test/browser/openFileHandler.test.ts @@ -8,7 +8,7 @@ import * as errors from 'vs/base/common/errors'; import * as objects from 'vs/base/common/objects'; import { CacheState } from 'vs/workbench/contrib/search/browser/openFileHandler'; import { DeferredPromise } from 'vs/base/test/common/utils'; -import { QueryType, IFileQuery } from 'vs/platform/search/common/search'; +import { QueryType, IFileQuery } from 'vs/workbench/services/search/common/search'; suite('CacheState', () => { diff --git a/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts b/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts index 452302f9df3..8f63fa9eb07 100644 --- a/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts +++ b/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts @@ -14,7 +14,7 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; -import { IFileMatch } from 'vs/platform/search/common/search'; +import { IFileMatch } from 'vs/workbench/services/search/common/search'; import { ReplaceAction } from 'vs/workbench/contrib/search/browser/searchActions'; import { FileMatch, FileMatchOrMatch, Match } from 'vs/workbench/contrib/search/common/searchModel'; import { MockObjectTree } from 'vs/workbench/contrib/search/test/browser/mockSearchTree'; diff --git a/src/vs/workbench/contrib/search/test/browser/searchViewlet.test.ts b/src/vs/workbench/contrib/search/test/browser/searchViewlet.test.ts index 7e4e27f20b6..447fffccfbe 100644 --- a/src/vs/workbench/contrib/search/test/browser/searchViewlet.test.ts +++ b/src/vs/workbench/contrib/search/test/browser/searchViewlet.test.ts @@ -9,7 +9,7 @@ import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; -import { IFileMatch, ITextSearchMatch, OneLineRange, QueryType } from 'vs/platform/search/common/search'; +import { IFileMatch, ITextSearchMatch, OneLineRange, QueryType } from 'vs/workbench/services/search/common/search'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; import { FileMatch, Match, searchMatchComparer, SearchResult } from 'vs/workbench/contrib/search/common/searchModel'; diff --git a/src/vs/workbench/contrib/search/test/common/queryBuilder.test.ts b/src/vs/workbench/contrib/search/test/common/queryBuilder.test.ts index a698314ec1f..1db3582949d 100644 --- a/src/vs/workbench/contrib/search/test/common/queryBuilder.test.ts +++ b/src/vs/workbench/contrib/search/test/common/queryBuilder.test.ts @@ -10,7 +10,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; -import { IFolderQuery, IPatternInfo, QueryType, ITextQuery, IFileQuery } from 'vs/platform/search/common/search'; +import { IFolderQuery, IPatternInfo, QueryType, ITextQuery, IFileQuery } from 'vs/workbench/services/search/common/search'; import { IWorkspaceContextService, toWorkspaceFolders, Workspace } from 'vs/platform/workspace/common/workspace'; import { ISearchPathsResult, QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder'; import { TestContextService, TestEnvironmentService } from 'vs/workbench/test/workbenchTestServices'; diff --git a/src/vs/workbench/contrib/search/test/common/searchModel.test.ts b/src/vs/workbench/contrib/search/test/common/searchModel.test.ts index 753daca49ba..d1438b530b7 100644 --- a/src/vs/workbench/contrib/search/test/common/searchModel.test.ts +++ b/src/vs/workbench/contrib/search/test/common/searchModel.test.ts @@ -14,7 +14,7 @@ import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; -import { IFileMatch, IFileSearchStats, IFolderQuery, ISearchComplete, ISearchProgressItem, ISearchQuery, ISearchService, ITextSearchMatch, OneLineRange, TextSearchMatch } from 'vs/platform/search/common/search'; +import { IFileMatch, IFileSearchStats, IFolderQuery, ISearchComplete, ISearchProgressItem, ISearchQuery, ISearchService, ITextSearchMatch, OneLineRange, TextSearchMatch } from 'vs/workbench/services/search/common/search'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { SearchModel } from 'vs/workbench/contrib/search/common/searchModel'; diff --git a/src/vs/workbench/contrib/search/test/common/searchResult.test.ts b/src/vs/workbench/contrib/search/test/common/searchResult.test.ts index 5824e9476b9..64f09791842 100644 --- a/src/vs/workbench/contrib/search/test/common/searchResult.test.ts +++ b/src/vs/workbench/contrib/search/test/common/searchResult.test.ts @@ -7,7 +7,7 @@ import * as sinon from 'sinon'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { Match, FileMatch, SearchResult, SearchModel } from 'vs/workbench/contrib/search/common/searchModel'; import { URI } from 'vs/base/common/uri'; -import { IFileMatch, TextSearchMatch, OneLineRange, ITextSearchMatch } from 'vs/platform/search/common/search'; +import { IFileMatch, TextSearchMatch, OneLineRange, ITextSearchMatch } from 'vs/workbench/services/search/common/search'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { Range } from 'vs/editor/common/core/range'; diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 02380f32f81..fe9a273da20 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -45,7 +45,7 @@ import { InstantiationService } from 'vs/platform/instantiation/node/instantiati import { ILifecycleService, LifecyclePhase, WillShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle'; import { IMarkerService } from 'vs/platform/markers/common/markers'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { ISearchService, ISearchHistoryService } from 'vs/platform/search/common/search'; +import { ISearchService, ISearchHistoryService } from 'vs/workbench/services/search/common/search'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { CommandService } from 'vs/workbench/services/commands/common/commandService'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; diff --git a/src/vs/workbench/services/history/electron-browser/history.ts b/src/vs/workbench/services/history/electron-browser/history.ts index 845c6a2e909..8de95889699 100644 --- a/src/vs/workbench/services/history/electron-browser/history.ts +++ b/src/vs/workbench/services/history/electron-browser/history.ts @@ -21,7 +21,7 @@ import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/co import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IWindowsService } from 'vs/platform/windows/common/windows'; import { getCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { getExcludes, ISearchConfiguration } from 'vs/platform/search/common/search'; +import { getExcludes, ISearchConfiguration } from 'vs/workbench/services/search/common/search'; import { IExpression } from 'vs/base/common/glob'; import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; diff --git a/src/vs/platform/search/common/replace.ts b/src/vs/workbench/services/search/common/replace.ts similarity index 98% rename from src/vs/platform/search/common/replace.ts rename to src/vs/workbench/services/search/common/replace.ts index 7ed4772449e..a6caab8223e 100644 --- a/src/vs/platform/search/common/replace.ts +++ b/src/vs/workbench/services/search/common/replace.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as strings from 'vs/base/common/strings'; -import { IPatternInfo } from 'vs/platform/search/common/search'; +import { IPatternInfo } from 'vs/workbench/services/search/common/search'; import { CharCode } from 'vs/base/common/charCode'; export class ReplacePattern { diff --git a/src/vs/platform/search/common/search.ts b/src/vs/workbench/services/search/common/search.ts similarity index 100% rename from src/vs/platform/search/common/search.ts rename to src/vs/workbench/services/search/common/search.ts diff --git a/src/vs/workbench/services/search/common/searchHelpers.ts b/src/vs/workbench/services/search/common/searchHelpers.ts index 988792bb112..e444f2b355c 100644 --- a/src/vs/workbench/services/search/common/searchHelpers.ts +++ b/src/vs/workbench/services/search/common/searchHelpers.ts @@ -5,7 +5,7 @@ import { Range } from 'vs/editor/common/core/range'; import { FindMatch, ITextModel } from 'vs/editor/common/model'; -import { ITextSearchPreviewOptions, TextSearchMatch, ITextSearchResult, ITextSearchMatch, ITextQuery, ITextSearchContext } from 'vs/platform/search/common/search'; +import { ITextSearchPreviewOptions, TextSearchMatch, ITextSearchResult, ITextSearchMatch, ITextQuery, ITextSearchContext } from 'vs/workbench/services/search/common/search'; function editorMatchToTextSearchResult(matches: FindMatch[], model: ITextModel, previewOptions?: ITextSearchPreviewOptions): TextSearchMatch { const firstLine = matches[0].range.startLineNumber; diff --git a/src/vs/workbench/services/search/node/fileSearch.ts b/src/vs/workbench/services/search/node/fileSearch.ts index e656f69ccc6..15413b37e43 100644 --- a/src/vs/workbench/services/search/node/fileSearch.ts +++ b/src/vs/workbench/services/search/node/fileSearch.ts @@ -21,7 +21,7 @@ import * as types from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import * as extfs from 'vs/base/node/extfs'; import * as flow from 'vs/base/node/flow'; -import { IFileQuery, IFolderQuery, IProgress, ISearchEngineStats } from 'vs/platform/search/common/search'; +import { IFileQuery, IFolderQuery, IProgress, ISearchEngineStats } from 'vs/workbench/services/search/common/search'; import { IRawFileMatch, ISearchEngine, ISearchEngineSuccess } from 'vs/workbench/services/search/node/search'; import { spawnRipgrepCmd } from './ripgrepFileSearch'; diff --git a/src/vs/workbench/services/search/node/fileSearchManager.ts b/src/vs/workbench/services/search/node/fileSearchManager.ts index 3c95ee21387..a7259d43873 100644 --- a/src/vs/workbench/services/search/node/fileSearchManager.ts +++ b/src/vs/workbench/services/search/node/fileSearchManager.ts @@ -10,7 +10,7 @@ import * as glob from 'vs/base/common/glob'; import * as resources from 'vs/base/common/resources'; import { StopWatch } from 'vs/base/common/stopwatch'; import { URI } from 'vs/base/common/uri'; -import { IFileMatch, IFileSearchProviderStats, IFolderQuery, ISearchCompleteStats, IFileQuery } from 'vs/platform/search/common/search'; +import { IFileMatch, IFileSearchProviderStats, IFolderQuery, ISearchCompleteStats, IFileQuery } from 'vs/workbench/services/search/common/search'; import { QueryGlobTester, resolvePatternsForProvider } from 'vs/workbench/services/search/node/search'; import * as vscode from 'vscode'; diff --git a/src/vs/workbench/services/search/node/rawSearchService.ts b/src/vs/workbench/services/search/node/rawSearchService.ts index da52da42622..019e327cf96 100644 --- a/src/vs/workbench/services/search/node/rawSearchService.ts +++ b/src/vs/workbench/services/search/node/rawSearchService.ts @@ -17,7 +17,7 @@ import * as strings from 'vs/base/common/strings'; import { URI, UriComponents } from 'vs/base/common/uri'; import { compareItemsByScore, IItemAccessor, prepareQuery, ScorerCache } from 'vs/base/parts/quickopen/common/quickOpenScorer'; import { MAX_FILE_SIZE } from 'vs/platform/files/node/files'; -import { ICachedSearchStats, IFileQuery, IFileSearchStats, IFolderQuery, IProgress, IRawFileQuery, IRawQuery, IRawTextQuery, ITextQuery } from 'vs/platform/search/common/search'; +import { ICachedSearchStats, IFileQuery, IFileSearchStats, IFolderQuery, IProgress, IRawFileQuery, IRawQuery, IRawTextQuery, ITextQuery } from 'vs/workbench/services/search/common/search'; import { Engine as FileSearchEngine } from 'vs/workbench/services/search/node/fileSearch'; import { TextSearchEngineAdapter } from 'vs/workbench/services/search/node/textSearchAdapter'; import { IFileSearchProgressItem, IRawFileMatch, IRawSearchService, ISearchEngine, ISearchEngineSuccess, ISerializedFileMatch, ISerializedSearchComplete, ISerializedSearchProgressItem, ISerializedSearchSuccess } from './search'; diff --git a/src/vs/workbench/services/search/node/ripgrepFileSearch.ts b/src/vs/workbench/services/search/node/ripgrepFileSearch.ts index f56f7a6b4aa..2c65ff9822e 100644 --- a/src/vs/workbench/services/search/node/ripgrepFileSearch.ts +++ b/src/vs/workbench/services/search/node/ripgrepFileSearch.ts @@ -11,7 +11,7 @@ import * as objects from 'vs/base/common/objects'; import * as paths from 'vs/base/common/paths'; import { isMacintosh as isMac } from 'vs/base/common/platform'; import * as strings from 'vs/base/common/strings'; -import { IFileQuery, IFolderQuery } from 'vs/platform/search/common/search'; +import { IFileQuery, IFolderQuery } from 'vs/workbench/services/search/common/search'; import { anchorGlob } from 'vs/workbench/services/search/node/ripgrepSearchUtils'; import { rgPath } from 'vscode-ripgrep'; diff --git a/src/vs/workbench/services/search/node/ripgrepSearchUtils.ts b/src/vs/workbench/services/search/node/ripgrepSearchUtils.ts index 720e020f4a2..3d8e787c342 100644 --- a/src/vs/workbench/services/search/node/ripgrepSearchUtils.ts +++ b/src/vs/workbench/services/search/node/ripgrepSearchUtils.ts @@ -5,7 +5,7 @@ import { startsWith } from 'vs/base/common/strings'; import { ILogService } from 'vs/platform/log/common/log'; -import { SearchRange, TextSearchMatch } from 'vs/platform/search/common/search'; +import { SearchRange, TextSearchMatch } from 'vs/workbench/services/search/common/search'; import * as vscode from 'vscode'; import { mapArrayOrNot } from 'vs/base/common/arrays'; diff --git a/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts b/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts index f70c901e072..98362b3e539 100644 --- a/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts +++ b/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts @@ -9,7 +9,7 @@ import * as path from 'path'; import { NodeStringDecoder, StringDecoder } from 'string_decoder'; import { createRegExp, startsWith, startsWithUTF8BOM, stripUTF8BOM, escapeRegExpCharacters, endsWith } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; -import { IExtendedExtensionSearchOptions, SearchError, SearchErrorCode, serializeSearchError } from 'vs/platform/search/common/search'; +import { IExtendedExtensionSearchOptions, SearchError, SearchErrorCode, serializeSearchError } from 'vs/workbench/services/search/common/search'; import * as vscode from 'vscode'; import { rgPath } from 'vscode-ripgrep'; import { anchorGlob, createTextSearchResult, IOutputChannel, Maybe, Range } from './ripgrepSearchUtils'; diff --git a/src/vs/workbench/services/search/node/search.ts b/src/vs/workbench/services/search/node/search.ts index d59a9c53a0b..635c1c1d1b1 100644 --- a/src/vs/workbench/services/search/node/search.ts +++ b/src/vs/workbench/services/search/node/search.ts @@ -5,7 +5,7 @@ import { Event } from 'vs/base/common/event'; import * as glob from 'vs/base/common/glob'; -import { IFileSearchStats, IFolderQuery, IProgress, IRawFileQuery, IRawTextQuery, ISearchEngineStats, ISearchQuery, ITextSearchMatch, ITextSearchStats, ITextSearchResult } from 'vs/platform/search/common/search'; +import { IFileSearchStats, IFolderQuery, IProgress, IRawFileQuery, IRawTextQuery, ISearchEngineStats, ISearchQuery, ITextSearchMatch, ITextSearchStats, ITextSearchResult } from 'vs/workbench/services/search/common/search'; import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; export interface ITelemetryEvent { diff --git a/src/vs/workbench/services/search/node/searchHistoryService.ts b/src/vs/workbench/services/search/node/searchHistoryService.ts index d3435bc34be..dbd9bebb186 100644 --- a/src/vs/workbench/services/search/node/searchHistoryService.ts +++ b/src/vs/workbench/services/search/node/searchHistoryService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { ISearchHistoryValues, ISearchHistoryService } from 'vs/platform/search/common/search'; +import { ISearchHistoryValues, ISearchHistoryService } from 'vs/workbench/services/search/common/search'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { isEmptyObject } from 'vs/base/common/types'; diff --git a/src/vs/workbench/services/search/node/searchIpc.ts b/src/vs/workbench/services/search/node/searchIpc.ts index d6ef91388c6..3d3b0ad9364 100644 --- a/src/vs/workbench/services/search/node/searchIpc.ts +++ b/src/vs/workbench/services/search/node/searchIpc.ts @@ -5,7 +5,7 @@ import { Event } from 'vs/base/common/event'; import { IChannel, IServerChannel } from 'vs/base/parts/ipc/node/ipc'; -import { IRawFileQuery, IRawTextQuery } from 'vs/platform/search/common/search'; +import { IRawFileQuery, IRawTextQuery } from 'vs/workbench/services/search/common/search'; import { IRawSearchService, ISerializedSearchComplete, ISerializedSearchProgressItem } from './search'; export class SearchChannel implements IServerChannel { diff --git a/src/vs/workbench/services/search/node/searchService.ts b/src/vs/workbench/services/search/node/searchService.ts index 08bb261385c..14f4c3d0296 100644 --- a/src/vs/workbench/services/search/node/searchService.ts +++ b/src/vs/workbench/services/search/node/searchService.ts @@ -20,7 +20,7 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { IDebugParams, IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; -import { deserializeSearchError, FileMatch, ICachedSearchStats, IFileMatch, IFileQuery, IFileSearchStats, IFolderQuery, IProgress, ISearchComplete, ISearchEngineStats, ISearchProgressItem, ISearchQuery, ISearchResultProvider, ISearchService, ITextQuery, pathIncludedInQuery, QueryType, SearchError, SearchErrorCode, SearchProviderType, ISearchConfiguration } from 'vs/platform/search/common/search'; +import { deserializeSearchError, FileMatch, ICachedSearchStats, IFileMatch, IFileQuery, IFileSearchStats, IFolderQuery, IProgress, ISearchComplete, ISearchEngineStats, ISearchProgressItem, ISearchQuery, ISearchResultProvider, ISearchService, ITextQuery, pathIncludedInQuery, QueryType, SearchError, SearchErrorCode, SearchProviderType, ISearchConfiguration } from 'vs/workbench/services/search/common/search'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; diff --git a/src/vs/workbench/services/search/node/textSearchAdapter.ts b/src/vs/workbench/services/search/node/textSearchAdapter.ts index 02117a2eda4..2308349c84d 100644 --- a/src/vs/workbench/services/search/node/textSearchAdapter.ts +++ b/src/vs/workbench/services/search/node/textSearchAdapter.ts @@ -5,7 +5,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import * as extfs from 'vs/base/node/extfs'; -import { IFileMatch, IProgress, ITextQuery, ITextSearchStats, ITextSearchMatch } from 'vs/platform/search/common/search'; +import { IFileMatch, IProgress, ITextQuery, ITextSearchStats, ITextSearchMatch } from 'vs/workbench/services/search/common/search'; import { RipgrepTextSearchEngine } from 'vs/workbench/services/search/node/ripgrepTextSearchEngine'; import { TextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; import { ISerializedFileMatch, ISerializedSearchSuccess } from './search'; diff --git a/src/vs/workbench/services/search/node/textSearchManager.ts b/src/vs/workbench/services/search/node/textSearchManager.ts index 6fbcba08b7e..79708b3d243 100644 --- a/src/vs/workbench/services/search/node/textSearchManager.ts +++ b/src/vs/workbench/services/search/node/textSearchManager.ts @@ -12,7 +12,7 @@ import * as resources from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { toCanonicalName } from 'vs/base/node/encoding'; import * as extfs from 'vs/base/node/extfs'; -import { IExtendedExtensionSearchOptions, IFileMatch, IFolderQuery, IPatternInfo, ISearchCompleteStats, ITextQuery, ITextSearchContext, ITextSearchMatch, ITextSearchResult } from 'vs/platform/search/common/search'; +import { IExtendedExtensionSearchOptions, IFileMatch, IFolderQuery, IPatternInfo, ISearchCompleteStats, ITextQuery, ITextSearchContext, ITextSearchMatch, ITextSearchResult } from 'vs/workbench/services/search/common/search'; import { QueryGlobTester, resolvePatternsForProvider } from 'vs/workbench/services/search/node/search'; import * as vscode from 'vscode'; diff --git a/src/vs/platform/search/test/common/replace.test.ts b/src/vs/workbench/services/search/test/common/replace.test.ts similarity index 99% rename from src/vs/platform/search/test/common/replace.test.ts rename to src/vs/workbench/services/search/test/common/replace.test.ts index c8685c2e2b4..47085ed1ec0 100644 --- a/src/vs/platform/search/test/common/replace.test.ts +++ b/src/vs/workbench/services/search/test/common/replace.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { ReplacePattern } from 'vs/platform/search/common/replace'; +import { ReplacePattern } from 'vs/workbench/services/search/common/replace'; suite('Replace Pattern test', () => { diff --git a/src/vs/platform/search/test/common/search.test.ts b/src/vs/workbench/services/search/test/common/search.test.ts similarity index 98% rename from src/vs/platform/search/test/common/search.test.ts rename to src/vs/workbench/services/search/test/common/search.test.ts index 147c0cfc65b..4e32035be54 100644 --- a/src/vs/platform/search/test/common/search.test.ts +++ b/src/vs/workbench/services/search/test/common/search.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { ITextSearchPreviewOptions, OneLineRange, TextSearchMatch, SearchRange } from 'vs/platform/search/common/search'; +import { ITextSearchPreviewOptions, OneLineRange, TextSearchMatch, SearchRange } from 'vs/workbench/services/search/common/search'; suite('TextSearchResult', () => { diff --git a/src/vs/workbench/services/search/test/common/searchHelpers.test.ts b/src/vs/workbench/services/search/test/common/searchHelpers.test.ts index 3bd14e02209..a39fead78dc 100644 --- a/src/vs/workbench/services/search/test/common/searchHelpers.test.ts +++ b/src/vs/workbench/services/search/test/common/searchHelpers.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { ITextModel, FindMatch } from 'vs/editor/common/model'; import { editorMatchesToTextSearchResults, addContextToEditorMatches } from 'vs/workbench/services/search/common/searchHelpers'; import { Range } from 'vs/editor/common/core/range'; -import { ITextQuery, QueryType, ITextSearchContext } from 'vs/platform/search/common/search'; +import { ITextQuery, QueryType, ITextSearchContext } from 'vs/workbench/services/search/common/search'; suite('SearchHelpers', () => { suite('editorMatchesToTextSearchResults', () => { diff --git a/src/vs/workbench/services/search/test/node/rawSearchService.test.ts b/src/vs/workbench/services/search/test/node/rawSearchService.test.ts index de7cf1d7964..271ba9c9eea 100644 --- a/src/vs/workbench/services/search/test/node/rawSearchService.test.ts +++ b/src/vs/workbench/services/search/test/node/rawSearchService.test.ts @@ -9,7 +9,7 @@ import { getPathFromAmdModule } from 'vs/base/common/amd'; import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; import { Emitter, Event } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; -import { IFileQuery, IFileSearchStats, IFolderQuery, IProgress, ISearchEngineStats, QueryType } from 'vs/platform/search/common/search'; +import { IFileQuery, IFileSearchStats, IFolderQuery, IProgress, ISearchEngineStats, QueryType } from 'vs/workbench/services/search/common/search'; import { SearchService as RawSearchService } from 'vs/workbench/services/search/node/rawSearchService'; import { IRawFileMatch, ISearchEngine, ISearchEngineSuccess, ISerializedFileMatch, ISerializedSearchComplete, ISerializedSearchProgressItem, ISerializedSearchSuccess } from 'vs/workbench/services/search/node/search'; import { DiskSearch } from 'vs/workbench/services/search/node/searchService'; diff --git a/src/vs/workbench/services/search/test/node/search.test.ts b/src/vs/workbench/services/search/test/node/search.test.ts index ff89992c919..3908cec9df8 100644 --- a/src/vs/workbench/services/search/test/node/search.test.ts +++ b/src/vs/workbench/services/search/test/node/search.test.ts @@ -10,7 +10,7 @@ import { join, normalize } from 'vs/base/common/paths'; import * as platform from 'vs/base/common/platform'; import { joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; -import { IFolderQuery, QueryType } from 'vs/platform/search/common/search'; +import { IFolderQuery, QueryType } from 'vs/workbench/services/search/common/search'; import { Engine as FileSearchEngine, FileWalker } from 'vs/workbench/services/search/node/fileSearch'; import { IRawFileMatch } from 'vs/workbench/services/search/node/search'; diff --git a/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts b/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts index 8b56afda721..30adc7912a3 100644 --- a/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts +++ b/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts @@ -9,7 +9,7 @@ import { getPathFromAmdModule } from 'vs/base/common/amd'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import * as glob from 'vs/base/common/glob'; import { URI } from 'vs/base/common/uri'; -import { deserializeSearchError, IFolderQuery, ISearchRange, ITextQuery, ITextSearchContext, ITextSearchMatch, QueryType, SearchErrorCode } from 'vs/platform/search/common/search'; +import { deserializeSearchError, IFolderQuery, ISearchRange, ITextQuery, ITextSearchContext, ITextSearchMatch, QueryType, SearchErrorCode } from 'vs/workbench/services/search/common/search'; import { ISerializedFileMatch } from 'vs/workbench/services/search/node/search'; import { TextSearchEngineAdapter } from 'vs/workbench/services/search/node/textSearchAdapter'; diff --git a/src/vs/workbench/services/search/test/node/textSearchManager.test.ts b/src/vs/workbench/services/search/test/node/textSearchManager.test.ts index 2b2dcf13734..6a1cb0a90e0 100644 --- a/src/vs/workbench/services/search/test/node/textSearchManager.test.ts +++ b/src/vs/workbench/services/search/test/node/textSearchManager.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { URI } from 'vs/base/common/uri'; -import { ITextQuery, QueryType } from 'vs/platform/search/common/search'; +import { ITextQuery, QueryType } from 'vs/workbench/services/search/common/search'; import { TextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; import * as vscode from 'vscode'; diff --git a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts index 985ccdb5ab4..5caa4710b56 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts @@ -10,7 +10,7 @@ import { dispose } from 'vs/base/common/lifecycle'; import { joinPath } from 'vs/base/common/resources'; import { URI, UriComponents } from 'vs/base/common/uri'; import * as extfs from 'vs/base/node/extfs'; -import { IFileMatch, IFileQuery, IPatternInfo, IRawFileMatch2, ISearchCompleteStats, ISearchQuery, ITextQuery, QueryType, resultIsMatch } from 'vs/platform/search/common/search'; +import { IFileMatch, IFileQuery, IPatternInfo, IRawFileMatch2, ISearchCompleteStats, ISearchQuery, ITextQuery, QueryType, resultIsMatch } from 'vs/workbench/services/search/common/search'; import { MainContext, MainThreadSearchShape } from 'vs/workbench/api/node/extHost.protocol'; import { ExtHostSearch } from 'vs/workbench/api/node/extHostSearch'; import { Range } from 'vs/workbench/api/node/extHostTypes'; diff --git a/src/vs/workbench/test/electron-browser/quickopen.perf.integrationTest.ts b/src/vs/workbench/test/electron-browser/quickopen.perf.integrationTest.ts index 11a15cc0c13..5f1e9a82081 100644 --- a/src/vs/workbench/test/electron-browser/quickopen.perf.integrationTest.ts +++ b/src/vs/workbench/test/electron-browser/quickopen.perf.integrationTest.ts @@ -18,7 +18,7 @@ import { createSyncDescriptor } from 'vs/platform/instantiation/common/descripto import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { Registry } from 'vs/platform/registry/common/platform'; -import { ISearchService } from 'vs/platform/search/common/search'; +import { ISearchService } from 'vs/workbench/services/search/common/search'; import { ITelemetryInfo, ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { testWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; diff --git a/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts b/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts index ba26107a57f..a24f600feae 100644 --- a/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts +++ b/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts @@ -9,7 +9,7 @@ import * as fs from 'fs'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { createSyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { ISearchService } from 'vs/platform/search/common/search'; +import { ISearchService } from 'vs/workbench/services/search/common/search'; import { ITelemetryService, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; From 08a4504e07939b793e7d50740796b31b1bda4049 Mon Sep 17 00:00:00 2001 From: Christopher Leidigh Date: Sun, 10 Feb 2019 05:56:20 -0500 Subject: [PATCH 089/207] Remove cloneElementFont Fixes: bpasero comments (#68332) --- src/vs/base/browser/ui/selectBox/selectBoxCustom.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts index 77ca7e4f06e..0ddce2da9e0 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts @@ -428,8 +428,6 @@ export class SelectBoxList implements ISelectBoxDelegate, IListVirtualDelegate Date: Sat, 9 Feb 2019 14:30:53 +0100 Subject: [PATCH 090/207] Ability to edit when expression --- .../platform/contextkey/common/contextkey.ts | 34 ++- .../preferences/browser/keybindingsEditor.ts | 268 ++++++++++++++---- .../browser/media/keybindingsEditor.css | 35 ++- .../contrib/preferences/common/preferences.ts | 10 +- .../preferences.contribution.ts | 15 +- .../keybinding/common/keybindingEditing.ts | 21 +- .../keybindingEditing.test.ts | 24 +- 7 files changed, 304 insertions(+), 103 deletions(-) diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index 71deee86ec4..6617af20f86 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -42,32 +42,32 @@ export abstract class ContextKeyExpr { return new ContextKeyAndExpr(expr); } - public static deserialize(serialized: string | null | undefined): ContextKeyExpr | null { + public static deserialize(serialized: string | null | undefined, strict: boolean = false): ContextKeyExpr | null { if (!serialized) { return null; } let pieces = serialized.split('&&'); - let result = new ContextKeyAndExpr(pieces.map(p => this._deserializeOne(p))); + let result = new ContextKeyAndExpr(pieces.map(p => this._deserializeOne(p, strict))); return result.normalize(); } - private static _deserializeOne(serializedOne: string): ContextKeyExpr { + private static _deserializeOne(serializedOne: string, strict: boolean): ContextKeyExpr { serializedOne = serializedOne.trim(); if (serializedOne.indexOf('!=') >= 0) { let pieces = serializedOne.split('!='); - return new ContextKeyNotEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1])); + return new ContextKeyNotEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); } if (serializedOne.indexOf('==') >= 0) { let pieces = serializedOne.split('=='); - return new ContextKeyEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1])); + return new ContextKeyEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); } if (serializedOne.indexOf('=~') >= 0) { let pieces = serializedOne.split('=~'); - return new ContextKeyRegexExpr(pieces[0].trim(), this._deserializeRegexValue(pieces[1])); + return new ContextKeyRegexExpr(pieces[0].trim(), this._deserializeRegexValue(pieces[1], strict)); } if (/^\!\s*/.test(serializedOne)) { @@ -77,7 +77,7 @@ export abstract class ContextKeyExpr { return new ContextKeyDefinedExpr(serializedOne); } - private static _deserializeValue(serializedValue: string): any { + private static _deserializeValue(serializedValue: string, strict: boolean): any { serializedValue = serializedValue.trim(); if (serializedValue === 'true') { @@ -96,17 +96,25 @@ export abstract class ContextKeyExpr { return serializedValue; } - private static _deserializeRegexValue(serializedValue: string): RegExp | null { + private static _deserializeRegexValue(serializedValue: string, strict: boolean): RegExp | null { if (isFalsyOrWhitespace(serializedValue)) { - console.warn('missing regexp-value for =~-expression'); + if (strict) { + throw new Error('missing regexp-value for =~-expression'); + } else { + console.warn('missing regexp-value for =~-expression'); + } return null; } let start = serializedValue.indexOf('/'); let end = serializedValue.lastIndexOf('/'); if (start === end || start < 0 /* || to < 0 */) { - console.warn(`bad regexp-value '${serializedValue}', missing /-enclosure`); + if (strict) { + throw new Error(`bad regexp-value '${serializedValue}', missing /-enclosure`); + } else { + console.warn(`bad regexp-value '${serializedValue}', missing /-enclosure`); + } return null; } @@ -115,7 +123,11 @@ export abstract class ContextKeyExpr { try { return new RegExp(value, caseIgnoreFlag); } catch (e) { - console.warn(`bad regexp-value '${serializedValue}', parse error: ${e}`); + if (strict) { + throw new Error(`bad regexp-value '${serializedValue}', parse error: ${e}`); + } else { + console.warn(`bad regexp-value '${serializedValue}', parse error: ${e}`); + } return null; } } diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index 0cdaaf7ac93..4f1034c4834 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -8,7 +8,7 @@ import { localize } from 'vs/nls'; import { Delayer } from 'vs/base/common/async'; import * as DOM from 'vs/base/browser/dom'; import { OS } from 'vs/base/common/platform'; -import { dispose } from 'vs/base/common/lifecycle'; +import { dispose, Disposable, toDisposable, IDisposable } from 'vs/base/common/lifecycle'; import { CheckboxActionItem } from 'vs/base/browser/ui/checkbox/checkbox'; import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel'; @@ -25,15 +25,15 @@ import { DefineKeybindingWidget, KeybindingsSearchWidget, KeybindingsSearchOptio import { IKeybindingsEditor, CONTEXT_KEYBINDING_FOCUS, CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, - KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS + KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN } from 'vs/workbench/contrib/preferences/common/preferences'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IKeybindingEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing'; import { List } from 'vs/base/browser/ui/list/listWidget'; import { IListVirtualDelegate, IListRenderer, IListContextMenuEvent, IListEvent } from 'vs/base/browser/ui/list/list'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; -import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode, ResolvedKeybinding } from 'vs/base/common/keyCodes'; import { listHighlightForeground, badgeBackground, contrastBorder, badgeForeground, listActiveSelectionForeground } from 'vs/platform/theme/common/colorRegistry'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -42,9 +42,11 @@ import { WorkbenchList } from 'vs/platform/list/browser/listService'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { KeybindingsEditorInput } from 'vs/workbench/services/preferences/common/preferencesEditorInput'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { attachStylerCallback } from 'vs/platform/theme/common/styler'; +import { attachStylerCallback, attachInputBoxStyler } from 'vs/platform/theme/common/styler'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; +import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; +import { Emitter, Event } from 'vs/base/common/event'; const $ = DOM.$; @@ -52,6 +54,9 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor static readonly ID: string = 'workbench.editor.keybindings'; + private _onDefineWhenExpression: Emitter = this._register(new Emitter()); + readonly onDefineWhenExpression: Event = this._onDefineWhenExpression.event; + private keybindingsEditorModel: KeybindingsEditorModel; private headerContainer: HTMLElement; @@ -155,16 +160,8 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.showOverlayContainer(); return this.defineKeybindingWidget.define().then(key => { if (key) { - const currentKey = keybindingEntry.keybindingItem.keybinding ? keybindingEntry.keybindingItem.keybinding.getUserSettingsLabel() : ''; - if (currentKey !== key) { - this.reportKeybindingAction(KEYBINDINGS_EDITOR_COMMAND_DEFINE, keybindingEntry.keybindingItem.command, key); - return this.keybindingEditingService.editKeybinding(key, keybindingEntry.keybindingItem.keybindingItem) - .then(() => { - if (!keybindingEntry.keybindingItem.keybinding) { // reveal only if keybinding was added to unassinged. Because the entry will be placed in different position after rendering - this.unAssignedKeybindingItemToRevealAndFocus = keybindingEntry; - } - }); - } + this.reportKeybindingAction(KEYBINDINGS_EDITOR_COMMAND_DEFINE, keybindingEntry.keybindingItem.command, key); + return this.updateKeybinding(keybindingEntry, key, keybindingEntry.keybindingItem.when); } return null; }).then(() => { @@ -178,6 +175,24 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor }); } + defineWhenExpression(keybindingEntry: IKeybindingItemEntry): void { + this.selectEntry(keybindingEntry); + this._onDefineWhenExpression.fire(keybindingEntry); + } + + updateKeybinding(keybindingEntry: IKeybindingItemEntry, key: string, when: string): Promise { + const currentKey = keybindingEntry.keybindingItem.keybinding ? keybindingEntry.keybindingItem.keybinding.getUserSettingsLabel() : ''; + if (currentKey !== key || keybindingEntry.keybindingItem.when !== when) { + return this.keybindingEditingService.editKeybinding(keybindingEntry.keybindingItem.keybindingItem, key, when) + .then(() => { + if (!keybindingEntry.keybindingItem.keybinding) { // reveal only if keybinding was added to unassinged. Because the entry will be placed in different position after rendering + this.unAssignedKeybindingItemToRevealAndFocus = keybindingEntry; + } + }); + } + return Promise.resolve(); + } + removeKeybinding(keybindingEntry: IKeybindingItemEntry): Promise { this.selectEntry(keybindingEntry); if (keybindingEntry.keybindingItem.keybinding) { // This should be a pre-condition @@ -400,13 +415,13 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor $('.header.actions'), $('.header.command', undefined, localize('command', "Command")), $('.header.keybinding', undefined, localize('keybinding', "Keybinding")), - $('.header.source', undefined, localize('source', "Source")), - $('.header.when', undefined, localize('when', "When"))); + $('.header.when', undefined, localize('when', "When")), + $('.header.source', undefined, localize('source', "Source"))); } private createList(parent: HTMLElement): void { this.keybindingsListContainer = DOM.append(parent, $('.keybindings-list-container')); - this.keybindingsList = this._register(this.instantiationService.createInstance(WorkbenchList, this.keybindingsListContainer, new Delegate(), [new KeybindingItemRenderer(this, this.keybindingsService)], + this.keybindingsList = this._register(this.instantiationService.createInstance(WorkbenchList, this.keybindingsListContainer, new Delegate(), [new KeybindingItemRenderer(this, this.instantiationService)], { identityProvider: { getId: e => e.id }, ariaLabel: localize('keybindingsLabel', "Keybindings"), @@ -557,6 +572,10 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.keybindingsList.setFocus([currentFocusIndices.length ? currentFocusIndices[0] : 0]); } + selectKeybinding(keybindingItemEntry: IKeybindingItemEntry): void { + this.selectEntry(keybindingItemEntry); + } + recordSearchKeys(): void { this.recordKeysAction.checked = true; } @@ -579,6 +598,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.createCopyCommandAction(e.element), new Separator(), this.createDefineAction(e.element), + this.createDefineWhenExpressionAction(e.element), this.createRemoveAction(e.element), this.createResetAction(e.element), new Separator(), @@ -607,6 +627,15 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor }; } + private createDefineWhenExpressionAction(keybindingItemEntry: IKeybindingItemEntry): IAction { + return { + label: localize('editWhen', "Change When Expression"), + enabled: true, + id: KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN, + run: () => this.defineWhenExpression(keybindingItemEntry) + }; + } + private createRemoveAction(keybindingItem: IKeybindingItemEntry): IAction { return { label: localize('removeLabel', "Remove Keybinding"), @@ -722,16 +751,19 @@ class KeybindingItemRenderer implements IListRenderer = this._register(new Emitter()); + private readonly onDidAccept: Event = this._onDidAccept.event; + + private _onDidReject: Emitter = this._register(new Emitter()); + private readonly onDidReject: Event = this._onDidReject.event; + + constructor( + parent: HTMLElement, + keybindingsEditor: IKeybindingsEditor, + @IContextViewService private readonly contextViewService: IContextViewService, + @IThemeService private readonly themeService: IThemeService + ) { + super(keybindingsEditor); + this.element = this.create(parent); + this._register(toDisposable(() => this.disposables = dispose(this.disposables))); + } + + private create(parent: HTMLElement): HTMLElement { + const column = DOM.append(parent, $('.column.when', { id: 'when_' + ++Column.COUNTER })); + + this.whenLabel = DOM.append(column, $('div.when-label')); + this.whenInput = new InputBox(column, this.contextViewService, { + validationOptions: { + validation: (value) => { + try { + ContextKeyExpr.deserialize(value, true); + } catch (error) { + return { + content: error.message, + formatContent: true, + type: MessageType.ERROR + }; + } + return null; + } + }, + ariaLabel: localize('whenContextInputAriaLabel', "Type when context. Press Enter to confirm or Escape to cancel.") + }); + this._register(attachInputBoxStyler(this.whenInput, this.themeService)); + this._register(DOM.addStandardDisposableListener(this.whenInput.inputElement, DOM.EventType.KEY_DOWN, e => this.onInputKeyDown(e))); + this._register(DOM.addDisposableListener(this.whenInput.inputElement, DOM.EventType.BLUR, () => this.cancelEditing())); + + return column; + } + + private onInputKeyDown(e: IKeyboardEvent): void { + let handled = false; + if (e.equals(KeyCode.Enter)) { + this.finishEditing(); + handled = true; + } else if (e.equals(KeyCode.Escape)) { + this.cancelEditing(); + handled = true; + } + if (handled) { + e.preventDefault(); + e.stopPropagation(); + } + } + + private startEditing(): void { + DOM.addClass(this.element, 'input-mode'); + this.whenInput.focus(); + this.whenInput.select(); + } + + private finishEditing(): void { + DOM.removeClass(this.element, 'input-mode'); + this._onDidAccept.fire(); + } + + private cancelEditing(): void { + DOM.removeClass(this.element, 'input-mode'); + this._onDidReject.fire(); } render(keybindingItemEntry: IKeybindingItemEntry): void { - DOM.clearNode(this.whenColumn); - this.whenColumn.setAttribute('aria-label', this.getAriaLabel(keybindingItemEntry)); - DOM.toggleClass(this.whenColumn, 'code', !!keybindingItemEntry.keybindingItem.when); - DOM.toggleClass(this.whenColumn, 'empty', !keybindingItemEntry.keybindingItem.when); + this.disposables = dispose(this.disposables); + DOM.clearNode(this.whenLabel); + + this.keybindingsEditor.onDefineWhenExpression(e => { + if (keybindingItemEntry === e) { + this.startEditing(); + } + }, this, this.disposables); + this.whenInput.value = keybindingItemEntry.keybindingItem.when || ''; + this.whenLabel.setAttribute('aria-label', this.getAriaLabel(keybindingItemEntry)); + DOM.toggleClass(this.whenLabel, 'code', !!keybindingItemEntry.keybindingItem.when); + DOM.toggleClass(this.whenLabel, 'empty', !keybindingItemEntry.keybindingItem.when); if (keybindingItemEntry.keybindingItem.when) { - const whenLabel = new HighlightedLabel(this.whenColumn, false); + const whenLabel = new HighlightedLabel(this.whenLabel, false); whenLabel.set(keybindingItemEntry.keybindingItem.when, keybindingItemEntry.whenMatches); - this.whenColumn.title = keybindingItemEntry.keybindingItem.when; + this.element.title = keybindingItemEntry.keybindingItem.when; whenLabel.element.title = keybindingItemEntry.keybindingItem.when; } else { - this.whenColumn.textContent = '—'; - this.whenColumn.title = ''; + this.whenLabel.textContent = '—'; + this.element.title = ''; } + this.onDidAccept(() => { + this.keybindingsEditor.updateKeybinding(keybindingItemEntry, keybindingItemEntry.keybindingItem.keybinding ? keybindingItemEntry.keybindingItem.keybinding.getUserSettingsLabel() : '', this.whenInput.value); + this.keybindingsEditor.selectKeybinding(keybindingItemEntry); + }, this, this.disposables); + this.onDidReject(() => { + this.whenInput.value = keybindingItemEntry.keybindingItem.when || ''; + this.keybindingsEditor.selectKeybinding(keybindingItemEntry); + }, this, this.disposables); } private getAriaLabel(keybindingItemEntry: IKeybindingItemEntry): string { diff --git a/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css b/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css index a3cf8082534..67b36507b1b 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css +++ b/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css @@ -45,30 +45,30 @@ margin-right: 4px; } -.keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .sort-by-precedence { +.keybindings-editor .monaco-action-bar .action-item > .sort-by-precedence { background: url('sort_precedence.svg') center center no-repeat; } -.hc-black .keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .sort-by-precedence, -.vs-dark .keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .sort-by-precedence { +.hc-black .keybindings-editor .monaco-action-bar .action-item > .sort-by-precedence, +.vs-dark .keybindings-editor .monaco-action-bar .action-item > .sort-by-precedence { background: url('sort_precedence_inverse.svg') center center no-repeat; } -.keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .record-keys { +.keybindings-editor .monaco-action-bar .action-item > .record-keys { background: url('record-keys.svg') center center no-repeat; } -.hc-black .keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .record-keys, -.vs-dark .keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .record-keys { +.hc-black .keybindings-editor .monaco-action-bar .action-item > .record-keys, +.vs-dark .keybindings-editor .monaco-action-bar .action-item > .record-keys { background: url('record-keys-inverse.svg') center center no-repeat; } -.keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .clear-input { +.keybindings-editor .monaco-action-bar .action-item > .clear-input { background: url('clear.svg') center center no-repeat; } -.hc-black .keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .clear-input, -.vs-dark .keybindings-editor > .keybindings-header > .search-container > .keybindings-search-actions-container > .monaco-action-bar .action-item > .clear-input { +.hc-black .keybindings-editor .monaco-action-bar .action-item > .clear-input, +.vs-dark .keybindings-editor .monaco-action-bar .action-item > .clear-input { background: url('clear-inverse.svg') center center no-repeat; } @@ -171,6 +171,21 @@ padding-left: 4px; } +.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when:not(.input-mode) .monaco-inputbox, +.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when.input-mode .when-label { + display: none; +} + +.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when .monaco-inputbox { + width: 100%; + line-height: normal; +} + +.mac > .monaco-workbench .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when .monaco-inputbox, +.mac > .monaco-workbench .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when .monaco-inputbox { + height: 24px; +} + .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .command .monaco-highlighted-label, .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .source .monaco-highlighted-label, .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .when .monaco-highlighted-label { @@ -201,7 +216,7 @@ color: inherit; } -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column .monaco-action-bar { +.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column.actions .monaco-action-bar { display: none; flex: 1; } diff --git a/src/vs/workbench/contrib/preferences/common/preferences.ts b/src/vs/workbench/contrib/preferences/common/preferences.ts index 82cef64f57e..a90620ab26b 100644 --- a/src/vs/workbench/contrib/preferences/common/preferences.ts +++ b/src/vs/workbench/contrib/preferences/common/preferences.ts @@ -10,6 +10,7 @@ import { ISettingsEditorModel, ISearchResult } from 'vs/workbench/services/prefe import { IEditor } from 'vs/workbench/common/editor'; import { IKeybindingItemEntry } from 'vs/workbench/services/preferences/common/keybindingsEditorModel'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { Event } from 'vs/base/common/event'; export interface IWorkbenchSettingsConfiguration { workbench: { @@ -45,7 +46,8 @@ export interface ISearchProvider { export interface IKeybindingsEditor extends IEditor { - activeKeybindingEntry: IKeybindingItemEntry; + readonly activeKeybindingEntry: IKeybindingItemEntry; + readonly onDefineWhenExpression: Event; search(filter: string): void; focusSearch(): void; @@ -53,7 +55,10 @@ export interface IKeybindingsEditor extends IEditor { focusKeybindings(): void; recordSearchKeys(): void; toggleSortByPrecedence(): void; - defineKeybinding(keybindingEntry: IKeybindingItemEntry): Promise; + selectKeybinding(keybindingEntry: IKeybindingItemEntry): void; + defineKeybinding(keybindingEntry: IKeybindingItemEntry): Promise; + defineWhenExpression(keybindingEntry: IKeybindingItemEntry): void; + updateKeybinding(keybindingEntry: IKeybindingItemEntry, key: string, when: string): Promise; removeKeybinding(keybindingEntry: IKeybindingItemEntry): Promise; resetKeybinding(keybindingEntry: IKeybindingItemEntry): Promise; copyKeybinding(keybindingEntry: IKeybindingItemEntry): void; @@ -88,6 +93,7 @@ export const KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS = 'keybindings.edit export const KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS = 'keybindings.editor.recordSearchKeys'; export const KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE = 'keybindings.editor.toggleSortByPrecedence'; export const KEYBINDINGS_EDITOR_COMMAND_DEFINE = 'keybindings.editor.defineKeybinding'; +export const KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN = 'keybindings.editor.defineWhenExpression'; export const KEYBINDINGS_EDITOR_COMMAND_REMOVE = 'keybindings.editor.removeKeybinding'; export const KEYBINDINGS_EDITOR_COMMAND_RESET = 'keybindings.editor.resetKeybinding'; export const KEYBINDINGS_EDITOR_COMMAND_COPY = 'keybindings.editor.copyKeybindingEntry'; diff --git a/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts index b1668428f7d..5ccb0154105 100644 --- a/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts @@ -29,7 +29,7 @@ import { ResourceContextKey } from 'vs/workbench/common/resources'; import { KeybindingsEditor } from 'vs/workbench/contrib/preferences/browser/keybindingsEditor'; import { ConfigureLanguageBasedSettingsAction, OpenDefaultKeybindingsFileAction, OpenFolderSettingsAction, OpenGlobalKeybindingsAction, OpenGlobalKeybindingsFileAction, OpenGlobalSettingsAction, OpenRawDefaultSettingsAction, OpenSettings2Action, OpenSettingsJsonAction, OpenWorkspaceSettingsAction, OPEN_FOLDER_SETTINGS_COMMAND, OPEN_FOLDER_SETTINGS_LABEL } from 'vs/workbench/contrib/preferences/browser/preferencesActions'; import { PreferencesEditor } from 'vs/workbench/contrib/preferences/browser/preferencesEditor'; -import { CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, CONTEXT_KEYBINDING_FOCUS, CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_JSON_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, IKeybindingsEditor, IPreferencesSearchService, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SEARCH, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_SHOW_DEFAULT_KEYBINDINGS, KEYBINDINGS_EDITOR_SHOW_USER_KEYBINDINGS, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING, SETTINGS_EDITOR_COMMAND_FILTER_MODIFIED, SETTINGS_EDITOR_COMMAND_FILTER_ONLINE, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_FROM_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_LIST, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON, SETTINGS_COMMAND_OPEN_SETTINGS } from 'vs/workbench/contrib/preferences/common/preferences'; +import { CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, CONTEXT_KEYBINDING_FOCUS, CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_JSON_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, IKeybindingsEditor, IPreferencesSearchService, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SEARCH, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_SHOW_DEFAULT_KEYBINDINGS, KEYBINDINGS_EDITOR_SHOW_USER_KEYBINDINGS, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING, SETTINGS_EDITOR_COMMAND_FILTER_MODIFIED, SETTINGS_EDITOR_COMMAND_FILTER_ONLINE, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_FROM_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_LIST, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON, SETTINGS_COMMAND_OPEN_SETTINGS, KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN } from 'vs/workbench/contrib/preferences/common/preferences'; import { PreferencesContribution } from 'vs/workbench/contrib/preferences/common/preferencesContribution'; import { PreferencesSearchService } from 'vs/workbench/contrib/preferences/electron-browser/preferencesSearch'; import { SettingsEditor2 } from 'vs/workbench/contrib/preferences/electron-browser/settingsEditor2'; @@ -231,6 +231,19 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN, + weight: KeybindingWeight.WorkbenchContrib, + when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDING_FOCUS), + primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_E), + handler: (accessor, args: any) => { + const control = accessor.get(IEditorService).activeControl as IKeybindingsEditor; + if (control && control instanceof KeybindingsEditor) { + control.defineWhenExpression(control.activeKeybindingEntry); + } + } +}); + KeybindingsRegistry.registerCommandAndKeybindingRule({ id: KEYBINDINGS_EDITOR_COMMAND_REMOVE, weight: KeybindingWeight.WorkbenchContrib, diff --git a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts index e832b4a11b0..9169b3ab298 100644 --- a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts +++ b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts @@ -32,7 +32,7 @@ export interface IKeybindingEditingService { _serviceBrand: ServiceIdentifier; - editKeybinding(key: string, keybindingItem: ResolvedKeybindingItem): Promise; + editKeybinding(keybindingItem: ResolvedKeybindingItem, key: string, when: string): Promise; removeKeybinding(keybindingItem: ResolvedKeybindingItem): Promise; @@ -57,8 +57,8 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding this.queue = new Queue(); } - editKeybinding(key: string, keybindingItem: ResolvedKeybindingItem): Promise { - return this.queue.queue(() => this.doEditKeybinding(key, keybindingItem)); // queue up writes to prevent race conditions + editKeybinding(keybindingItem: ResolvedKeybindingItem, key: string, when: string): Promise { + return this.queue.queue(() => this.doEditKeybinding(keybindingItem, key, when)); // queue up writes to prevent race conditions } resetKeybinding(keybindingItem: ResolvedKeybindingItem): Promise { @@ -69,13 +69,13 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding return this.queue.queue(() => this.doRemoveKeybinding(keybindingItem)); // queue up writes to prevent race conditions } - private doEditKeybinding(key: string, keybindingItem: ResolvedKeybindingItem): Promise { + private doEditKeybinding(keybindingItem: ResolvedKeybindingItem, key: string, when: string): Promise { return this.resolveAndValidate() .then(reference => { const model = reference.object.textEditorModel; const userKeybindingEntries = json.parse(model.getValue()); const userKeybindingEntryIndex = this.findUserKeybindingEntryIndex(keybindingItem, userKeybindingEntries); - this.updateKeybinding(key, keybindingItem, model, userKeybindingEntryIndex); + this.updateKeybinding(keybindingItem, key, when, model, userKeybindingEntryIndex); if (keybindingItem.isDefault && keybindingItem.resolvedKeybinding) { this.removeDefaultKeybinding(keybindingItem, model); } @@ -112,15 +112,16 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding return this.textFileService.save(this.resource); } - private updateKeybinding(newKey: string, keybindingItem: ResolvedKeybindingItem, model: ITextModel, userKeybindingEntryIndex: number): void { + private updateKeybinding(keybindingItem: ResolvedKeybindingItem, newKey: string, when: string, model: ITextModel, userKeybindingEntryIndex: number): void { const { tabSize, insertSpaces } = model.getOptions(); const eol = model.getEOL(); if (userKeybindingEntryIndex !== -1) { // Update the keybinding with new key this.applyEditsToBuffer(setProperty(model.getValue(), [userKeybindingEntryIndex, 'key'], newKey, { tabSize, insertSpaces, eol })[0], model); + this.applyEditsToBuffer(setProperty(model.getValue(), [userKeybindingEntryIndex, 'when'], when, { tabSize, insertSpaces, eol })[0], model); } else { // Add the new keybinding with new key - this.applyEditsToBuffer(setProperty(model.getValue(), [-1], this.asObject(newKey, keybindingItem.command, keybindingItem.when, false), { tabSize, insertSpaces, eol })[0], model); + this.applyEditsToBuffer(setProperty(model.getValue(), [-1], this.asObject(newKey, keybindingItem.command, when, false), { tabSize, insertSpaces, eol })[0], model); } } @@ -137,7 +138,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding private removeDefaultKeybinding(keybindingItem: ResolvedKeybindingItem, model: ITextModel): void { const { tabSize, insertSpaces } = model.getOptions(); const eol = model.getEOL(); - this.applyEditsToBuffer(setProperty(model.getValue(), [-1], this.asObject(keybindingItem.resolvedKeybinding.getUserSettingsLabel(), keybindingItem.command, keybindingItem.when, true), { tabSize, insertSpaces, eol })[0], model); + this.applyEditsToBuffer(setProperty(model.getValue(), [-1], this.asObject(keybindingItem.resolvedKeybinding.getUserSettingsLabel(), keybindingItem.command, keybindingItem.when.serialize(), true), { tabSize, insertSpaces, eol })[0], model); } private removeUnassignedDefaultKeybinding(keybindingItem: ResolvedKeybindingItem, model: ITextModel): void { @@ -177,11 +178,11 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding return indices; } - private asObject(key: string, command: string, when: ContextKeyExpr, negate: boolean): any { + private asObject(key: string, command: string, when: string, negate: boolean): any { const object = { key }; object['command'] = negate ? `-${command}` : command; if (when) { - object['when'] = when.serialize(); + object['when'] = when; } return object; } diff --git a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts index 3240a4cb1fb..e25ae34990c 100644 --- a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts @@ -120,28 +120,28 @@ suite('KeybindingsEditing', () => { test('errors cases - parse errors', () => { fs.writeFileSync(keybindingsFile, ',,,,,,,,,,,,,,'); - return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } })) + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }), 'alt+c', '') .then(() => assert.fail('Should fail with parse errors'), error => assert.equal(error.message, 'Unable to write to the keybindings configuration file. Please open it to correct errors/warnings in the file and try again.')); }); test('errors cases - parse errors 2', () => { fs.writeFileSync(keybindingsFile, '[{"key": }]'); - return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } })) + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }), 'alt+c', '') .then(() => assert.fail('Should fail with parse errors'), error => assert.equal(error.message, 'Unable to write to the keybindings configuration file. Please open it to correct errors/warnings in the file and try again.')); }); test('errors cases - dirty', () => { instantiationService.stub(ITextFileService, 'isDirty', true); - return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } })) + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }), 'alt+c', '') .then(() => assert.fail('Should fail with dirty error'), error => assert.equal(error.message, 'Unable to write because the keybindings configuration file is dirty. Please save it first and then try again.')); }); test('errors cases - did not find an array', () => { fs.writeFileSync(keybindingsFile, '{"key": "alt+c", "command": "hello"}'); - return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } })) + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }), 'alt+c', '') .then(() => assert.fail('Should fail with dirty error'), error => assert.equal(error.message, 'Unable to write to the keybindings configuration file. It has an object which is not of type Array. Please open the file to clean up and try again.')); }); @@ -149,7 +149,7 @@ suite('KeybindingsEditing', () => { test('edit a default keybinding to an empty file', () => { fs.writeFileSync(keybindingsFile, ''); const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'a' }, { key: 'escape', command: '-a' }]; - return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' })) + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', '') .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); @@ -159,41 +159,41 @@ suite('KeybindingsEditing', () => { testObject = instantiationService.createInstance(KeybindingsEditingService); const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'a' }, { key: 'escape', command: '-a' }]; - return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' })) + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', '') .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); test('edit a default keybinding to an empty array', () => { writeToKeybindingsFile(); const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'a' }, { key: 'escape', command: '-a' }]; - return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' })) + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', '') .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); test('edit a default keybinding in an existing array', () => { writeToKeybindingsFile({ command: 'b', key: 'shift+c' }); const expected: IUserFriendlyKeybinding[] = [{ key: 'shift+c', command: 'b' }, { key: 'alt+c', command: 'a' }, { key: 'escape', command: '-a' }]; - return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' })) + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', '') .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); test('add a new default keybinding', () => { const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'a' }]; - return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ command: 'a' })) + return testObject.editKeybinding(aResolvedKeybindingItem({ command: 'a' }), 'alt+c', '') .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); test('edit an user keybinding', () => { writeToKeybindingsFile({ key: 'escape', command: 'b' }); const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'b' }]; - return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'b', isDefault: false })) + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'b', isDefault: false }), 'alt+c', '') .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); test('edit an user keybinding with more than one element', () => { writeToKeybindingsFile({ key: 'escape', command: 'b' }, { key: 'alt+shift+g', command: 'c' }); const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'b' }, { key: 'alt+shift+g', command: 'c' }]; - return testObject.editKeybinding('alt+c', aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'b', isDefault: false })) + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'b', isDefault: false }), 'alt+c', '') .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); @@ -232,7 +232,7 @@ suite('KeybindingsEditing', () => { test('add a new keybinding to unassigned keybinding', () => { writeToKeybindingsFile({ key: 'alt+c', command: '-a' }); const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: '-a' }, { key: 'shift+alt+c', command: 'a' }]; - return testObject.editKeybinding('shift+alt+c', aResolvedKeybindingItem({ command: 'a', isDefault: false })) + return testObject.editKeybinding(aResolvedKeybindingItem({ command: 'a', isDefault: false }), 'shift+alt+c', '') .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); From 33b11270debb22b9c6dbd9122646afc585fd47d4 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Sat, 9 Feb 2019 19:04:56 +0100 Subject: [PATCH 091/207] layout column width in code --- .../preferences/browser/keybindingsEditor.ts | 92 ++++++++++++------- .../browser/media/keybindingsEditor.css | 22 ----- .../contrib/preferences/common/preferences.ts | 2 + 3 files changed, 59 insertions(+), 57 deletions(-) diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index 4f1034c4834..880c5ffa061 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -57,6 +57,9 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor private _onDefineWhenExpression: Emitter = this._register(new Emitter()); readonly onDefineWhenExpression: Event = this._onDefineWhenExpression.event; + private _onLayout: Emitter = this._register(new Emitter()); + readonly onLayout: Event = this._onLayout.event; + private keybindingsEditorModel: KeybindingsEditorModel; private headerContainer: HTMLElement; @@ -66,6 +69,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor private overlayContainer: HTMLElement; private defineKeybindingWidget: DefineKeybindingWidget; + private columns: HTMLElement[] = []; private keybindingsListContainer: HTMLElement; private unAssignedKeybindingItemToRevealAndFocus: IKeybindingItemEntry; private listEntries: IListEntry[]; @@ -139,6 +143,23 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.defineKeybindingWidget.layout(this.dimension); this.layoutKeybindingsList(); + this._onLayout.fire(); + } + + layoutColumns(columns: HTMLElement[]): void { + if (this.dimension) { + const marginRight = 6; + columns[0].style.width = '24px'; + const width = this.dimension.width - 30; + columns[1].style.width = `${(width * 0.3) - marginRight}px`; + columns[2].style.width = `${(width * 0.2) - marginRight}px`; + columns[3].style.width = `${(width * 0.5) - marginRight}px`; + columns[4].style.width = `${(width * 0.1) - marginRight}px`; + + for (const column of columns) { + column.style.marginRight = `${marginRight}px`; + } + } } focus(): void { @@ -411,12 +432,12 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor const keybindingsListHeader = DOM.append(parent, $('.keybindings-list-header')); keybindingsListHeader.style.height = '30px'; keybindingsListHeader.style.lineHeight = '30px'; - DOM.append(keybindingsListHeader, - $('.header.actions'), - $('.header.command', undefined, localize('command', "Command")), - $('.header.keybinding', undefined, localize('keybinding', "Keybinding")), - $('.header.when', undefined, localize('when', "When")), - $('.header.source', undefined, localize('source', "Source"))); + this.columns.push($('.header.actions')); + this.columns.push($('.header.command', undefined, localize('command', "Command"))); + this.columns.push($('.header.keybinding', undefined, localize('keybinding', "Keybinding"))); + this.columns.push($('.header.when', undefined, localize('when', "When"))); + this.columns.push($('.header.source', undefined, localize('source', "Source"))); + DOM.append(keybindingsListHeader, ...this.columns); } private createList(parent: HTMLElement): void { @@ -527,6 +548,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor } private layoutKeybindingsList(): void { + this.layoutColumns(this.columns); const listHeight = this.dimension.height - (DOM.getDomNodePagePosition(this.headerContainer).height + 12 /*padding*/ + 30 /*list header*/); this.keybindingsListContainer.style.height = `${listHeight}px`; this.keybindingsList.layout(listHeight); @@ -740,11 +762,8 @@ class Delegate implements IListVirtualDelegate { interface KeybindingItemTemplate { parent: HTMLElement; - actions: ActionsColumn; - command: CommandColumn; - keybinding: KeybindingColumn; - source: SourceColumn; - when: WhenColumn; + columns: Column[]; + disposable: IDisposable; } class KeybindingItemRenderer implements IListRenderer { @@ -756,39 +775,39 @@ class KeybindingItemRenderer implements IListRenderer element); + + this.keybindingsEditor.layoutColumns(elements); + this.keybindingsEditor.onLayout(() => this.keybindingsEditor.layoutColumns(elements)); + parent.setAttribute('aria-labelledby', elements.map(e => e.getAttribute('id')).join(' ')); + return { - parent: container, - actions, - command, - keybinding, - source, - when + parent, + columns, + disposable: toDisposable(() => dispose(disposables)) }; } renderElement(keybindingEntry: IKeybindingItemEntry, index: number, template: KeybindingItemTemplate): void { DOM.toggleClass(template.parent, 'odd', index % 2 === 1); - template.actions.render(keybindingEntry); - template.command.render(keybindingEntry); - template.keybinding.render(keybindingEntry); - template.source.render(keybindingEntry); - template.when.render(keybindingEntry); + for (const column of template.columns) { + column.render(keybindingEntry); + } } disposeTemplate(template: KeybindingItemTemplate): void { - template.actions.dispose(); - template.command.dispose(); - template.keybinding.dispose(); - template.source.dispose(); - template.when.dispose(); + template.disposable.dispose(); } } @@ -796,6 +815,9 @@ abstract class Column extends Disposable { static COUNTER = 0; + abstract readonly element: HTMLElement; + abstract render(keybindingItemEntry: IKeybindingItemEntry): void; + constructor(protected keybindingsEditor: IKeybindingsEditor) { super(); } diff --git a/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css b/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css index 67b36507b1b..31de2b967c0 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css +++ b/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css @@ -123,18 +123,6 @@ align-items: center; display: flex; overflow: hidden; - margin-right: 6px; -} - -.keybindings-editor > .keybindings-body > .keybindings-list-header > .actions, -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .actions { - width: 24px; - padding-right: 2px; -} - -.keybindings-editor > .keybindings-body > .keybindings-list-header > .command, -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .command { - flex: 0.75; } .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .command.vertical-align-column { @@ -148,11 +136,6 @@ margin-top: 2px; } -.keybindings-editor > .keybindings-body > .keybindings-list-header > .keybinding, -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .keybinding { - flex: 0.5; -} - .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .keybinding .monaco-highlighted-label { padding-left: 10px; } @@ -162,11 +145,6 @@ flex: 0 0 100px; } -.keybindings-editor > .keybindings-body > .keybindings-list-header > .when, -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .when { - flex: 1; -} - .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when .empty { padding-left: 4px; } diff --git a/src/vs/workbench/contrib/preferences/common/preferences.ts b/src/vs/workbench/contrib/preferences/common/preferences.ts index a90620ab26b..8c6868085aa 100644 --- a/src/vs/workbench/contrib/preferences/common/preferences.ts +++ b/src/vs/workbench/contrib/preferences/common/preferences.ts @@ -48,6 +48,7 @@ export interface IKeybindingsEditor extends IEditor { readonly activeKeybindingEntry: IKeybindingItemEntry; readonly onDefineWhenExpression: Event; + readonly onLayout: Event; search(filter: string): void; focusSearch(): void; @@ -55,6 +56,7 @@ export interface IKeybindingsEditor extends IEditor { focusKeybindings(): void; recordSearchKeys(): void; toggleSortByPrecedence(): void; + layoutColumns(columns: HTMLElement[]): void; selectKeybinding(keybindingEntry: IKeybindingItemEntry): void; defineKeybinding(keybindingEntry: IKeybindingItemEntry): Promise; defineWhenExpression(keybindingEntry: IKeybindingItemEntry): void; From 80d48da9587812309aee48af443cb98e8bdec34d Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Sun, 10 Feb 2019 17:51:29 +0100 Subject: [PATCH 092/207] :lipstick --- .../preferences/browser/keybindingsEditor.ts | 68 +++++++++++++------ .../browser/media/keybindingsEditor.css | 5 -- 2 files changed, 48 insertions(+), 25 deletions(-) diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index 880c5ffa061..e1d8476630f 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -50,6 +50,12 @@ import { Emitter, Event } from 'vs/base/common/event'; const $ = DOM.$; +interface ColumnItem { + column: HTMLElement; + proportion?: number; + width: number; +} + export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor { static readonly ID: string = 'workbench.editor.keybindings'; @@ -69,7 +75,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor private overlayContainer: HTMLElement; private defineKeybindingWidget: DefineKeybindingWidget; - private columns: HTMLElement[] = []; + private columnItems: ColumnItem[] = []; private keybindingsListContainer: HTMLElement; private unAssignedKeybindingItemToRevealAndFocus: IKeybindingItemEntry; private listEntries: IListEntry[]; @@ -142,23 +148,21 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.overlayContainer.style.height = dimension.height + 'px'; this.defineKeybindingWidget.layout(this.dimension); + this.columnItems.forEach(columnItem => { + if (columnItem.proportion) { + columnItem.width = 0; + } + }); this.layoutKeybindingsList(); this._onLayout.fire(); } layoutColumns(columns: HTMLElement[]): void { - if (this.dimension) { - const marginRight = 6; - columns[0].style.width = '24px'; - const width = this.dimension.width - 30; - columns[1].style.width = `${(width * 0.3) - marginRight}px`; - columns[2].style.width = `${(width * 0.2) - marginRight}px`; - columns[3].style.width = `${(width * 0.5) - marginRight}px`; - columns[4].style.width = `${(width * 0.1) - marginRight}px`; - - for (const column of columns) { - column.style.marginRight = `${marginRight}px`; - } + if (this.columnItems) { + columns.forEach((column, index) => { + column.style.paddingRight = `6px`; + column.style.width = `${this.columnItems[index].width}px`; + }); } } @@ -432,12 +436,24 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor const keybindingsListHeader = DOM.append(parent, $('.keybindings-list-header')); keybindingsListHeader.style.height = '30px'; keybindingsListHeader.style.lineHeight = '30px'; - this.columns.push($('.header.actions')); - this.columns.push($('.header.command', undefined, localize('command', "Command"))); - this.columns.push($('.header.keybinding', undefined, localize('keybinding', "Keybinding"))); - this.columns.push($('.header.when', undefined, localize('when', "When"))); - this.columns.push($('.header.source', undefined, localize('source', "Source"))); - DOM.append(keybindingsListHeader, ...this.columns); + + this.columnItems = []; + let column = $('.header.actions'); + this.columnItems.push({ column, width: 30 }); + + column = $('.header.command', undefined, localize('command', "Command")); + this.columnItems.push({ column, proportion: 0.3, width: 0 }); + + column = $('.header.keybinding', undefined, localize('keybinding', "Keybinding")); + this.columnItems.push({ column, proportion: 0.2, width: 0 }); + + column = $('.header.when', undefined, localize('when', "When")); + this.columnItems.push({ column, proportion: 0.4, width: 0 }); + + column = $('.header.source', undefined, localize('source', "Source")); + this.columnItems.push({ column, proportion: 0.1, width: 0 }); + + DOM.append(keybindingsListHeader, ...this.columnItems.map(({ column }) => column)); } private createList(parent: HTMLElement): void { @@ -548,7 +564,19 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor } private layoutKeybindingsList(): void { - this.layoutColumns(this.columns); + let width = this.dimension.width - 27; + for (const columnItem of this.columnItems) { + if (columnItem.width && !columnItem.proportion) { + width = width - columnItem.width; + } + } + for (const columnItem of this.columnItems) { + if (columnItem.proportion && !columnItem.width) { + columnItem.width = width * columnItem.proportion; + } + } + + this.layoutColumns(this.columnItems.map(({ column }) => column)); const listHeight = this.dimension.height - (DOM.getDomNodePagePosition(this.headerContainer).height + 12 /*padding*/ + 30 /*list header*/); this.keybindingsListContainer.style.height = `${listHeight}px`; this.keybindingsList.layout(listHeight); diff --git a/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css b/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css index 31de2b967c0..2a20cd52885 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css +++ b/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css @@ -140,11 +140,6 @@ padding-left: 10px; } -.keybindings-editor > .keybindings-body > .keybindings-list-header > .source, -.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row .source { - flex: 0 0 100px; -} - .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when .empty { padding-left: 4px; } From 5877b0f894d3756261ef356dd71e212958041287 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Sun, 10 Feb 2019 18:54:22 +0100 Subject: [PATCH 093/207] remove open keybindings file link in editor --- .../preferences/browser/keybindingsEditor.ts | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index e1d8476630f..037b9d7c28d 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -44,7 +44,6 @@ import { KeybindingsEditorInput } from 'vs/workbench/services/preferences/common import { CancellationToken } from 'vs/base/common/cancellation'; import { attachStylerCallback, attachInputBoxStyler } from 'vs/platform/theme/common/styler'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; import { Emitter, Event } from 'vs/base/common/event'; @@ -106,8 +105,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor @IClipboardService private readonly clipboardService: IClipboardService, @IInstantiationService private readonly instantiationService: IInstantiationService, @IEditorService private readonly editorService: IEditorService, - @IStorageService storageService: IStorageService, - @IPreferencesService private readonly preferencesService: IPreferencesService + @IStorageService storageService: IStorageService ) { super(KeybindingsEditor.ID, telemetryService, themeService, storageService); this.delayedFiltering = new Delayer(300); @@ -381,8 +379,6 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor })); this.actionBar.push([this.recordKeysAction, this.sortByPrecedenceAction, clearInputAction], { label: false, icon: true }); - - this.createOpenKeybindingsElement(this.headerContainer); } private createRecordingBadge(container: HTMLElement): HTMLElement { @@ -402,24 +398,6 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor return recordingBadge; } - private createOpenKeybindingsElement(parent: HTMLElement): void { - const openKeybindingsContainer = DOM.append(parent, $('.open-keybindings-container')); - DOM.append(openKeybindingsContainer, $('', undefined, localize('header-message', "For advanced customizations open and edit"))); - const fileElement = DOM.append(openKeybindingsContainer, $('.file-name', undefined, localize('keybindings-file-name', "keybindings.json"))); - fileElement.tabIndex = 0; - this._register(DOM.addDisposableListener(fileElement, DOM.EventType.CLICK, () => this.preferencesService.openGlobalKeybindingSettings(true))); - this._register(DOM.addDisposableListener(fileElement, DOM.EventType.KEY_UP, e => { - const keyboardEvent = new StandardKeyboardEvent(e); - switch (keyboardEvent.keyCode) { - case KeyCode.Enter: - this.preferencesService.openGlobalKeybindingSettings(true); - keyboardEvent.preventDefault(); - keyboardEvent.stopPropagation(); - return; - } - })); - } - private layoutSearchWidget(dimension: DOM.Dimension): void { this.searchWidget.layout(dimension); DOM.toggleClass(this.headerContainer, 'small', dimension.width < 400); From 5082ec9e4d84624df4eb4afce23b977bb1555806 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Sun, 10 Feb 2019 18:54:38 +0100 Subject: [PATCH 094/207] by default do not open default keybindings --- src/vs/workbench/browser/workbench.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index 3798dbde4fd..12f78547309 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -154,7 +154,7 @@ configurationRegistry.registerConfiguration({ 'workbench.settings.openDefaultKeybindings': { 'type': 'boolean', 'description': nls.localize('openDefaultKeybindings', "Controls whether opening keybinding settings also opens an editor showing all default keybindings."), - 'default': true + 'default': false }, 'workbench.sideBar.location': { 'type': 'string', From 0701858f78469723f8e53b7fb703ea9a0d31793e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Sun, 10 Feb 2019 18:55:10 +0100 Subject: [PATCH 095/207] do not serialize 'when' if not defined --- .../workbench/services/keybinding/common/keybindingEditing.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts index 9169b3ab298..e7a5144d133 100644 --- a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts +++ b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts @@ -138,7 +138,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding private removeDefaultKeybinding(keybindingItem: ResolvedKeybindingItem, model: ITextModel): void { const { tabSize, insertSpaces } = model.getOptions(); const eol = model.getEOL(); - this.applyEditsToBuffer(setProperty(model.getValue(), [-1], this.asObject(keybindingItem.resolvedKeybinding.getUserSettingsLabel(), keybindingItem.command, keybindingItem.when.serialize(), true), { tabSize, insertSpaces, eol })[0], model); + this.applyEditsToBuffer(setProperty(model.getValue(), [-1], this.asObject(keybindingItem.resolvedKeybinding.getUserSettingsLabel(), keybindingItem.command, keybindingItem.when ? keybindingItem.when.serialize() : undefined, true), { tabSize, insertSpaces, eol })[0], model); } private removeUnassignedDefaultKeybinding(keybindingItem: ResolvedKeybindingItem, model: ITextModel): void { From f0e925cd75b7de9c6bbd8b5af2da29924e889ebe Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Sun, 10 Feb 2019 18:59:06 +0100 Subject: [PATCH 096/207] fix tests --- .../test/electron-browser/keybindingEditing.test.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts index e25ae34990c..161b34552b8 100644 --- a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts @@ -236,6 +236,13 @@ suite('KeybindingsEditing', () => { .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); + test('add update when expression', () => { + writeToKeybindingsFile({ key: 'alt+c', command: '-a' }); + const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: '-a' }, { key: 'shift+alt+c', command: 'a', when: 'editorTextFocus' }]; + return testObject.editKeybinding(aResolvedKeybindingItem({ command: 'a', isDefault: false }), 'shift+alt+c', 'editorTextFocus') + .then(() => assert.deepEqual(getUserKeybindings(), expected)); + }); + function writeToKeybindingsFile(...keybindings: IUserFriendlyKeybinding[]) { fs.writeFileSync(keybindingsFile, JSON.stringify(keybindings || [])); } From d049558486b5ccebc607c826ac4055970b0bc80e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Sun, 10 Feb 2019 19:23:33 +0100 Subject: [PATCH 097/207] write tests and clean up keybinding editing service --- .../preferences/browser/keybindingsEditor.ts | 4 +- .../contrib/preferences/common/preferences.ts | 2 +- .../keybinding/common/keybindingEditing.ts | 13 +++--- .../keybindingEditing.test.ts | 40 +++++++++++++------ 4 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index 037b9d7c28d..d0fa562b51f 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -203,10 +203,10 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this._onDefineWhenExpression.fire(keybindingEntry); } - updateKeybinding(keybindingEntry: IKeybindingItemEntry, key: string, when: string): Promise { + updateKeybinding(keybindingEntry: IKeybindingItemEntry, key: string, when: string | undefined): Promise { const currentKey = keybindingEntry.keybindingItem.keybinding ? keybindingEntry.keybindingItem.keybinding.getUserSettingsLabel() : ''; if (currentKey !== key || keybindingEntry.keybindingItem.when !== when) { - return this.keybindingEditingService.editKeybinding(keybindingEntry.keybindingItem.keybindingItem, key, when) + return this.keybindingEditingService.editKeybinding(keybindingEntry.keybindingItem.keybindingItem, key, when || undefined) .then(() => { if (!keybindingEntry.keybindingItem.keybinding) { // reveal only if keybinding was added to unassinged. Because the entry will be placed in different position after rendering this.unAssignedKeybindingItemToRevealAndFocus = keybindingEntry; diff --git a/src/vs/workbench/contrib/preferences/common/preferences.ts b/src/vs/workbench/contrib/preferences/common/preferences.ts index 8c6868085aa..c80bcaffa8a 100644 --- a/src/vs/workbench/contrib/preferences/common/preferences.ts +++ b/src/vs/workbench/contrib/preferences/common/preferences.ts @@ -60,7 +60,7 @@ export interface IKeybindingsEditor extends IEditor { selectKeybinding(keybindingEntry: IKeybindingItemEntry): void; defineKeybinding(keybindingEntry: IKeybindingItemEntry): Promise; defineWhenExpression(keybindingEntry: IKeybindingItemEntry): void; - updateKeybinding(keybindingEntry: IKeybindingItemEntry, key: string, when: string): Promise; + updateKeybinding(keybindingEntry: IKeybindingItemEntry, key: string, when: string | undefined): Promise; removeKeybinding(keybindingEntry: IKeybindingItemEntry): Promise; resetKeybinding(keybindingEntry: IKeybindingItemEntry): Promise; copyKeybinding(keybindingEntry: IKeybindingItemEntry): void; diff --git a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts index e7a5144d133..e21a0e65f59 100644 --- a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts +++ b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts @@ -32,7 +32,7 @@ export interface IKeybindingEditingService { _serviceBrand: ServiceIdentifier; - editKeybinding(keybindingItem: ResolvedKeybindingItem, key: string, when: string): Promise; + editKeybinding(keybindingItem: ResolvedKeybindingItem, key: string, when: string | undefined): Promise; removeKeybinding(keybindingItem: ResolvedKeybindingItem): Promise; @@ -57,7 +57,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding this.queue = new Queue(); } - editKeybinding(keybindingItem: ResolvedKeybindingItem, key: string, when: string): Promise { + editKeybinding(keybindingItem: ResolvedKeybindingItem, key: string, when: string | undefined): Promise { return this.queue.queue(() => this.doEditKeybinding(keybindingItem, key, when)); // queue up writes to prevent race conditions } @@ -69,7 +69,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding return this.queue.queue(() => this.doRemoveKeybinding(keybindingItem)); // queue up writes to prevent race conditions } - private doEditKeybinding(keybindingItem: ResolvedKeybindingItem, key: string, when: string): Promise { + private doEditKeybinding(keybindingItem: ResolvedKeybindingItem, key: string, when: string | undefined): Promise { return this.resolveAndValidate() .then(reference => { const model = reference.object.textEditorModel; @@ -112,13 +112,16 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding return this.textFileService.save(this.resource); } - private updateKeybinding(keybindingItem: ResolvedKeybindingItem, newKey: string, when: string, model: ITextModel, userKeybindingEntryIndex: number): void { + private updateKeybinding(keybindingItem: ResolvedKeybindingItem, newKey: string, when: string | undefined, model: ITextModel, userKeybindingEntryIndex: number): void { const { tabSize, insertSpaces } = model.getOptions(); const eol = model.getEOL(); if (userKeybindingEntryIndex !== -1) { // Update the keybinding with new key this.applyEditsToBuffer(setProperty(model.getValue(), [userKeybindingEntryIndex, 'key'], newKey, { tabSize, insertSpaces, eol })[0], model); - this.applyEditsToBuffer(setProperty(model.getValue(), [userKeybindingEntryIndex, 'when'], when, { tabSize, insertSpaces, eol })[0], model); + const edits = setProperty(model.getValue(), [userKeybindingEntryIndex, 'when'], when, { tabSize, insertSpaces, eol }); + if (edits.length > 1) { + this.applyEditsToBuffer(edits[0], model); + } } else { // Add the new keybinding with new key this.applyEditsToBuffer(setProperty(model.getValue(), [-1], this.asObject(newKey, keybindingItem.command, when, false), { tabSize, insertSpaces, eol })[0], model); diff --git a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts index 161b34552b8..1a68fbad581 100644 --- a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts @@ -120,28 +120,28 @@ suite('KeybindingsEditing', () => { test('errors cases - parse errors', () => { fs.writeFileSync(keybindingsFile, ',,,,,,,,,,,,,,'); - return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }), 'alt+c', '') + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }), 'alt+c', undefined) .then(() => assert.fail('Should fail with parse errors'), error => assert.equal(error.message, 'Unable to write to the keybindings configuration file. Please open it to correct errors/warnings in the file and try again.')); }); test('errors cases - parse errors 2', () => { fs.writeFileSync(keybindingsFile, '[{"key": }]'); - return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }), 'alt+c', '') + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }), 'alt+c', undefined) .then(() => assert.fail('Should fail with parse errors'), error => assert.equal(error.message, 'Unable to write to the keybindings configuration file. Please open it to correct errors/warnings in the file and try again.')); }); test('errors cases - dirty', () => { instantiationService.stub(ITextFileService, 'isDirty', true); - return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }), 'alt+c', '') + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }), 'alt+c', undefined) .then(() => assert.fail('Should fail with dirty error'), error => assert.equal(error.message, 'Unable to write because the keybindings configuration file is dirty. Please save it first and then try again.')); }); test('errors cases - did not find an array', () => { fs.writeFileSync(keybindingsFile, '{"key": "alt+c", "command": "hello"}'); - return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }), 'alt+c', '') + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape } }), 'alt+c', undefined) .then(() => assert.fail('Should fail with dirty error'), error => assert.equal(error.message, 'Unable to write to the keybindings configuration file. It has an object which is not of type Array. Please open the file to clean up and try again.')); }); @@ -149,7 +149,7 @@ suite('KeybindingsEditing', () => { test('edit a default keybinding to an empty file', () => { fs.writeFileSync(keybindingsFile, ''); const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'a' }, { key: 'escape', command: '-a' }]; - return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', '') + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', undefined) .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); @@ -159,41 +159,41 @@ suite('KeybindingsEditing', () => { testObject = instantiationService.createInstance(KeybindingsEditingService); const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'a' }, { key: 'escape', command: '-a' }]; - return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', '') + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', undefined) .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); test('edit a default keybinding to an empty array', () => { writeToKeybindingsFile(); const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'a' }, { key: 'escape', command: '-a' }]; - return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', '') + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', undefined) .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); test('edit a default keybinding in an existing array', () => { writeToKeybindingsFile({ command: 'b', key: 'shift+c' }); const expected: IUserFriendlyKeybinding[] = [{ key: 'shift+c', command: 'b' }, { key: 'alt+c', command: 'a' }, { key: 'escape', command: '-a' }]; - return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', '') + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', undefined) .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); test('add a new default keybinding', () => { const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'a' }]; - return testObject.editKeybinding(aResolvedKeybindingItem({ command: 'a' }), 'alt+c', '') + return testObject.editKeybinding(aResolvedKeybindingItem({ command: 'a' }), 'alt+c', undefined) .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); test('edit an user keybinding', () => { writeToKeybindingsFile({ key: 'escape', command: 'b' }); const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'b' }]; - return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'b', isDefault: false }), 'alt+c', '') + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'b', isDefault: false }), 'alt+c', undefined) .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); test('edit an user keybinding with more than one element', () => { writeToKeybindingsFile({ key: 'escape', command: 'b' }, { key: 'alt+shift+g', command: 'c' }); const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'b' }, { key: 'alt+shift+g', command: 'c' }]; - return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'b', isDefault: false }), 'alt+c', '') + return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'b', isDefault: false }), 'alt+c', undefined) .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); @@ -232,17 +232,31 @@ suite('KeybindingsEditing', () => { test('add a new keybinding to unassigned keybinding', () => { writeToKeybindingsFile({ key: 'alt+c', command: '-a' }); const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: '-a' }, { key: 'shift+alt+c', command: 'a' }]; - return testObject.editKeybinding(aResolvedKeybindingItem({ command: 'a', isDefault: false }), 'shift+alt+c', '') + return testObject.editKeybinding(aResolvedKeybindingItem({ command: 'a', isDefault: false }), 'shift+alt+c', undefined) .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); - test('add update when expression', () => { + test('add when expression', () => { writeToKeybindingsFile({ key: 'alt+c', command: '-a' }); const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: '-a' }, { key: 'shift+alt+c', command: 'a', when: 'editorTextFocus' }]; return testObject.editKeybinding(aResolvedKeybindingItem({ command: 'a', isDefault: false }), 'shift+alt+c', 'editorTextFocus') .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); + test('update when expression', () => { + writeToKeybindingsFile({ key: 'alt+c', command: '-a', when: 'editorTextFocus && !editorReadonly' }); + const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: '-a', when: 'editorTextFocus && !editorReadonly' }, { key: 'shift+alt+c', command: 'a', when: 'editorTextFocus' }]; + return testObject.editKeybinding(aResolvedKeybindingItem({ command: 'a', isDefault: false }), 'shift+alt+c', 'editorTextFocus') + .then(() => assert.deepEqual(getUserKeybindings(), expected)); + }); + + test('remove when expression', () => { + writeToKeybindingsFile({ key: 'alt+c', command: '-a', when: 'editorTextFocus && !editorReadonly' }); + const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: '-a', when: 'editorTextFocus && !editorReadonly' }, { key: 'shift+alt+c', command: 'a' }]; + return testObject.editKeybinding(aResolvedKeybindingItem({ command: 'a', isDefault: false }), 'shift+alt+c', undefined) + .then(() => assert.deepEqual(getUserKeybindings(), expected)); + }); + function writeToKeybindingsFile(...keybindings: IUserFriendlyKeybinding[]) { fs.writeFileSync(keybindingsFile, JSON.stringify(keybindings || [])); } From 799794ecef9aed7e9ae683ac728cdc5874d94cf8 Mon Sep 17 00:00:00 2001 From: "Gleisson Ricardo @mattos" Date: Mon, 11 Feb 2019 05:15:24 -0200 Subject: [PATCH 098/207] main code review (#68245) --- src/main.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main.js b/src/main.js index 064f5da1934..d846bcd0173 100644 --- a/src/main.js +++ b/src/main.js @@ -57,7 +57,7 @@ registerListeners(); */ let nlsConfiguration = undefined; const userDefinedLocale = getUserDefinedLocale(); -userDefinedLocale.then((locale) => { +userDefinedLocale.then(locale => { if (locale && !nlsConfiguration) { nlsConfiguration = getNLSConfiguration(locale); } @@ -98,7 +98,7 @@ function onReady() { // First, we need to test a user defined locale. If it fails we try the app locale. // If that fails we fall back to English. - nlsConfiguration.then((nlsConfig) => { + nlsConfiguration.then(nlsConfig => { const startup = nlsConfig => { nlsConfig._languagePackSupport = true; @@ -129,7 +129,7 @@ function onReady() { // See above the comment about the loader and case sensitiviness appLocale = appLocale.toLowerCase(); - getNLSConfiguration(appLocale).then((nlsConfig) => { + getNLSConfiguration(appLocale).then(nlsConfig => { if (!nlsConfig) { nlsConfig = { locale: appLocale, availableLanguages: {} }; } @@ -437,7 +437,7 @@ function getUserDefinedLocale() { } const localeConfig = path.join(userDataPath, 'User', 'locale.json'); - return bootstrap.readFile(localeConfig).then((content) => { + return bootstrap.readFile(localeConfig).then(content => { content = stripComments(content); try { const value = JSON.parse(content).locale; @@ -535,7 +535,7 @@ function getNLSConfiguration(locale) { if (!packConfig || typeof packConfig.hash !== 'string' || !packConfig.translations || typeof (mainPack = packConfig.translations['vscode']) !== 'string') { return defaultResult(initialLocale); } - return exists(mainPack).then((fileExists) => { + return exists(mainPack).then(fileExists => { if (!fileExists) { return defaultResult(initialLocale); } @@ -553,7 +553,7 @@ function getNLSConfiguration(locale) { _resolvedLanguagePackCoreLocation: coreLocation, _corruptedFile: corruptedFile }; - return exists(corruptedFile).then((corrupted) => { + return exists(corruptedFile).then(corrupted => { // The nls cache directory is corrupted. let toDelete; if (corrupted) { @@ -562,7 +562,7 @@ function getNLSConfiguration(locale) { toDelete = Promise.resolve(undefined); } return toDelete.then(() => { - return exists(coreLocation).then((fileExists) => { + return exists(coreLocation).then(fileExists => { if (fileExists) { // We don't wait for this. No big harm if we can't touch touch(coreLocation).catch(() => { }); @@ -571,7 +571,7 @@ function getNLSConfiguration(locale) { } return mkdirp(coreLocation).then(() => { return Promise.all([bootstrap.readFile(path.join(__dirname, 'nls.metadata.json')), bootstrap.readFile(mainPack)]); - }).then((values) => { + }).then(values => { const metadata = JSON.parse(values[0]); const packData = JSON.parse(values[1]).contents; const bundles = Object.keys(metadata.bundles); @@ -607,7 +607,7 @@ function getNLSConfiguration(locale) { }).then(() => { perf.mark('nlsGeneration:end'); return result; - }).catch((err) => { + }).catch(err => { console.error('Generating translation files failed.', err); return defaultResult(locale); }); From 426256a892a339adf4628c614e1294d2d627b7b6 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 11 Feb 2019 09:16:54 +0100 Subject: [PATCH 099/207] editor - have a ignoreError option --- src/vs/platform/editor/common/editor.ts | 6 ++++++ .../browser/parts/editor/editorGroupView.ts | 13 +++++-------- src/vs/workbench/common/editor.ts | 11 +++++++++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/vs/platform/editor/common/editor.ts b/src/vs/platform/editor/common/editor.ts index 933f56cdc17..48953aa64e7 100644 --- a/src/vs/platform/editor/common/editor.ts +++ b/src/vs/platform/editor/common/editor.ts @@ -109,6 +109,12 @@ export interface IEditorOptions { * in the background. */ readonly inactive?: boolean; + + /** + * Will not show an error in case opening the editor fails and thus allows to show a custom error + * message as needed. By default, an error will be presented as notification if opening was not possible. + */ + readonly ignoreError?: boolean; } export interface ITextEditorSelection { diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 4abd300bcd0..cfb228841ae 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -108,7 +108,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView { private editorContainer: HTMLElement; private editorControl: EditorControl; - private ignoreOpenEditorErrors: boolean; private disposedEditorsWorker: RunOnceWorker; private mapEditorToPendingConfirmation: Map> = new Map>(); @@ -818,7 +817,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Report error only if this was not us restoring previous error state or // we are told to ignore errors that occur from opening an editor - if (this.isRestored && !isPromiseCanceledError(error) && !this.ignoreOpenEditorErrors) { + if (this.isRestored && !isPromiseCanceledError(error) && (!options || !options.ignoreError)) { const actions: INotificationActions = { primary: [] }; if (isErrorWithActions(error)) { actions.primary = (error as IErrorWithActions).actions; @@ -1020,20 +1019,18 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Open next active if there are more to show const nextActiveEditor = this._group.activeEditor; if (nextActiveEditor) { + const options = EditorOptions.create({ preserveFocus: !focusNext }); // When closing an editor due to an error we can end up in a loop where we continue closing // editors that fail to open (e.g. when the file no longer exists). We do not want to show // repeated errors in this case to the user. As such, if we open the next editor and we are // in a scope of a previous editor failing, we silence the input errors until the editor is - // opened. + // opened by setting ignoreError: true. if (fromError) { - this.ignoreOpenEditorErrors = true; + options.ignoreError = true; } - const options = !focusNext ? EditorOptions.create({ preserveFocus: true }) : undefined; - this.openEditor(nextActiveEditor, options).then(() => { - this.ignoreOpenEditorErrors = false; - }); + this.openEditor(nextActiveEditor, options); } // Otherwise we are empty, so clear from editor control and send event diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index a9113661957..40845a01c42 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -688,6 +688,7 @@ export class EditorOptions implements IEditorOptions { options.pinned = settings.pinned; options.index = settings.index; options.inactive = settings.inactive; + options.ignoreError = settings.ignoreError; return options; } @@ -731,6 +732,12 @@ export class EditorOptions implements IEditorOptions { * in the background. */ inactive: boolean | undefined; + + /** + * Will not show an error in case opening the editor fails and thus allows to show a custom error + * message as needed. By default, an error will be presented as notification if opening was not possible. + */ + ignoreError: boolean | undefined; } /** @@ -796,6 +803,10 @@ export class TextEditorOptions extends EditorOptions { textEditorOptions.inactive = true; } + if (options.ignoreError) { + textEditorOptions.ignoreError = true; + } + if (typeof options.index === 'number') { textEditorOptions.index = options.index; } From 47e7e4c7d64bde919da9072c73a408e90c4d094c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 11 Feb 2019 09:17:04 +0100 Subject: [PATCH 100/207] import style --- src/vs/workbench/contrib/outline/browser/outlinePanel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts index a6421a616e6..2d1f9061d38 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts @@ -41,7 +41,7 @@ import { ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { CollapseAction2 } from 'vs/workbench/browser/viewlet'; import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; -import { OutlineConfigKeys, OutlineViewFiltered, OutlineViewFocused } from '../../../../editor/contrib/documentSymbols/outline'; +import { OutlineConfigKeys, OutlineViewFocused, OutlineViewFiltered } from 'vs/editor/contrib/documentSymbols/outline'; import { FuzzyScore } from 'vs/base/common/filters'; import { OutlineDataSource, OutlineItemComparator, OutlineSortOrder, OutlineVirtualDelegate, OutlineGroupRenderer, OutlineElementRenderer, OutlineItem, OutlineIdentityProvider, OutlineNavigationLabelProvider } from 'vs/editor/contrib/documentSymbols/outlineTree'; import { IDataTreeViewState } from 'vs/base/browser/ui/tree/dataTree'; From 3055f672a0971b9164efa24723b9935e779cef56 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 11 Feb 2019 09:29:30 +0100 Subject: [PATCH 101/207] remove console.logs --- src/vs/platform/backup/electron-main/backupMainService.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/platform/backup/electron-main/backupMainService.ts b/src/vs/platform/backup/electron-main/backupMainService.ts index af82955b242..7bf248799b7 100644 --- a/src/vs/platform/backup/electron-main/backupMainService.ts +++ b/src/vs/platform/backup/electron-main/backupMainService.ts @@ -252,7 +252,6 @@ export class BackupMainService implements IBackupMainService { // Validate Workspaces for (let workspace of rootWorkspaces) { if (!isWorkspaceIdentifier(workspace)) { - console.log('not a workspace identifer'); return []; // wrong format, skip all entries } @@ -267,7 +266,6 @@ export class BackupMainService implements IBackupMainService { if (workspace.configPath.scheme !== Schemas.file || await exists(workspace.configPath.fsPath)) { result.push(workspace); } else { - console.log('target workspace missing'); // If the workspace has backups, but the target workspace is missing, convert backups to empty ones await this.convertToEmptyWindowBackup(backupPath); } From 7f6be1297cb3df29428777d3efa6cb79bfef6381 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Feb 2019 09:54:02 +0100 Subject: [PATCH 102/207] support multiple cursors #41838 for now via multiple calls to the api... --- .../editor/contrib/smartSelect/smartSelect.ts | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/vs/editor/contrib/smartSelect/smartSelect.ts b/src/vs/editor/contrib/smartSelect/smartSelect.ts index 66d7733573b..fc70404aab9 100644 --- a/src/vs/editor/contrib/smartSelect/smartSelect.ts +++ b/src/vs/editor/contrib/smartSelect/smartSelect.ts @@ -10,6 +10,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, IActionOptions, registerEditorAction, registerEditorContribution, ServicesAccessor, registerDefaultLanguageCommand } from 'vs/editor/browser/editorExtensions'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; +import { Selection } from 'vs/editor/common/core/selection'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ITextModel } from 'vs/editor/common/model'; @@ -53,7 +54,7 @@ class SmartSelectController implements IEditorContribution { private readonly _editor: ICodeEditor; - private _state?: SelectionRanges; + private _state?: SelectionRanges[]; private _selectionListener?: IDisposable; private _ignoreSelection: boolean = false; @@ -74,7 +75,7 @@ class SmartSelectController implements IEditorContribution { return; } - const selection = this._editor.getSelection(); + const selections = this._editor.getSelections(); const model = this._editor.getModel(); if (!modes.SelectionRangeRegistry.has(model)) { @@ -85,25 +86,27 @@ class SmartSelectController implements IEditorContribution { let promise: Promise = Promise.resolve(undefined); if (!this._state) { - promise = provideSelectionRanges(model, selection.getPosition(), CancellationToken.None).then(ranges => { - if (!arrays.isNonEmptyArray(ranges)) { + promise = provideSelectionRangesN(model, selections.map(s => s.getPosition()), CancellationToken.None).then(ranges => { + if (!arrays.isNonEmptyArray(ranges) || ranges.length !== selections.length) { // invalid result return; } - if (!this._editor.hasModel() || !this._editor.getSelection().equalsSelection(selection)) { + if (!this._editor.hasModel() || !arrays.equals(this._editor.getSelections(), selections, (a, b) => a.equalsSelection(b))) { // invalid editor state return; } - ranges = ranges.filter(range => { - // filter ranges inside the selection - return range.containsPosition(selection.getStartPosition()) && range.containsPosition(selection.getEndPosition()); - }); + for (let i = 0; i < ranges.length; i++) { + ranges[i] = ranges[i].filter(range => { + // filter ranges inside the selection + return range.containsPosition(selections[i].getStartPosition()) && range.containsPosition(selections[i].getEndPosition()); + }); + // prepend current selection + ranges[i].unshift(selections[i]); + } - // prepend current selection - ranges.unshift(selection); - this._state = new SelectionRanges(0, ranges); + this._state = ranges.map(ranges => new SelectionRanges(0, ranges)); // listen to caret move and forget about state dispose(this._selectionListener); @@ -121,11 +124,11 @@ class SmartSelectController implements IEditorContribution { // no state return; } - this._state = this._state.mov(forward); - const selection = this._state.ranges[this._state.index]; + this._state = this._state.map(state => state.mov(forward)); + const selections = this._state.map(state => Selection.fromPositions(state.ranges[state.index].getStartPosition(), state.ranges[state.index].getEndPosition())); this._ignoreSelection = true; try { - this._editor.setSelection(selection); + this._editor.setSelections(selections); } finally { this._ignoreSelection = false; } @@ -292,6 +295,12 @@ export function provideSelectionRanges(model: ITextModel, position: Position, to }); } +export function provideSelectionRangesN(model: ITextModel, position: Position[], token: CancellationToken): Promise { + return Promise.all(position.map(pos => { + return provideSelectionRanges(model, pos, token); + })); +} + registerDefaultLanguageCommand('_executeSelectionRangeProvider', function (model, position) { return provideSelectionRanges(model, position, CancellationToken.None); }); From 2eb40a886c7b700fc899635e36f456f89112c791 Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Mon, 11 Feb 2019 10:12:26 +0100 Subject: [PATCH 103/207] improve comment --- src/vs/workbench/contrib/debug/node/debugger.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/debug/node/debugger.ts b/src/vs/workbench/contrib/debug/node/debugger.ts index 93e37f35d61..86cc18f2d3f 100644 --- a/src/vs/workbench/contrib/debug/node/debugger.ts +++ b/src/vs/workbench/contrib/debug/node/debugger.ts @@ -46,13 +46,13 @@ export class Debugger implements IDebugger { public merge(otherDebuggerContribution: IDebuggerContribution, extensionDescription: IExtensionDescription): void { - // remember all extensions that are merged for this debugger + // remember all extensions that have been merged for this debugger this.mergedExtensionDescriptions.push(extensionDescription); - // merge debugger contributions + // merge new debugger contribution into existing contributions. objects.mixin(this.debuggerContribution, otherDebuggerContribution, extensionDescription.isBuiltin); - // remember the extension that has the "main" debugger contribution + // remember the extension that is considered the "main" debugger contribution if (isDebuggerMainContribution(otherDebuggerContribution)) { this.mainExtensionDescription = extensionDescription; } From 19c85f8894dfb2c858f846534577e167eb3e8d98 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Feb 2019 10:25:19 +0100 Subject: [PATCH 104/207] for rapid render data use a file, not storage, #68395 --- .../electron-browser/workbench/workbench.js | 10 ++++--- src/vs/code/electron-main/window.ts | 4 +-- src/vs/platform/windows/common/windows.ts | 2 +- .../partsSplash.contribution.ts | 26 ++++++++++++------- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/vs/code/electron-browser/workbench/workbench.js b/src/vs/code/electron-browser/workbench/workbench.js index 84c258ca734..0f12a5a6f97 100644 --- a/src/vs/code/electron-browser/workbench/workbench.js +++ b/src/vs/code/electron-browser/workbench/workbench.js @@ -56,10 +56,12 @@ function showPartsSplash(configuration) { perf.mark('willShowPartsSplash'); let data; - try { - data = JSON.parse(configuration.partsSplashData); - } catch (e) { - // ignore + if (typeof configuration.partsSplashPath === 'string') { + try { + data = JSON.parse(require('fs').readFileSync(configuration.partsSplashPath, 'utf8')); + } catch (e) { + // ignore + } } // high contrast mode has been turned on from the outside, e.g OS -> ignore stored colors and layouts diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 03d22708966..e4cbdac4e2f 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -24,7 +24,6 @@ import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import * as perf from 'vs/base/common/performance'; import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/node/extensionGalleryService'; import { getBackgroundColor } from 'vs/code/electron-main/theme'; -import { IStorageMainService } from 'vs/platform/storage/node/storageMainService'; import { RunOnceScheduler } from 'vs/base/common/async'; export interface IWindowCreationOptions { @@ -87,7 +86,6 @@ export class CodeWindow extends Disposable implements ICodeWindow { @IStateService private readonly stateService: IStateService, @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, @IBackupMainService private readonly backupMainService: IBackupMainService, - @IStorageMainService private readonly storageMainService: IStorageMainService ) { super(); @@ -590,7 +588,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { windowConfiguration.perfEntries = perf.exportEntries(); // Parts splash - windowConfiguration.partsSplashData = this.storageMainService.get('parts-splash-data', undefined); + windowConfiguration.partsSplashPath = path.join(this.environmentService.userDataPath, 'rapid_render.json'); // Config (combination of process.argv and window configuration) const environment = parseArgs(process.argv); diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index f86580a7d73..7447410922f 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -395,7 +395,7 @@ export interface IWindowConfiguration extends ParsedArgs { highContrast?: boolean; frameless?: boolean; accessibilitySupport?: boolean; - partsSplashData?: string; + partsSplashPath?: string; perfStartTime?: number; perfAppReady?: number; diff --git a/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts b/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts index cae6bc95caa..651a29e8268 100644 --- a/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts +++ b/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts @@ -11,7 +11,6 @@ import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { IBroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ColorIdentifier, editorBackground, foreground } from 'vs/platform/theme/common/colorRegistry'; import { getThemeTypeSelector, IThemeService } from 'vs/platform/theme/common/themeService'; import { DEFAULT_EDITOR_MIN_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor'; @@ -19,6 +18,9 @@ import { Extensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common import * as themes from 'vs/workbench/common/theme'; import { IPartService, Parts, Position } from 'vs/workbench/services/part/common/partService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IFileService } from 'vs/platform/files/common/files'; +import { URI } from 'vs/base/common/uri'; +import { join } from 'vs/base/common/paths'; class PartsSplash { @@ -32,10 +34,10 @@ class PartsSplash { constructor( @IThemeService private readonly _themeService: IThemeService, @IPartService private readonly _partService: IPartService, - @IStorageService private readonly _storageService: IStorageService, + @IFileService private readonly _fileService: IFileService, @IEnvironmentService private readonly _envService: IEnvironmentService, + @IBroadcastService private readonly _broadcastService: IBroadcastService, @ILifecycleService lifecycleService: ILifecycleService, - @IBroadcastService private readonly broadcastService: IBroadcastService ) { lifecycleService.when(LifecyclePhase.Restored).then(_ => this._removePartsSplash()); Event.debounce(Event.any( @@ -67,12 +69,16 @@ class PartsSplash { sideBarWidth: getTotalWidth(this._partService.getContainer(Parts.SIDEBAR_PART)!), statusBarHeight: getTotalHeight(this._partService.getContainer(Parts.STATUSBAR_PART)!), }; - this._storageService.store('parts-splash-data', JSON.stringify({ - id: PartsSplash._splashElementId, - colorInfo, - layoutInfo, - baseTheme - }), StorageScope.GLOBAL); + this._fileService.updateContent( + URI.file(join(this._envService.userDataPath, 'rapid_render.json')), + JSON.stringify({ + id: PartsSplash._splashElementId, + colorInfo, + layoutInfo, + baseTheme + }), + { encoding: 'utf8' } + ); if (baseTheme !== this._lastBaseTheme || colorInfo.editorBackground !== this._lastBackground) { // notify the main window on background color changes: the main window sets the background color to new windows @@ -81,7 +87,7 @@ class PartsSplash { // the color needs to be in hex const backgroundColor = this._themeService.getTheme().getColor(editorBackground) || themes.WORKBENCH_BACKGROUND(this._themeService.getTheme()); - this.broadcastService.broadcast({ channel: 'vscode:changeColorTheme', payload: JSON.stringify({ baseTheme, background: Color.Format.CSS.formatHex(backgroundColor) }) }); + this._broadcastService.broadcast({ channel: 'vscode:changeColorTheme', payload: JSON.stringify({ baseTheme, background: Color.Format.CSS.formatHex(backgroundColor) }) }); } } From 0aa8cb1f0ca8cf6f0bcfc425109f39935135ddc9 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 11 Feb 2019 10:25:06 +0100 Subject: [PATCH 105/207] Fix build --- build/gulpfile.vscode.win32.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/gulpfile.vscode.win32.js b/build/gulpfile.vscode.win32.js index b49fcbabcfc..efea0701d3f 100644 --- a/build/gulpfile.vscode.win32.js +++ b/build/gulpfile.vscode.win32.js @@ -105,7 +105,7 @@ function buildWin32Setup(arch, target) { } function defineWin32SetupTasks(arch, target) { - const cleanTask = () => util.primraf(setupDir(arch, target)); + const cleanTask = util.rimraf(setupDir(arch, target)); gulp.task(`vscode-win32-${arch}-${target}-setup`, util.task.series(cleanTask, buildWin32Setup(arch, target))); } From 8509ae3ffbfb09f3556b3bc52e0fae10614defa0 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Feb 2019 10:29:49 +0100 Subject: [PATCH 106/207] strict null trouble --- src/vs/editor/contrib/smartSelect/smartSelect.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/smartSelect/smartSelect.ts b/src/vs/editor/contrib/smartSelect/smartSelect.ts index fc70404aab9..edc84451523 100644 --- a/src/vs/editor/contrib/smartSelect/smartSelect.ts +++ b/src/vs/editor/contrib/smartSelect/smartSelect.ts @@ -297,7 +297,9 @@ export function provideSelectionRanges(model: ITextModel, position: Position, to export function provideSelectionRangesN(model: ITextModel, position: Position[], token: CancellationToken): Promise { return Promise.all(position.map(pos => { - return provideSelectionRanges(model, pos, token); + return provideSelectionRanges(model, pos, token).then(value => { + return value || []; + }); })); } From 8afbf7ce55c9f14ad5940252ea9da36268d20405 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 11 Feb 2019 10:31:39 +0100 Subject: [PATCH 107/207] move define when expression command to the bottom --- .../workbench/contrib/preferences/browser/keybindingsEditor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index d0fa562b51f..43cfe12b938 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -626,9 +626,9 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.createCopyCommandAction(e.element), new Separator(), this.createDefineAction(e.element), - this.createDefineWhenExpressionAction(e.element), this.createRemoveAction(e.element), this.createResetAction(e.element), + this.createDefineWhenExpressionAction(e.element), new Separator(), this.createShowConflictsAction(e.element)] }); From 8bbe6acdc895d9a649806fcc86084ad4526237ad Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 11 Feb 2019 11:24:22 +0100 Subject: [PATCH 108/207] debt - lift textfileservice into browser (#68302) --- .../workbench/electron-browser/workbench.ts | 2 +- .../textfile/common/textFileService.ts | 166 ++++++++++++++--- .../electron-browser/textFileService.ts | 176 ------------------ .../test/common/editor/editorGroups.test.ts | 2 +- .../workbench/test/workbenchTestServices.ts | 38 +++- 5 files changed, 176 insertions(+), 208 deletions(-) delete mode 100644 src/vs/workbench/services/textfile/electron-browser/textFileService.ts diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 3b279295ead..4ed5b6cb199 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -61,7 +61,7 @@ import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboa import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { TextFileService } from 'vs/workbench/services/textfile/electron-browser/textFileService'; +import { TextFileService } from 'vs/workbench/services/textfile/common/textFileService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IProgressService2 } from 'vs/platform/progress/common/progress'; import { ProgressService2 } from 'vs/workbench/services/progress/browser/progressService2'; diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index 6f135af2307..146db7414b0 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -28,11 +28,16 @@ import { ResourceMap } from 'vs/base/common/map'; import { Schemas } from 'vs/base/common/network'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel'; +import { createTextBufferFactoryFromSnapshot, createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; import { IModelService } from 'vs/editor/common/services/modelService'; -import { INotificationService } from 'vs/platform/notification/common/notification'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { isEqualOrParent, isEqual, joinPath, dirname } from 'vs/base/common/resources'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; +import { getConfirmMessage, IDialogService, IFileDialogService, ISaveDialogOptions, IConfirmation } from 'vs/platform/dialogs/common/dialogs'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { coalesce } from 'vs/base/common/arrays'; +import { trim } from 'vs/base/common/strings'; export interface IBackupResult { didBackup: boolean; @@ -43,7 +48,7 @@ export interface IBackupResult { * * It also adds diagnostics and logging around file system operations. */ -export abstract class TextFileService extends Disposable implements ITextFileService { +export class TextFileService extends Disposable implements ITextFileService { _serviceBrand: any; @@ -65,27 +70,31 @@ export abstract class TextFileService extends Disposable implements ITextFileSer private autoSaveContext: IContextKey; constructor( - private lifecycleService: ILifecycleService, - private contextService: IWorkspaceContextService, - private configurationService: IConfigurationService, - protected fileService: IFileService, - private untitledEditorService: IUntitledEditorService, - private instantiationService: IInstantiationService, - private notificationService: INotificationService, - protected environmentService: IEnvironmentService, - private backupFileService: IBackupFileService, - private windowsService: IWindowsService, - protected windowService: IWindowService, - private historyService: IHistoryService, - contextKeyService: IContextKeyService, - private modelService: IModelService + @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, + @IFileService protected readonly fileService: IFileService, + @IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService, + @ILifecycleService private readonly lifecycleService: ILifecycleService, + @IInstantiationService instantiationService: IInstantiationService, + @IConfigurationService private readonly configurationService: IConfigurationService, + @IModeService private readonly modeService: IModeService, + @IModelService private readonly modelService: IModelService, + @IWindowService private readonly windowService: IWindowService, + @IEnvironmentService private readonly environmentService: IEnvironmentService, + @INotificationService private readonly notificationService: INotificationService, + @IBackupFileService private readonly backupFileService: IBackupFileService, + @IWindowsService private readonly windowsService: IWindowsService, + @IHistoryService private readonly historyService: IHistoryService, + @IContextKeyService contextKeyService: IContextKeyService, + @IDialogService private readonly dialogService: IDialogService, + @IFileDialogService private readonly fileDialogService: IFileDialogService, + @IEditorService private readonly editorService: IEditorService ) { super(); - this._models = this.instantiationService.createInstance(TextFileEditorModelManager); + this._models = instantiationService.createInstance(TextFileEditorModelManager); this.autoSaveContext = AutoSaveContext.bindTo(contextKeyService); - const configuration = this.configurationService.getValue(); + const configuration = configurationService.getValue(); this.currentFilesAssociationConfig = configuration && configuration.files && configuration.files.associations; this.onFilesConfigurationChange(configuration); @@ -97,13 +106,124 @@ export abstract class TextFileService extends Disposable implements ITextFileSer return this._models; } - abstract resolveTextContent(resource: URI, options?: IResolveContentOptions): Promise; + resolveTextContent(resource: URI, options?: IResolveContentOptions): Promise { + return this.fileService.resolveStreamContent(resource, options).then(streamContent => { + return createTextBufferFactoryFromStream(streamContent.value).then(res => { + const r: IRawTextContent = { + resource: streamContent.resource, + name: streamContent.name, + mtime: streamContent.mtime, + etag: streamContent.etag, + encoding: streamContent.encoding, + isReadonly: streamContent.isReadonly, + value: res + }; + return r; + }); + }); + } - abstract promptForPath(resource: URI, defaultPath: URI): Promise; + promptForPath(resource: URI, defaultUri: URI): Promise { - abstract confirmSave(resources?: URI[]): Promise; + // Help user to find a name for the file by opening it first + return this.editorService.openEditor({ resource, options: { revealIfOpened: true, preserveFocus: true, } }).then(() => { + return this.fileDialogService.showSaveDialog(this.getSaveDialogOptions(defaultUri)); + }); + } - abstract confirmOverwrite(resource: URI): Promise; + private getSaveDialogOptions(defaultUri: URI): ISaveDialogOptions { + const options: ISaveDialogOptions = { + defaultUri, + title: nls.localize('saveAsTitle', "Save As") + }; + + // Filters are only enabled on Windows where they work properly + if (!platform.isWindows) { + return options; + } + + interface IFilter { name: string; extensions: string[]; } + + // Build the file filter by using our known languages + const ext: string = defaultUri ? paths.extname(defaultUri.path) : undefined; + let matchingFilter: IFilter; + const filters: IFilter[] = coalesce(this.modeService.getRegisteredLanguageNames().map(languageName => { + const extensions = this.modeService.getExtensions(languageName); + if (!extensions || !extensions.length) { + return null; + } + + const filter: IFilter = { name: languageName, extensions: extensions.slice(0, 10).map(e => trim(e, '.')) }; + + if (ext && extensions.indexOf(ext) >= 0) { + matchingFilter = filter; + + return null; // matching filter will be added last to the top + } + + return filter; + })); + + // Filters are a bit weird on Windows, based on having a match or not: + // Match: we put the matching filter first so that it shows up selected and the all files last + // No match: we put the all files filter first + const allFilesFilter = { name: nls.localize('allFiles', "All Files"), extensions: ['*'] }; + if (matchingFilter) { + filters.unshift(matchingFilter); + filters.unshift(allFilesFilter); + } else { + filters.unshift(allFilesFilter); + } + + // Allow to save file without extension + filters.push({ name: nls.localize('noExt', "No Extension"), extensions: [''] }); + + options.filters = filters; + + return options; + } + + confirmSave(resources?: URI[]): Promise { + if (this.environmentService.isExtensionDevelopment) { + return Promise.resolve(ConfirmResult.DONT_SAVE); // no veto when we are in extension dev mode because we cannot assum we run interactive (e.g. tests) + } + + const resourcesToConfirm = this.getDirty(resources); + if (resourcesToConfirm.length === 0) { + return Promise.resolve(ConfirmResult.DONT_SAVE); + } + + const message = resourcesToConfirm.length === 1 ? nls.localize('saveChangesMessage', "Do you want to save the changes you made to {0}?", paths.basename(resourcesToConfirm[0].fsPath)) + : getConfirmMessage(nls.localize('saveChangesMessages', "Do you want to save the changes to the following {0} files?", resourcesToConfirm.length), resourcesToConfirm); + + const buttons: string[] = [ + resourcesToConfirm.length > 1 ? nls.localize({ key: 'saveAll', comment: ['&& denotes a mnemonic'] }, "&&Save All") : nls.localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save"), + nls.localize({ key: 'dontSave', comment: ['&& denotes a mnemonic'] }, "Do&&n't Save"), + nls.localize('cancel', "Cancel") + ]; + + return this.dialogService.show(Severity.Warning, message, buttons, { + cancelId: 2, + detail: nls.localize('saveChangesDetail', "Your changes will be lost if you don't save them.") + }).then(index => { + switch (index) { + case 0: return ConfirmResult.SAVE; + case 1: return ConfirmResult.DONT_SAVE; + default: return ConfirmResult.CANCEL; + } + }); + } + + confirmOverwrite(resource: URI): Promise { + const confirm: IConfirmation = { + message: nls.localize('confirmOverwrite', "'{0}' already exists. Do you want to replace it?", paths.basename(resource.fsPath)), + detail: nls.localize('irreversible', "A file or folder with the same name already exists in the folder {0}. Replacing it will overwrite its current contents.", paths.basename(paths.dirname(resource.fsPath))), + primaryButton: nls.localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), + type: 'warning' + }; + + return this.dialogService.confirm(confirm).then(result => result.confirmed); + } private registerListeners(): void { diff --git a/src/vs/workbench/services/textfile/electron-browser/textFileService.ts b/src/vs/workbench/services/textfile/electron-browser/textFileService.ts deleted file mode 100644 index 51d4869b322..00000000000 --- a/src/vs/workbench/services/textfile/electron-browser/textFileService.ts +++ /dev/null @@ -1,176 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as nls from 'vs/nls'; -import * as paths from 'vs/base/common/paths'; -import * as strings from 'vs/base/common/strings'; -import { isWindows } from 'vs/base/common/platform'; -import { URI } from 'vs/base/common/uri'; -import { ConfirmResult } from 'vs/workbench/common/editor'; -import { TextFileService as AbstractTextFileService } from 'vs/workbench/services/textfile/common/textFileService'; -import { IRawTextContent } from 'vs/workbench/services/textfile/common/textfiles'; -import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { IFileService, IResolveContentOptions } from 'vs/platform/files/common/files'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IModeService } from 'vs/editor/common/services/modeService'; -import { createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; -import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows'; -import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IModelService } from 'vs/editor/common/services/modelService'; -import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; -import { getConfirmMessage, IDialogService, ISaveDialogOptions, IFileDialogService, IConfirmation } from 'vs/platform/dialogs/common/dialogs'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { coalesce } from 'vs/base/common/arrays'; - -export class TextFileService extends AbstractTextFileService { - - constructor( - @IWorkspaceContextService contextService: IWorkspaceContextService, - @IFileService fileService: IFileService, - @IUntitledEditorService untitledEditorService: IUntitledEditorService, - @ILifecycleService lifecycleService: ILifecycleService, - @IInstantiationService instantiationService: IInstantiationService, - @IConfigurationService configurationService: IConfigurationService, - @IModeService private readonly modeService: IModeService, - @IModelService modelService: IModelService, - @IWindowService windowService: IWindowService, - @IEnvironmentService environmentService: IEnvironmentService, - @INotificationService notificationService: INotificationService, - @IBackupFileService backupFileService: IBackupFileService, - @IWindowsService windowsService: IWindowsService, - @IHistoryService historyService: IHistoryService, - @IContextKeyService contextKeyService: IContextKeyService, - @IDialogService private readonly dialogService: IDialogService, - @IFileDialogService private readonly fileDialogService: IFileDialogService, - @IEditorService private readonly editorService: IEditorService - ) { - super(lifecycleService, contextService, configurationService, fileService, untitledEditorService, instantiationService, notificationService, environmentService, backupFileService, windowsService, windowService, historyService, contextKeyService, modelService); - } - - resolveTextContent(resource: URI, options?: IResolveContentOptions): Promise { - return this.fileService.resolveStreamContent(resource, options).then(streamContent => { - return createTextBufferFactoryFromStream(streamContent.value).then(res => { - const r: IRawTextContent = { - resource: streamContent.resource, - name: streamContent.name, - mtime: streamContent.mtime, - etag: streamContent.etag, - encoding: streamContent.encoding, - isReadonly: streamContent.isReadonly, - value: res - }; - return r; - }); - }); - } - - confirmSave(resources?: URI[]): Promise { - if (this.environmentService.isExtensionDevelopment) { - return Promise.resolve(ConfirmResult.DONT_SAVE); // no veto when we are in extension dev mode because we cannot assum we run interactive (e.g. tests) - } - - const resourcesToConfirm = this.getDirty(resources); - if (resourcesToConfirm.length === 0) { - return Promise.resolve(ConfirmResult.DONT_SAVE); - } - - const message = resourcesToConfirm.length === 1 ? nls.localize('saveChangesMessage', "Do you want to save the changes you made to {0}?", paths.basename(resourcesToConfirm[0].fsPath)) - : getConfirmMessage(nls.localize('saveChangesMessages', "Do you want to save the changes to the following {0} files?", resourcesToConfirm.length), resourcesToConfirm); - - const buttons: string[] = [ - resourcesToConfirm.length > 1 ? nls.localize({ key: 'saveAll', comment: ['&& denotes a mnemonic'] }, "&&Save All") : nls.localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save"), - nls.localize({ key: 'dontSave', comment: ['&& denotes a mnemonic'] }, "Do&&n't Save"), - nls.localize('cancel', "Cancel") - ]; - - return this.dialogService.show(Severity.Warning, message, buttons, { - cancelId: 2, - detail: nls.localize('saveChangesDetail', "Your changes will be lost if you don't save them.") - }).then(index => { - switch (index) { - case 0: return ConfirmResult.SAVE; - case 1: return ConfirmResult.DONT_SAVE; - default: return ConfirmResult.CANCEL; - } - }); - } - - confirmOverwrite(resource: URI): Promise { - const confirm: IConfirmation = { - message: nls.localize('confirmOverwrite', "'{0}' already exists. Do you want to replace it?", paths.basename(resource.fsPath)), - detail: nls.localize('irreversible', "A file or folder with the same name already exists in the folder {0}. Replacing it will overwrite its current contents.", paths.basename(paths.dirname(resource.fsPath))), - primaryButton: nls.localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), - type: 'warning' - }; - - return this.dialogService.confirm(confirm).then(result => result.confirmed); - } - - promptForPath(resource: URI, defaultUri: URI): Promise { - - // Help user to find a name for the file by opening it first - return this.editorService.openEditor({ resource, options: { revealIfOpened: true, preserveFocus: true, } }).then(() => { - return this.fileDialogService.showSaveDialog(this.getSaveDialogOptions(defaultUri)); - }); - } - - private getSaveDialogOptions(defaultUri: URI): ISaveDialogOptions { - const options: ISaveDialogOptions = { - defaultUri, - title: nls.localize('saveAsTitle', "Save As") - }; - - // Filters are only enabled on Windows where they work properly - if (!isWindows) { - return options; - } - - interface IFilter { name: string; extensions: string[]; } - - // Build the file filter by using our known languages - const ext: string = defaultUri ? paths.extname(defaultUri.path) : undefined; - let matchingFilter: IFilter; - const filters: IFilter[] = coalesce(this.modeService.getRegisteredLanguageNames().map(languageName => { - const extensions = this.modeService.getExtensions(languageName); - if (!extensions || !extensions.length) { - return null; - } - - const filter: IFilter = { name: languageName, extensions: extensions.slice(0, 10).map(e => strings.trim(e, '.')) }; - - if (ext && extensions.indexOf(ext) >= 0) { - matchingFilter = filter; - - return null; // matching filter will be added last to the top - } - - return filter; - })); - - // Filters are a bit weird on Windows, based on having a match or not: - // Match: we put the matching filter first so that it shows up selected and the all files last - // No match: we put the all files filter first - const allFilesFilter = { name: nls.localize('allFiles', "All Files"), extensions: ['*'] }; - if (matchingFilter) { - filters.unshift(matchingFilter); - filters.unshift(allFilesFilter); - } else { - filters.unshift(allFilesFilter); - } - - // Allow to save file without extension - filters.push({ name: nls.localize('noExt', "No Extension"), extensions: [''] }); - - options.filters = filters; - - return options; - } -} diff --git a/src/vs/workbench/test/common/editor/editorGroups.test.ts b/src/vs/workbench/test/common/editor/editorGroups.test.ts index b29dbd3f74d..bc186f8d331 100644 --- a/src/vs/workbench/test/common/editor/editorGroups.test.ts +++ b/src/vs/workbench/test/common/editor/editorGroups.test.ts @@ -656,7 +656,7 @@ suite('Workbench editor groups', () => { config.setUserConfiguration('workbench', { editor: { focusRecentEditorAfterClose: false } }); inst.stub(IConfigurationService, config); - const group = inst.createInstance(EditorGroup); + const group = inst.createInstance(EditorGroup, undefined); const events = groupListener(group); const input1 = input(); diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 0e13742ee46..f7f05c56919 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -179,21 +179,45 @@ export class TestTextFileService extends TextFileService { private resolveTextContentError: FileOperationError | null; constructor( - @ILifecycleService lifecycleService: ILifecycleService, @IWorkspaceContextService contextService: IWorkspaceContextService, - @IConfigurationService configurationService: IConfigurationService, - @IFileService fileService: IFileService, + @IFileService protected fileService: IFileService, @IUntitledEditorService untitledEditorService: IUntitledEditorService, + @ILifecycleService lifecycleService: ILifecycleService, @IInstantiationService instantiationService: IInstantiationService, + @IConfigurationService configurationService: IConfigurationService, + @IModeService modeService: IModeService, + @IModelService modelService: IModelService, + @IWindowService windowService: IWindowService, + @IEnvironmentService environmentService: IEnvironmentService, @INotificationService notificationService: INotificationService, @IBackupFileService backupFileService: IBackupFileService, @IWindowsService windowsService: IWindowsService, - @IWindowService windowService: IWindowService, @IHistoryService historyService: IHistoryService, @IContextKeyService contextKeyService: IContextKeyService, - @IModelService modelService: IModelService + @IDialogService dialogService: IDialogService, + @IFileDialogService fileDialogService: IFileDialogService, + @IEditorService editorService: IEditorService ) { - super(lifecycleService, contextService, configurationService, fileService, untitledEditorService, instantiationService, notificationService, TestEnvironmentService, backupFileService, windowsService, windowService, historyService, contextKeyService, modelService); + super( + contextService, + fileService, + untitledEditorService, + lifecycleService, + instantiationService, + configurationService, + modeService, + modelService, + windowService, + environmentService, + notificationService, + backupFileService, + windowsService, + historyService, + contextKeyService, + dialogService, + fileDialogService, + editorService + ); } public setPromptPath(path: URI): void { @@ -252,6 +276,7 @@ export class TestTextFileService extends TextFileService { export function workbenchInstantiationService(): IInstantiationService { let instantiationService = new TestInstantiationService(new ServiceCollection([ILifecycleService, new TestLifecycleService()])); + instantiationService.stub(IEnvironmentService, TestEnvironmentService); instantiationService.stub(IContextKeyService, instantiationService.createInstance(MockContextKeyService)); const workspaceContextService = new TestContextService(TestWorkspace); instantiationService.stub(IWorkspaceContextService, workspaceContextService); @@ -278,7 +303,6 @@ export function workbenchInstantiationService(): IInstantiationService { instantiationService.stub(IWindowsService, new TestWindowsService()); instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); - instantiationService.stub(IEnvironmentService, TestEnvironmentService); instantiationService.stub(IThemeService, new TestThemeService()); instantiationService.stub(IHashService, new TestHashService()); instantiationService.stub(ILogService, new TestLogService()); From d50b568d8778a0e377915349e07928d8105fe9b5 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Feb 2019 11:33:32 +0100 Subject: [PATCH 109/207] multiple cursor in internal api of smart select, #41838 --- src/vs/editor/common/modes.ts | 2 +- .../contrib/smartSelect/bracketSelections.ts | 19 ++- .../editor/contrib/smartSelect/smartSelect.ts | 146 +++++++++--------- .../smartSelect/test/smartSelect.test.ts | 6 +- .../contrib/smartSelect/wordSelections.ts | 16 +- src/vs/editor/contrib/suggest/wordDistance.ts | 8 +- src/vs/monaco.d.ts | 2 +- .../mainThreadLanguageFeatures.ts | 4 +- src/vs/workbench/api/node/extHost.protocol.ts | 2 +- .../workbench/api/node/extHostApiCommands.ts | 17 +- .../api/node/extHostLanguageFeatures.ts | 38 ++--- .../api/extHostApiCommands.test.ts | 7 +- .../api/extHostLanguageFeatures.test.ts | 5 +- 13 files changed, 141 insertions(+), 131 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index d04c849653a..0e9fdec3f13 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1064,7 +1064,7 @@ export interface SelectionRangeProvider { /** * Provide ranges that should be selected from the given position. */ - provideSelectionRanges(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult; + provideSelectionRanges(model: model.ITextModel, positions: Position[], token: CancellationToken): ProviderResult; } export interface FoldingContext { diff --git a/src/vs/editor/contrib/smartSelect/bracketSelections.ts b/src/vs/editor/contrib/smartSelect/bracketSelections.ts index c69442aaf73..6bd8d884235 100644 --- a/src/vs/editor/contrib/smartSelect/bracketSelections.ts +++ b/src/vs/editor/contrib/smartSelect/bracketSelections.ts @@ -11,12 +11,19 @@ import { LinkedList } from 'vs/base/common/linkedList'; export class BracketSelectionRangeProvider implements SelectionRangeProvider { - provideSelectionRanges(model: ITextModel, position: Position): Promise { - const bucket: SelectionRange[] = []; - const ranges = new Map>(); - return new Promise(resolve => BracketSelectionRangeProvider._bracketsRightYield(resolve, 0, model, position, ranges)) - .then(() => new Promise(resolve => BracketSelectionRangeProvider._bracketsLeftYield(resolve, 0, model, position, ranges, bucket))) - .then(() => bucket); + async provideSelectionRanges(model: ITextModel, positions: Position[]): Promise { + const result: SelectionRange[][] = []; + + for (const position of positions) { + const bucket: SelectionRange[] = []; + result.push(bucket); + + const ranges = new Map>(); + await new Promise(resolve => BracketSelectionRangeProvider._bracketsRightYield(resolve, 0, model, position, ranges)); + await new Promise(resolve => BracketSelectionRangeProvider._bracketsLeftYield(resolve, 0, model, position, ranges, bucket)); + } + + return result; } private static readonly _maxDuration = 30; diff --git a/src/vs/editor/contrib/smartSelect/smartSelect.ts b/src/vs/editor/contrib/smartSelect/smartSelect.ts index edc84451523..9c911f92294 100644 --- a/src/vs/editor/contrib/smartSelect/smartSelect.ts +++ b/src/vs/editor/contrib/smartSelect/smartSelect.ts @@ -86,7 +86,7 @@ class SmartSelectController implements IEditorContribution { let promise: Promise = Promise.resolve(undefined); if (!this._state) { - promise = provideSelectionRangesN(model, selections.map(s => s.getPosition()), CancellationToken.None).then(ranges => { + promise = provideSelectionRanges(model, selections.map(s => s.getPosition()), CancellationToken.None).then(ranges => { if (!arrays.isNonEmptyArray(ranges) || ranges.length !== selections.length) { // invalid result return; @@ -210,99 +210,93 @@ registerEditorAction(ShrinkSelectionAction); // word selection modes.SelectionRangeRegistry.register('*', new WordSelectionRangeProvider()); -export function provideSelectionRanges(model: ITextModel, position: Position, token: CancellationToken): Promise { +export function provideSelectionRanges(model: ITextModel, positions: Position[], token: CancellationToken): Promise { - const provider = modes.SelectionRangeRegistry.orderedGroups(model); + const providers = modes.SelectionRangeRegistry.all(model); - if (provider.length === 1) { + if (providers.length === 1) { // add word selection and bracket selection when no provider exists - provider.unshift([new BracketSelectionRangeProvider()]); - } - - interface RankedRange { - rank: number; - range: Range; + providers.unshift(new BracketSelectionRangeProvider()); } let work: Promise[] = []; - let ranges: RankedRange[] = []; - let rank = 0; + let allRawRanges: Range[][] = []; + arrays.fill(positions.length, [], allRawRanges); - for (const group of provider) { - rank += 1; - for (const prov of group) { - work.push(Promise.resolve(prov.provideSelectionRanges(model, position, token)).then(selectionRanges => { - if (arrays.isNonEmptyArray(selectionRanges)) { - for (const sel of selectionRanges) { - if (Range.isIRange(sel.range) && Range.containsPosition(sel.range, position)) { - ranges.push({ range: Range.lift(sel.range), rank }); + for (const provider of providers) { + + work.push(Promise.resolve(provider.provideSelectionRanges(model, positions, token)).then(allProviderRanges => { + if (arrays.isNonEmptyArray(allProviderRanges) && allProviderRanges.length === positions.length) { + for (let i = 0; i < positions.length; i++) { + for (const oneProviderRanges of allProviderRanges[i]) { + if (Range.isIRange(oneProviderRanges.range) && Range.containsPosition(oneProviderRanges.range, positions[i])) { + allRawRanges[i].push(Range.lift(oneProviderRanges.range)); } } } - })); - } + } + })); } return Promise.all(work).then(() => { - if (ranges.length === 0) { - return []; - } + return allRawRanges.map(oneRawRanges => { - ranges.sort((a, b) => { - if (Position.isBefore(a.range.getStartPosition(), b.range.getStartPosition())) { - return 1; - } else if (Position.isBefore(b.range.getStartPosition(), a.range.getStartPosition())) { - return -1; - } else if (Position.isBefore(a.range.getEndPosition(), b.range.getEndPosition())) { - return -1; - } else if (Position.isBefore(b.range.getEndPosition(), a.range.getEndPosition())) { - return 1; - } else { - return b.rank - a.rank; + if (oneRawRanges.length === 0) { + return []; } + + // sort all by start/end position + oneRawRanges.sort((a, b) => { + if (Position.isBefore(a.getStartPosition(), b.getStartPosition())) { + return 1; + } else if (Position.isBefore(b.getStartPosition(), a.getStartPosition())) { + return -1; + } else if (Position.isBefore(a.getEndPosition(), b.getEndPosition())) { + return -1; + } else if (Position.isBefore(b.getEndPosition(), a.getEndPosition())) { + return 1; + } else { + return 0; + } + }); + + // remove ranges that don't contain the former range or that are equal to the + // former range + let oneRanges: Range[] = []; + let last: Range | undefined; + for (const range of oneRawRanges) { + if (!last || (Range.containsRange(range, last) && !Range.equalsRange(range, last))) { + oneRanges.push(range); + last = range; + } + } + + // add ranges that expand trivia at line starts and ends whenever a range + // wraps onto the a new line + let oneRangesWithTrivia: Range[] = [oneRanges[0]]; + for (let i = 1; i < oneRanges.length; i++) { + const prev = oneRanges[i - 1]; + const cur = oneRanges[i]; + if (cur.startLineNumber !== prev.startLineNumber || cur.endLineNumber !== prev.endLineNumber) { + // add line/block range without leading/failing whitespace + const rangeNoWhitespace = new Range(prev.startLineNumber, model.getLineFirstNonWhitespaceColumn(prev.startLineNumber), prev.endLineNumber, model.getLineLastNonWhitespaceColumn(prev.endLineNumber)); + if (rangeNoWhitespace.containsRange(prev) && !rangeNoWhitespace.equalsRange(prev)) { + oneRangesWithTrivia.push(rangeNoWhitespace); + } + // add line/block range + const rangeFull = new Range(prev.startLineNumber, 1, prev.endLineNumber, model.getLineMaxColumn(prev.endLineNumber)); + if (rangeFull.containsRange(prev) && !rangeFull.equalsRange(rangeNoWhitespace)) { + oneRangesWithTrivia.push(rangeFull); + } + } + oneRangesWithTrivia.push(cur); + } + return oneRangesWithTrivia; }); - - let result: Range[] = []; - let last: Range | undefined; - for (const { range } of ranges) { - if (!last || (Range.containsRange(range, last) && !Range.equalsRange(range, last))) { - result.push(range); - last = range; - } - } - - let result2: Range[] = [result[0]]; - for (let i = 1; i < result.length; i++) { - const prev = result[i - 1]; - const cur = result[i]; - if (cur.startLineNumber !== prev.startLineNumber || cur.endLineNumber !== prev.endLineNumber) { - // add line/block range without leading/failing whitespace - const rangeNoWhitespace = new Range(prev.startLineNumber, model.getLineFirstNonWhitespaceColumn(prev.startLineNumber), prev.endLineNumber, model.getLineLastNonWhitespaceColumn(prev.endLineNumber)); - if (rangeNoWhitespace.containsRange(prev) && !rangeNoWhitespace.equalsRange(prev)) { - result2.push(rangeNoWhitespace); - } - // add line/block range - const rangeFull = new Range(prev.startLineNumber, 1, prev.endLineNumber, model.getLineMaxColumn(prev.endLineNumber)); - if (rangeFull.containsRange(prev) && !rangeFull.equalsRange(rangeNoWhitespace)) { - result2.push(rangeFull); - } - } - result2.push(cur); - } - - return result2; }); } -export function provideSelectionRangesN(model: ITextModel, position: Position[], token: CancellationToken): Promise { - return Promise.all(position.map(pos => { - return provideSelectionRanges(model, pos, token).then(value => { - return value || []; - }); - })); -} - -registerDefaultLanguageCommand('_executeSelectionRangeProvider', function (model, position) { - return provideSelectionRanges(model, position, CancellationToken.None); +registerDefaultLanguageCommand('_executeSelectionRangeProvider', function (model, _position, args) { + return provideSelectionRanges(model, args.positions, CancellationToken.None); }); diff --git a/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts b/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts index 43b94bd2d05..de3a2ed6a75 100644 --- a/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts +++ b/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts @@ -79,7 +79,7 @@ suite('SmartSelect', () => { async function assertGetRangesToPosition(text: string[], lineNumber: number, column: number, ranges: Range[]): Promise { let uri = URI.file('test.js'); let model = modelService.createModel(text.join('\n'), new StaticLanguageSelector(mode.getLanguageIdentifier()), uri); - let actual = await provideSelectionRanges(model, new Position(lineNumber, column), CancellationToken.None); + let [actual] = await provideSelectionRanges(model, [new Position(lineNumber, column)], CancellationToken.None); let actualStr = actual!.map(r => new Range(r.startLineNumber, r.startColumn, r.endLineNumber, r.endColumn).toString()); let desiredStr = ranges.reverse().map(r => String(r)); @@ -203,7 +203,9 @@ suite('SmartSelect', () => { let model = modelService.createModel(value, new StaticLanguageSelector(mode.getLanguageIdentifier()), URI.parse('fake:lang')); let pos = model.getPositionAt(value.indexOf('|')); - let ranges = await provider.provideSelectionRanges(model, pos, CancellationToken.None); + let all = await provider.provideSelectionRanges(model, [pos], CancellationToken.None); + let ranges = all![0]; + modelService.destroyModel(model.uri); assert.equal(expected.length, ranges!.length); diff --git a/src/vs/editor/contrib/smartSelect/wordSelections.ts b/src/vs/editor/contrib/smartSelect/wordSelections.ts index 6c6c1ffd65b..1dcabbd65c9 100644 --- a/src/vs/editor/contrib/smartSelect/wordSelections.ts +++ b/src/vs/editor/contrib/smartSelect/wordSelections.ts @@ -12,12 +12,16 @@ import { isUpperAsciiLetter, isLowerAsciiLetter } from 'vs/base/common/strings'; export class WordSelectionRangeProvider implements SelectionRangeProvider { - provideSelectionRanges(model: ITextModel, position: Position): SelectionRange[] { - let result: SelectionRange[] = []; - this._addInWordRanges(result, model, position); - this._addWordRanges(result, model, position); - this._addWhitespaceLine(result, model, position); - result.push({ range: model.getFullModelRange(), kind: 'statement.all' }); + provideSelectionRanges(model: ITextModel, positions: Position[]): SelectionRange[][] { + const result: SelectionRange[][] = []; + for (const position of positions) { + const bucket: SelectionRange[] = []; + result.push(bucket); + this._addInWordRanges(bucket, model, position); + this._addWordRanges(bucket, model, position); + this._addWhitespaceLine(bucket, model, position); + bucket.push({ range: model.getFullModelRange(), kind: 'statement.all' }); + } return result; } diff --git a/src/vs/editor/contrib/suggest/wordDistance.ts b/src/vs/editor/contrib/suggest/wordDistance.ts index 1ab1cddad5a..c076d21a0b3 100644 --- a/src/vs/editor/contrib/suggest/wordDistance.ts +++ b/src/vs/editor/contrib/suggest/wordDistance.ts @@ -34,11 +34,11 @@ export abstract class WordDistance { return Promise.resolve(WordDistance.None); } - return new BracketSelectionRangeProvider().provideSelectionRanges(model, position).then(ranges => { - if (!ranges || ranges.length === 0) { + return new BracketSelectionRangeProvider().provideSelectionRanges(model, [position]).then(ranges => { + if (!ranges || ranges.length === 0 || ranges[0].length === 0) { return WordDistance.None; } - return service.computeWordRanges(model.uri, ranges[0].range).then(wordRanges => { + return service.computeWordRanges(model.uri, ranges[0][0].range).then(wordRanges => { return new class extends WordDistance { distance(anchor: IPosition, suggestion: CompletionItem) { if (!wordRanges || !position.equals(editor.getPosition())) { @@ -55,7 +55,7 @@ export abstract class WordDistance { let idx = binarySearch(wordLines, Range.fromPositions(anchor), Range.compareRangesUsingStarts); let bestWordRange = idx >= 0 ? wordLines[idx] : wordLines[Math.max(0, ~idx - 1)]; let blockDistance = ranges.length; - for (const range of ranges) { + for (const range of ranges[0]) { if (!Range.containsRange(range.range, bestWordRange)) { break; } diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 18a83b0c2b4..b994864125b 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -5303,7 +5303,7 @@ declare namespace monaco.languages { /** * Provide ranges that should be selected from the given position. */ - provideSelectionRanges(model: editor.ITextModel, position: Position, token: CancellationToken): ProviderResult; + provideSelectionRanges(model: editor.ITextModel, positions: Position[], token: CancellationToken): ProviderResult; } export interface FoldingContext { diff --git a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts index 9dfc7c5cf97..7a88d4dee39 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts @@ -408,8 +408,8 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha $registerSelectionRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void { this._registrations[handle] = modes.SelectionRangeRegistry.register(typeConverters.LanguageSelector.from(selector), { - provideSelectionRanges: (model, position, token) => { - return this._proxy.$provideSelectionRanges(handle, model.uri, position, token); + provideSelectionRanges: (model, positions, token) => { + return this._proxy.$provideSelectionRanges(handle, model.uri, positions, token); } }); } diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 9f936d07521..67998818428 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -921,7 +921,7 @@ export interface ExtHostLanguageFeaturesShape { $provideDocumentColors(handle: number, resource: UriComponents, token: CancellationToken): Promise; $provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Promise; $provideFoldingRanges(handle: number, resource: UriComponents, context: modes.FoldingContext, token: CancellationToken): Promise; - $provideSelectionRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; + $provideSelectionRanges(handle: number, resource: UriComponents, positions: IPosition[], token: CancellationToken): Promise; } export interface ExtHostQuickOpenShape { diff --git a/src/vs/workbench/api/node/extHostApiCommands.ts b/src/vs/workbench/api/node/extHostApiCommands.ts index bb76263617f..ef757ca94f0 100644 --- a/src/vs/workbench/api/node/extHostApiCommands.ts +++ b/src/vs/workbench/api/node/extHostApiCommands.ts @@ -17,7 +17,7 @@ import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands'; import { CustomCodeAction } from 'vs/workbench/api/node/extHostLanguageFeatures'; import { ICommandsExecutor, PreviewHTMLAPICommand, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand, SetEditorLayoutAPICommand } from './apiCommands'; import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { isFalsyOrEmpty, isNonEmptyArray } from 'vs/base/common/arrays'; +import { isFalsyOrEmpty } from 'vs/base/common/arrays'; export class ExtHostApiCommands { @@ -199,7 +199,7 @@ export class ExtHostApiCommands { description: 'Execute selection range provider.', args: [ { name: 'uri', description: 'Uri of a text document', constraint: URI }, - { name: 'position', description: 'Position in a text document', constraint: types.Position } + { name: 'positions', description: 'Positions in a text document', constraint: a => Array.isArray(a) } ], returns: 'A promise that resolves to an array of ranges.' }); @@ -420,16 +420,15 @@ export class ExtHostApiCommands { }); } - private _executeSelectionRangeProvider(resource: URI, position: types.Position): Promise { + private _executeSelectionRangeProvider(resource: URI, positions: types.Position[]): Promise { + let pos = positions.map(typeConverters.Position.from); const args = { resource, - position: position && typeConverters.Position.from(position) + position: pos[0], + positions: pos }; - return this._commands.executeCommand('_executeSelectionRangeProvider', args).then(result => { - if (isNonEmptyArray(result)) { - return result.map(typeConverters.SelectionRange.to); - } - return []; + return this._commands.executeCommand('_executeSelectionRangeProvider', args).then(result => { + return result.map(oneResult => oneResult.map(typeConverters.SelectionRange.to)); }); } diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 8cbf6ad2d1e..98db2266d0d 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -876,24 +876,26 @@ class SelectionRangeAdapter { private readonly _provider: vscode.SelectionRangeProvider ) { } - provideSelectionRanges(resource: URI, position: IPosition, token: CancellationToken): Promise { + provideSelectionRanges(resource: URI, positions: IPosition[], token: CancellationToken): Promise { const { document } = this._documents.getDocumentData(resource); - const pos = typeConvert.Position.to(position); - return asPromise(() => this._provider.provideSelectionRanges(document, pos, token)).then(selectionRanges => { - if (isFalsyOrEmpty(selectionRanges)) { - return undefined; - } - let result: modes.SelectionRange[] = []; - let last: vscode.Position | vscode.Range = pos; - for (const sel of selectionRanges) { - if (!sel.range.contains(last)) { - throw new Error('INVALID selection range, must contain the previous range'); + return Promise.all(positions.map(position => { + const pos = typeConvert.Position.to(position); + return asPromise(() => this._provider.provideSelectionRanges(document, pos, token)).then(selectionRanges => { + if (isFalsyOrEmpty(selectionRanges)) { + return undefined; } - result.push(typeConvert.SelectionRange.from(sel)); - last = sel.range; - } - return result; - }); + let oneResult: modes.SelectionRange[] = []; + let last: vscode.Position | vscode.Range = pos; + for (const sel of selectionRanges) { + if (!sel.range.contains(last)) { + throw new Error('INVALID selection range, must contain the previous range'); + } + oneResult.push(typeConvert.SelectionRange.from(sel)); + last = sel.range; + } + return oneResult; + }); + })); } } @@ -1307,8 +1309,8 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideSelectionRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise { - return this._withAdapter(handle, SelectionRangeAdapter, adapter => adapter.provideSelectionRanges(URI.revive(resource), position, token)); + $provideSelectionRanges(handle: number, resource: UriComponents, positions: IPosition[], token: CancellationToken): Promise { + return this._withAdapter(handle, SelectionRangeAdapter, adapter => adapter.provideSelectionRanges(URI.revive(resource), positions, token)); } // --- configuration diff --git a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts index 418690b7e06..a4b2571349b 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts @@ -796,7 +796,7 @@ suite('ExtHostLanguageFeatureCommands', function () { // --- selection ranges - test('Links, back and forth', async function () { + test('Selection Range, back and forth', async function () { disposables.push(extHost.registerSelectionRangeProvider(nullExtensionDescription, defaultSelector, { provideSelectionRanges() { @@ -808,8 +808,9 @@ suite('ExtHostLanguageFeatureCommands', function () { })); await rpcProtocol.sync(); - let value = await commands.executeCommand('vscode.executeSelectionRangeProvider', model.uri, new types.Position(0, 10)); - assert.ok(value.length >= 2); + let value = await commands.executeCommand('vscode.executeSelectionRangeProvider', model.uri, [new types.Position(0, 10)]); + assert.equal(value.length, 1); + assert.ok(value[0].length >= 2); }); }); diff --git a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts index c2fc1dc68eb..e02865feb1e 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts @@ -1103,8 +1103,9 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); - provideSelectionRanges(model, new Position(1, 17), CancellationToken.None).then(ranges => { - assert.ok(ranges.length >= 2); + provideSelectionRanges(model, [new Position(1, 17)], CancellationToken.None).then(ranges => { + assert.equal(ranges.length, 1); + assert.ok(ranges[0].length >= 2); }); }); }); From 41f9e978c9fde4a56c75b4066b3c1abb0e11e85c Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 11 Feb 2019 12:04:56 +0100 Subject: [PATCH 110/207] DialogService: open remote based on defaultURI and current window --- .../workbench/electron-browser/workbench.ts | 4 +- .../dialogs/electron-browser/dialogService.ts | 77 +++++++++++-------- .../electron-browser/remoteFileDialog.ts | 32 ++++---- 3 files changed, 60 insertions(+), 53 deletions(-) diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 3b279295ead..d570c503f17 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -109,7 +109,7 @@ import { ContextViewService } from 'vs/platform/contextview/browser/contextViewS import { WorkbenchThemeService } from 'vs/workbench/services/themes/electron-browser/workbenchThemeService'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { RemoteFileDialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService'; +import { FileDialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService'; import { LogStorageAction } from 'vs/platform/storage/node/storageService'; import { Sizing, Direction, Grid, View } from 'vs/base/browser/ui/grid/grid'; import { IEditor } from 'vs/editor/common/editorCommon'; @@ -425,7 +425,7 @@ export class Workbench extends Disposable implements IPartService { serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService)); // File Dialogs - serviceCollection.set(IFileDialogService, new SyncDescriptor(RemoteFileDialogService)); + serviceCollection.set(IFileDialogService, new SyncDescriptor(FileDialogService)); // Backup File Service if (this.workbenchParams.configuration.backupPath) { diff --git a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts index 4b80e39c48a..7c69a8008d8 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import product from 'vs/platform/node/product'; import Severity from 'vs/base/common/severity'; import { isLinux, isWindows } from 'vs/base/common/platform'; -import { IWindowService, INativeOpenDialogOptions, OpenDialogOptions } from 'vs/platform/windows/common/windows'; +import { IWindowService, INativeOpenDialogOptions, OpenDialogOptions, IURIToOpen, FileFilter } from 'vs/platform/windows/common/windows'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { IDialogService, IConfirmation, IConfirmationResult, IDialogOptions, IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { ILogService } from 'vs/platform/log/common/log'; @@ -15,12 +15,12 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/ import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { URI } from 'vs/base/common/uri'; -import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { Schemas } from 'vs/base/common/network'; import * as resources from 'vs/base/common/resources'; -import { isParent } from 'vs/platform/files/common/files'; +import { isParent, IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { RemoteFileDialog } from 'vs/workbench/services/dialogs/electron-browser/remoteFileDialog'; +import { WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces'; interface IMassagedMessageBoxOptions { @@ -165,6 +165,7 @@ export class FileDialogService implements IFileDialogService { @IHistoryService private readonly historyService: IHistoryService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @IInstantiationService private readonly instantiationService: IInstantiationService, + @IFileService private readonly fileService: IFileService ) { } defaultFilePath(schemeFilter: string): URI | undefined { @@ -228,28 +229,41 @@ export class FileDialogService implements IFileDialogService { pickFileAndOpen(options: IPickAndOpenOptions): Promise { const defaultUri = options.defaultUri; + if (this.useRemoteDialogs(defaultUri)) { + const title = nls.localize('openFile.title', 'Open File'); + return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri, title }, options.forceNewWindow, true); + } + if (!defaultUri) { options.defaultUri = this.defaultFilePath(Schemas.file); } - return this.windowService.pickFileAndOpen(this.toNativeOpenDialogOptions(options)); } pickFolderAndOpen(options: IPickAndOpenOptions): Promise { const defaultUri = options.defaultUri; + if (this.useRemoteDialogs(defaultUri)) { + const title = nls.localize('openFolder.title', 'Open Folder'); + return this.pickRemoteResourceAndOpen({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, defaultUri, title }, options.forceNewWindow, false); + } + if (!defaultUri) { options.defaultUri = this.defaultFolderPath(Schemas.file); } - return this.windowService.pickFolderAndOpen(this.toNativeOpenDialogOptions(options)); } pickWorkspaceAndOpen(options: IPickAndOpenOptions): Promise { const defaultUri = options.defaultUri; + if (this.useRemoteDialogs(defaultUri)) { + const title = nls.localize('openWorkspace.title', 'Open Workspace'); + const filters: FileFilter[] = [{ name: nls.localize('filterName.workspace', 'Workspace'), extensions: [WORKSPACE_EXTENSION] }]; + return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri, title, filters }, options.forceNewWindow, false); + } + if (!defaultUri) { options.defaultUri = this.defaultWorkspacePath(Schemas.file); } - return this.windowService.pickWorkspaceAndOpen(this.toNativeOpenDialogOptions(options)); } @@ -264,8 +278,8 @@ export class FileDialogService implements IFileDialogService { showSaveDialog(options: ISaveDialogOptions): Promise { const defaultUri = options.defaultUri; - if (defaultUri && defaultUri.scheme !== Schemas.file) { - return Promise.reject(new Error('Not supported - Save-dialogs can only be opened on `file`-uris.')); + if (this.useRemoteDialogs(defaultUri)) { + return this.saveRemoteResource(options); } return this.windowService.showSaveDialog(this.toNativeSaveDialogOptions(options)).then(result => { @@ -277,15 +291,12 @@ export class FileDialogService implements IFileDialogService { }); } - public showSaveRemoteDialog(options: ISaveDialogOptions): Promise { - const remoteFileDialog = this.instantiationService.createInstance(RemoteFileDialog); - return remoteFileDialog.showSaveDialog(options); - } - showOpenDialog(options: IOpenDialogOptions): Promise { const defaultUri = options.defaultUri; - if (defaultUri && defaultUri.scheme !== Schemas.file) { - return Promise.reject(new Error('Not supported - Open-dialogs can only be opened on `file`-uris.')); + if (this.useRemoteDialogs(defaultUri)) { + return this.pickRemoteResource(options).then(urisToOpen => { + return urisToOpen && urisToOpen.map(uto => uto.uri); + }); } const newOptions: OpenDialogOptions = { @@ -313,31 +324,33 @@ export class FileDialogService implements IFileDialogService { return this.windowService.showOpenDialog(newOptions).then(result => result ? result.map(URI.file) : undefined); } - public showOpenRemoteDialog(options: IOpenDialogOptions): Promise { + private pickRemoteResourceAndOpen(options: IOpenDialogOptions, forceNewWindow: boolean, forceOpenWorkspaceAsFile: boolean) { + return this.pickRemoteResource(options).then(urisToOpen => { + if (urisToOpen) { + return this.windowService.openWindow(urisToOpen, { forceNewWindow, forceOpenWorkspaceAsFile }); + } + return void 0; + }); + } + + private pickRemoteResource(options: IOpenDialogOptions): Promise { const remoteFileDialog = this.instantiationService.createInstance(RemoteFileDialog); return remoteFileDialog.showOpenDialog(options); } -} -export class RemoteFileDialogService extends FileDialogService { - - constructor( - @IWindowService windowService: IWindowService, - @IWorkspaceContextService contextService: IWorkspaceContextService, - @IHistoryService historyService: IHistoryService, - @IEnvironmentService environmentService: IEnvironmentService, - @IInstantiationService instantiationService: IInstantiationService, - ) { - super(windowService, contextService, historyService, environmentService, instantiationService); + private saveRemoteResource(options: ISaveDialogOptions): Promise { + const remoteFileDialog = this.instantiationService.createInstance(RemoteFileDialog); + return remoteFileDialog.showSaveDialog(options); } - public showSaveDialog(options: ISaveDialogOptions): Promise { - const defaultUri = options.defaultUri; - if (defaultUri && defaultUri.scheme === REMOTE_HOST_SCHEME) { - return this.showSaveRemoteDialog(options); + private useRemoteDialogs(defaultUri: URI) { + if (defaultUri) { + return defaultUri.scheme !== Schemas.file && this.fileService.canHandleResource(defaultUri); + } else { + return !!this.windowService.getConfiguration().remoteAuthority; } - return super.showSaveDialog(options); } + } function isUntitledWorkspace(path: string, environmentService: IEnvironmentService): boolean { diff --git a/src/vs/workbench/services/dialogs/electron-browser/remoteFileDialog.ts b/src/vs/workbench/services/dialogs/electron-browser/remoteFileDialog.ts index cb03268fdc2..6c53cf72a35 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/remoteFileDialog.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/remoteFileDialog.ts @@ -12,10 +12,9 @@ import { URI } from 'vs/base/common/uri'; import { isWindows } from 'vs/base/common/platform'; import { ISaveDialogOptions, IOpenDialogOptions } from 'vs/platform/dialogs/common/dialogs'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IWindowService, IURIToOpen } from 'vs/platform/windows/common/windows'; import { ILabelService } from 'vs/platform/label/common/label'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { INotificationService } from 'vs/platform/notification/common/notification'; interface FileQuickPickItem extends IQuickPickItem { @@ -43,40 +42,35 @@ export class RemoteFileDialog { @IWindowService private readonly windowService: IWindowService, @ILabelService private readonly labelService: ILabelService, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, - @IEditorService private readonly editorService: IEditorService, @INotificationService private readonly notificationService: INotificationService, ) { this.remoteAuthority = this.windowService.getConfiguration().remoteAuthority; } - public async showOpenDialog(options: IOpenDialogOptions = {}): Promise { - if (!this.remoteAuthority) { - this.notificationService.info(nls.localize('remoteFileDialog.notConnectedToRemote', 'Not connected to a remote.')); - return Promise.resolve(); - } + public async showOpenDialog(options: IOpenDialogOptions = {}): Promise { const defaultUri = options.defaultUri ? options.defaultUri : URI.from({ scheme: REMOTE_HOST_SCHEME, authority: this.remoteAuthority, path: '/' }); + if (!this.remoteFileService.canHandleResource(defaultUri)) { + this.notificationService.info(nls.localize('remoteFileDialog.notConnectedToRemote', 'File system provider for {0} is not available.', defaultUri.toString())); + return Promise.resolve(undefined); + } + const title = nls.localize('remoteFileDialog.openTitle', 'Open File or Folder'); return this.pickResource({ title, defaultUri, canSelectFiles: true, canSelectFolders: true }).then(async fileFolderUri => { if (fileFolderUri) { const stat = await this.remoteFileService.resolveFile(fileFolderUri); - if (stat.isDirectory) { - return this.windowService.openWindow([{ uri: fileFolderUri, typeHint: 'folder' }]); - } else { - return this.editorService.openEditor({ resource: fileFolderUri }).then(() => { - return Promise.resolve(); - }); - } + return [{ uri: fileFolderUri, type: stat.isDirectory ? 'folder' : 'file' }]; } - return Promise.resolve(); + return Promise.resolve(undefined); }); } public showSaveDialog(options: ISaveDialogOptions): Promise { - if (!this.remoteAuthority) { - this.notificationService.info(nls.localize('remoteFileDialog.notConnectedToRemote', 'Not connected to a remote.')); + const defaultUri = options.defaultUri ? options.defaultUri : URI.from({ scheme: REMOTE_HOST_SCHEME, authority: this.remoteAuthority, path: '/' }); + if (!this.remoteFileService.canHandleResource(defaultUri)) { + this.notificationService.info(nls.localize('remoteFileDialog.notConnectedToRemote', 'File system provider for {0} is not available.', defaultUri.toString())); return Promise.resolve(undefined); } - const defaultUri = options.defaultUri ? options.defaultUri : URI.from({ scheme: REMOTE_HOST_SCHEME, authority: this.remoteAuthority, path: '/' }); + return new Promise((resolve) => { let saveNameBox = this.quickInputService.createInputBox(); saveNameBox.title = options.title; From 52d134aacb9209a757e3074f71787e19712c97bc Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Feb 2019 12:08:27 +0100 Subject: [PATCH 111/207] update proposed api to have multiple positions, #41838 --- .../client/src/cssMain.ts | 44 ++++++++++--------- .../client/src/htmlMain.ts | 26 ++++++----- .../client/src/jsonMain.ts | 24 +++++----- src/vs/vscode.proposed.d.ts | 9 ++-- .../api/node/extHostLanguageFeatures.ts | 42 +++++++++++------- .../api/extHostApiCommands.test.ts | 4 +- .../api/extHostLanguageFeatures.test.ts | 4 +- 7 files changed, 87 insertions(+), 66 deletions(-) diff --git a/extensions/css-language-features/client/src/cssMain.ts b/extensions/css-language-features/client/src/cssMain.ts index 59bd8db7d26..0312498f672 100644 --- a/extensions/css-language-features/client/src/cssMain.ts +++ b/extensions/css-language-features/client/src/cssMain.ts @@ -81,35 +81,39 @@ export function activate(context: ExtensionContext) { documentSelector.forEach(selector => { context.subscriptions.push(languages.registerSelectionRangeProvider(selector, { - async provideSelectionRanges(document: TextDocument, position: Position): Promise { + async provideSelectionRanges(document: TextDocument, positions: Position[]): Promise { const textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(document); - const rawRanges = await client.sendRequest('$/textDocument/selectionRange', { textDocument, position }); - if (Array.isArray(rawRanges)) { - return rawRanges.map(r => { - return { - range: client.protocol2CodeConverter.asRange(r), - kind: SelectionRangeKind.Declaration - }; - }); - } - return []; + return Promise.all(positions.map(async position => { + const rawRanges = await client.sendRequest('$/textDocument/selectionRange', { textDocument, position }); + if (Array.isArray(rawRanges)) { + return rawRanges.map(r => { + return { + range: client.protocol2CodeConverter.asRange(r), + kind: SelectionRangeKind.Declaration + }; + }); + } + return []; + })); } })); }); }); const selectionRangeProvider = { - async provideSelectionRanges(document: TextDocument, position: Position): Promise { + async provideSelectionRanges(document: TextDocument, positions: Position[]): Promise { const textDocument = TextDocumentIdentifier.create(document.uri.toString()); - const rawRanges: Range[] = await client.sendRequest('$/textDocument/selectionRange', { textDocument, position }); + return Promise.all(positions.map(async position => { + const rawRanges: Range[] = await client.sendRequest('$/textDocument/selectionRange', { textDocument, position }); - return rawRanges.map(r => { - const actualRange = new Range(new Position(r.start.line, r.start.character), new Position(r.end.line, r.end.character)); - return { - range: actualRange, - kind: SelectionRangeKind.Declaration - }; - }); + return rawRanges.map(r => { + const actualRange = new Range(new Position(r.start.line, r.start.character), new Position(r.end.line, r.end.character)); + return { + range: actualRange, + kind: SelectionRangeKind.Declaration + }; + }); + })); } }; documentSelector.forEach(selector => { diff --git a/extensions/html-language-features/client/src/htmlMain.ts b/extensions/html-language-features/client/src/htmlMain.ts index 218e05b3e32..848ed4c6fad 100644 --- a/extensions/html-language-features/client/src/htmlMain.ts +++ b/extensions/html-language-features/client/src/htmlMain.ts @@ -90,18 +90,20 @@ export function activate(context: ExtensionContext) { documentSelector.forEach(selector => { context.subscriptions.push(languages.registerSelectionRangeProvider(selector, { - async provideSelectionRanges(document: TextDocument, position: Position): Promise { + async provideSelectionRanges(document: TextDocument, positions: Position[]): Promise { const textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(document); - const rawRanges = await client.sendRequest('$/textDocument/selectionRange', { textDocument, position }); - if (Array.isArray(rawRanges)) { - return rawRanges.map(r => { - return { - range: client.protocol2CodeConverter.asRange(r), - kind: SelectionRangeKind.Declaration - }; - }); - } - return []; + return Promise.all(positions.map(async position => { + const rawRanges = await client.sendRequest('$/textDocument/selectionRange', { textDocument, position }); + if (Array.isArray(rawRanges)) { + return rawRanges.map(r => { + return { + range: client.protocol2CodeConverter.asRange(r), + kind: SelectionRangeKind.Declaration + }; + }); + } + return []; + })); } })); }); @@ -206,4 +208,4 @@ function readJSONFile(location: string) { export function deactivate(): Promise { return telemetryReporter ? telemetryReporter.dispose() : Promise.resolve(null); -} \ No newline at end of file +} diff --git a/extensions/json-language-features/client/src/jsonMain.ts b/extensions/json-language-features/client/src/jsonMain.ts index 0ea7b420e3a..4b313efb650 100644 --- a/extensions/json-language-features/client/src/jsonMain.ts +++ b/extensions/json-language-features/client/src/jsonMain.ts @@ -200,18 +200,20 @@ export function activate(context: ExtensionContext) { documentSelector.forEach(selector => { toDispose.push(languages.registerSelectionRangeProvider(selector, { - async provideSelectionRanges(document: TextDocument, position: Position): Promise { + async provideSelectionRanges(document: TextDocument, positions: Position[]): Promise { const textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(document); - const rawRanges = await client.sendRequest('$/textDocument/selectionRange', { textDocument, position }); - if (Array.isArray(rawRanges)) { - return rawRanges.map(r => { - return { - range: client.protocol2CodeConverter.asRange(r), - kind: SelectionRangeKind.Declaration - }; - }); - } - return []; + return Promise.all(positions.map(async position => { + const rawRanges = await client.sendRequest('$/textDocument/selectionRange', { textDocument, position }); + if (Array.isArray(rawRanges)) { + return rawRanges.map(r => { + return { + range: client.protocol2CodeConverter.asRange(r), + kind: SelectionRangeKind.Declaration + }; + }); + } + return []; + })); } })); }); diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 7bc245848d0..f10cedde620 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -52,10 +52,13 @@ declare module 'vscode' { export interface SelectionRangeProvider { /** - * Provide selection ranges starting at a given position. The first range must [contain](#Range.contains) - * position and subsequent ranges must contain the previous range. + * Provide selection ranges for the given positions. Selection ranges should be computed individually and + * independend for each postion. The editor will merge and deduplicate ranges but providers must return sequences + * of ranges (per position) where a range must [contain](#Range.contains) and subsequent ranges. + * + * todo@joh */ - provideSelectionRanges(document: TextDocument, position: Position, token: CancellationToken): ProviderResult; + provideSelectionRanges(document: TextDocument, positions: Position[], token: CancellationToken): ProviderResult; } export namespace languages { diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 98db2266d0d..d35863c8a6d 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -876,26 +876,36 @@ class SelectionRangeAdapter { private readonly _provider: vscode.SelectionRangeProvider ) { } - provideSelectionRanges(resource: URI, positions: IPosition[], token: CancellationToken): Promise { + provideSelectionRanges(resource: URI, pos: IPosition[], token: CancellationToken): Promise { const { document } = this._documents.getDocumentData(resource); - return Promise.all(positions.map(position => { - const pos = typeConvert.Position.to(position); - return asPromise(() => this._provider.provideSelectionRanges(document, pos, token)).then(selectionRanges => { - if (isFalsyOrEmpty(selectionRanges)) { - return undefined; - } - let oneResult: modes.SelectionRange[] = []; - let last: vscode.Position | vscode.Range = pos; - for (const sel of selectionRanges) { - if (!sel.range.contains(last)) { + const positions = pos.map(typeConvert.Position.to); + + return asPromise(() => this._provider.provideSelectionRanges(document, positions, token)).then(allProviderRanges => { + if (isFalsyOrEmpty(allProviderRanges)) { + return []; + } + if (allProviderRanges.length !== positions.length) { + console.warn('BAD selection ranges, provider must return ranges for each position'); + return []; + } + + let allResults: modes.SelectionRange[][] = []; + for (let i = 0; i < positions.length; i++) { + const oneResult: modes.SelectionRange[] = []; + allResults.push(oneResult); + + const oneProviderRanges = allProviderRanges[i]; + let last: vscode.Position | vscode.Range = positions[i]; + for (const selectionRange of oneProviderRanges) { + if (!selectionRange.range.contains(last)) { throw new Error('INVALID selection range, must contain the previous range'); } - oneResult.push(typeConvert.SelectionRange.from(sel)); - last = sel.range; + oneResult.push(typeConvert.SelectionRange.from(selectionRange)); + last = selectionRange.range; } - return oneResult; - }); - })); + } + return allResults; + }); } } diff --git a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts index a4b2571349b..7a82f2483eb 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts @@ -800,10 +800,10 @@ suite('ExtHostLanguageFeatureCommands', function () { disposables.push(extHost.registerSelectionRangeProvider(nullExtensionDescription, defaultSelector, { provideSelectionRanges() { - return [ + return [[ new types.SelectionRange(new types.Range(0, 10, 0, 18), types.SelectionRangeKind.Empty), new types.SelectionRange(new types.Range(0, 2, 0, 20), types.SelectionRangeKind.Empty) - ]; + ]]; } })); diff --git a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts index e02865feb1e..81605448c0a 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts @@ -1094,10 +1094,10 @@ suite('ExtHostLanguageFeatures', function () { test('Selection Ranges, data conversion', async () => { disposables.push(extHost.registerSelectionRangeProvider(defaultExtension, defaultSelector, new class implements vscode.SelectionRangeProvider { provideSelectionRanges() { - return [ + return [[ new types.SelectionRange(new types.Range(0, 10, 0, 18), types.SelectionRangeKind.Empty), new types.SelectionRange(new types.Range(0, 2, 0, 20), types.SelectionRangeKind.Empty) - ]; + ]]; } })); From f1ab745e58f1e8d48833b16649ec102fe92fb6cf Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Feb 2019 12:14:04 +0100 Subject: [PATCH 112/207] Revert "make vscode.Uri.parse throw when scheme is missing, #66802" This reverts commit 2422c987f44339ad4b6f9227ffbbf1e358d8a3d6. --- .../workbench/services/extensions/node/extensionHostMain.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/extensions/node/extensionHostMain.ts b/src/vs/workbench/services/extensions/node/extensionHostMain.ts index c203584c723..1a9fa2f0b5f 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostMain.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostMain.ts @@ -7,7 +7,7 @@ import { timeout } from 'vs/base/common/async'; import * as errors from 'vs/base/common/errors'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Counter } from 'vs/base/common/numbers'; -import { URI } from 'vs/base/common/uri'; +import { URI, setUriThrowOnMissingScheme } from 'vs/base/common/uri'; import { IURITransformer } from 'vs/base/common/uriIpc'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/node/ipc'; import { IEnvironment, IInitData, MainContext, MainThreadConsoleShape } from 'vs/workbench/api/node/extHost.protocol'; @@ -20,7 +20,7 @@ import { RPCProtocol } from 'vs/workbench/services/extensions/node/rpcProtocol'; // we don't (yet) throw when extensions parse // uris that have no scheme -// setUriThrowOnMissingScheme(false); +setUriThrowOnMissingScheme(false); const nativeExit = process.exit.bind(process); function patchProcess(allowExit: boolean) { From 7ff2398cfd0776409ff687ce811f1d7ff3375dc8 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Feb 2019 12:22:29 +0100 Subject: [PATCH 113/207] fix issue with #41838 --- src/vs/editor/contrib/smartSelect/smartSelect.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/smartSelect/smartSelect.ts b/src/vs/editor/contrib/smartSelect/smartSelect.ts index 9c911f92294..63e1579a348 100644 --- a/src/vs/editor/contrib/smartSelect/smartSelect.ts +++ b/src/vs/editor/contrib/smartSelect/smartSelect.ts @@ -221,13 +221,15 @@ export function provideSelectionRanges(model: ITextModel, positions: Position[], let work: Promise[] = []; let allRawRanges: Range[][] = []; - arrays.fill(positions.length, [], allRawRanges); for (const provider of providers) { work.push(Promise.resolve(provider.provideSelectionRanges(model, positions, token)).then(allProviderRanges => { if (arrays.isNonEmptyArray(allProviderRanges) && allProviderRanges.length === positions.length) { for (let i = 0; i < positions.length; i++) { + if (!allRawRanges[i]) { + allRawRanges[i] = []; + } for (const oneProviderRanges of allProviderRanges[i]) { if (Range.isIRange(oneProviderRanges.range) && Range.containsPosition(oneProviderRanges.range, positions[i])) { allRawRanges[i].push(Range.lift(oneProviderRanges.range)); From 0507edbcf6c7bb72062fec0e330f59fbffd852a7 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Fri, 8 Feb 2019 10:10:20 +0100 Subject: [PATCH 114/207] Move keytar.test.ts (fixes #68206) --- src/tsconfig.strictNullChecks.json | 1 - src/vs/{platform/credentials => base}/test/node/keytar.test.ts | 0 2 files changed, 1 deletion(-) rename src/vs/{platform/credentials => base}/test/node/keytar.test.ts (100%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index a2f5b68454b..30c1ce0767f 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -234,7 +234,6 @@ "./vs/platform/contextview/browser/contextMenuService.ts", "./vs/platform/contextview/browser/contextView.ts", "./vs/platform/contextview/browser/contextViewService.ts", - "./vs/platform/credentials/test/node/keytar.test.ts", "./vs/platform/diagnostics/electron-main/diagnosticsService.ts", "./vs/platform/dialogs/common/dialogs.ts", "./vs/platform/dialogs/node/dialogIpc.ts", diff --git a/src/vs/platform/credentials/test/node/keytar.test.ts b/src/vs/base/test/node/keytar.test.ts similarity index 100% rename from src/vs/platform/credentials/test/node/keytar.test.ts rename to src/vs/base/test/node/keytar.test.ts From 146211b771a4f50b8aa9695ecdf6c2b5c484ef86 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 11 Feb 2019 12:48:16 +0100 Subject: [PATCH 115/207] Implement #68408 --- .../electron-browser/extensionsActions.ts | 71 +++++++++++++++---- .../themes/common/workbenchThemeService.ts | 3 +- .../electron-browser/workbenchThemeService.ts | 6 +- 3 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts index ee26c75549d..16314fb5df6 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/extensionActions'; import { localize } from 'vs/nls'; import { IAction, Action } from 'vs/base/common/actions'; -import { Throttler } from 'vs/base/common/async'; +import { Throttler, Delayer } from 'vs/base/common/async'; import * as DOM from 'vs/base/browser/dom'; import * as paths from 'vs/base/common/paths'; import { Event } from 'vs/base/common/event'; @@ -29,7 +29,7 @@ import { IWindowService, IWindowsService } from 'vs/platform/windows/common/wind import { IExtensionService, IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import { URI } from 'vs/base/common/uri'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, ConfigurationTarget } 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'; @@ -55,6 +55,7 @@ import { clipboard } from 'electron'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { coalesce } from 'vs/base/common/arrays'; +import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; function toExtensionDescription(local: ILocalExtension): IExtensionDescription { return { @@ -145,7 +146,10 @@ export class InstallAction extends ExtensionAction { @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IInstantiationService private readonly instantiationService: IInstantiationService, @INotificationService private readonly notificationService: INotificationService, - @IOpenerService private readonly openerService: IOpenerService + @IOpenerService private readonly openerService: IOpenerService, + @IQuickInputService private readonly quickInputService: IQuickInputService, + @IExtensionService private readonly runtimeExtensionService: IExtensionService, + @IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService ) { super(`extensions.install`, InstallAction.INSTALL_LABEL, InstallAction.Class, false); this.update(); @@ -172,24 +176,65 @@ export class InstallAction extends ExtensionAction { } } - run(): Promise { + async run(): Promise { this.extensionsWorkbenchService.open(this.extension); alert(localize('installExtensionStart', "Installing extension {0} started. An editor is now open with more details on this extension", this.extension.displayName)); - return this.install(this.extension); + const extension = await this.install(this.extension); + + if (extension.local && extension.local.manifest.contributes.themes && extension.local.manifest.contributes.themes.length) { + return this.applyInstalledTheme(extension.local); + } + } - private install(extension: IExtension): Promise { - return this.extensionsWorkbenchService.install(extension).then(null, err => { - if (!extension.gallery) { - return this.notificationService.error(err); - } + private install(extension: IExtension): Promise { + return this.extensionsWorkbenchService.install(extension) + .then(null, err => { + if (!extension.gallery) { + return this.notificationService.error(err); + } - console.error(err); + console.error(err); - return promptDownloadManually(extension.gallery, localize('failedToInstall', "Failed to install \'{0}\'.", extension.identifier.id), err, this.instantiationService, this.notificationService, this.openerService); - }); + return promptDownloadManually(extension.gallery, localize('failedToInstall', "Failed to install \'{0}\'.", extension.identifier.id), err, this.instantiationService, this.notificationService, this.openerService); + }); + } + + private async applyInstalledTheme(extension: ILocalExtension): Promise { + const runningExtension = await this.getRunningExtension(extension); + if (runningExtension) { + const currentTheme = this.workbenchThemeService.getColorTheme(); + const themes = await this.workbenchThemeService.getColorThemes(runningExtension.identifier); + const delayer = new Delayer(100); + const pickedTheme = await this.quickInputService.pick( + themes.map(theme => ({ label: theme.label, id: theme.id })), + { + placeHolder: localize('apply installed theme', "Apply installed theme"), + onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setColorTheme(item.id, ConfigurationTarget.MEMORY).then(() => null)) + }); + this.workbenchThemeService.setColorTheme(pickedTheme ? pickedTheme.id : currentTheme.id, undefined); + } + } + + private async getRunningExtension(extension: ILocalExtension): Promise { + const runningExtension = await this.runtimeExtensionService.getExtension(extension.identifier.id); + if (runningExtension) { + return runningExtension; + } + if (this.runtimeExtensionService.canAddExtension(toExtensionDescription(extension))) { + return new Promise((c, e) => { + const disposable = this.runtimeExtensionService.onDidChangeExtensions(async () => { + const runningExtension = await this.runtimeExtensionService.getExtension(extension.identifier.id); + if (runningExtension) { + disposable.dispose(); + c(runningExtension); + } + }); + }); + } + return null; } } diff --git a/src/vs/workbench/services/themes/common/workbenchThemeService.ts b/src/vs/workbench/services/themes/common/workbenchThemeService.ts index 533d44586f5..9e386c7960c 100644 --- a/src/vs/workbench/services/themes/common/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/common/workbenchThemeService.ts @@ -8,6 +8,7 @@ import { Event } from 'vs/base/common/event'; import { Color } from 'vs/base/common/color'; import { ITheme, IThemeService, IIconTheme } from 'vs/platform/theme/common/themeService'; import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; export const IWorkbenchThemeService = createDecorator('themeService'); @@ -54,7 +55,7 @@ export interface IWorkbenchThemeService extends IThemeService { _serviceBrand: any; setColorTheme(themeId: string | undefined, settingsTarget: ConfigurationTarget | undefined): Promise; getColorTheme(): IColorTheme; - getColorThemes(): Promise; + getColorThemes(extensionId?: ExtensionIdentifier): Promise; onDidColorThemeChange: Event; restoreColorTheme(); diff --git a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts index 8413a65817a..d4b2043c48d 100644 --- a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts @@ -31,6 +31,7 @@ import * as resources from 'vs/base/common/resources'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { textmateColorsSchemaId, registerColorThemeSchemas, textmateColorSettingsSchemaId } from 'vs/workbench/services/themes/common/colorThemeSchema'; import { workbenchColorsSchemaId } from 'vs/platform/theme/common/colorRegistry'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; // implementation @@ -319,8 +320,9 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { return this.currentColorTheme; } - public getColorThemes(): Promise { - return this.colorThemeStore.getColorThemes(); + public async getColorThemes(extensionId?: ExtensionIdentifier): Promise { + const colorThemes = await this.colorThemeStore.getColorThemes(); + return extensionId ? colorThemes.filter(c => ExtensionIdentifier.equals(new ExtensionIdentifier(c.extensionData.extensionId), extensionId)) : colorThemes; } public getTheme(): ITheme { From 80417805842cfff3eb310c1e20e17378aed723a0 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Feb 2019 12:59:10 +0100 Subject: [PATCH 116/207] perf-marks - use global or self or nothing --- src/vs/base/common/performance.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/vs/base/common/performance.js b/src/vs/base/common/performance.js index c7825a0e310..351b26d88ba 100644 --- a/src/vs/base/common/performance.js +++ b/src/vs/base/common/performance.js @@ -22,22 +22,30 @@ if (typeof define !== "function" && typeof module === "object" && typeof module. define([], function () { - global._performanceEntries = global._performanceEntries || []; + let _performanceEntries; + if (typeof global === 'object') { + _performanceEntries = global._performanceEntries = []; + } else if (typeof self === 'object') { + _performanceEntries = self._performanceEntries = []; + } else { + _performanceEntries = []; + } + const _dataLen = 2; const _timeStamp = typeof console.timeStamp === 'function' ? console.timeStamp.bind(console) : () => { }; function importEntries(entries) { - global._performanceEntries.splice(0, 0, ...entries); + _performanceEntries.splice(0, 0, ...entries); } function exportEntries() { - return global._performanceEntries.slice(0); + return _performanceEntries.slice(0); } function getEntries() { const result = []; - const entries = global._performanceEntries; + const entries = _performanceEntries; for (let i = 0; i < entries.length; i += _dataLen) { result.push({ name: entries[i], @@ -48,7 +56,7 @@ define([], function () { } function getEntry(name) { - const entries = global._performanceEntries; + const entries = _performanceEntries; for (let i = 0; i < entries.length; i += _dataLen) { if (entries[i] === name) { return { @@ -60,7 +68,7 @@ define([], function () { } function getDuration(from, to) { - const entries = global._performanceEntries; + const entries = _performanceEntries; let target = to; let endIndex = 0; for (let i = entries.length - _dataLen; i >= 0; i -= _dataLen) { @@ -79,7 +87,7 @@ define([], function () { } function mark(name) { - global._performanceEntries.push(name, Date.now()); + _performanceEntries.push(name, Date.now()); _timeStamp(name); } From 40a9104fa521879c51ffa4d94db20bcb4b9ada30 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Feb 2019 13:01:49 +0100 Subject: [PATCH 117/207] Revert "perf-marks - use global or self or nothing" This reverts commit 80417805842cfff3eb310c1e20e17378aed723a0. --- src/vs/base/common/performance.js | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/vs/base/common/performance.js b/src/vs/base/common/performance.js index 351b26d88ba..c7825a0e310 100644 --- a/src/vs/base/common/performance.js +++ b/src/vs/base/common/performance.js @@ -22,30 +22,22 @@ if (typeof define !== "function" && typeof module === "object" && typeof module. define([], function () { - let _performanceEntries; - if (typeof global === 'object') { - _performanceEntries = global._performanceEntries = []; - } else if (typeof self === 'object') { - _performanceEntries = self._performanceEntries = []; - } else { - _performanceEntries = []; - } - + global._performanceEntries = global._performanceEntries || []; const _dataLen = 2; const _timeStamp = typeof console.timeStamp === 'function' ? console.timeStamp.bind(console) : () => { }; function importEntries(entries) { - _performanceEntries.splice(0, 0, ...entries); + global._performanceEntries.splice(0, 0, ...entries); } function exportEntries() { - return _performanceEntries.slice(0); + return global._performanceEntries.slice(0); } function getEntries() { const result = []; - const entries = _performanceEntries; + const entries = global._performanceEntries; for (let i = 0; i < entries.length; i += _dataLen) { result.push({ name: entries[i], @@ -56,7 +48,7 @@ define([], function () { } function getEntry(name) { - const entries = _performanceEntries; + const entries = global._performanceEntries; for (let i = 0; i < entries.length; i += _dataLen) { if (entries[i] === name) { return { @@ -68,7 +60,7 @@ define([], function () { } function getDuration(from, to) { - const entries = _performanceEntries; + const entries = global._performanceEntries; let target = to; let endIndex = 0; for (let i = entries.length - _dataLen; i >= 0; i -= _dataLen) { @@ -87,7 +79,7 @@ define([], function () { } function mark(name) { - _performanceEntries.push(name, Date.now()); + global._performanceEntries.push(name, Date.now()); _timeStamp(name); } From 1c1f93652fb41f24d4e8ab0f84e0002a533e2c24 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 11 Feb 2019 13:19:40 +0100 Subject: [PATCH 118/207] Fix #68116. Adopt in search, problems and debug land --- src/vs/platform/list/browser/listService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index aee424a621b..d2b17c92720 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -707,6 +707,7 @@ export class TreeResourceNavigator2 extends Disposable { return; } + const isMiddleClick = e.browserEvent instanceof MouseEvent ? e.browserEvent.button === 1 : false; const isDoubleClick = e.browserEvent.detail === 2; const preserveFocus = (e.browserEvent instanceof KeyboardEvent && typeof (e.browserEvent).preserveFocus === 'boolean') ? !!(e.browserEvent).preserveFocus : @@ -714,7 +715,7 @@ export class TreeResourceNavigator2 extends Disposable { if (this.tree.openOnSingleClick || isDoubleClick) { const sideBySide = e.browserEvent instanceof MouseEvent && (e.browserEvent.ctrlKey || e.browserEvent.metaKey || e.browserEvent.altKey); - this.open(preserveFocus, isDoubleClick, sideBySide); + this.open(preserveFocus, isDoubleClick || isMiddleClick, sideBySide); } } From d2771d8ed1d469794659a5f257033fd59de28703 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 11 Feb 2019 04:29:19 -0800 Subject: [PATCH 119/207] Strict null check terminalActions Part of #60565 --- src/tsconfig.strictNullChecks.json | 1 + .../electron-browser/terminalActions.ts | 34 +++++++++---------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 30c1ce0767f..006c210ae53 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -635,6 +635,7 @@ "./vs/workbench/contrib/terminal/common/terminalCommands.ts", "./vs/workbench/contrib/terminal/common/terminalMenu.ts", "./vs/workbench/contrib/terminal/common/terminalService.ts", + "./vs/workbench/contrib/terminal/electron-browser/terminalActions.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalConfigHelper.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts", "./vs/workbench/contrib/terminal/electron-browser/terminalLinkHandler.ts", diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalActions.ts index a54c1b7758d..a202076042b 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalActions.ts @@ -40,23 +40,23 @@ export const TERMINAL_PICKER_PREFIX = 'term '; function getCwdForSplit(configHelper: ITerminalConfigHelper, instance: ITerminalInstance, folders?: IWorkspaceFolder[], commandService?: ICommandService): Promise { switch (configHelper.config.splitCwd) { case 'workspaceRoot': - let pathPromise: Promise; - if (folders.length === 0) { - pathPromise = Promise.resolve(''); - } else if (folders.length === 1) { - pathPromise = Promise.resolve(folders[0].uri); - } else if (folders.length > 1) { - // Only choose a path when there's more than 1 folder - const options: IPickOptions = { - placeHolder: nls.localize('workbench.action.terminal.newWorkspacePlaceholder', "Select current working directory for new terminal") - }; - pathPromise = commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND_ID, [options]).then(workspace => { - if (!workspace) { - // Don't split the instance if the workspace picker was canceled - return undefined; - } - return Promise.resolve(workspace.uri); - }); + let pathPromise: Promise = Promise.resolve(''); + if (folders !== undefined && commandService !== undefined) { + if (folders.length === 1) { + pathPromise = Promise.resolve(folders[0].uri); + } else if (folders.length > 1) { + // Only choose a path when there's more than 1 folder + const options: IPickOptions = { + placeHolder: nls.localize('workbench.action.terminal.newWorkspacePlaceholder', "Select current working directory for new terminal") + }; + pathPromise = commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND_ID, [options]).then(workspace => { + if (!workspace) { + // Don't split the instance if the workspace picker was canceled + return undefined; + } + return Promise.resolve(workspace.uri); + }); + } } return pathPromise; case 'initial': From c7f83b2c854c187abb863c58ab5c69f0d3240f2b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 11 Feb 2019 04:35:20 -0800 Subject: [PATCH 120/207] Strict null check mainThreadTerminalService Part of #60565 --- src/tsconfig.strictNullChecks.json | 1 + .../api/electron-browser/mainThreadTerminalService.ts | 10 +++++++--- src/vs/workbench/api/node/extHost.protocol.ts | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 006c210ae53..7b4b9f867cd 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -413,6 +413,7 @@ "./vs/workbench/api/electron-browser/mainThreadStatusBar.ts", "./vs/workbench/api/electron-browser/mainThreadStorage.ts", "./vs/workbench/api/electron-browser/mainThreadTelemetry.ts", + "./vs/workbench/api/electron-browser/mainThreadTerminalService.ts", "./vs/workbench/api/electron-browser/mainThreadUrls.ts", "./vs/workbench/api/electron-browser/mainThreadWindow.ts", "./vs/workbench/api/electron-browser/mainThreadWorkspace.ts", diff --git a/src/vs/workbench/api/electron-browser/mainThreadTerminalService.ts b/src/vs/workbench/api/electron-browser/mainThreadTerminalService.ts index d340f73f602..3f30d465934 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadTerminalService.ts @@ -37,7 +37,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._toDispose.push(terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance))); this._toDispose.push(terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance))); this._toDispose.push(terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request))); - this._toDispose.push(terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : undefined))); + this._toDispose.push(terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : null))); this._toDispose.push(terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title))); // Set initial ext host state @@ -90,7 +90,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape } public $hide(terminalId: number): void { - if (this.terminalService.getActiveInstance().id === terminalId) { + const instance = this.terminalService.getActiveInstance(); + if (instance && instance.id === terminalId) { this.terminalService.hidePanel(); } } @@ -164,7 +165,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape terminalInstance.addDisposable(this._terminalOnDidWriteDataListeners[terminalId]); } - private _onActiveTerminalChanged(terminalId: number | undefined): void { + private _onActiveTerminalChanged(terminalId: number | null): void { this._proxy.$acceptActiveTerminalChanged(terminalId); } @@ -195,6 +196,9 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape } private _onTerminalProcessIdReady(terminalInstance: ITerminalInstance): void { + if (terminalInstance.processId === undefined) { + return; + } this._proxy.$acceptTerminalProcessId(terminalInstance.id, terminalInstance.processId); } diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 67998818428..671a13706eb 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -940,7 +940,7 @@ export interface ShellLaunchConfigDto { executable?: string; args?: string[] | string; cwd?: string | URI; - env?: { [key: string]: string }; + env?: { [key: string]: string | null }; } export interface ExtHostTerminalServiceShape { From 1ad850c01556e70e2c0d6591ee1a26d46bf368cc Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 11 Feb 2019 13:55:11 +0100 Subject: [PATCH 121/207] debt - do not depend on implementation of service --- src/vs/workbench/electron-browser/shell.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index fe9a273da20..f1faa78b49d 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -74,7 +74,6 @@ import { HashService } from 'vs/workbench/services/hash/node/hashService'; import { IHashService } from 'vs/workbench/services/hash/common/hashService'; import { ILogService } from 'vs/platform/log/common/log'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { StorageService } from 'vs/platform/storage/node/storageService'; import { Event, Emitter } from 'vs/base/common/event'; import { WORKBENCH_BACKGROUND } from 'vs/workbench/common/theme'; import { LocalizationsChannelClient } from 'vs/platform/localizations/node/localizationsIpc'; @@ -113,7 +112,7 @@ export interface ICoreServices { configurationService: IConfigurationService; environmentService: IEnvironmentService; logService: ILogService; - storageService: StorageService; + storageService: IStorageService; } /** @@ -125,7 +124,7 @@ export class Shell extends Disposable { private readonly _onWillShutdown = this._register(new Emitter()); get onWillShutdown(): Event { return this._onWillShutdown.event; } - private storageService: StorageService; + private storageService: IStorageService; private environmentService: IEnvironmentService; private logService: ILogService; private configurationService: IConfigurationService; @@ -144,7 +143,13 @@ export class Shell extends Disposable { private configuration: IWindowConfiguration; private workbench: Workbench; - constructor(container: HTMLElement, coreServices: ICoreServices, mainProcessServices: ServiceCollection, private mainProcessClient: IPCClient, configuration: IWindowConfiguration) { + constructor( + container: HTMLElement, + coreServices: ICoreServices, + mainProcessServices: ServiceCollection, + private mainProcessClient: IPCClient, + configuration: IWindowConfiguration + ) { super(); this.container = container; @@ -265,7 +270,6 @@ export class Shell extends Disposable { perf.mark('didStartWorkbench'); } - private initServiceCollection(container: HTMLElement): [IInstantiationService, ServiceCollection] { const serviceCollection = new ServiceCollection(); serviceCollection.set(IWorkspaceContextService, this.contextService); From 14f2514c39538a2e18bb01aba777f4b9ccd8303d Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 11 Feb 2019 05:39:07 -0800 Subject: [PATCH 122/207] Remove font-family from xterm.css Fixes #68422 --- .../workbench/contrib/terminal/electron-browser/media/xterm.css | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/electron-browser/media/xterm.css b/src/vs/workbench/contrib/terminal/electron-browser/media/xterm.css index be7a3c7a177..9c52131931b 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/media/xterm.css +++ b/src/vs/workbench/contrib/terminal/electron-browser/media/xterm.css @@ -40,7 +40,6 @@ */ .xterm { - font-family: courier-new, courier, monospace; font-feature-settings: "liga" 0; position: relative; user-select: none; From 1b69f896d9c650f3a0a4862adf56e7b395f75431 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 11 Feb 2019 05:39:31 -0800 Subject: [PATCH 123/207] Fix terminal char draw from uncached chars Fixes #68045 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1f252eb0cab..ae4721901d6 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "vscode-ripgrep": "^1.2.5", "vscode-sqlite3": "4.0.7", "vscode-textmate": "^4.0.1", - "vscode-xterm": "3.12.0-beta3", + "vscode-xterm": "3.12.0-beta4", "winreg": "^1.2.4", "yauzl": "^2.9.1", "yazl": "^2.4.3" diff --git a/yarn.lock b/yarn.lock index 9a934e15461..053bd5abe32 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9442,10 +9442,10 @@ vscode-uri@^1.0.6: resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.6.tgz#6b8f141b0bbc44ad7b07e94f82f168ac7608ad4d" integrity sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww== -vscode-xterm@3.12.0-beta3: - version "3.12.0-beta3" - resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.12.0-beta3.tgz#d642d249fe01615dbe1ab4d11b333c1d52b65ee8" - integrity sha512-rR9EmZjVJiQZ39Q4msSzZcwLzMQPzmxdjvr6uJogo3ht3+cEFnZbtJ8cHKYpU7gkKnj+l56d5uC3pbmt3MB/Nw== +vscode-xterm@3.12.0-beta4: + version "3.12.0-beta4" + resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.12.0-beta4.tgz#b8ed223e00e6b53efea62e7c7dce5bc2ac556df3" + integrity sha512-coUhJoIIjSlIZ33VCxI6EEyEKSqet41753wfSy/Av3UCv1oiwrrCRfvLdRYC+qdabWDtVy5K7aYYDh1k7WsVeA== vso-node-api@6.1.2-preview: version "6.1.2-preview" From 17d85e8361e04937fd7cf227299c7a3a90f2d422 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Feb 2019 14:59:35 +0100 Subject: [PATCH 124/207] outline - remove size limit --- src/vs/workbench/contrib/outline/browser/outlinePanel.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts index 2d1f9061d38..d8a31cc9f72 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts @@ -448,17 +448,12 @@ export class OutlinePanel extends ViewletPanel { return this._showMessage(localize('no-symbols', "No symbols found in document '{0}'", basename(textModel.uri))); } - let newSize = TreeElement.size(newModel); - if (newSize > 7500) { - // this is a workaround for performance issues with the tree: https://github.com/Microsoft/vscode/issues/18180 - return this._showMessage(localize('too-many-symbols', "We are sorry, but this file is too large for showing an outline.")); - } - dom.removeClass(this._domNode, 'message'); if (event && oldModel && textModel.getLineCount() >= 25) { // heuristic: when the symbols-to-lines ratio changes by 50% between edits // wait a little (and hope that the next change isn't as drastic). + let newSize = TreeElement.size(newModel); let newLength = textModel.getValueLength(); let newRatio = newSize / newLength; let oldSize = TreeElement.size(oldModel); From b34154e028359d737bef819e11b97e855bb1187f Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 11 Feb 2019 15:05:32 +0100 Subject: [PATCH 125/207] resource.join with multiple fragments --- src/vs/base/common/resources.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts index 9d236790f5e..c759010f214 100644 --- a/src/vs/base/common/resources.ts +++ b/src/vs/base/common/resources.ts @@ -89,18 +89,18 @@ export function dirname(resource: URI): URI | null { } /** - * Join a URI path with a path fragment and normalizes the resulting path. + * Join a URI path with path fragments and normalizes the resulting path. * * @param resource The input URI. * @param pathFragment The path fragment to add to the URI path. * @returns The resulting URI. */ -export function joinPath(resource: URI, pathFragment: string): URI { +export function joinPath(resource: URI, ...pathFragment: string[]): URI { let joinedPath: string; if (resource.scheme === Schemas.file) { - joinedPath = URI.file(paths.join(fsPath(resource), pathFragment)).path; + joinedPath = URI.file(paths.join(fsPath(resource), ...pathFragment)).path; } else { - joinedPath = paths.join(resource.path, pathFragment); + joinedPath = paths.join(resource.path, ...pathFragment); } return resource.with({ path: joinedPath From d77d7d29d8081b594bd59ebd28a02e9a9912f454 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 11 Feb 2019 15:25:32 +0100 Subject: [PATCH 126/207] workspaceHome -> untitledWorkspacesHome, is URI --- src/vs/code/electron-main/windows.ts | 6 +- src/vs/code/node/windowsFinder.ts | 10 +-- src/vs/code/test/node/windowsFinder.test.ts | 2 +- .../environment/common/environment.ts | 2 +- .../environment/node/environmentService.ts | 2 +- .../electron-main/historyMainService.ts | 2 +- src/vs/platform/label/common/label.ts | 4 +- .../launch/electron-main/launchService.ts | 3 +- .../platform/workspaces/common/workspaces.ts | 2 +- .../electron-main/workspacesMainService.ts | 65 +++++++++---------- .../workspacesMainService.test.ts | 28 ++++---- .../dialogs/electron-browser/dialogService.ts | 9 ++- .../services/label/common/labelService.ts | 2 +- 13 files changed, 67 insertions(+), 70 deletions(-) diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 60fed9a17bf..468c9c65c3f 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -531,7 +531,7 @@ export class WindowsManager implements IWindowsMainService { newWindow: openFilesInNewWindow, context: openConfig.context, fileUri: fileToCheck && fileToCheck.fileUri, - workspaceResolver: workspace => workspace.configPath.scheme === Schemas.file ? this.workspacesMainService.resolveWorkspaceSync(fsPath(workspace.configPath)) : null + localWorkspaceResolver: workspace => workspace.configPath.scheme === Schemas.file ? this.workspacesMainService.resolveLocalWorkspaceSync(workspace.configPath) : null }); // We found a window to open the files in @@ -1051,7 +1051,7 @@ export class WindowsManager implements IWindowsMainService { // Workspace (unless disabled via flag) if (!options.forceOpenWorkspaceAsFile) { - const workspace = this.workspacesMainService.resolveWorkspaceSync(candidate); + const workspace = this.workspacesMainService.resolveLocalWorkspaceSync(URI.file(candidate)); if (workspace) { return { workspace: { id: workspace.id, configPath: workspace.configPath }, remoteAuthority }; } @@ -2128,7 +2128,7 @@ class WorkspacesManager { return workspace.scheme === Schemas.file ? dirname(workspace.fsPath) : undefined; } - const resolvedWorkspace = workspace.configPath.scheme === Schemas.file && this.workspacesMainService.resolveWorkspaceSync(workspace.configPath.fsPath); + const resolvedWorkspace = workspace.configPath.scheme === Schemas.file && this.workspacesMainService.resolveLocalWorkspaceSync(workspace.configPath); if (resolvedWorkspace && resolvedWorkspace.folders.length > 0) { for (const folder of resolvedWorkspace.folders) { if (folder.uri.scheme === Schemas.file) { diff --git a/src/vs/code/node/windowsFinder.ts b/src/vs/code/node/windowsFinder.ts index 99c06e09b4e..2145d0242f4 100644 --- a/src/vs/code/node/windowsFinder.ts +++ b/src/vs/code/node/windowsFinder.ts @@ -25,10 +25,10 @@ export interface IBestWindowOrFolderOptions { fileUri?: URI; userHome?: string; codeSettingsFolder?: string; - workspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null; + localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null; } -export function findBestWindowOrFolderForFile({ windows, newWindow, context, fileUri, workspaceResolver }: IBestWindowOrFolderOptions): W | undefined { +export function findBestWindowOrFolderForFile({ windows, newWindow, context, fileUri, localWorkspaceResolver: workspaceResolver }: IBestWindowOrFolderOptions): W | undefined { if (!newWindow && fileUri && (context === OpenContext.DESKTOP || context === OpenContext.CLI || context === OpenContext.DOCK)) { const windowOnFilePath = findWindowOnFilePath(windows, fileUri, workspaceResolver); if (windowOnFilePath) { @@ -38,15 +38,15 @@ export function findBestWindowOrFolderForFile({ windows return !newWindow ? getLastActiveWindow(windows) : undefined; } -function findWindowOnFilePath(windows: W[], fileUri: URI, workspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null): W | null { +function findWindowOnFilePath(windows: W[], fileUri: URI, localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null): W | null { // First check for windows with workspaces that have a parent folder of the provided path opened for (const window of windows) { const workspace = window.openedWorkspace; if (workspace) { - const resolvedWorkspace = workspaceResolver(workspace); + const resolvedWorkspace = localWorkspaceResolver(workspace); if (resolvedWorkspace) { - // workspace cpuld be resolved: It's in the local file system + // workspace could be resolved: It's in the local file system if (resolvedWorkspace.folders.some(folder => isEqualOrParent(fileUri, folder.uri))) { return window; } diff --git a/src/vs/code/test/node/windowsFinder.test.ts b/src/vs/code/test/node/windowsFinder.test.ts index 79d476c53d0..925a8e9fceb 100644 --- a/src/vs/code/test/node/windowsFinder.test.ts +++ b/src/vs/code/test/node/windowsFinder.test.ts @@ -24,7 +24,7 @@ function options(custom?: Partial>): I newWindow: false, context: OpenContext.CLI, codeSettingsFolder: '_vscode', - 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!; }, + localWorkspaceResolver: 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/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 93f117ad29e..5f803747718 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -109,7 +109,7 @@ export interface IEnvironmentService { backupHome: string; backupWorkspacesPath: string; - workspacesHome: string; + untitledWorkspacesHome: URI; isExtensionDevelopment: boolean; disableExtensions: boolean | string[]; diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index 8c33dbaec1e..33b8eb7af6e 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -135,7 +135,7 @@ export class EnvironmentService implements IEnvironmentService { get backupWorkspacesPath(): string { return path.join(this.backupHome, 'workspaces.json'); } @memoize - get workspacesHome(): string { return path.join(this.userDataPath, 'Workspaces'); } + get untitledWorkspacesHome(): URI { return URI.file(path.join(this.userDataPath, 'Workspaces')); } @memoize get installSourcePath(): string { return path.join(this.userDataPath, 'installSource'); } diff --git a/src/vs/platform/history/electron-main/historyMainService.ts b/src/vs/platform/history/electron-main/historyMainService.ts index 4e854d1a1e5..676f7303b71 100644 --- a/src/vs/platform/history/electron-main/historyMainService.ts +++ b/src/vs/platform/history/electron-main/historyMainService.ts @@ -289,7 +289,7 @@ export class HistoryMainService implements IHistoryMainService { type: 'custom', name: nls.localize('recentFolders', "Recent Workspaces"), items: arrays.coalesce(this.getRecentlyOpened().workspaces.slice(0, 7 /* limit number of entries here */).map(workspace => { - const title = getSimpleWorkspaceLabel(workspace, this.environmentService.workspacesHome); + const title = getSimpleWorkspaceLabel(workspace, this.environmentService.untitledWorkspacesHome); let description; let args; if (isSingleFolderWorkspaceIdentifier(workspace)) { diff --git a/src/vs/platform/label/common/label.ts b/src/vs/platform/label/common/label.ts index 87746ef28af..6322da863b5 100644 --- a/src/vs/platform/label/common/label.ts +++ b/src/vs/platform/label/common/label.ts @@ -43,12 +43,12 @@ export interface ResourceLabelFormatting { const LABEL_SERVICE_ID = 'label'; -export function getSimpleWorkspaceLabel(workspace: IWorkspaceIdentifier | URI, workspaceHome: string): string { +export function getSimpleWorkspaceLabel(workspace: IWorkspaceIdentifier | URI, workspaceHome: URI): string { if (isSingleFolderWorkspaceIdentifier(workspace)) { return basename(workspace); } // Workspace: Untitled - if (isEqualOrParent(workspace.configPath, URI.file(workspaceHome))) { + if (isEqualOrParent(workspace.configPath, workspaceHome)) { return localize('untitledWorkspace', "Untitled (Workspace)"); } diff --git a/src/vs/platform/launch/electron-main/launchService.ts b/src/vs/platform/launch/electron-main/launchService.ts index aa77f122c84..7a3a44f41e7 100644 --- a/src/vs/platform/launch/electron-main/launchService.ts +++ b/src/vs/platform/launch/electron-main/launchService.ts @@ -19,7 +19,6 @@ import { BrowserWindow } from 'electron'; import { Event } from 'vs/base/common/event'; import { hasArgs } from 'vs/platform/environment/node/argv'; import { coalesce } from 'vs/base/common/arrays'; -import { Schemas } from 'vs/base/common/network'; export const ID = 'launchService'; export const ILaunchService = createDecorator(ID); @@ -273,7 +272,7 @@ export class LaunchService implements ILaunchService { } else if (window.openedWorkspace) { // workspace folders can only be shown for local workspaces const workspaceConfigPath = window.openedWorkspace.configPath; - const resolvedWorkspace = workspaceConfigPath.scheme === Schemas.file && this.workspacesMainService.resolveWorkspaceSync(workspaceConfigPath.fsPath); + const resolvedWorkspace = this.workspacesMainService.resolveLocalWorkspaceSync(workspaceConfigPath); if (resolvedWorkspace) { const rootFolders = resolvedWorkspace.folders; rootFolders.forEach(root => { diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index 29aa68c5325..2a6df51c8ff 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -88,7 +88,7 @@ export interface IWorkspacesMainService extends IWorkspacesService { createUntitledWorkspaceSync(folders?: IWorkspaceFolderCreationData[]): IWorkspaceIdentifier; - resolveWorkspaceSync(path: string): IResolvedWorkspace | null; + resolveLocalWorkspaceSync(path: URI): IResolvedWorkspace | null; isUntitledWorkspace(workspace: IWorkspaceIdentifier): boolean; diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index e4d66cbac8e..12ab6cb3163 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { IWorkspacesMainService, IWorkspaceIdentifier, hasWorkspaceFileExtension, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; -import { isParent } from 'vs/platform/files/common/files'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { join, dirname } from 'path'; import { mkdirp, writeFile, readFile } from 'vs/base/node/pfs'; @@ -21,7 +20,7 @@ import { toWorkspaceFolders } from 'vs/platform/workspace/common/workspace'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; import { Disposable } from 'vs/base/common/lifecycle'; -import { fsPath, dirname as resourcesDirname } from 'vs/base/common/resources'; +import { fsPath, dirname as resourcesDirname, isEqualOrParent, joinPath } from 'vs/base/common/resources'; export interface IStoredWorkspace { folders: IStoredWorkspaceFolder[]; @@ -31,7 +30,7 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain _serviceBrand: any; - private workspacesHome: string; + private readonly untitledWorkspacesHome: URI; // local URI that contains all untitled workspaces private readonly _onUntitledWorkspaceDeleted = this._register(new Emitter()); get onUntitledWorkspaceDeleted(): Event { return this._onUntitledWorkspaceDeleted.event; } @@ -42,26 +41,29 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain ) { super(); - this.workspacesHome = environmentService.workspacesHome; + this.untitledWorkspacesHome = environmentService.untitledWorkspacesHome; } - resolveWorkspaceSync(path: string): IResolvedWorkspace | null { - if (!this.isWorkspacePath(path)) { + resolveLocalWorkspaceSync(uri: URI): IResolvedWorkspace | null { + if (!this.isWorkspacePath(uri)) { return null; // does not look like a valid workspace config file } + if (uri.scheme !== Schemas.file) { + return null; + } let contents: string; try { - contents = readFileSync(path, 'utf8'); + contents = readFileSync(uri.fsPath, 'utf8'); } catch (error) { return null; // invalid workspace } - return this.doResolveWorkspace(URI.file(path), contents); + return this.doResolveWorkspace(uri, contents); } - private isWorkspacePath(path: string): boolean { - return this.isInsideWorkspacesHome(path) || hasWorkspaceFileExtension(path); + private isWorkspacePath(uri: URI): boolean { + return this.isInsideWorkspacesHome(uri) || hasWorkspaceFileExtension(uri.path); } private doResolveWorkspace(path: URI, contents: string): IResolvedWorkspace | null { @@ -98,36 +100,34 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain return storedWorkspace; } - private isInsideWorkspacesHome(path: string): boolean { - return isParent(path, this.environmentService.workspacesHome, !isLinux /* ignore case */); + private isInsideWorkspacesHome(path: URI): boolean { + return isEqualOrParent(path, this.environmentService.untitledWorkspacesHome); } createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[]): Promise { - const { workspace, configParent, storedWorkspace } = this.newUntitledWorkspace(folders); + const { workspace, storedWorkspace } = this.newUntitledWorkspace(folders); + const configPath = workspace.configPath.fsPath; - return mkdirp(configParent).then(() => { - return writeFile(workspace.configPath.fsPath, JSON.stringify(storedWorkspace, null, '\t')).then(() => workspace); + return mkdirp(dirname(configPath)).then(() => { + return writeFile(configPath, JSON.stringify(storedWorkspace, null, '\t')).then(() => workspace); }); } createUntitledWorkspaceSync(folders?: IWorkspaceFolderCreationData[]): IWorkspaceIdentifier { - const { workspace, configParent, storedWorkspace } = this.newUntitledWorkspace(folders); + const { workspace, storedWorkspace } = this.newUntitledWorkspace(folders); + const configPath = workspace.configPath.fsPath; - if (!existsSync(this.workspacesHome)) { - mkdirSync(this.workspacesHome); - } + mkdirSync(dirname(configPath), { recursive: true }); - mkdirSync(configParent); - - writeFileAndFlushSync(workspace.configPath.fsPath, JSON.stringify(storedWorkspace, null, '\t')); + writeFileAndFlushSync(configPath, JSON.stringify(storedWorkspace, null, '\t')); return workspace; } - private newUntitledWorkspace(folders: IWorkspaceFolderCreationData[] = []): { workspace: IWorkspaceIdentifier, configParent: string, storedWorkspace: IStoredWorkspace } { + private newUntitledWorkspace(folders: IWorkspaceFolderCreationData[] = []): { workspace: IWorkspaceIdentifier, storedWorkspace: IStoredWorkspace } { const randomId = (Date.now() + Math.round(Math.random() * 1000)).toString(); - const untitledWorkspaceConfigFolder = join(this.workspacesHome, randomId); - const untitledWorkspaceConfigPath = join(untitledWorkspaceConfigFolder, UNTITLED_WORKSPACE_NAME); + const untitledWorkspaceConfigFolder = joinPath(this.untitledWorkspacesHome, randomId); + const untitledWorkspaceConfigPath = joinPath(untitledWorkspaceConfigFolder, UNTITLED_WORKSPACE_NAME); const storedWorkspace: IStoredWorkspace = { folders: folders.map(folder => { @@ -136,7 +136,7 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain // File URI if (folderResource.scheme === Schemas.file) { - storedWorkspace = { path: massageFolderPathForWorkspace(fsPath(folderResource), URI.file(untitledWorkspaceConfigFolder), []) }; + storedWorkspace = { path: massageFolderPathForWorkspace(fsPath(folderResource), untitledWorkspaceConfigFolder, []) }; } // Any URI @@ -153,8 +153,7 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain }; return { - workspace: this.getWorkspaceIdentifier(URI.file(untitledWorkspaceConfigPath)), - configParent: untitledWorkspaceConfigFolder, + workspace: this.getWorkspaceIdentifier(untitledWorkspaceConfigPath), storedWorkspace }; } @@ -176,7 +175,7 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain } isUntitledWorkspace(workspace: IWorkspaceIdentifier): boolean { - return workspace.configPath.scheme === Schemas.file && this.isInsideWorkspacesHome(fsPath(workspace.configPath)); + return this.isInsideWorkspacesHome(workspace.configPath); } saveWorkspaceAs(workspace: IWorkspaceIdentifier, targetConfigPath: string): Promise { @@ -234,10 +233,10 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain getUntitledWorkspacesSync(): IWorkspaceIdentifier[] { let untitledWorkspaces: IWorkspaceIdentifier[] = []; try { - const untitledWorkspacePaths = readdirSync(this.workspacesHome).map(folder => join(this.workspacesHome, folder, UNTITLED_WORKSPACE_NAME)); + const untitledWorkspacePaths = readdirSync(this.untitledWorkspacesHome.fsPath).map(folder => joinPath(this.untitledWorkspacesHome, folder, UNTITLED_WORKSPACE_NAME)); for (const untitledWorkspacePath of untitledWorkspacePaths) { - const workspace = this.getWorkspaceIdentifier(URI.file(untitledWorkspacePath)); - if (!this.resolveWorkspaceSync(untitledWorkspacePath)) { + const workspace = this.getWorkspaceIdentifier(untitledWorkspacePath); + if (!this.resolveLocalWorkspaceSync(untitledWorkspacePath)) { this.doDeleteUntitledWorkspaceSync(workspace); } else { untitledWorkspaces.push(workspace); @@ -245,7 +244,7 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain } } catch (error) { if (error && error.code !== 'ENOENT') { - this.logService.warn(`Unable to read folders in ${this.workspacesHome} (${error}).`); + this.logService.warn(`Unable to read folders in ${this.untitledWorkspacesHome} (${error}).`); } } return untitledWorkspaces; 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 d902534458c..7e22ba3cc66 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts @@ -21,11 +21,11 @@ import { normalizeDriveLetter } from 'vs/base/common/labels'; suite('WorkspacesMainService', () => { const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'workspacesservice'); - const workspacesHome = path.join(parentDir, 'Workspaces'); + const untitledWorkspacesHomePath = path.join(parentDir, 'Workspaces'); class TestEnvironmentService extends EnvironmentService { - get workspacesHome(): string { - return workspacesHome; + get untitledWorkspacesHome(): URI { + return URI.file(untitledWorkspacesHomePath); } } @@ -56,13 +56,13 @@ suite('WorkspacesMainService', () => { service = new TestWorkspacesMainService(environmentService, logService); // Delete any existing backups completely and then re-create it. - return pfs.del(workspacesHome, os.tmpdir()).then(() => { - return pfs.mkdirp(workspacesHome); + return pfs.del(untitledWorkspacesHomePath, os.tmpdir()).then(() => { + return pfs.mkdirp(untitledWorkspacesHomePath); }); }); teardown(() => { - return pfs.del(workspacesHome, os.tmpdir()); + return pfs.del(untitledWorkspacesHomePath, os.tmpdir()); }); function assertPathEquals(p1: string, p2): void { @@ -173,20 +173,20 @@ suite('WorkspacesMainService', () => { test('resolveWorkspaceSync', () => { return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { - assert.ok(service.resolveWorkspaceSync(workspace.configPath.fsPath)); + assert.ok(service.resolveLocalWorkspaceSync(workspace.configPath)); // make it a valid workspace path const newPath = path.join(path.dirname(workspace.configPath.fsPath), `workspace.${WORKSPACE_EXTENSION}`); fs.renameSync(workspace.configPath.fsPath, newPath); workspace.configPath = URI.file(newPath); - const resolved = service.resolveWorkspaceSync(workspace.configPath.fsPath); + const resolved = service.resolveLocalWorkspaceSync(workspace.configPath); assert.equal(2, resolved!.folders.length); assertEqualURI(resolved!.configPath, workspace.configPath); assert.ok(resolved!.id); fs.writeFileSync(workspace.configPath.fsPath, JSON.stringify({ something: 'something' })); // invalid workspace - const resolvedInvalid = service.resolveWorkspaceSync(workspace.configPath.fsPath); + const resolvedInvalid = service.resolveLocalWorkspaceSync(workspace.configPath); assert.ok(!resolvedInvalid); }); }); @@ -195,7 +195,7 @@ suite('WorkspacesMainService', () => { return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { fs.writeFileSync(workspace.configPath.fsPath, JSON.stringify({ folders: [{ path: './ticino-playground/lib' }] })); - const resolved = service.resolveWorkspaceSync(workspace.configPath.fsPath); + const resolved = service.resolveLocalWorkspaceSync(workspace.configPath); assertEqualURI(resolved!.folders[0].uri, URI.file(path.join(path.dirname(workspace.configPath.fsPath), 'ticino-playground', 'lib'))); }); }); @@ -204,7 +204,7 @@ suite('WorkspacesMainService', () => { return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { fs.writeFileSync(workspace.configPath.fsPath, JSON.stringify({ folders: [{ path: './ticino-playground/lib/../other' }] })); - const resolved = service.resolveWorkspaceSync(workspace.configPath.fsPath); + const resolved = service.resolveLocalWorkspaceSync(workspace.configPath); assertEqualURI(resolved!.folders[0].uri, URI.file(path.join(path.dirname(workspace.configPath.fsPath), 'ticino-playground', 'other'))); }); }); @@ -213,7 +213,7 @@ suite('WorkspacesMainService', () => { return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { fs.writeFileSync(workspace.configPath.fsPath, JSON.stringify({ folders: [{ path: 'ticino-playground/lib' }] })); - const resolved = service.resolveWorkspaceSync(workspace.configPath.fsPath); + const resolved = service.resolveLocalWorkspaceSync(workspace.configPath); assertEqualURI(resolved!.folders[0].uri, URI.file(path.join(path.dirname(workspace.configPath.fsPath), 'ticino-playground', 'lib'))); }); }); @@ -222,7 +222,7 @@ suite('WorkspacesMainService', () => { return createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { fs.writeFileSync(workspace.configPath.fsPath, '{ "folders": [ { "path": "./ticino-playground/lib" } , ] }'); // trailing comma - const resolved = service.resolveWorkspaceSync(workspace.configPath.fsPath); + const resolved = service.resolveLocalWorkspaceSync(workspace.configPath); assertEqualURI(resolved!.folders[0].uri, URI.file(path.join(path.dirname(workspace.configPath.fsPath), 'ticino-playground', 'lib'))); }); }); @@ -345,7 +345,7 @@ suite('WorkspacesMainService', () => { test('getUntitledWorkspaceSync', () => { let untitled = service.getUntitledWorkspacesSync(); - assert.equal(0, untitled.length); + assert.equal(untitled.length, 0); return createWorkspace([process.cwd(), os.tmpdir()]).then(untitledOne => { assert.ok(fs.existsSync(untitledOne.configPath.fsPath)); diff --git a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts index 4b80e39c48a..dd4833fdec1 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts @@ -18,7 +18,6 @@ import { URI } from 'vs/base/common/uri'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { Schemas } from 'vs/base/common/network'; import * as resources from 'vs/base/common/resources'; -import { isParent } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { RemoteFileDialog } from 'vs/workbench/services/dialogs/electron-browser/remoteFileDialog'; @@ -196,9 +195,9 @@ export class FileDialogService implements IFileDialogService { defaultWorkspacePath(schemeFilter: string): URI | undefined { // Check for current workspace config file first... - if (schemeFilter === Schemas.file && this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { + if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { const configuration = this.contextService.getWorkspace().configuration; - if (configuration && !isUntitledWorkspace(configuration.fsPath, this.environmentService)) { + if (configuration && !isUntitledWorkspace(configuration, this.environmentService)) { return resources.dirname(configuration) || undefined; } } @@ -340,6 +339,6 @@ export class RemoteFileDialogService extends FileDialogService { } } -function isUntitledWorkspace(path: string, environmentService: IEnvironmentService): boolean { - return isParent(path, environmentService.workspacesHome, !isLinux /* ignore case */); +function isUntitledWorkspace(path: URI, environmentService: IEnvironmentService): boolean { + return resources.isEqualOrParent(path, environmentService.untitledWorkspacesHome); } \ No newline at end of file diff --git a/src/vs/workbench/services/label/common/labelService.ts b/src/vs/workbench/services/label/common/labelService.ts index 51e39703916..fe6aec07335 100644 --- a/src/vs/workbench/services/label/common/labelService.ts +++ b/src/vs/workbench/services/label/common/labelService.ts @@ -186,7 +186,7 @@ export class LabelService implements ILabelService { } // Workspace: Untitled - if (isEqualOrParent(workspace.configPath, URI.file(this.environmentService.workspacesHome))) { + if (isEqualOrParent(workspace.configPath, this.environmentService.untitledWorkspacesHome)) { return localize('untitledWorkspace', "Untitled (Workspace)"); } From d1bd67cbfa1b0cb1330a523c65e3c37f5a40c822 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 11 Feb 2019 15:36:55 +0100 Subject: [PATCH 127/207] debt - silence console.log() --- src/vs/platform/backup/electron-main/backupMainService.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/platform/backup/electron-main/backupMainService.ts b/src/vs/platform/backup/electron-main/backupMainService.ts index 7bf248799b7..267a97e7c07 100644 --- a/src/vs/platform/backup/electron-main/backupMainService.ts +++ b/src/vs/platform/backup/electron-main/backupMainService.ts @@ -270,7 +270,6 @@ export class BackupMainService implements IBackupMainService { await this.convertToEmptyWindowBackup(backupPath); } } else { - console.log('no backups'); await this.deleteStaleBackup(backupPath); } } From 3f2ec216abace5db0d292c92040aa5c42106d25e Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 11 Feb 2019 15:46:56 +0100 Subject: [PATCH 128/207] use default also for remote, add pickFileFolderAndOpen --- .../dialogs/electron-browser/dialogService.ts | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts index 7c69a8008d8..a4d9434ddab 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts @@ -21,6 +21,7 @@ import { isParent, IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { RemoteFileDialog } from 'vs/workbench/services/dialogs/electron-browser/remoteFileDialog'; import { WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces'; +import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; interface IMassagedMessageBoxOptions { @@ -219,51 +220,63 @@ export class FileDialogService implements IFileDialogService { } pickFileFolderAndOpen(options: IPickAndOpenOptions): Promise { - const defaultUri = options.defaultUri; + let defaultUri = options.defaultUri; if (!defaultUri) { - options.defaultUri = this.defaultFilePath(Schemas.file); + defaultUri = options.defaultUri = this.defaultFilePath(this.getSchemeFilterForWindow()); + } + + if (this.useRemoteDialogs(defaultUri)) { + const title = nls.localize('openFileOrFolder.title', 'Open File Or Folder'); + return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: true, canSelectMany: false, defaultUri, title }, options.forceNewWindow, true); } return this.windowService.pickFileFolderAndOpen(this.toNativeOpenDialogOptions(options)); } pickFileAndOpen(options: IPickAndOpenOptions): Promise { - const defaultUri = options.defaultUri; + let defaultUri = options.defaultUri; + if (!defaultUri) { + defaultUri = options.defaultUri = this.defaultFilePath(this.getSchemeFilterForWindow()); + } + if (this.useRemoteDialogs(defaultUri)) { const title = nls.localize('openFile.title', 'Open File'); return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri, title }, options.forceNewWindow, true); } - if (!defaultUri) { - options.defaultUri = this.defaultFilePath(Schemas.file); - } return this.windowService.pickFileAndOpen(this.toNativeOpenDialogOptions(options)); } pickFolderAndOpen(options: IPickAndOpenOptions): Promise { - const defaultUri = options.defaultUri; + let defaultUri = options.defaultUri; + if (!defaultUri) { + defaultUri = options.defaultUri = this.defaultFolderPath(this.getSchemeFilterForWindow()); + } + if (this.useRemoteDialogs(defaultUri)) { const title = nls.localize('openFolder.title', 'Open Folder'); return this.pickRemoteResourceAndOpen({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, defaultUri, title }, options.forceNewWindow, false); } - if (!defaultUri) { - options.defaultUri = this.defaultFolderPath(Schemas.file); - } return this.windowService.pickFolderAndOpen(this.toNativeOpenDialogOptions(options)); } + getSchemeFilterForWindow() { + return !this.windowService.getConfiguration().remoteAuthority ? Schemas.file : REMOTE_HOST_SCHEME; + } + pickWorkspaceAndOpen(options: IPickAndOpenOptions): Promise { - const defaultUri = options.defaultUri; + let defaultUri = options.defaultUri; + if (!defaultUri) { + defaultUri = options.defaultUri = this.defaultWorkspacePath(this.getSchemeFilterForWindow()); + } + if (this.useRemoteDialogs(defaultUri)) { const title = nls.localize('openWorkspace.title', 'Open Workspace'); const filters: FileFilter[] = [{ name: nls.localize('filterName.workspace', 'Workspace'), extensions: [WORKSPACE_EXTENSION] }]; return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri, title, filters }, options.forceNewWindow, false); } - if (!defaultUri) { - options.defaultUri = this.defaultWorkspacePath(Schemas.file); - } return this.windowService.pickWorkspaceAndOpen(this.toNativeOpenDialogOptions(options)); } From 32361179efc02e9923adbed77ae99c250013ede3 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 11 Feb 2019 16:06:30 +0100 Subject: [PATCH 129/207] allowLocalPaths in open options --- src/vs/platform/dialogs/common/dialogs.ts | 6 ++++++ src/vs/workbench/browser/actions/workspaceActions.ts | 8 ++++---- src/vs/workbench/browser/actions/workspaceCommands.ts | 8 ++++---- .../services/dialogs/electron-browser/dialogService.ts | 8 ++++---- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/vs/platform/dialogs/common/dialogs.ts b/src/vs/platform/dialogs/common/dialogs.ts index 9daa60dc2c7..6691a887d51 100644 --- a/src/vs/platform/dialogs/common/dialogs.ts +++ b/src/vs/platform/dialogs/common/dialogs.ts @@ -43,6 +43,7 @@ export interface IPickAndOpenOptions { forceNewWindow?: boolean; defaultUri?: URI; telemetryExtraData?: ITelemetryData; + allowLocalPaths?: boolean; } export interface ISaveDialogOptions { @@ -104,6 +105,11 @@ export interface IOpenDialogOptions { * like "TypeScript", and an array of extensions. */ filters?: FileFilter[]; + + /** + * Wheter the user can pick local files or folders as well (only applies to remote dialogs) + */ + allowLocalPaths?: boolean; } diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index a8847e2cbb7..1f85680d771 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -33,7 +33,7 @@ export class OpenFileAction extends Action { } run(event?: any, data?: ITelemetryData): Promise { - return this.dialogService.pickFileAndOpen({ forceNewWindow: false, telemetryExtraData: data }); + return this.dialogService.pickFileAndOpen({ forceNewWindow: false, telemetryExtraData: data, allowLocalPaths: true }); } } @@ -51,7 +51,7 @@ export class OpenFolderAction extends Action { } run(event?: any, data?: ITelemetryData): Promise { - return this.dialogService.pickFolderAndOpen({ forceNewWindow: false, telemetryExtraData: data }); + return this.dialogService.pickFolderAndOpen({ forceNewWindow: false, telemetryExtraData: data, allowLocalPaths: true }); } } @@ -69,7 +69,7 @@ export class OpenFileFolderAction extends Action { } run(event?: any, data?: ITelemetryData): Promise { - return this.dialogService.pickFileFolderAndOpen({ forceNewWindow: false, telemetryExtraData: data }); + return this.dialogService.pickFileFolderAndOpen({ forceNewWindow: false, telemetryExtraData: data, allowLocalPaths: true }); } } @@ -180,7 +180,7 @@ export class OpenWorkspaceAction extends Action { } run(event?: any, data?: ITelemetryData): Promise { - return this.dialogService.pickWorkspaceAndOpen({ telemetryExtraData: data }); + return this.dialogService.pickWorkspaceAndOpen({ telemetryExtraData: data, allowLocalPaths: true }); } } diff --git a/src/vs/workbench/browser/actions/workspaceCommands.ts b/src/vs/workbench/browser/actions/workspaceCommands.ts index 95c6eba1bcb..8b5663d25b6 100644 --- a/src/vs/workbench/browser/actions/workspaceCommands.ts +++ b/src/vs/workbench/browser/actions/workspaceCommands.ts @@ -30,7 +30,7 @@ export const PICK_WORKSPACE_FOLDER_COMMAND_ID = '_workbench.pickWorkspaceFolder' CommandsRegistry.registerCommand({ id: 'workbench.action.files.openFileFolderInNewWindow', - handler: (accessor: ServicesAccessor) => accessor.get(IFileDialogService).pickFileFolderAndOpen({ forceNewWindow: true }) + handler: (accessor: ServicesAccessor) => accessor.get(IFileDialogService).pickFileFolderAndOpen({ forceNewWindow: true, allowLocalPaths: true }) }); CommandsRegistry.registerCommand({ @@ -40,17 +40,17 @@ CommandsRegistry.registerCommand({ CommandsRegistry.registerCommand({ id: 'workbench.action.files.openFolderInNewWindow', - handler: (accessor: ServicesAccessor) => accessor.get(IFileDialogService).pickFolderAndOpen({ forceNewWindow: true }) + handler: (accessor: ServicesAccessor) => accessor.get(IFileDialogService).pickFolderAndOpen({ forceNewWindow: true, allowLocalPaths: true }) }); CommandsRegistry.registerCommand({ id: 'workbench.action.files.openFileInNewWindow', - handler: (accessor: ServicesAccessor) => accessor.get(IFileDialogService).pickFileAndOpen({ forceNewWindow: true }) + handler: (accessor: ServicesAccessor) => accessor.get(IFileDialogService).pickFileAndOpen({ forceNewWindow: true, allowLocalPaths: true }) }); CommandsRegistry.registerCommand({ id: 'workbench.action.openWorkspaceInNewWindow', - handler: (accessor: ServicesAccessor) => accessor.get(IFileDialogService).pickWorkspaceAndOpen({ forceNewWindow: true }) + handler: (accessor: ServicesAccessor) => accessor.get(IFileDialogService).pickWorkspaceAndOpen({ forceNewWindow: true, allowLocalPaths: true }) }); CommandsRegistry.registerCommand({ diff --git a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts index a4d9434ddab..6e2e7f300c9 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts @@ -227,7 +227,7 @@ export class FileDialogService implements IFileDialogService { if (this.useRemoteDialogs(defaultUri)) { const title = nls.localize('openFileOrFolder.title', 'Open File Or Folder'); - return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: true, canSelectMany: false, defaultUri, title }, options.forceNewWindow, true); + return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: true, canSelectMany: false, defaultUri, title, allowLocalPaths: options.allowLocalPaths }, options.forceNewWindow, true); } return this.windowService.pickFileFolderAndOpen(this.toNativeOpenDialogOptions(options)); @@ -241,7 +241,7 @@ export class FileDialogService implements IFileDialogService { if (this.useRemoteDialogs(defaultUri)) { const title = nls.localize('openFile.title', 'Open File'); - return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri, title }, options.forceNewWindow, true); + return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri, title, allowLocalPaths: options.allowLocalPaths }, options.forceNewWindow, true); } return this.windowService.pickFileAndOpen(this.toNativeOpenDialogOptions(options)); @@ -255,7 +255,7 @@ export class FileDialogService implements IFileDialogService { if (this.useRemoteDialogs(defaultUri)) { const title = nls.localize('openFolder.title', 'Open Folder'); - return this.pickRemoteResourceAndOpen({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, defaultUri, title }, options.forceNewWindow, false); + return this.pickRemoteResourceAndOpen({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, defaultUri, title, allowLocalPaths: options.allowLocalPaths }, options.forceNewWindow, false); } return this.windowService.pickFolderAndOpen(this.toNativeOpenDialogOptions(options)); @@ -274,7 +274,7 @@ export class FileDialogService implements IFileDialogService { if (this.useRemoteDialogs(defaultUri)) { const title = nls.localize('openWorkspace.title', 'Open Workspace'); const filters: FileFilter[] = [{ name: nls.localize('filterName.workspace', 'Workspace'), extensions: [WORKSPACE_EXTENSION] }]; - return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri, title, filters }, options.forceNewWindow, false); + return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri, title, filters, allowLocalPaths: options.allowLocalPaths }, options.forceNewWindow, false); } return this.windowService.pickWorkspaceAndOpen(this.toNativeOpenDialogOptions(options)); From 520884580548c801dfa3fd3bb288fbe8483393f9 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 11 Feb 2019 16:11:22 +0100 Subject: [PATCH 130/207] mkdirSync recursive problem on macos --- .../workspaces/electron-main/workspacesMainService.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index 12ab6cb3163..9d53a05a37b 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -117,7 +117,14 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain const { workspace, storedWorkspace } = this.newUntitledWorkspace(folders); const configPath = workspace.configPath.fsPath; - mkdirSync(dirname(configPath), { recursive: true }); + const configPathDir = dirname(configPath); + if (!existsSync(configPathDir)) { + const configPathDirDir = dirname(configPath); + if (!existsSync(configPathDirDir)) { + mkdirSync(configPathDirDir); + } + mkdirSync(configPathDir); + } writeFileAndFlushSync(configPath, JSON.stringify(storedWorkspace, null, '\t')); From 8a1dc6e19ea01d06c3e5bf8735ce8939efbfb2ab Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 11 Feb 2019 16:21:32 +0100 Subject: [PATCH 131/207] tasks.json validation issue Fixes #68006 --- .../contrib/tasks/electron-browser/jsonSchema_v2.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/vs/workbench/contrib/tasks/electron-browser/jsonSchema_v2.ts b/src/vs/workbench/contrib/tasks/electron-browser/jsonSchema_v2.ts index 1543a793850..ef6e4f9eedb 100644 --- a/src/vs/workbench/contrib/tasks/electron-browser/jsonSchema_v2.ts +++ b/src/vs/workbench/contrib/tasks/electron-browser/jsonSchema_v2.ts @@ -358,7 +358,11 @@ TaskDefinitionRegistry.onReady().then(() => { }; if (taskType.required) { schema.required = taskType.required.slice(); + } else { + schema.required = []; } + // Customized tasks require that the task type be set. + schema.required.push('type'); if (taskType.properties) { for (let key of Object.keys(taskType.properties)) { let property = taskType.properties[key]; @@ -375,6 +379,10 @@ customize.properties!.customize = { type: 'string', deprecationMessage: nls.localize('JsonSchema.tasks.customize.deprecated', 'The customize property is deprecated. See the 1.14 release notes on how to migrate to the new task customization approach') }; +if (!customize.required) { + customize.required = []; +} +customize.required.push('customize'); taskDefinitions.push(customize); let definitions = Objects.deepClone(commonSchemaDefinitions); From f7e113ce1a86f7755db1cddda4a0ce1aa494e0d3 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 11 Feb 2019 16:24:59 +0100 Subject: [PATCH 132/207] IFileDialogService.default..Path: schemeFilter is optional --- src/vs/platform/dialogs/common/dialogs.ts | 12 +++++----- .../browser/actions/workspaceActions.ts | 3 +-- .../browser/actions/workspaceCommands.ts | 3 +-- .../dialogs/electron-browser/dialogService.ts | 22 +++++++++---------- .../workbench/test/workbenchTestServices.ts | 6 ++--- 5 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/vs/platform/dialogs/common/dialogs.ts b/src/vs/platform/dialogs/common/dialogs.ts index 6691a887d51..4c9156aa99a 100644 --- a/src/vs/platform/dialogs/common/dialogs.ts +++ b/src/vs/platform/dialogs/common/dialogs.ts @@ -156,21 +156,21 @@ export interface IFileDialogService { /** * The default path for a new file based on previously used files. - * @param schemeFilter The scheme of the file path. + * @param schemeFilter The scheme of the file path. If no filter given, the scheme of the current window is used. */ - defaultFilePath(schemeFilter: string): URI | undefined; + defaultFilePath(schemeFilter?: string): URI | undefined; /** * The default path for a new folder based on previously used folders. - * @param schemeFilter The scheme of the folder path. + * @param schemeFilter The scheme of the folder path. If no filter given, the scheme of the current window is used. */ - defaultFolderPath(schemeFilter: string): URI | undefined; + defaultFolderPath(schemeFilter?: string): URI | undefined; /** * The default path for a new workspace based on previously used workspaces. - * @param schemeFilter The scheme of the workspace path. + * @param schemeFilter The scheme of the workspace path. If no filter given, the scheme of the current window is used. */ - defaultWorkspacePath(schemeFilter: string): URI | undefined; + defaultWorkspacePath(schemeFilter?: string): URI | undefined; /** * Shows a file-folder selection dialog and opens the selected entry. diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index 1f85680d771..5464ca6a1ec 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -15,7 +15,6 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { ICommandService } from 'vs/platform/commands/common/commands'; import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL, PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; import { URI } from 'vs/base/common/uri'; -import { Schemas } from 'vs/base/common/network'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -161,7 +160,7 @@ export class SaveWorkspaceAsAction extends Action { saveLabel: mnemonicButtonLabel(nls.localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save")), title: nls.localize('saveWorkspace', "Save Workspace"), filters: WORKSPACE_FILTER, - defaultUri: this.dialogService.defaultWorkspacePath(Schemas.file) + defaultUri: this.dialogService.defaultWorkspacePath() }); } } diff --git a/src/vs/workbench/browser/actions/workspaceCommands.ts b/src/vs/workbench/browser/actions/workspaceCommands.ts index 8b5663d25b6..e87473ea7ba 100644 --- a/src/vs/workbench/browser/actions/workspaceCommands.ts +++ b/src/vs/workbench/browser/actions/workspaceCommands.ts @@ -18,7 +18,6 @@ import { IQuickInputService, IPickOptions, IQuickPickItem } from 'vs/platform/qu import { getIconClasses } from 'vs/editor/common/services/getIconClasses'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IModeService } from 'vs/editor/common/services/modeService'; -import { Schemas } from 'vs/base/common/network'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; export const ADD_ROOT_FOLDER_COMMAND_ID = 'addRootFolder'; @@ -64,7 +63,7 @@ CommandsRegistry.registerCommand({ title: nls.localize('addFolderToWorkspaceTitle', "Add Folder to Workspace"), canSelectFolders: true, canSelectMany: true, - defaultUri: dialogsService.defaultFolderPath(Schemas.file) + defaultUri: dialogsService.defaultFolderPath() }).then((folders): Promise | null => { if (!folders || !folders.length) { return null; diff --git a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts index 6e2e7f300c9..9ef75a7ca59 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts @@ -169,7 +169,7 @@ export class FileDialogService implements IFileDialogService { @IFileService private readonly fileService: IFileService ) { } - defaultFilePath(schemeFilter: string): URI | undefined { + defaultFilePath(schemeFilter = this.getSchemeFilterForWindow()): URI | undefined { // Check for last active file first... let candidate = this.historyService.getLastActiveFile(schemeFilter); @@ -182,7 +182,7 @@ export class FileDialogService implements IFileDialogService { return candidate && resources.dirname(candidate) || undefined; } - defaultFolderPath(schemeFilter: string): URI | undefined { + defaultFolderPath(schemeFilter = this.getSchemeFilterForWindow()): URI | undefined { // Check for last active file root first... let candidate = this.historyService.getLastActiveWorkspaceRoot(schemeFilter); @@ -195,7 +195,7 @@ export class FileDialogService implements IFileDialogService { return candidate && resources.dirname(candidate) || undefined; } - defaultWorkspacePath(schemeFilter: string): URI | undefined { + defaultWorkspacePath(schemeFilter = this.getSchemeFilterForWindow()): URI | undefined { // Check for current workspace config file first... if (schemeFilter === Schemas.file && this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { @@ -209,6 +209,10 @@ export class FileDialogService implements IFileDialogService { return this.defaultFolderPath(schemeFilter); } + private getSchemeFilterForWindow() { + return !this.windowService.getConfiguration().remoteAuthority ? Schemas.file : REMOTE_HOST_SCHEME; + } + private toNativeOpenDialogOptions(options: IPickAndOpenOptions): INativeOpenDialogOptions { return { forceNewWindow: options.forceNewWindow, @@ -222,7 +226,7 @@ export class FileDialogService implements IFileDialogService { pickFileFolderAndOpen(options: IPickAndOpenOptions): Promise { let defaultUri = options.defaultUri; if (!defaultUri) { - defaultUri = options.defaultUri = this.defaultFilePath(this.getSchemeFilterForWindow()); + defaultUri = options.defaultUri = this.defaultFilePath(); } if (this.useRemoteDialogs(defaultUri)) { @@ -236,7 +240,7 @@ export class FileDialogService implements IFileDialogService { pickFileAndOpen(options: IPickAndOpenOptions): Promise { let defaultUri = options.defaultUri; if (!defaultUri) { - defaultUri = options.defaultUri = this.defaultFilePath(this.getSchemeFilterForWindow()); + defaultUri = options.defaultUri = this.defaultFilePath(); } if (this.useRemoteDialogs(defaultUri)) { @@ -250,7 +254,7 @@ export class FileDialogService implements IFileDialogService { pickFolderAndOpen(options: IPickAndOpenOptions): Promise { let defaultUri = options.defaultUri; if (!defaultUri) { - defaultUri = options.defaultUri = this.defaultFolderPath(this.getSchemeFilterForWindow()); + defaultUri = options.defaultUri = this.defaultFolderPath(); } if (this.useRemoteDialogs(defaultUri)) { @@ -261,14 +265,10 @@ export class FileDialogService implements IFileDialogService { return this.windowService.pickFolderAndOpen(this.toNativeOpenDialogOptions(options)); } - getSchemeFilterForWindow() { - return !this.windowService.getConfiguration().remoteAuthority ? Schemas.file : REMOTE_HOST_SCHEME; - } - pickWorkspaceAndOpen(options: IPickAndOpenOptions): Promise { let defaultUri = options.defaultUri; if (!defaultUri) { - defaultUri = options.defaultUri = this.defaultWorkspacePath(this.getSchemeFilterForWindow()); + defaultUri = options.defaultUri = this.defaultWorkspacePath(); } if (this.useRemoteDialogs(defaultUri)) { diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 0e13742ee46..45ab0ebe98a 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -388,13 +388,13 @@ export class TestFileDialogService implements IFileDialogService { public _serviceBrand: any; - public defaultFilePath(_schemeFilter: string): URI | undefined { + public defaultFilePath(_schemeFilter?: string): URI | undefined { return undefined; } - public defaultFolderPath(_schemeFilter: string): URI | undefined { + public defaultFolderPath(_schemeFilter?: string): URI | undefined { return undefined; } - public defaultWorkspacePath(_schemeFilter: string): URI | undefined { + public defaultWorkspacePath(_schemeFilter?: string): URI | undefined { return undefined; } public pickFileFolderAndOpen(_options: IPickAndOpenOptions): Promise { From 75a2197095bf68c26110566def7a04b342f1b3a4 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 11 Feb 2019 16:26:14 +0100 Subject: [PATCH 133/207] fix strict null check errors --- .../contrib/extensions/electron-browser/extensionsActions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts index 16314fb5df6..d5415c06432 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts @@ -183,7 +183,7 @@ export class InstallAction extends ExtensionAction { const extension = await this.install(this.extension); - if (extension.local && extension.local.manifest.contributes.themes && extension.local.manifest.contributes.themes.length) { + if (extension.local && extension.local.manifest.contributes && extension.local.manifest.contributes.themes && extension.local.manifest.contributes.themes.length) { return this.applyInstalledTheme(extension.local); } @@ -212,7 +212,7 @@ export class InstallAction extends ExtensionAction { themes.map(theme => ({ label: theme.label, id: theme.id })), { placeHolder: localize('apply installed theme', "Apply installed theme"), - onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setColorTheme(item.id, ConfigurationTarget.MEMORY).then(() => null)) + onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setColorTheme(item.id, ConfigurationTarget.MEMORY).then(() => undefined)) }); this.workbenchThemeService.setColorTheme(pickedTheme ? pickedTheme.id : currentTheme.id, undefined); } From 5dfc3bd95804e4f4962e03d2a4602c1e892ead01 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 11 Feb 2019 16:46:36 +0100 Subject: [PATCH 134/207] #68408 Add current theme to the list. --- .../extensions/electron-browser/extensionsActions.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts index d5415c06432..e5fc6a2016c 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts @@ -49,7 +49,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; import product from 'vs/platform/node/product'; -import { IQuickPickItem, IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; +import { IQuickPickItem, IQuickInputService, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { CancellationToken } from 'vs/base/common/cancellation'; import { clipboard } from 'electron'; import { IPartService } from 'vs/workbench/services/part/common/partService'; @@ -208,10 +208,13 @@ export class InstallAction extends ExtensionAction { const currentTheme = this.workbenchThemeService.getColorTheme(); const themes = await this.workbenchThemeService.getColorThemes(runningExtension.identifier); const delayer = new Delayer(100); + const picks: (IQuickPickItem | IQuickPickSeparator)[] = themes.map(theme => ({ label: theme.label, id: theme.id })); + picks.push({ type: 'separator' }); + picks.push({ label: localize('stay with current theme', "Stay with current theme ({0})", currentTheme.label), id: currentTheme.id }); const pickedTheme = await this.quickInputService.pick( - themes.map(theme => ({ label: theme.label, id: theme.id })), + picks, { - placeHolder: localize('apply installed theme', "Apply installed theme"), + placeHolder: localize('apply installed theme', "Apply installed theme or press Escape to cancel."), onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setColorTheme(item.id, ConfigurationTarget.MEMORY).then(() => undefined)) }); this.workbenchThemeService.setColorTheme(pickedTheme ? pickedTheme.id : currentTheme.id, undefined); From 274a2379b57f12d9daa1172d0b1bca5f34e66e45 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 11 Feb 2019 17:24:07 +0100 Subject: [PATCH 135/207] fix #68436 --- src/vs/workbench/api/node/extHostTypes.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index 4ea1942b4c1..f9d1658215e 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -1930,7 +1930,6 @@ export enum TreeItemCollapsibleState { Expanded = 2 } -@es5ClassCompat export class ThemeIcon { static readonly File = new ThemeIcon('file'); From a3e9a987f41452f8f0553e32f2cb52ffb3d92ea7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 11 Feb 2019 17:45:10 +0100 Subject: [PATCH 136/207] debt - move CSS --- .../{electron-browser/media/shell.css => browser/media/style.css} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/vs/workbench/{electron-browser/media/shell.css => browser/media/style.css} (100%) diff --git a/src/vs/workbench/electron-browser/media/shell.css b/src/vs/workbench/browser/media/style.css similarity index 100% rename from src/vs/workbench/electron-browser/media/shell.css rename to src/vs/workbench/browser/media/style.css From 41c7d3788f254be5fa75c4738086cf037f9ff7ab Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 11 Feb 2019 17:47:24 +0100 Subject: [PATCH 137/207] debt - get rid of monaco-shell CSS indirection (#68302) --- .../electron-browser/workbench/workbench.html | 2 +- .../electron-browser/workbench/workbench.js | 1 - src/vs/workbench/browser/media/part.css | 5 + src/vs/workbench/browser/media/style.css | 161 ++++++++++-------- src/vs/workbench/browser/style.ts | 137 +++++++++++++++ .../electron-browser/media/workbench.css | 31 ---- src/vs/workbench/electron-browser/shell.ts | 134 +-------------- .../workbench/electron-browser/workbench.ts | 2 +- 8 files changed, 237 insertions(+), 236 deletions(-) create mode 100644 src/vs/workbench/browser/style.ts delete mode 100644 src/vs/workbench/electron-browser/media/workbench.css diff --git a/src/vs/code/electron-browser/workbench/workbench.html b/src/vs/code/electron-browser/workbench/workbench.html index ab864aa3432..13232577758 100644 --- a/src/vs/code/electron-browser/workbench/workbench.html +++ b/src/vs/code/electron-browser/workbench/workbench.html @@ -5,7 +5,7 @@ - + diff --git a/src/vs/code/electron-browser/workbench/workbench.js b/src/vs/code/electron-browser/workbench/workbench.js index 0f12a5a6f97..b67a5167da6 100644 --- a/src/vs/code/electron-browser/workbench/workbench.js +++ b/src/vs/code/electron-browser/workbench/workbench.js @@ -42,7 +42,6 @@ bootstrapWindow.load([ onNodeCachedData.push(arguments); }; } - }, beforeRequire: function () { perf.mark('willLoadWorkbenchMain'); diff --git a/src/vs/workbench/browser/media/part.css b/src/vs/workbench/browser/media/part.css index 32c3fe76eae..e01628bccc6 100644 --- a/src/vs/workbench/browser/media/part.css +++ b/src/vs/workbench/browser/media/part.css @@ -3,6 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +.monaco-workbench .part { + position: absolute; + box-sizing: border-box; +} + .monaco-workbench .part > .title { display: none; /* Parts have to opt in to show title area */ } diff --git a/src/vs/workbench/browser/media/style.css b/src/vs/workbench/browser/media/style.css index 1162363e9f8..6a7b6261f3e 100644 --- a/src/vs/workbench/browser/media/style.css +++ b/src/vs/workbench/browser/media/style.css @@ -3,7 +3,29 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-shell { +/* Font Families (with CJK support) */ + +.mac { font-family: -apple-system, BlinkMacSystemFont, sans-serif; } +.mac:lang(zh-Hans) { font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", sans-serif; } +.mac:lang(zh-Hant) { font-family: -apple-system, BlinkMacSystemFont, "PingFang TC", sans-serif; } +.mac:lang(ja) { font-family: -apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic Pro", sans-serif; } +.mac:lang(ko) { font-family: -apple-system, BlinkMacSystemFont, "Nanum Gothic", "Apple SD Gothic Neo", "AppleGothic", sans-serif; } + +.windows { font-family: "Segoe WPC", "Segoe UI", sans-serif; } +.windows:lang(zh-Hans) { font-family: "Segoe WPC", "Segoe UI", "Microsoft YaHei", sans-serif; } +.windows:lang(zh-Hant) { font-family: "Segoe WPC", "Segoe UI", "Microsoft Jhenghei", sans-serif; } +.windows:lang(ja) { font-family: "Segoe WPC", "Segoe UI", "Meiryo", sans-serif; } +.windows:lang(ko) { font-family: "Segoe WPC", "Segoe UI", "Malgun Gothic", "Dotom", sans-serif; } + +.linux { font-family: "Ubuntu", "Droid Sans", sans-serif; } +.linux:lang(zh-Hans) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif; } +.linux:lang(zh-Hant) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans TC", "Source Han Sans TW", "Source Han Sans", sans-serif; } +.linux:lang(ja) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", sans-serif; } +.linux:lang(ko) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif; } + +/* Global Styles */ + +body { height: 100%; width: 100%; margin: 0; @@ -13,155 +35,156 @@ user-select: none; } -/* Font Families (with CJK support) */ - -/* mac */ -.monaco-shell.mac { font-family: -apple-system, BlinkMacSystemFont, sans-serif; } -.monaco-shell.mac:lang(zh-Hans) { font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", sans-serif; } -.monaco-shell.mac:lang(zh-Hant) { font-family: -apple-system, BlinkMacSystemFont, "PingFang TC", sans-serif; } -.monaco-shell.mac:lang(ja) { font-family: -apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic Pro", sans-serif; } -.monaco-shell.mac:lang(ko) { font-family: -apple-system, BlinkMacSystemFont, "Nanum Gothic", "Apple SD Gothic Neo", "AppleGothic", sans-serif; } -/* windows */ -.monaco-shell.windows { font-family: "Segoe WPC", "Segoe UI", sans-serif; } -.monaco-shell.windows:lang(zh-Hans) { font-family: "Segoe WPC", "Segoe UI", "Microsoft YaHei", sans-serif; } -.monaco-shell.windows:lang(zh-Hant) { font-family: "Segoe WPC", "Segoe UI", "Microsoft Jhenghei", sans-serif; } -.monaco-shell.windows:lang(ja) { font-family: "Segoe WPC", "Segoe UI", "Meiryo", sans-serif; } -.monaco-shell.windows:lang(ko) { font-family: "Segoe WPC", "Segoe UI", "Malgun Gothic", "Dotom", sans-serif; } -/* linux */ -.monaco-shell.linux { font-family: "Ubuntu", "Droid Sans", sans-serif; } -.monaco-shell.linux:lang(zh-Hans) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif; } -.monaco-shell.linux:lang(zh-Hant) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans TC", "Source Han Sans TW", "Source Han Sans", sans-serif; } -.monaco-shell.linux:lang(ja) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", sans-serif; } -.monaco-shell.linux:lang(ko) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif; } - @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } -.monaco-shell img { +.monaco-font-aliasing-antialiased { + -webkit-font-smoothing: antialiased; +} + +.monaco-font-aliasing-none { + -webkit-font-smoothing: none; +} + +@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { + .monaco-font-aliasing-auto { + -webkit-font-smoothing: antialiased; + } +} + +.monaco-workbench { + font-size: 13px; + line-height: 1.4em; + position: relative; + z-index: 1; + overflow: hidden; +} + +.monaco-workbench img { border: 0; } -.monaco-shell label { +.monaco-workbench label { cursor: pointer; } -.monaco-shell a { +.monaco-workbench a { text-decoration: none; } -.monaco-shell a:active { +.monaco-workbench a:active { color: inherit; background-color: inherit; } -.monaco-shell a.plain { +.monaco-workbench a.plain { color: inherit; text-decoration: none; } -.monaco-shell a.plain:hover, -.monaco-shell a.plain.hover { +.monaco-workbench a.plain:hover, +.monaco-workbench a.plain.hover { color: inherit; text-decoration: none; } -.monaco-shell input { +.monaco-workbench input { color: inherit; font-family: inherit; font-size: 100%; } -.monaco-shell select { +.monaco-workbench select { font-family: inherit; } -.monaco-shell .pointer { +.monaco-workbench .pointer { cursor: pointer; } -.monaco-shell .context-view { +.monaco-workbench .context-view { -webkit-app-region: no-drag; } -.monaco-shell .monaco-menu .monaco-action-bar.vertical { +.monaco-workbench .monaco-menu .monaco-action-bar.vertical { padding: .5em 0; } -.monaco-shell .monaco-menu .monaco-action-bar.vertical .action-menu-item { +.monaco-workbench .monaco-menu .monaco-action-bar.vertical .action-menu-item { height: 1.8em; } -.monaco-shell .monaco-menu .monaco-action-bar.vertical .action-label:not(.separator), -.monaco-shell .monaco-menu .monaco-action-bar.vertical .keybinding { +.monaco-workbench .monaco-menu .monaco-action-bar.vertical .action-label:not(.separator), +.monaco-workbench .monaco-menu .monaco-action-bar.vertical .keybinding { font-size: inherit; padding: 0 2em; } -.monaco-shell .monaco-menu .monaco-action-bar.vertical .menu-item-check { +.monaco-workbench .monaco-menu .monaco-action-bar.vertical .menu-item-check { font-size: inherit; width: 2em; } -.monaco-shell .monaco-menu .monaco-action-bar.vertical .action-label.separator { +.monaco-workbench .monaco-menu .monaco-action-bar.vertical .action-label.separator { font-size: inherit; padding: 0.2em 0 0 0; margin-bottom: 0.2em; } -.monaco-shell.linux .monaco-menu .monaco-action-bar.vertical .action-label.separator { +.linux .monaco-workbench .monaco-menu .monaco-action-bar.vertical .action-label.separator { margin-left: 0; margin-right: 0; } -.monaco-shell .monaco-menu .monaco-action-bar.vertical .submenu-indicator { +.monaco-workbench .monaco-menu .monaco-action-bar.vertical .submenu-indicator { font-size: 60%; padding: 0 1.8em; } -.monaco-shell.linux .monaco-menu .monaco-action-bar.vertical .submenu-indicator { +.linux .monaco-workbench .monaco-menu .monaco-action-bar.vertical .submenu-indicator { height: 100%; -webkit-mask-size: 10px 10px; mask-size: 10px 10px; } -.monaco-shell .monaco-menu .action-item { +.monaco-workbench .monaco-menu .action-item { cursor: default; } /* START Keyboard Focus Indication Styles */ -.monaco-shell [tabindex="0"]:focus, -.monaco-shell .synthetic-focus, -.monaco-shell select:focus, -.monaco-shell input[type="button"]:focus, -.monaco-shell input[type="text"]:focus, -.monaco-shell textarea:focus, -.monaco-shell input[type="checkbox"]:focus { +.monaco-workbench [tabindex="0"]:focus, +.monaco-workbench .synthetic-focus, +.monaco-workbench select:focus, +.monaco-workbench input[type="button"]:focus, +.monaco-workbench input[type="text"]:focus, +.monaco-workbench textarea:focus, +.monaco-workbench input[type="checkbox"]:focus { outline-width: 1px; outline-style: solid; outline-offset: -1px; opacity: 1 !important; } -.monaco-shell [tabindex="0"]:active, -.monaco-shell select:active, -.monaco-shell input[type="button"]:active, -.monaco-shell input[type="checkbox"]:active, -.monaco-shell .monaco-tree .monaco-tree-row -.monaco-shell .monaco-tree.focused.no-focused-item:active:before { +.monaco-workbench [tabindex="0"]:active, +.monaco-workbench select:active, +.monaco-workbench input[type="button"]:active, +.monaco-workbench input[type="checkbox"]:active, +.monaco-workbench .monaco-tree .monaco-tree-row +.monaco-workbench .monaco-tree.focused.no-focused-item:active:before { outline: 0 !important; /* fixes some flashing outlines from showing up when clicking */ } -.monaco-shell .mac select:focus { +.mac select:focus { border-color: transparent; /* outline is a square, but border has a radius, so we avoid this glitch when focused (https://github.com/Microsoft/vscode/issues/26045) */ } -.monaco-shell .monaco-tree.focused .monaco-tree-row.focused [tabindex="0"]:focus { +.monaco-workbench .monaco-tree.focused .monaco-tree-row.focused [tabindex="0"]:focus { outline-width: 1px; /* higher contrast color for focusable elements in a row that shows focus feedback */ outline-style: solid; } -.monaco-shell .monaco-tree.focused.no-focused-item:focus:before, -.monaco-shell .monaco-list:not(.element-focused):focus:before { +.monaco-workbench .monaco-tree.focused.no-focused-item:focus:before, +.monaco-workbench .monaco-list:not(.element-focused):focus:before { position: absolute; top: 0; left: 0; @@ -176,20 +199,20 @@ outline-offset: -1px; } -.monaco-shell .synthetic-focus :focus { +.monaco-workbench .synthetic-focus :focus { outline: 0 !important; /* elements within widgets that draw synthetic-focus should never show focus */ } -.monaco-shell .monaco-inputbox.info.synthetic-focus, -.monaco-shell .monaco-inputbox.warning.synthetic-focus, -.monaco-shell .monaco-inputbox.error.synthetic-focus, -.monaco-shell .monaco-inputbox.info input[type="text"]:focus, -.monaco-shell .monaco-inputbox.warning input[type="text"]:focus, -.monaco-shell .monaco-inputbox.error input[type="text"]:focus { +.monaco-workbench .monaco-inputbox.info.synthetic-focus, +.monaco-workbench .monaco-inputbox.warning.synthetic-focus, +.monaco-workbench .monaco-inputbox.error.synthetic-focus, +.monaco-workbench .monaco-inputbox.info input[type="text"]:focus, +.monaco-workbench .monaco-inputbox.warning input[type="text"]:focus, +.monaco-workbench .monaco-inputbox.error input[type="text"]:focus { outline: 0 !important; /* outline is not going well with decoration */ } -.monaco-shell .monaco-tree.focused:focus, -.monaco-shell .monaco-list:focus { +.monaco-workbench .monaco-tree.focused:focus, +.monaco-workbench .monaco-list:focus { outline: 0 !important; /* tree indicates focus not via outline but through the focused item */ } diff --git a/src/vs/workbench/browser/style.ts b/src/vs/workbench/browser/style.ts new file mode 100644 index 00000000000..8db78ac9953 --- /dev/null +++ b/src/vs/workbench/browser/style.ts @@ -0,0 +1,137 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/css!./media/style'; + +import { registerThemingParticipant, ITheme, ICssStyleCollector, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService'; +import { foreground, selectionBackground, focusBorder, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listHighlightForeground, inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry'; +import { WORKBENCH_BACKGROUND } from 'vs/workbench/common/theme'; + +registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { + + // Foreground + const windowForeground = theme.getColor(foreground); + if (windowForeground) { + collector.addRule(`.monaco-workbench { color: ${windowForeground}; }`); + } + + // Selection + const windowSelectionBackground = theme.getColor(selectionBackground); + if (windowSelectionBackground) { + collector.addRule(`.monaco-workbench ::selection { background-color: ${windowSelectionBackground}; }`); + } + + // Input placeholder + const placeholderForeground = theme.getColor(inputPlaceholderForeground); + if (placeholderForeground) { + collector.addRule(`.monaco-workbench input::-webkit-input-placeholder { color: ${placeholderForeground}; }`); + collector.addRule(`.monaco-workbench textarea::-webkit-input-placeholder { color: ${placeholderForeground}; }`); + } + + // List highlight + const listHighlightForegroundColor = theme.getColor(listHighlightForeground); + if (listHighlightForegroundColor) { + collector.addRule(` + .monaco-workbench .monaco-tree .monaco-tree-row .monaco-highlighted-label .highlight, + .monaco-workbench .monaco-list .monaco-list-row .monaco-highlighted-label .highlight { + color: ${listHighlightForegroundColor}; + } + `); + } + + // We need to set the workbench background color so that on Windows we get subpixel-antialiasing. + const workbenchBackground = WORKBENCH_BACKGROUND(theme); + collector.addRule(`.monaco-workbench { background-color: ${workbenchBackground}; }`); + + // Scrollbars + const scrollbarShadowColor = theme.getColor(scrollbarShadow); + if (scrollbarShadowColor) { + collector.addRule(` + .monaco-workbench .monaco-scrollable-element > .shadow.top { + box-shadow: ${scrollbarShadowColor} 0 6px 6px -6px inset; + } + + .monaco-workbench .monaco-scrollable-element > .shadow.left { + box-shadow: ${scrollbarShadowColor} 6px 0 6px -6px inset; + } + + .monaco-workbench .monaco-scrollable-element > .shadow.top.left { + box-shadow: ${scrollbarShadowColor} 6px 6px 6px -6px inset; + } + `); + } + + const scrollbarSliderBackgroundColor = theme.getColor(scrollbarSliderBackground); + if (scrollbarSliderBackgroundColor) { + collector.addRule(` + .monaco-workbench .monaco-scrollable-element > .scrollbar > .slider { + background: ${scrollbarSliderBackgroundColor}; + } + `); + } + + const scrollbarSliderHoverBackgroundColor = theme.getColor(scrollbarSliderHoverBackground); + if (scrollbarSliderHoverBackgroundColor) { + collector.addRule(` + .monaco-workbench .monaco-scrollable-element > .scrollbar > .slider:hover { + background: ${scrollbarSliderHoverBackgroundColor}; + } + `); + } + + const scrollbarSliderActiveBackgroundColor = theme.getColor(scrollbarSliderActiveBackground); + if (scrollbarSliderActiveBackgroundColor) { + collector.addRule(` + .monaco-workbench .monaco-scrollable-element > .scrollbar > .slider.active { + background: ${scrollbarSliderActiveBackgroundColor}; + } + `); + } + + // Focus outline + const focusOutline = theme.getColor(focusBorder); + if (focusOutline) { + collector.addRule(` + .monaco-workbench [tabindex="0"]:focus, + .monaco-workbench .synthetic-focus, + .monaco-workbench select:focus, + .monaco-workbench .monaco-tree.focused.no-focused-item:focus:before, + .monaco-workbench .monaco-list:not(.element-focused):focus:before, + .monaco-workbench input[type="button"]:focus, + .monaco-workbench input[type="text"]:focus, + .monaco-workbench button:focus, + .monaco-workbench textarea:focus, + .monaco-workbench input[type="search"]:focus, + .monaco-workbench input[type="checkbox"]:focus { + outline-color: ${focusOutline}; + } + `); + } + + // High Contrast theme overwrites for outline + if (theme.type === HIGH_CONTRAST) { + collector.addRule(` + .hc-black [tabindex="0"]:focus, + .hc-black .synthetic-focus, + .hc-black select:focus, + .hc-black input[type="button"]:focus, + .hc-black input[type="text"]:focus, + .hc-black textarea:focus, + .hc-black input[type="checkbox"]:focus { + outline-style: solid; + outline-width: 1px; + } + + .hc-black .monaco-tree.focused.no-focused-item:focus:before { + outline-width: 1px; + outline-offset: -2px; + } + + .hc-black .synthetic-focus input { + background: transparent; /* Search input focus fix when in high contrast */ + } + `); + } +}); diff --git a/src/vs/workbench/electron-browser/media/workbench.css b/src/vs/workbench/electron-browser/media/workbench.css deleted file mode 100644 index 951d0972276..00000000000 --- a/src/vs/workbench/electron-browser/media/workbench.css +++ /dev/null @@ -1,31 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -.monaco-workbench { - font-size: 13px; - line-height: 1.4em; - position: relative; - z-index: 1; - overflow: hidden; -} - -.monaco-workbench .part { - position: absolute; - box-sizing: border-box; -} - -.monaco-font-aliasing-antialiased { - -webkit-font-smoothing: antialiased; -} - -.monaco-font-aliasing-none { - -webkit-font-smoothing: none; -} - -@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { - .monaco-font-aliasing-auto { - -webkit-font-smoothing: antialiased; - } -} diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index f1faa78b49d..8ca9af866cf 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/css!./media/shell'; - import * as platform from 'vs/base/common/platform'; import * as perf from 'vs/base/common/performance'; import * as aria from 'vs/base/browser/ui/aria/aria'; @@ -65,8 +63,6 @@ import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/work import { WorkbenchThemeService } from 'vs/workbench/services/themes/electron-browser/workbenchThemeService'; import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; import { TextResourceConfigurationService } from 'vs/editor/common/services/resourceConfigurationImpl'; -import { registerThemingParticipant, ITheme, ICssStyleCollector, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService'; -import { foreground, selectionBackground, focusBorder, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listHighlightForeground, inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry'; import { TextMateService } from 'vs/workbench/services/textMate/electron-browser/TMSyntax'; import { ITextMateService } from 'vs/workbench/services/textMate/electron-browser/textMateService'; import { IBroadcastService, BroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService'; @@ -75,7 +71,6 @@ import { IHashService } from 'vs/workbench/services/hash/common/hashService'; import { ILogService } from 'vs/platform/log/common/log'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { Event, Emitter } from 'vs/base/common/event'; -import { WORKBENCH_BACKGROUND } from 'vs/workbench/common/theme'; import { LocalizationsChannelClient } from 'vs/platform/localizations/node/localizationsIpc'; import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -414,7 +409,7 @@ export class Shell extends Disposable { }); // Shell Class for CSS Scoping - addClasses(this.container, 'monaco-shell', platform.isWindows ? 'windows' : platform.isLinux ? 'linux' : 'mac'); + addClasses(this.container, platform.isWindows ? 'windows' : platform.isLinux ? 'linux' : 'mac'); // Create Contents this.renderContents(); @@ -489,130 +484,3 @@ export class Shell extends Disposable { this.mainProcessClient.dispose(); } } - -registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { - - // Foreground - const windowForeground = theme.getColor(foreground); - if (windowForeground) { - collector.addRule(`.monaco-shell { color: ${windowForeground}; }`); - } - - // Selection - const windowSelectionBackground = theme.getColor(selectionBackground); - if (windowSelectionBackground) { - collector.addRule(`.monaco-shell ::selection { background-color: ${windowSelectionBackground}; }`); - } - - // Input placeholder - const placeholderForeground = theme.getColor(inputPlaceholderForeground); - if (placeholderForeground) { - collector.addRule(`.monaco-shell input::-webkit-input-placeholder { color: ${placeholderForeground}; }`); - collector.addRule(`.monaco-shell textarea::-webkit-input-placeholder { color: ${placeholderForeground}; }`); - } - - // List highlight - const listHighlightForegroundColor = theme.getColor(listHighlightForeground); - if (listHighlightForegroundColor) { - collector.addRule(` - .monaco-shell .monaco-tree .monaco-tree-row .monaco-highlighted-label .highlight, - .monaco-shell .monaco-list .monaco-list-row .monaco-highlighted-label .highlight { - color: ${listHighlightForegroundColor}; - } - `); - } - - // We need to set the workbench background color so that on Windows we get subpixel-antialiasing. - const workbenchBackground = WORKBENCH_BACKGROUND(theme); - collector.addRule(`.monaco-workbench { background-color: ${workbenchBackground}; }`); - - // Scrollbars - const scrollbarShadowColor = theme.getColor(scrollbarShadow); - if (scrollbarShadowColor) { - collector.addRule(` - .monaco-shell .monaco-scrollable-element > .shadow.top { - box-shadow: ${scrollbarShadowColor} 0 6px 6px -6px inset; - } - - .monaco-shell .monaco-scrollable-element > .shadow.left { - box-shadow: ${scrollbarShadowColor} 6px 0 6px -6px inset; - } - - .monaco-shell .monaco-scrollable-element > .shadow.top.left { - box-shadow: ${scrollbarShadowColor} 6px 6px 6px -6px inset; - } - `); - } - - const scrollbarSliderBackgroundColor = theme.getColor(scrollbarSliderBackground); - if (scrollbarSliderBackgroundColor) { - collector.addRule(` - .monaco-shell .monaco-scrollable-element > .scrollbar > .slider { - background: ${scrollbarSliderBackgroundColor}; - } - `); - } - - const scrollbarSliderHoverBackgroundColor = theme.getColor(scrollbarSliderHoverBackground); - if (scrollbarSliderHoverBackgroundColor) { - collector.addRule(` - .monaco-shell .monaco-scrollable-element > .scrollbar > .slider:hover { - background: ${scrollbarSliderHoverBackgroundColor}; - } - `); - } - - const scrollbarSliderActiveBackgroundColor = theme.getColor(scrollbarSliderActiveBackground); - if (scrollbarSliderActiveBackgroundColor) { - collector.addRule(` - .monaco-shell .monaco-scrollable-element > .scrollbar > .slider.active { - background: ${scrollbarSliderActiveBackgroundColor}; - } - `); - } - - // Focus outline - const focusOutline = theme.getColor(focusBorder); - if (focusOutline) { - collector.addRule(` - .monaco-shell [tabindex="0"]:focus, - .monaco-shell .synthetic-focus, - .monaco-shell select:focus, - .monaco-shell .monaco-tree.focused.no-focused-item:focus:before, - .monaco-shell .monaco-list:not(.element-focused):focus:before, - .monaco-shell input[type="button"]:focus, - .monaco-shell input[type="text"]:focus, - .monaco-shell button:focus, - .monaco-shell textarea:focus, - .monaco-shell input[type="search"]:focus, - .monaco-shell input[type="checkbox"]:focus { - outline-color: ${focusOutline}; - } - `); - } - - // High Contrast theme overwrites for outline - if (theme.type === HIGH_CONTRAST) { - collector.addRule(` - .monaco-shell.hc-black [tabindex="0"]:focus, - .monaco-shell.hc-black .synthetic-focus, - .monaco-shell.hc-black select:focus, - .monaco-shell.hc-black input[type="button"]:focus, - .monaco-shell.hc-black input[type="text"]:focus, - .monaco-shell.hc-black textarea:focus, - .monaco-shell.hc-black input[type="checkbox"]:focus { - outline-style: solid; - outline-width: 1px; - } - - .monaco-shell.hc-black .monaco-tree.focused.no-focused-item:focus:before { - outline-width: 1px; - outline-offset: -2px; - } - - .monaco-shell.hc-black .synthetic-focus input { - background: transparent; /* Search input focus fix when in high contrast */ - } - `); - } -}); diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 4ed5b6cb199..2e8002f0744 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/css!./media/workbench'; +import 'vs/workbench/browser/style'; import { localize } from 'vs/nls'; import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; From 110c864b9d7918d4bfea8dc0ddc55034af384bf1 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 11 Feb 2019 18:04:08 +0100 Subject: [PATCH 138/207] test fix --- .../platform/workspaces/electron-main/workspacesMainService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index 9d53a05a37b..5e09c0af7a4 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -119,7 +119,7 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain const configPathDir = dirname(configPath); if (!existsSync(configPathDir)) { - const configPathDirDir = dirname(configPath); + const configPathDirDir = dirname(configPathDir); if (!existsSync(configPathDirDir)) { mkdirSync(configPathDirDir); } From 7fa41896c9b45019f238f577b27edc572828d0fe Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 11 Feb 2019 18:18:18 +0100 Subject: [PATCH 139/207] debt - add platform class to monaco-workbench --- src/vs/workbench/browser/media/style.css | 36 +++++++++---------- .../parts/editor/media/notabstitlecontrol.css | 4 +-- .../parts/titlebar/media/titlebarpart.css | 19 +++++----- .../browser/media/debug.contribution.css | 6 ++-- .../debug/browser/media/debugViewlet.css | 2 +- .../debug/browser/media/exceptionWidget.css | 8 ++--- .../contrib/debug/browser/media/repl.css | 18 +++++----- .../media/explorerviewlet.css | 4 +-- .../browser/media/keybindingsEditor.css | 4 +-- .../electron-browser/media/terminal.css | 4 +-- .../page/electron-browser/welcomePage.css | 12 +++---- .../electron-browser/walkThroughPart.css | 6 ++-- src/vs/workbench/electron-browser/shell.ts | 5 +-- .../workbench/electron-browser/workbench.ts | 3 +- 14 files changed, 63 insertions(+), 68 deletions(-) diff --git a/src/vs/workbench/browser/media/style.css b/src/vs/workbench/browser/media/style.css index 6a7b6261f3e..81d4f95693c 100644 --- a/src/vs/workbench/browser/media/style.css +++ b/src/vs/workbench/browser/media/style.css @@ -5,23 +5,23 @@ /* Font Families (with CJK support) */ -.mac { font-family: -apple-system, BlinkMacSystemFont, sans-serif; } -.mac:lang(zh-Hans) { font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", sans-serif; } -.mac:lang(zh-Hant) { font-family: -apple-system, BlinkMacSystemFont, "PingFang TC", sans-serif; } -.mac:lang(ja) { font-family: -apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic Pro", sans-serif; } -.mac:lang(ko) { font-family: -apple-system, BlinkMacSystemFont, "Nanum Gothic", "Apple SD Gothic Neo", "AppleGothic", sans-serif; } +.monaco-workbench.mac { font-family: -apple-system, BlinkMacSystemFont, sans-serif; } +.monaco-workbench.mac:lang(zh-Hans) { font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", sans-serif; } +.monaco-workbench.mac:lang(zh-Hant) { font-family: -apple-system, BlinkMacSystemFont, "PingFang TC", sans-serif; } +.monaco-workbench.mac:lang(ja) { font-family: -apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic Pro", sans-serif; } +.monaco-workbench.mac:lang(ko) { font-family: -apple-system, BlinkMacSystemFont, "Nanum Gothic", "Apple SD Gothic Neo", "AppleGothic", sans-serif; } -.windows { font-family: "Segoe WPC", "Segoe UI", sans-serif; } -.windows:lang(zh-Hans) { font-family: "Segoe WPC", "Segoe UI", "Microsoft YaHei", sans-serif; } -.windows:lang(zh-Hant) { font-family: "Segoe WPC", "Segoe UI", "Microsoft Jhenghei", sans-serif; } -.windows:lang(ja) { font-family: "Segoe WPC", "Segoe UI", "Meiryo", sans-serif; } -.windows:lang(ko) { font-family: "Segoe WPC", "Segoe UI", "Malgun Gothic", "Dotom", sans-serif; } +.monaco-workbench.windows { font-family: "Segoe WPC", "Segoe UI", sans-serif; } +.monaco-workbench.windows:lang(zh-Hans) { font-family: "Segoe WPC", "Segoe UI", "Microsoft YaHei", sans-serif; } +.monaco-workbench.windows:lang(zh-Hant) { font-family: "Segoe WPC", "Segoe UI", "Microsoft Jhenghei", sans-serif; } +.monaco-workbench.windows:lang(ja) { font-family: "Segoe WPC", "Segoe UI", "Meiryo", sans-serif; } +.monaco-workbench.windows:lang(ko) { font-family: "Segoe WPC", "Segoe UI", "Malgun Gothic", "Dotom", sans-serif; } -.linux { font-family: "Ubuntu", "Droid Sans", sans-serif; } -.linux:lang(zh-Hans) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif; } -.linux:lang(zh-Hant) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans TC", "Source Han Sans TW", "Source Han Sans", sans-serif; } -.linux:lang(ja) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", sans-serif; } -.linux:lang(ko) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif; } +.monaco-workbench.linux { font-family: "Ubuntu", "Droid Sans", sans-serif; } +.monaco-workbench.linux:lang(zh-Hans) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif; } +.monaco-workbench.linux:lang(zh-Hant) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans TC", "Source Han Sans TW", "Source Han Sans", sans-serif; } +.monaco-workbench.linux:lang(ja) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", sans-serif; } +.monaco-workbench.linux:lang(ko) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif; } /* Global Styles */ @@ -130,7 +130,7 @@ body { margin-bottom: 0.2em; } -.linux .monaco-workbench .monaco-menu .monaco-action-bar.vertical .action-label.separator { +.monaco-workbench.linux .monaco-menu .monaco-action-bar.vertical .action-label.separator { margin-left: 0; margin-right: 0; } @@ -140,7 +140,7 @@ body { padding: 0 1.8em; } -.linux .monaco-workbench .monaco-menu .monaco-action-bar.vertical .submenu-indicator { +.monaco-workbench.linux .monaco-menu .monaco-action-bar.vertical .submenu-indicator { height: 100%; -webkit-mask-size: 10px 10px; mask-size: 10px 10px; @@ -174,7 +174,7 @@ body { outline: 0 !important; /* fixes some flashing outlines from showing up when clicking */ } -.mac select:focus { +.monaco-workbench.mac select:focus { border-color: transparent; /* outline is a square, but border has a radius, so we avoid this glitch when focused (https://github.com/Microsoft/vscode/issues/26045) */ } diff --git a/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css b/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css index 1190f855b69..85e4d64ebb1 100644 --- a/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css +++ b/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css @@ -54,14 +54,14 @@ background-image: none; } -.windows > .monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item::before { +.monaco-workbench.windows .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item::before { content: '\\'; } .monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item.root_folder::before, .monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item.root_folder + .monaco-breadcrumb-item::before, .monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control.relative-path .monaco-breadcrumb-item:nth-child(2)::before, -.windows > .monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item:nth-child(2)::before { +.monaco-workbench.windows .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item:nth-child(2)::before { /* workspace folder, item following workspace folder, or relative path -> hide first seperator */ display: none; } diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index 38794f793dd..7ea3b3d5ee2 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -42,8 +42,8 @@ /* Windows/Linux: Rules for custom title (icon, window controls) */ -.windows > .monaco-workbench .part.titlebar, -.linux > .monaco-workbench .part.titlebar { +.monaco-workbench.windows .part.titlebar, +.monaco-workbench.linux .part.titlebar { padding: 0; height: 30px; line-height: 30px; @@ -51,17 +51,17 @@ overflow: visible; } -.windows > .monaco-workbench .part.titlebar > .window-title, -.linux > .monaco-workbench .part.titlebar > .window-title { +.monaco-workbench.windows .part.titlebar > .window-title, +.monaco-workbench.linux .part.titlebar > .window-title { cursor: default; } -.linux > .monaco-workbench .part.titlebar > .window-title { +.monaco-workbench.linux .part.titlebar > .window-title { font-size: inherit; } -.windows > .monaco-workbench .part.titlebar > .resizer, -.linux > .monaco-workbench .part.titlebar > .resizer { +.monaco-workbench.windows .part.titlebar > .resizer, +.monaco-workbench.linux .part.titlebar > .resizer { -webkit-app-region: no-drag; position: absolute; top: 0; @@ -69,12 +69,11 @@ height: 20%; } -.windows > .monaco-workbench.fullscreen .part.titlebar > .resizer, -.linux > .monaco-workbench.fullscreen .part.titlebar > .resizer { +.monaco-workbench.windows.fullscreen .part.titlebar > .resizer, +.monaco-workbench.linux.fullscreen .part.titlebar > .resizer { display: none; } - .monaco-workbench .part.titlebar > .window-appicon { width: 35px; height: 100%; diff --git a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css index 7a5e0f3cfa2..a33316e6efe 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css @@ -142,12 +142,12 @@ font-family: Monaco, Menlo, Consolas, "Droid Sans Mono", "Inconsolata", "Courier New", monospace, "Droid Sans Fallback"; } -.mac > .monaco-workbench .monaco-list-row .expression { +.monaco-workbench.mac .monaco-list-row .expression { font-size: 11px; } -.windows > .monaco-workbench .monaco-list-row .expression, -.linux > .monaco-workbench .monaco-list-row .expression { +.monaco-workbench.windows .monaco-list-row .expression, +.monaco-workbench.linux .monaco-list-row .expression { font-size: 13px; } diff --git a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css index 9d27545f44b..90390db77d7 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css @@ -64,7 +64,7 @@ margin-top: 7px; } -.mac > .monaco-workbench .part > .title > .title-actions .start-debug-action-item { +.monaco-workbench.mac .part > .title > .title-actions .start-debug-action-item { border-radius: 4px; } diff --git a/src/vs/workbench/contrib/debug/browser/media/exceptionWidget.css b/src/vs/workbench/contrib/debug/browser/media/exceptionWidget.css index 5ddc57325e8..400a9188f2e 100644 --- a/src/vs/workbench/contrib/debug/browser/media/exceptionWidget.css +++ b/src/vs/workbench/contrib/debug/browser/media/exceptionWidget.css @@ -31,13 +31,11 @@ cursor: pointer; } -/* High Contrast Theming */ - -.mac > .monaco-workbench .zone-widget .zone-widget-container.exception-widget { +.monaco-workbench.mac .zone-widget .zone-widget-container.exception-widget { font-size: 11px; } -.windows > .monaco-workbench .zone-widget .zone-widget-container.exception-widget, -.linux > .monaco-workbench .zone-widget .zone-widget-container.exception-widget { +.monaco-workbench.windows .zone-widget .zone-widget-container.exception-widget, +.monaco-workbench.linux .zone-widget .zone-widget-container.exception-widget { font-size: 13px; } diff --git a/src/vs/workbench/contrib/debug/browser/media/repl.css b/src/vs/workbench/contrib/debug/browser/media/repl.css index 9662f5852ee..f1c18dce896 100644 --- a/src/vs/workbench/contrib/debug/browser/media/repl.css +++ b/src/vs/workbench/contrib/debug/browser/media/repl.css @@ -36,13 +36,13 @@ word-break: break-all; } -.mac > .monaco-workbench .repl .repl-tree .monaco-tl-twistie.collapsible + .monaco-tl-contents, -.mac > .monaco-workbench .repl .repl-tree .monaco-tl-twistie { +.monaco-workbench.mac .repl .repl-tree .monaco-tl-twistie.collapsible + .monaco-tl-contents, +.monaco-workbench.mac .repl .repl-tree .monaco-tl-twistie { cursor: pointer; } -.mac > .monaco-workbench .repl .repl-tree .input.expression, -.mac > .monaco-workbench .repl .repl-tree .output.expression { +.monaco-workbench.mac .repl .repl-tree .input.expression, +.monaco-workbench.mac .repl .repl-tree .output.expression { font-size: 12px; } @@ -65,10 +65,10 @@ cursor: text; } -.windows > .monaco-workbench .repl .repl-tree .monaco-list-row .input.expression, -.windows > .monaco-workbench .repl .repl-tree .monaco-list-row .output.expression, -.linux > .monaco-workbench .repl .repl-tree .monaco-list-row .input.expression, -.linux > .monaco-workbench .repl .repl-tree .monaco-list-row .output.expression { +.monaco-workbench.windows .repl .repl-tree .monaco-list-row .input.expression, +.monaco-workbench.windows .repl .repl-tree .monaco-list-row .output.expression, +.monaco-workbench.linux .repl .repl-tree .monaco-list-row .input.expression, +.monaco-workbench.linux .repl .repl-tree .monaco-list-row .output.expression { font-size: 14px; } @@ -106,7 +106,7 @@ line-height: 18px; } -.linux > .monaco-workbench .repl .repl-input-wrapper:before { +.monaco-workbench.linux .repl .repl-input-wrapper:before { font-size: 9px; } diff --git a/src/vs/workbench/contrib/files/electron-browser/media/explorerviewlet.css b/src/vs/workbench/contrib/files/electron-browser/media/explorerviewlet.css index e993c16c5ff..a0c0f8de7f4 100644 --- a/src/vs/workbench/contrib/files/electron-browser/media/explorerviewlet.css +++ b/src/vs/workbench/contrib/files/electron-browser/media/explorerviewlet.css @@ -120,8 +120,8 @@ line-height: normal; } -.linux > .monaco-workbench .explorer-viewlet .explorer-item .monaco-inputbox, -.mac > .monaco-workbench .explorer-viewlet .explorer-item .monaco-inputbox { +.monaco-workbench.linux .explorer-viewlet .explorer-item .monaco-inputbox, +.monaco-workbench.mac .explorer-viewlet .explorer-item .monaco-inputbox { height: 22px; } diff --git a/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css b/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css index 2a20cd52885..4ba0ee5f72a 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css +++ b/src/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css @@ -154,8 +154,8 @@ line-height: normal; } -.mac > .monaco-workbench .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when .monaco-inputbox, -.mac > .monaco-workbench .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when .monaco-inputbox { +.monaco-workbench.mac .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when .monaco-inputbox, +.monaco-workbench.mac .keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .when .monaco-inputbox { height: 24px; } diff --git a/src/vs/workbench/contrib/terminal/electron-browser/media/terminal.css b/src/vs/workbench/contrib/terminal/electron-browser/media/terminal.css index 74e79a263ed..c5da665535e 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/media/terminal.css +++ b/src/vs/workbench/contrib/terminal/electron-browser/media/terminal.css @@ -157,8 +157,8 @@ .vs-dark .monaco-workbench .terminal-action.split, .hc-black .monaco-workbench .terminal-action.split { background: url('split-inverse.svg') center center no-repeat; } .vs-dark .monaco-workbench .panel.right .terminal-action.split, .hc-black .monaco-workbench .panel.right .terminal-action.split { background: url('split-horizontal-inverse.svg') center center no-repeat; } -.vs-dark.mac .monaco-workbench .panel.integrated-terminal .terminal-outer-container:not(.alt-active) .terminal:not(.enable-mouse-events), -.hc-black.mac .monaco-workbench .panel.integrated-terminal .terminal-outer-container:not(.alt-active) .terminal:not(.enable-mouse-events) { +.vs-dark .monaco-workbench.mac .panel.integrated-terminal .terminal-outer-container:not(.alt-active) .terminal:not(.enable-mouse-events), +.hc-black .monaco-workbench.mac .panel.integrated-terminal .terminal-outer-container:not(.alt-active) .terminal:not(.enable-mouse-events) { cursor: -webkit-image-set(url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAL0lEQVQoz2NgCD3x//9/BhBYBWdhgFVAiVW4JBFKGIa4AqD0//9D3pt4I4tAdAMAHTQ/j5Zom30AAAAASUVORK5CYII=') 1x, url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAz0lEQVRIx2NgYGBY/R8I/vx5eelX3n82IJ9FxGf6tksvf/8FiTMQAcAGQMDvSwu09abffY8QYSAScNk45G198eX//yev73/4///701eh//kZSARckrNBRvz//+8+6ZohwCzjGNjdgQxkAg7B9WADeBjIBqtJCbhRA0YNoIkBSNmaPEMoNmA0FkYNoFKhapJ6FGyAH3nauaSmPfwI0v/3OukVi0CIZ+F25KrtYcx/CTIy0e+rC7R1Z4KMICVTQQ14feVXIbR695u14+Ir4gwAAD49E54wc1kWAAAAAElFTkSuQmCC') 2x) 5 8, text; } diff --git a/src/vs/workbench/contrib/welcome/page/electron-browser/welcomePage.css b/src/vs/workbench/contrib/welcome/page/electron-browser/welcomePage.css index a24da657f52..756182d9e54 100644 --- a/src/vs/workbench/contrib/welcome/page/electron-browser/welcomePage.css +++ b/src/vs/workbench/contrib/welcome/page/electron-browser/welcomePage.css @@ -228,21 +228,21 @@ .monaco-workbench .part.editor > .content .welcomePage .linux-only { display: none; } -.mac > .monaco-workbench .part.editor > .content .welcomePage .mac-only { +.monaco-workbench.mac .part.editor > .content .welcomePage .mac-only { display: initial; } -.windows > .monaco-workbench .part.editor > .content .welcomePage .windows-only { +.monaco-workbench.windows .part.editor > .content .welcomePage .windows-only { display: initial; } -.linux > .monaco-workbench .part.editor > .content .welcomePage .linux-only { +.monaco-workbench.linux .part.editor > .content .welcomePage .linux-only { display: initial; } -.mac > .monaco-workbench .part.editor > .content .welcomePage li.mac-only { +.monaco-workbench.mac .part.editor > .content .welcomePage li.mac-only { display: list-item; } -.windows > .monaco-workbench .part.editor > .content .welcomePage li.windows-only { +.monaco-workbench.windows .part.editor > .content .welcomePage li.windows-only { display: list-item; } -.linux > .monaco-workbench .part.editor > .content .welcomePage li.linux-only { +.monaco-workbench.linux .part.editor > .content .welcomePage li.linux-only { display: list-item; } diff --git a/src/vs/workbench/contrib/welcome/walkThrough/electron-browser/walkThroughPart.css b/src/vs/workbench/contrib/welcome/walkThrough/electron-browser/walkThroughPart.css index 2194a2a98c7..401db65c7be 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/electron-browser/walkThroughPart.css +++ b/src/vs/workbench/contrib/welcome/walkThrough/electron-browser/walkThroughPart.css @@ -123,13 +123,13 @@ .monaco-workbench .part.editor > .content .walkThroughContent .linux-only { display: none; } -.mac > .monaco-workbench .part.editor > .content .walkThroughContent .mac-only { +.monaco-workbench.mac .part.editor > .content .walkThroughContent .mac-only { display: initial; } -.windows > .monaco-workbench .part.editor > .content .walkThroughContent .windows-only { +.monaco-workbench.windows .part.editor > .content .walkThroughContent .windows-only { display: initial; } -.linux > .monaco-workbench .part.editor > .content .walkThroughContent .linux-only { +.monaco-workbench.linux .part.editor > .content .walkThroughContent .linux-only { display: initial; } diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 8ca9af866cf..c28fe9ca74f 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -78,7 +78,7 @@ import { NotificationService } from 'vs/workbench/services/notification/common/n import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { DialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService'; import { DialogChannel } from 'vs/platform/dialogs/node/dialogIpc'; -import { EventType, addDisposableListener, scheduleAtNextAnimationFrame, addClasses } from 'vs/base/browser/dom'; +import { EventType, addDisposableListener, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; import { IRemoteAgentService } from 'vs/workbench/services/remote/node/remoteAgentService'; import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import { IOpenerService } from 'vs/platform/opener/common/opener'; @@ -408,9 +408,6 @@ export class Shell extends Disposable { this.onUnexpectedError(error); }); - // Shell Class for CSS Scoping - addClasses(this.container, platform.isWindows ? 'windows' : platform.isLinux ? 'linux' : 'mac'); - // Create Contents this.renderContents(); diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 2e8002f0744..cb0f4ed466d 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -314,7 +314,8 @@ export class Workbench extends Disposable implements IPartService { private createWorkbench(): void { this.workbench = document.createElement('div'); this.workbench.id = Identifiers.WORKBENCH_CONTAINER; - DOM.addClass(this.workbench, 'monaco-workbench'); + + DOM.addClasses(this.workbench, 'monaco-workbench', isWindows ? 'windows' : isLinux ? 'linux' : 'mac'); this._register(DOM.addDisposableListener(this.workbench, DOM.EventType.SCROLL, () => { this.workbench.scrollTop = 0; // Prevent workbench from scrolling #55456 From d18d0edce11ac396bf7654ac96e0d522681b5553 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 11 Feb 2019 18:26:43 +0100 Subject: [PATCH 140/207] Update to vscode-nls-dev@3.2.5 (fixes #68393) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ae4721901d6..0a2f69dc996 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,7 @@ "vinyl": "^2.0.0", "vinyl-fs": "^3.0.0", "vsce": "1.48.0", - "vscode-nls-dev": "3.2.4", + "vscode-nls-dev": "3.2.5", "webpack": "^4.16.5", "webpack-cli": "^3.1.0", "webpack-stream": "^5.1.1" diff --git a/yarn.lock b/yarn.lock index 053bd5abe32..35c689a7ae9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9380,10 +9380,10 @@ vscode-languageserver@^5.1.0: vscode-languageserver-protocol "3.13.0" vscode-uri "^1.0.6" -vscode-nls-dev@3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/vscode-nls-dev/-/vscode-nls-dev-3.2.4.tgz#9eb92a539fb1ee675836b6aeab8a2846c281c8d9" - integrity sha512-mWERxHbifhuNZomuL3iRyw2LTwKnoKoA8fjWJrlfnbOUF9EN/tbDT0ly2GnOEvLRq0hzEzZNqKLWu0jXPDs7UA== +vscode-nls-dev@3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/vscode-nls-dev/-/vscode-nls-dev-3.2.5.tgz#bea2b6e0cae709c48144180585e1a511edc9fb8d" + integrity sha512-eiNkwDHgTjP1h23BCOmAlXbFVembGokALYIvID5LMBzYppOiJzN/rGatHBlThQl6lnHWv599UEre6/AbjioYYw== dependencies: ansi-colors "^3.2.3" clone "^2.1.1" From 9ee60773731926a2d418c6a4caafc013169d41b6 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 8 Feb 2019 17:55:48 -0800 Subject: [PATCH 141/207] Strict null work in extHost --- .../editor/common/modes/languageSelector.ts | 2 +- src/vs/workbench/api/node/extHost.protocol.ts | 4 ++-- .../node/extHostDocumentContentProviders.ts | 7 ++++-- .../node/extHostDocumentSaveParticipant.ts | 4 ++-- src/vs/workbench/api/node/extHostDocuments.ts | 2 +- .../api/node/extHostExtensionService.ts | 22 +++++++++---------- .../api/node/extHostLanguageFeatures.ts | 12 +++++----- src/vs/workbench/api/node/extHostLanguages.ts | 5 +++-- src/vs/workbench/api/node/extHostProgress.ts | 6 ++--- src/vs/workbench/api/node/extHostSearch.ts | 4 ++-- .../workbench/api/node/extHostTextEditors.ts | 5 +++-- .../api/node/extHostTypeConverters.ts | 10 ++++----- .../parts/editor/editor.contribution.ts | 8 +++---- .../parts/editor/noTabsTitleControl.ts | 4 ++-- .../parts/editor/textResourceEditor.ts | 4 ++-- src/vs/workbench/common/editor.ts | 4 ++-- src/vs/workbench/common/editor/editorGroup.ts | 2 +- .../history/electron-browser/history.ts | 2 +- 18 files changed, 56 insertions(+), 51 deletions(-) diff --git a/src/vs/editor/common/modes/languageSelector.ts b/src/vs/editor/common/modes/languageSelector.ts index b878e2232c7..4cf93dc4d23 100644 --- a/src/vs/editor/common/modes/languageSelector.ts +++ b/src/vs/editor/common/modes/languageSelector.ts @@ -19,7 +19,7 @@ export interface LanguageFilter { export type LanguageSelector = string | LanguageFilter | Array; -export function score(selector: LanguageSelector, candidateUri: URI, candidateLanguage: string, candidateIsSynchronized: boolean): number { +export function score(selector: LanguageSelector | undefined, candidateUri: URI, candidateLanguage: string, candidateIsSynchronized: boolean): number { if (Array.isArray(selector)) { // array -> take max individual value diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 671a13706eb..a2883df2540 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -655,7 +655,7 @@ export interface ExtHostDiagnosticsShape { } export interface ExtHostDocumentContentProvidersShape { - $provideTextDocumentContent(handle: number, uri: UriComponents): Promise; + $provideTextDocumentContent(handle: number, uri: UriComponents): Promise; } export interface IModelAddedData { @@ -961,7 +961,7 @@ export interface ExtHostTerminalServiceShape { } export interface ExtHostSCMShape { - $provideOriginalResource(sourceControlHandle: number, uri: UriComponents, token: CancellationToken): Promise; + $provideOriginalResource(sourceControlHandle: number, uri: UriComponents, token: CancellationToken): Promise; $onInputBoxValueChange(sourceControlHandle: number, value: string): void; $executeResourceCommand(sourceControlHandle: number, groupHandle: number, handle: number): Promise; $validateInput(sourceControlHandle: number, value: string, cursorPosition: number): Promise<[string, number] | undefined>; diff --git a/src/vs/workbench/api/node/extHostDocumentContentProviders.ts b/src/vs/workbench/api/node/extHostDocumentContentProviders.ts index 4c7ed33685d..89c7332e1b1 100644 --- a/src/vs/workbench/api/node/extHostDocumentContentProviders.ts +++ b/src/vs/workbench/api/node/extHostDocumentContentProviders.ts @@ -45,7 +45,7 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro this._documentContentProviders.set(handle, provider); this._proxy.$registerTextContentProvider(handle, scheme); - let subscription: IDisposable; + let subscription: IDisposable | undefined; if (typeof provider.onDidChange === 'function') { subscription = provider.onDidChange(uri => { if (uri.scheme !== scheme) { @@ -54,6 +54,9 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro } if (this._documentsAndEditors.getDocument(uri.toString())) { this.$provideTextDocumentContent(handle, uri).then(value => { + if (!value) { + return; + } const document = this._documentsAndEditors.getDocument(uri.toString()); if (!document) { @@ -84,7 +87,7 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro }); } - $provideTextDocumentContent(handle: number, uri: UriComponents): Promise { + $provideTextDocumentContent(handle: number, uri: UriComponents): Promise { const provider = this._documentContentProviders.get(handle); if (!provider) { return Promise.reject(new Error(`unsupported uri-scheme: ${uri.scheme}`)); diff --git a/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts b/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts index 29c19a7cefc..5fe6b6dffda 100644 --- a/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts +++ b/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts @@ -72,7 +72,7 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic private _deliverEventAsyncAndBlameBadListeners([listener, thisArg, extension]: Listener, stubEvent: vscode.TextDocumentWillSaveEvent): Promise { const errors = this._badListeners.get(listener); - if (errors > this._thresholds.errors) { + if (typeof errors === 'number' && errors > this._thresholds.errors) { // bad listener - ignore return Promise.resolve(false); } @@ -90,7 +90,7 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic const errors = this._badListeners.get(listener); this._badListeners.set(listener, !errors ? 1 : errors + 1); - if (errors > this._thresholds.errors) { + if (typeof errors === 'number' && errors > this._thresholds.errors) { this._logService.info(`onWillSaveTextDocument-listener from extension '${extension.identifier.value}' will now be IGNORED because of timeouts and/or errors`); } } diff --git a/src/vs/workbench/api/node/extHostDocuments.ts b/src/vs/workbench/api/node/extHostDocuments.ts index 313dec0438e..e7c6cff941a 100644 --- a/src/vs/workbench/api/node/extHostDocuments.ts +++ b/src/vs/workbench/api/node/extHostDocuments.ts @@ -56,7 +56,7 @@ export class ExtHostDocuments implements ExtHostDocumentsShape { return this._documentsAndEditors.allDocuments(); } - public getDocumentData(resource: vscode.Uri): ExtHostDocumentData { + public getDocumentData(resource: vscode.Uri): ExtHostDocumentData | undefined { if (!resource) { return undefined; } diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index f88bfac108a..04ddf5fc460 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -81,13 +81,13 @@ class ExtensionMemento implements IExtensionMemento { class ExtensionStoragePath { - private readonly _workspace: IStaticWorkspaceData; + private readonly _workspace?: IStaticWorkspaceData; private readonly _environment: IEnvironment; - private readonly _ready: Promise; - private _value: string; + private readonly _ready: Promise; + private _value?: string; - constructor(workspace: IStaticWorkspaceData, environment: IEnvironment) { + constructor(workspace: IStaticWorkspaceData | undefined, environment: IEnvironment) { this._workspace = workspace; this._environment = environment; this._ready = this._getOrCreateWorkspaceStoragePath().then(value => this._value = value); @@ -97,7 +97,7 @@ class ExtensionStoragePath { return this._ready; } - workspaceValue(extension: IExtensionDescription): string { + workspaceValue(extension: IExtensionDescription): string | undefined { if (this._value) { return path.join(this._value, extension.identifier.value); } @@ -108,7 +108,7 @@ class ExtensionStoragePath { return path.join(this._environment.globalStorageHome.fsPath, extension.identifier.value.toLowerCase()); } - private async _getOrCreateWorkspaceStoragePath(): Promise { + private async _getOrCreateWorkspaceStoragePath(): Promise { if (!this._workspace) { return Promise.resolve(undefined); } @@ -493,7 +493,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { return this._handleWorkspaceContainsEagerExtensions(workspaceProvider.workspace); } - private _handleWorkspaceContainsEagerExtensions(workspace: IWorkspace): Promise { + private _handleWorkspaceContainsEagerExtensions(workspace: IWorkspace | undefined): Promise { if (!workspace || workspace.folders.length === 0) { return Promise.resolve(undefined); } @@ -567,7 +567,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { .then(undefined, err => console.error(err)); }, ExtHostExtensionService.WORKSPACE_CONTAINS_TIMEOUT); - let exists: boolean; + let exists: boolean = false; try { exists = await searchP; } catch (err) { @@ -608,8 +608,8 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { } // Require the test runner via node require from the provided path - let testRunner: ITestRunner; - let requireError: Error; + let testRunner: ITestRunner | undefined; + let requireError: Error | undefined; try { testRunner = require.__$__nodeRequire(this._initData.environment.extensionTestsPath); } catch (error) { @@ -619,7 +619,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { // Execute the runner if it follows our spec if (testRunner && typeof testRunner.run === 'function') { return new Promise((c, e) => { - testRunner.run(this._initData.environment.extensionTestsPath, (error, failures) => { + testRunner!.run(this._initData.environment.extensionTestsPath, (error, failures) => { if (error) { e(error.toString()); } else { diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index d35863c8a6d..ee1a0622d25 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -499,7 +499,7 @@ class RenameAdapter { private readonly _provider: vscode.RenameProvider ) { } - provideRenameEdits(resource: URI, position: IPosition, newName: string, token: CancellationToken): Promise { + provideRenameEdits(resource: URI, position: IPosition, newName: string, token: CancellationToken): Promise { let doc = this._documents.getDocumentData(resource).document; let pos = typeConvert.Position.to(position); @@ -520,7 +520,7 @@ class RenameAdapter { }); } - resolveRenameLocation(resource: URI, position: IPosition, token: CancellationToken): Promise { + resolveRenameLocation(resource: URI, position: IPosition, token: CancellationToken): Promise<(modes.RenameLocation & modes.Rejection) | undefined> { if (typeof this._provider.prepareRename !== 'function') { return Promise.resolve(undefined); } @@ -530,7 +530,7 @@ class RenameAdapter { return asPromise(() => this._provider.prepareRename(doc, pos, token)).then(rangeOrLocation => { - let range: vscode.Range; + let range: vscode.Range | undefined; let text: string; if (Range.isRange(rangeOrLocation)) { range = rangeOrLocation; @@ -670,7 +670,7 @@ class SuggestAdapter { this._cache.delete(id); } - private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, defaultRange: vscode.Range, _id: number, _parentId: number): SuggestionDto { + private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, defaultRange: vscode.Range, _id: number, _parentId: number): SuggestionDto | undefined { if (typeof item.label !== 'string' || item.label.length === 0) { console.warn('INVALID text edit -> must have at least a label'); return undefined; @@ -930,7 +930,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { private static _handlePool: number = 0; - private readonly _schemeTransformer: ISchemeTransformer; + private readonly _schemeTransformer: ISchemeTransformer | null; private _proxy: MainThreadLanguageFeaturesShape; private _documents: ExtHostDocuments; private _commands: ExtHostCommands; @@ -941,7 +941,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { constructor( mainContext: IMainContext, - schemeTransformer: ISchemeTransformer, + schemeTransformer: ISchemeTransformer | null, documents: ExtHostDocuments, commands: ExtHostCommands, heapMonitor: ExtHostHeapService, diff --git a/src/vs/workbench/api/node/extHostLanguages.ts b/src/vs/workbench/api/node/extHostLanguages.ts index 6449d452e76..4d67385bd67 100644 --- a/src/vs/workbench/api/node/extHostLanguages.ts +++ b/src/vs/workbench/api/node/extHostLanguages.ts @@ -24,9 +24,10 @@ export class ExtHostLanguages { return this._proxy.$getLanguages(); } - changeLanguage(uri: vscode.Uri, languageId: string): Promise { + changeLanguage(uri: vscode.Uri, languageId: string): Promise { return this._proxy.$changeLanguage(uri, languageId).then(() => { - return this._documents.getDocumentData(uri).document; + const data = this._documents.getDocumentData(uri); + return data ? data.document : undefined; }); } } diff --git a/src/vs/workbench/api/node/extHostProgress.ts b/src/vs/workbench/api/node/extHostProgress.ts index 4eb444f677a..c365acee488 100644 --- a/src/vs/workbench/api/node/extHostProgress.ts +++ b/src/vs/workbench/api/node/extHostProgress.ts @@ -27,11 +27,11 @@ export class ExtHostProgress implements ExtHostProgressShape { const { title, location, cancellable } = options; const source = localize('extensionSource', "{0} (Extension)", extension.displayName || extension.name); this._proxy.$startProgress(handle, { location: ProgressLocation.from(location), title, source, cancellable }); - return this._withProgress(handle, task, cancellable); + return this._withProgress(handle, task, !!cancellable); } private _withProgress(handle: number, task: (progress: Progress, token: CancellationToken) => Thenable, cancellable: boolean): Thenable { - let source: CancellationTokenSource; + let source: CancellationTokenSource | undefined; if (cancellable) { source = new CancellationTokenSource(); this._mapHandleToCancellationSource.set(handle, source); @@ -48,7 +48,7 @@ export class ExtHostProgress implements ExtHostProgressShape { let p: Thenable; try { - p = task(new ProgressCallback(this._proxy, handle), cancellable ? source.token : CancellationToken.None); + p = task(new ProgressCallback(this._proxy, handle), cancellable && source ? source.token : CancellationToken.None); } catch (err) { progressEnd(handle); throw err; diff --git a/src/vs/workbench/api/node/extHostSearch.ts b/src/vs/workbench/api/node/extHostSearch.ts index 80559688fb1..d5a17a18809 100644 --- a/src/vs/workbench/api/node/extHostSearch.ts +++ b/src/vs/workbench/api/node/extHostSearch.ts @@ -35,12 +35,12 @@ export class ExtHostSearch implements ExtHostSearchShape { private _handlePool: number = 0; private _internalFileSearchHandle: number; - private _internalFileSearchProvider: SearchService; + private _internalFileSearchProvider: SearchService | null; private _fileSearchManager: FileSearchManager; private _fileIndexSearchManager: FileIndexSearchManager; - constructor(mainContext: IMainContext, private _schemeTransformer: ISchemeTransformer, private _logService: ILogService, private _extfs = extfs) { + constructor(mainContext: IMainContext, private _schemeTransformer: ISchemeTransformer | null, private _logService: ILogService, private _extfs = extfs) { this._proxy = mainContext.getProxy(MainContext.MainThreadSearch); this._fileSearchManager = new FileSearchManager(); this._fileIndexSearchManager = new FileIndexSearchManager(); diff --git a/src/vs/workbench/api/node/extHostTextEditors.ts b/src/vs/workbench/api/node/extHostTextEditors.ts index 8889172ad67..2ebad811a31 100644 --- a/src/vs/workbench/api/node/extHostTextEditors.ts +++ b/src/vs/workbench/api/node/extHostTextEditors.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; +import * as arrays from 'vs/base/common/arrays'; import { ExtHostEditorsShape, IEditorPropertiesChangeData, IMainContext, ITextDocumentShowOptions, ITextEditorPositionData, MainContext, MainThreadTextEditorsShape } from 'vs/workbench/api/node/extHost.protocol'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors'; import { ExtHostTextEditor, TextEditorDecorationType } from 'vs/workbench/api/node/extHostTextEditor'; @@ -106,7 +107,7 @@ export class ExtHostEditors implements ExtHostEditorsShape { textEditor._acceptSelections(selections); } if (data.visibleRanges) { - const visibleRanges = data.visibleRanges.map(TypeConverters.Range.to); + const visibleRanges = arrays.coalesce(data.visibleRanges.map(TypeConverters.Range.to)); textEditor._acceptVisibleRanges(visibleRanges); } @@ -127,7 +128,7 @@ export class ExtHostEditors implements ExtHostEditorsShape { }); } if (data.visibleRanges) { - const visibleRanges = data.visibleRanges.map(TypeConverters.Range.to); + const visibleRanges = arrays.coalesce(data.visibleRanges.map(TypeConverters.Range.to)); this._onDidChangeTextEditorVisibleRanges.fire({ textEditor, visibleRanges diff --git a/src/vs/workbench/api/node/extHostTypeConverters.ts b/src/vs/workbench/api/node/extHostTypeConverters.ts index 61e6846831b..83786a14276 100644 --- a/src/vs/workbench/api/node/extHostTypeConverters.ts +++ b/src/vs/workbench/api/node/extHostTypeConverters.ts @@ -182,12 +182,12 @@ export namespace ViewColumn { return ACTIVE_GROUP; // default is always the active group } - export function to(position?: EditorViewColumn): vscode.ViewColumn | undefined { + export function to(position: EditorViewColumn): vscode.ViewColumn { if (typeof position === 'number' && position >= 0) { return position + 1; // adjust to index (ViewColumn.ONE => 1) } - return undefined; + throw new Error(`invalid 'EditorViewColumn'`); } } @@ -908,13 +908,13 @@ export namespace EndOfLine { } export namespace ProgressLocation { - export function from(loc: vscode.ProgressLocation): MainProgressLocation | undefined { + export function from(loc: vscode.ProgressLocation): MainProgressLocation { switch (loc) { case types.ProgressLocation.SourceControl: return MainProgressLocation.Scm; case types.ProgressLocation.Window: return MainProgressLocation.Window; case types.ProgressLocation.Notification: return MainProgressLocation.Notification; } - return undefined; + throw new Error(`Unknown 'ProgressLocation'`); } } @@ -986,7 +986,7 @@ export namespace GlobPattern { export namespace LanguageSelector { - export function from(selector: vscode.DocumentSelector): languageSelector.LanguageSelector | undefined { + export function from(selector: vscode.DocumentSelector | undefined): languageSelector.LanguageSelector | undefined { if (!selector) { return undefined; } else if (Array.isArray(selector)) { diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index b262c8aeef8..5c1e6ef0f87 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -114,7 +114,7 @@ class UntitledEditorInputFactory implements IEditorInputFactory { @ITextFileService private readonly textFileService: ITextFileService ) { } - serialize(editorInput: EditorInput): string { + serialize(editorInput: EditorInput): string | null { if (!this.textFileService.isHotExitEnabled) { return null; // never restore untitled unless hot exit is enabled } @@ -165,7 +165,7 @@ interface ISerializedSideBySideEditorInput { // Register Side by Side Editor Input Factory class SideBySideEditorInputFactory implements IEditorInputFactory { - serialize(editorInput: EditorInput): string { + serialize(editorInput: EditorInput): string | null { const input = editorInput; if (input.details && input.master) { @@ -193,7 +193,7 @@ class SideBySideEditorInputFactory implements IEditorInputFactory { return null; } - deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput { + deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput | null { const deserialized: ISerializedSideBySideEditorInput = JSON.parse(serializedEditorInput); const registry = Registry.as(EditorInputExtensions.EditorInputFactories); @@ -261,7 +261,7 @@ export class QuickOpenActionContributor extends ActionBarContributor { return actions; } - private getEntry(context: any): IEditorQuickOpenEntry { + private getEntry(context: any): IEditorQuickOpenEntry | null { if (!context || !context.element) { return null; } diff --git a/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts index 67be1c251c1..4e1e729e2b7 100644 --- a/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts @@ -244,7 +244,7 @@ export class NoTabsTitleControl extends TitleControl { title = ''; // dont repeat what is already shown } - this.editorLabel.setResource({ name, description, resource }, { title, italic: !isEditorPinned, extraClasses: ['no-tabs', 'title-label'] }); + this.editorLabel.setResource({ name, description, resource: resource || undefined }, { title, italic: !isEditorPinned, extraClasses: ['no-tabs', 'title-label'] }); if (isGroupActive) { this.editorLabel.element.style.color = this.getColor(TAB_ACTIVE_FOREGROUND); } else { @@ -256,7 +256,7 @@ export class NoTabsTitleControl extends TitleControl { } } - private getVerbosity(style: string): Verbosity { + private getVerbosity(style: string | undefined): Verbosity { switch (style) { case 'short': return Verbosity.SHORT; case 'long': return Verbosity.LONG; diff --git a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts index 7e0e7e52a27..7c8160aa080 100644 --- a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts @@ -46,7 +46,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor { super(id, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, windowService); } - getTitle(): string { + getTitle(): string | null { if (this.input) { return this.input.getName(); } @@ -168,7 +168,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor { super.saveState(); } - private saveTextResourceEditorViewState(input: EditorInput): void { + private saveTextResourceEditorViewState(input: EditorInput | null): void { if (!(input instanceof UntitledEditorInput) && !(input instanceof ResourceEditorInput)) { return; // only enabled for untitled and resource inputs } diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 40845a01c42..bd9740edb23 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -184,13 +184,13 @@ export interface IEditorInputFactory { * Returns a string representation of the provided editor input that contains enough information * to deserialize back to the original editor input from the deserialize() method. */ - serialize(editorInput: EditorInput): string; + serialize(editorInput: EditorInput): string | null; /** * Returns an editor input from the provided serialized form of the editor input. This form matches * the value returned from the serialize() method. */ - deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput; + deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput | null; } export interface IUntitledResourceInput extends IBaseResourceInput { diff --git a/src/vs/workbench/common/editor/editorGroup.ts b/src/vs/workbench/common/editor/editorGroup.ts index af7ff8be8bb..c5f5e8bd159 100644 --- a/src/vs/workbench/common/editor/editorGroup.ts +++ b/src/vs/workbench/common/editor/editorGroup.ts @@ -678,7 +678,7 @@ export class EditorGroup extends Disposable { this.editors = coalesce(data.editors.map(e => { const factory = registry.getEditorInputFactory(e.id); if (factory) { - const editor = factory.deserialize(this.instantiationService, e.value); + const editor = factory.deserialize(this.instantiationService, e.value)!; this.registerEditorListeners(editor); this.updateResourceMap(editor, false /* add */); diff --git a/src/vs/workbench/services/history/electron-browser/history.ts b/src/vs/workbench/services/history/electron-browser/history.ts index 8de95889699..a870f1f404f 100644 --- a/src/vs/workbench/services/history/electron-browser/history.ts +++ b/src/vs/workbench/services/history/electron-browser/history.ts @@ -899,7 +899,7 @@ export class HistoryService extends Disposable implements IHistoryService { this.onEditorDispose(input, () => this.removeFromHistory(input), this.editorHistoryListeners); } - return input; + return input || undefined; } } From f1afe720873f8d11f2eff8d0c3c3fb8045d33c48 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 8 Feb 2019 18:06:08 -0800 Subject: [PATCH 142/207] Add getDocument helper method Many places in `extHostLanguageFeatures` were calling `getDocumentData` without checking if the result is undefined. Add an `getDocument` that cannot return undefined values and instead throws an error if there is no document --- src/vs/workbench/api/node/extHostComments.ts | 71 +++++-------------- src/vs/workbench/api/node/extHostDocuments.ts | 8 +++ .../api/node/extHostLanguageFeatures.ts | 44 ++++++------ 3 files changed, 46 insertions(+), 77 deletions(-) diff --git a/src/vs/workbench/api/node/extHostComments.ts b/src/vs/workbench/api/node/extHostComments.ts index 3e76d66a03e..547da7fe41f 100644 --- a/src/vs/workbench/api/node/extHostComments.ts +++ b/src/vs/workbench/api/node/extHostComments.ts @@ -111,107 +111,68 @@ export class ExtHostComments implements ExtHostCommentsShape { } $editComment(handle: number, uri: UriComponents, comment: modes.Comment, text: string): Promise { - const data = this._documents.getDocumentData(URI.revive(uri)); - - if (!data || !data.document) { - throw new Error('Unable to retrieve document from URI'); - } - + const document = this._documents.getDocument(URI.revive(uri)); const handlerData = this._documentProviders.get(handle); return asPromise(() => { - return handlerData.provider.editComment(data.document, convertFromComment(comment), text, CancellationToken.None); + return handlerData.provider.editComment(document, convertFromComment(comment), text, CancellationToken.None); }); } $deleteComment(handle: number, uri: UriComponents, comment: modes.Comment): Promise { - const data = this._documents.getDocumentData(URI.revive(uri)); - - if (!data || !data.document) { - throw new Error('Unable to retrieve document from URI'); - } - + const document = this._documents.getDocument(URI.revive(uri)); const handlerData = this._documentProviders.get(handle); return asPromise(() => { - return handlerData.provider.deleteComment(data.document, convertFromComment(comment), CancellationToken.None); + return handlerData.provider.deleteComment(document, convertFromComment(comment), CancellationToken.None); }); } $startDraft(handle: number, uri: UriComponents): Promise { - const data = this._documents.getDocumentData(URI.revive(uri)); - - if (!data || !data.document) { - throw new Error('Unable to retrieve document from URI'); - } + const document = this._documents.getDocument(URI.revive(uri)); const handlerData = this._documentProviders.get(handle); return asPromise(() => { - return handlerData.provider.startDraft(data.document, CancellationToken.None); + return handlerData.provider.startDraft(document, CancellationToken.None); }); } $deleteDraft(handle: number, uri: UriComponents): Promise { - const data = this._documents.getDocumentData(URI.revive(uri)); - - if (!data || !data.document) { - throw new Error('Unable to retrieve document from URI'); - } - + const document = this._documents.getDocument(URI.revive(uri)); const handlerData = this._documentProviders.get(handle); return asPromise(() => { - return handlerData.provider.deleteDraft(data.document, CancellationToken.None); + return handlerData.provider.deleteDraft(document, CancellationToken.None); }); } $finishDraft(handle: number, uri: UriComponents): Promise { - const data = this._documents.getDocumentData(URI.revive(uri)); - - if (!data || !data.document) { - throw new Error('Unable to retrieve document from URI'); - } - + const document = this._documents.getDocument(URI.revive(uri)); const handlerData = this._documentProviders.get(handle); return asPromise(() => { - return handlerData.provider.finishDraft(data.document, CancellationToken.None); + return handlerData.provider.finishDraft(document, CancellationToken.None); }); } $addReaction(handle: number, uri: UriComponents, comment: modes.Comment, reaction: modes.CommentReaction): Promise { - const data = this._documents.getDocumentData(URI.revive(uri)); - - if (!data || !data.document) { - throw new Error('Unable to retrieve document from URI'); - } - + const document = this._documents.getDocument(URI.revive(uri)); const handlerData = this._documentProviders.get(handle); return asPromise(() => { - return handlerData.provider.addReaction(data.document, convertFromComment(comment), reaction); + return handlerData.provider.addReaction(document, convertFromComment(comment), reaction); }); } $deleteReaction(handle: number, uri: UriComponents, comment: modes.Comment, reaction: modes.CommentReaction): Promise { - const data = this._documents.getDocumentData(URI.revive(uri)); - - if (!data || !data.document) { - throw new Error('Unable to retrieve document from URI'); - } - + const document = this._documents.getDocument(URI.revive(uri)); const handlerData = this._documentProviders.get(handle); - return asPromise(() => { - return handlerData.provider.deleteReaction(data.document, convertFromComment(comment), reaction); + return handlerData.provider.deleteReaction(document, convertFromComment(comment), reaction); }); } $provideDocumentComments(handle: number, uri: UriComponents): Promise { - const data = this._documents.getDocumentData(URI.revive(uri)); - if (!data || !data.document) { - return Promise.resolve(null); - } - + const document = this._documents.getDocument(URI.revive(uri)); const handlerData = this._documentProviders.get(handle); return asPromise(() => { - return handlerData.provider.provideDocumentComments(data.document, CancellationToken.None); + return handlerData.provider.provideDocumentComments(document, CancellationToken.None); }).then(commentInfo => commentInfo ? convertCommentInfo(handle, handlerData.extensionId, handlerData.provider, commentInfo, this._commandsConverter) : null); } diff --git a/src/vs/workbench/api/node/extHostDocuments.ts b/src/vs/workbench/api/node/extHostDocuments.ts index e7c6cff941a..5928a917384 100644 --- a/src/vs/workbench/api/node/extHostDocuments.ts +++ b/src/vs/workbench/api/node/extHostDocuments.ts @@ -67,6 +67,14 @@ export class ExtHostDocuments implements ExtHostDocumentsShape { return undefined; } + public getDocument(resource: vscode.Uri): vscode.TextDocument { + const data = this.getDocumentData(resource); + if (!data || !data.document) { + throw new Error('Unable to retrieve document from URI'); + } + return data.document; + } + public ensureDocumentData(uri: URI): Promise { let cached = this._documentsAndEditors.getDocument(uri.toString()); diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index ee1a0622d25..72cb8b1f545 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -40,7 +40,7 @@ class DocumentSymbolAdapter { } provideDocumentSymbols(resource: URI, token: CancellationToken): Promise { - let doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); return asPromise(() => this._provider.provideDocumentSymbols(doc, token)).then(value => { if (isFalsyOrEmpty(value)) { return undefined; @@ -105,7 +105,7 @@ class CodeLensAdapter { ) { } provideCodeLenses(resource: URI, token: CancellationToken): Promise { - const doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); return asPromise(() => this._provider.provideCodeLenses(doc, token)).then(lenses => { let result: CodeLensDto[] = []; @@ -161,7 +161,7 @@ class DefinitionAdapter { ) { } provideDefinition(resource: URI, position: IPosition, token: CancellationToken): Promise { - let doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); let pos = typeConvert.Position.to(position); return asPromise(() => this._provider.provideDefinition(doc, pos, token)).then(convertToLocationLinks); } @@ -175,7 +175,7 @@ class DeclarationAdapter { ) { } provideDeclaration(resource: URI, position: IPosition, token: CancellationToken): Promise { - let doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); let pos = typeConvert.Position.to(position); return asPromise(() => this._provider.provideDeclaration(doc, pos, token)).then(convertToLocationLinks); } @@ -189,7 +189,7 @@ class ImplementationAdapter { ) { } provideImplementation(resource: URI, position: IPosition, token: CancellationToken): Promise { - let doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); let pos = typeConvert.Position.to(position); return asPromise(() => this._provider.provideImplementation(doc, pos, token)).then(convertToLocationLinks); } @@ -203,7 +203,7 @@ class TypeDefinitionAdapter { ) { } provideTypeDefinition(resource: URI, position: IPosition, token: CancellationToken): Promise { - const doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); const pos = typeConvert.Position.to(position); return asPromise(() => this._provider.provideTypeDefinition(doc, pos, token)).then(convertToLocationLinks); } @@ -218,7 +218,7 @@ class HoverAdapter { public provideHover(resource: URI, position: IPosition, token: CancellationToken): Promise { - let doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); let pos = typeConvert.Position.to(position); return asPromise(() => this._provider.provideHover(doc, pos, token)).then(value => { @@ -246,7 +246,7 @@ class DocumentHighlightAdapter { provideDocumentHighlights(resource: URI, position: IPosition, token: CancellationToken): Promise { - let doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); let pos = typeConvert.Position.to(position); return asPromise(() => this._provider.provideDocumentHighlights(doc, pos, token)).then(value => { @@ -266,7 +266,7 @@ class ReferenceAdapter { ) { } provideReferences(resource: URI, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise { - let doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); let pos = typeConvert.Position.to(position); return asPromise(() => this._provider.provideReferences(doc, pos, context, token)).then(value => { @@ -296,7 +296,7 @@ class CodeActionAdapter { provideCodeActions(resource: URI, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise { - const doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); const ran = Selection.isISelection(rangeOrSelection) ? typeConvert.Selection.to(rangeOrSelection) : typeConvert.Range.to(rangeOrSelection); @@ -371,7 +371,7 @@ class DocumentFormattingAdapter { provideDocumentFormattingEdits(resource: URI, options: modes.FormattingOptions, token: CancellationToken): Promise { - const { document } = this._documents.getDocumentData(resource); + const document = this._documents.getDocument(resource); return asPromise(() => this._provider.provideDocumentFormattingEdits(document, options, token)).then(value => { if (Array.isArray(value)) { @@ -391,7 +391,7 @@ class RangeFormattingAdapter { provideDocumentRangeFormattingEdits(resource: URI, range: IRange, options: modes.FormattingOptions, token: CancellationToken): Promise { - const { document } = this._documents.getDocumentData(resource); + const document = this._documents.getDocument(resource); const ran = typeConvert.Range.to(range); return asPromise(() => this._provider.provideDocumentRangeFormattingEdits(document, ran, options, token)).then(value => { @@ -414,7 +414,7 @@ class OnTypeFormattingAdapter { provideOnTypeFormattingEdits(resource: URI, position: IPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise { - const { document } = this._documents.getDocumentData(resource); + const document = this._documents.getDocument(resource); const pos = typeConvert.Position.to(position); return asPromise(() => this._provider.provideOnTypeFormattingEdits(document, pos, ch, options, token)).then(value => { @@ -501,7 +501,7 @@ class RenameAdapter { provideRenameEdits(resource: URI, position: IPosition, newName: string, token: CancellationToken): Promise { - let doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); let pos = typeConvert.Position.to(position); return asPromise(() => this._provider.provideRenameEdits(doc, pos, newName, token)).then(value => { @@ -525,7 +525,7 @@ class RenameAdapter { return Promise.resolve(undefined); } - let doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); let pos = typeConvert.Position.to(position); return asPromise(() => this._provider.prepareRename(doc, pos, token)).then(rangeOrLocation => { @@ -591,7 +591,7 @@ class SuggestAdapter { provideCompletionItems(resource: URI, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise { - const doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); const pos = typeConvert.Position.to(position); return asPromise( @@ -654,7 +654,7 @@ class SuggestAdapter { return suggestion; } - const doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); const pos = typeConvert.Position.to(position); const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) as Range || new Range(pos, pos)).with({ end: pos }); const newSuggestion = this._convertCompletionItem(resolvedItem, pos, wordRangeBeforePos, _id, _parentId); @@ -741,7 +741,7 @@ class SignatureHelpAdapter { ) { } provideSignatureHelp(resource: URI, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise { - const doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); const pos = typeConvert.Position.to(position); const vscodeContext = this.reviveContext(context); @@ -780,7 +780,7 @@ class LinkProviderAdapter { ) { } provideLinks(resource: URI, token: CancellationToken): Promise { - const doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); return asPromise(() => this._provider.provideDocumentLinks(doc, token)).then(links => { if (!Array.isArray(links)) { @@ -824,7 +824,7 @@ class ColorProviderAdapter { ) { } provideColors(resource: URI, token: CancellationToken): Promise { - const doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); return asPromise(() => this._provider.provideDocumentColors(doc, token)).then(colors => { if (!Array.isArray(colors)) { return []; @@ -842,7 +842,7 @@ class ColorProviderAdapter { } provideColorPresentations(resource: URI, raw: IRawColorInfo, token: CancellationToken): Promise { - const document = this._documents.getDocumentData(resource).document; + const document = this._documents.getDocument(resource); const range = typeConvert.Range.to(raw.range); const color = typeConvert.Color.to(raw.color); return asPromise(() => this._provider.provideColorPresentations(color, { document, range }, token)).then(value => { @@ -859,7 +859,7 @@ class FoldingProviderAdapter { ) { } provideFoldingRanges(resource: URI, context: modes.FoldingContext, token: CancellationToken): Promise { - const doc = this._documents.getDocumentData(resource).document; + const doc = this._documents.getDocument(resource); return asPromise(() => this._provider.provideFoldingRanges(doc, context, token)).then(ranges => { if (!Array.isArray(ranges)) { return undefined; From f9687fc5ec93f8820264ec730da4900366c78f9d Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 8 Feb 2019 20:54:53 -0800 Subject: [PATCH 143/207] Strict null work on extHostLanguageFeatures --- src/vs/base/common/types.ts | 2 +- src/vs/vscode.d.ts | 2 +- .../mainThreadLanguageFeatures.ts | 4 +- src/vs/workbench/api/node/extHost.protocol.ts | 30 ++--- src/vs/workbench/api/node/extHostCommands.ts | 12 +- .../workbench/api/node/extHostDocumentData.ts | 2 +- src/vs/workbench/api/node/extHostDocuments.ts | 2 +- .../api/node/extHostDocumentsAndEditors.ts | 8 +- .../api/node/extHostLanguageFeatures.ts | 126 ++++++++++-------- .../api/node/extHostTypeConverters.ts | 4 +- src/vs/workbench/api/node/extHostTypes.ts | 4 +- 11 files changed, 106 insertions(+), 90 deletions(-) diff --git a/src/vs/base/common/types.ts b/src/vs/base/common/types.ts index ad873be97b1..9dbae8ce1e2 100644 --- a/src/vs/base/common/types.ts +++ b/src/vs/base/common/types.ts @@ -49,7 +49,7 @@ export function isStringArray(value: any): value is string[] { * @returns whether the provided parameter is of type `object` but **not** * `null`, an `array`, a `regexp`, nor a `date`. */ -export function isObject(obj: any): boolean { +export function isObject(obj: any): obj is Object { // The method can't do a type cast since there are type (like strings) which // are subclasses of any put not positvely matched by the function. Hence type // narrowing results in wrong results. diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 7fa1945c4b2..ebaf0431533 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2019,7 +2019,7 @@ declare module 'vscode' { /** * String value of the kind, e.g. `"refactor.extract.function"`. */ - readonly value?: string; + readonly value: string; /** * Create a new kind by appending a more specific selector to the current kind. diff --git a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts index 7a88d4dee39..009f0323c6e 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts @@ -111,7 +111,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha $registerDocumentSymbolProvider(handle: number, selector: ISerializedDocumentFilter[], displayName: string): void { this._registrations[handle] = modes.DocumentSymbolProviderRegistry.register(typeConverters.LanguageSelector.from(selector), { displayName, - provideDocumentSymbols: (model: ITextModel, token: CancellationToken): Promise => { + provideDocumentSymbols: (model: ITextModel, token: CancellationToken): Promise => { return this._proxy.$provideDocumentSymbols(handle, model.uri, token); } }); @@ -119,7 +119,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha // --- code lens - $registerCodeLensSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number): void { + $registerCodeLensSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number | undefined): void { const provider = { provideCodeLenses: (model: ITextModel, token: CancellationToken): modes.ICodeLensSymbol[] | Promise => { diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index a2883df2540..c64f2d0d430 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -298,7 +298,7 @@ export interface ISerializedSignatureHelpProviderMetadata { export interface MainThreadLanguageFeaturesShape extends IDisposable { $unregister(handle: number): void; $registerDocumentSymbolProvider(handle: number, selector: ISerializedDocumentFilter[], label: string): void; - $registerCodeLensSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number): void; + $registerCodeLensSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number | undefined): void; $emitCodeLensEvent(eventHandle: number, event?: any): void; $registerDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void; $registerDeclarationSupport(handle: number, selector: ISerializedDocumentFilter[]): void; @@ -893,31 +893,31 @@ export interface CodeLensDto extends ObjectIdentifier { } export interface ExtHostLanguageFeaturesShape { - $provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise; + $provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise; $provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise; $resolveCodeLens(handle: number, resource: UriComponents, symbol: CodeLensDto, token: CancellationToken): Promise; $provideDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; $provideDeclaration(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; $provideImplementation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; $provideTypeDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; - $provideHover(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; - $provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; - $provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise; - $provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise; - $provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: modes.FormattingOptions, token: CancellationToken): Promise; - $provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: modes.FormattingOptions, token: CancellationToken): Promise; - $provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise; + $provideHover(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; + $provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; + $provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise; + $provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise; + $provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: modes.FormattingOptions, token: CancellationToken): Promise; + $provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: modes.FormattingOptions, token: CancellationToken): Promise; + $provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise; $provideWorkspaceSymbols(handle: number, search: string, token: CancellationToken): Promise; - $resolveWorkspaceSymbol(handle: number, symbol: WorkspaceSymbolDto, token: CancellationToken): Promise; + $resolveWorkspaceSymbol(handle: number, symbol: WorkspaceSymbolDto, token: CancellationToken): Promise; $releaseWorkspaceSymbols(handle: number, id: number): void; - $provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Promise; - $resolveRenameLocation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; + $provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Promise; + $resolveRenameLocation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; $provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise; $resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, suggestion: modes.CompletionItem, token: CancellationToken): Promise; $releaseCompletionItems(handle: number, id: number): void; - $provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise; - $provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise; - $resolveDocumentLink(handle: number, link: LinkDto, token: CancellationToken): Promise; + $provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise; + $provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise; + $resolveDocumentLink(handle: number, link: LinkDto, token: CancellationToken): Promise; $provideDocumentColors(handle: number, resource: UriComponents, token: CancellationToken): Promise; $provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Promise; $provideFoldingRanges(handle: number, resource: UriComponents, context: modes.FoldingContext, token: CancellationToken): Promise; diff --git a/src/vs/workbench/api/node/extHostCommands.ts b/src/vs/workbench/api/node/extHostCommands.ts index 8b73f059351..cc707471087 100644 --- a/src/vs/workbench/api/node/extHostCommands.ts +++ b/src/vs/workbench/api/node/extHostCommands.ts @@ -138,7 +138,11 @@ export class ExtHostCommands implements ExtHostCommandsShape { } private _executeContributedCommand(id: string, args: any[]): Promise { - let { callback, thisArg, description } = this._commands.get(id); + const command = this._commands.get(id); + if (!command) { + throw new Error('Unknown command'); + } + let { callback, thisArg, description } = command; if (description) { for (let i = 0; i < description.args.length; i++) { try { @@ -207,7 +211,7 @@ export class CommandsConverter { this._commands.registerCommand(true, this._delegatingCommandId, this._executeConvertedCommand, this); } - toInternal(command: vscode.Command): CommandDto { + toInternal(command: vscode.Command | undefined): CommandDto | undefined { if (!command) { return undefined; @@ -237,7 +241,7 @@ export class CommandsConverter { return result; } - fromInternal(command: modes.Command): vscode.Command { + fromInternal(command: modes.Command | undefined): vscode.Command | undefined { if (!command) { return undefined; @@ -258,7 +262,7 @@ export class CommandsConverter { private _executeConvertedCommand(...args: any[]): Promise { const actualCmd = this._heap.get(args[0]); - return this._commands.executeCommand(actualCmd.command, ...actualCmd.arguments); + return this._commands.executeCommand(actualCmd.command, ...(actualCmd.arguments || [])); } } diff --git a/src/vs/workbench/api/node/extHostDocumentData.ts b/src/vs/workbench/api/node/extHostDocumentData.ts index d659a17e676..c05dbb6855d 100644 --- a/src/vs/workbench/api/node/extHostDocumentData.ts +++ b/src/vs/workbench/api/node/extHostDocumentData.ts @@ -14,7 +14,7 @@ import { EndOfLine, Position, Range } from 'vs/workbench/api/node/extHostTypes'; import * as vscode from 'vscode'; const _modeId2WordDefinition = new Map(); -export function setWordDefinitionFor(modeId: string, wordDefinition: RegExp): void { +export function setWordDefinitionFor(modeId: string, wordDefinition: RegExp | undefined): void { _modeId2WordDefinition.set(modeId, wordDefinition); } export function getWordDefinitionFor(modeId: string): RegExp | undefined { diff --git a/src/vs/workbench/api/node/extHostDocuments.ts b/src/vs/workbench/api/node/extHostDocuments.ts index 5928a917384..dfc39581f84 100644 --- a/src/vs/workbench/api/node/extHostDocuments.ts +++ b/src/vs/workbench/api/node/extHostDocuments.ts @@ -151,7 +151,7 @@ export class ExtHostDocuments implements ExtHostDocumentsShape { }); } - public setWordDefinitionFor(modeId: string, wordDefinition: RegExp): void { + public setWordDefinitionFor(modeId: string, wordDefinition: RegExp | undefined): void { setWordDefinitionFor(modeId, wordDefinition); } } diff --git a/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts b/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts index bee6279e748..1cf6b396280 100644 --- a/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts +++ b/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts @@ -52,7 +52,9 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha const id = uri.toString(); const data = this._documents.get(id); this._documents.delete(id); - removedDocuments.push(data); + if (data) { + removedDocuments.push(data); + } } } @@ -79,7 +81,9 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha for (const id of delta.removedEditors) { const editor = this._editors.get(id); this._editors.delete(id); - removedEditors.push(editor); + if (editor) { + removedEditors.push(editor); + } } } diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 72cb8b1f545..9a1f33723b3 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -39,12 +39,12 @@ class DocumentSymbolAdapter { this._provider = provider; } - provideDocumentSymbols(resource: URI, token: CancellationToken): Promise { + provideDocumentSymbols(resource: URI, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); return asPromise(() => this._provider.provideDocumentSymbols(doc, token)).then(value => { if (isFalsyOrEmpty(value)) { return undefined; - } else if (value[0] instanceof DocumentSymbol) { + } else if (value![0] instanceof DocumentSymbol) { return (value).map(typeConvert.DocumentSymbol.from); } else { return DocumentSymbolAdapter._asDocumentSymbolTree(value); @@ -122,18 +122,18 @@ class CodeLensAdapter { }); } - resolveCodeLens(resource: URI, symbol: CodeLensDto, token: CancellationToken): Promise { + resolveCodeLens(resource: URI, symbol: CodeLensDto, token: CancellationToken): Promise { const lens = this._heapService.get(ObjectIdentifier.of(symbol)); if (!lens) { - return undefined; + return Promise.resolve(undefined); } - let resolve: Promise; + let resolve: Promise; if (typeof this._provider.resolveCodeLens !== 'function' || lens.isResolved) { resolve = Promise.resolve(lens); } else { - resolve = asPromise(() => this._provider.resolveCodeLens(lens, token)); + resolve = asPromise(() => this._provider.resolveCodeLens!(lens, token)); } return resolve.then(newLens => { @@ -150,7 +150,7 @@ function convertToLocationLinks(value: vscode.Definition): modes.LocationLink[] } else if (value) { return [typeConvert.DefinitionLink.from(value)]; } - return undefined; + return []; } class DefinitionAdapter { @@ -216,7 +216,7 @@ class HoverAdapter { private readonly _provider: vscode.HoverProvider, ) { } - public provideHover(resource: URI, position: IPosition, token: CancellationToken): Promise { + public provideHover(resource: URI, position: IPosition, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); let pos = typeConvert.Position.to(position); @@ -244,7 +244,7 @@ class DocumentHighlightAdapter { private readonly _provider: vscode.DocumentHighlightProvider ) { } - provideDocumentHighlights(resource: URI, position: IPosition, token: CancellationToken): Promise { + provideDocumentHighlights(resource: URI, position: IPosition, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); let pos = typeConvert.Position.to(position); @@ -265,7 +265,7 @@ class ReferenceAdapter { private readonly _provider: vscode.ReferenceProvider ) { } - provideReferences(resource: URI, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise { + provideReferences(resource: URI, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); let pos = typeConvert.Position.to(position); @@ -294,7 +294,7 @@ class CodeActionAdapter { private readonly _extensionId: ExtensionIdentifier ) { } - provideCodeActions(resource: URI, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise { + provideCodeActions(resource: URI, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); const ran = Selection.isISelection(rangeOrSelection) @@ -317,7 +317,7 @@ class CodeActionAdapter { }; return asPromise(() => this._provider.provideCodeActions(doc, ran, codeActionContext, token)).then(commandsOrActions => { - if (isFalsyOrEmpty(commandsOrActions)) { + if (!isNonEmptyArray(commandsOrActions)) { return undefined; } const result: CustomCodeAction[] = []; @@ -369,7 +369,7 @@ class DocumentFormattingAdapter { private readonly _provider: vscode.DocumentFormattingEditProvider ) { } - provideDocumentFormattingEdits(resource: URI, options: modes.FormattingOptions, token: CancellationToken): Promise { + provideDocumentFormattingEdits(resource: URI, options: modes.FormattingOptions, token: CancellationToken): Promise { const document = this._documents.getDocument(resource); @@ -389,7 +389,7 @@ class RangeFormattingAdapter { private readonly _provider: vscode.DocumentRangeFormattingEditProvider ) { } - provideDocumentRangeFormattingEdits(resource: URI, range: IRange, options: modes.FormattingOptions, token: CancellationToken): Promise { + provideDocumentRangeFormattingEdits(resource: URI, range: IRange, options: modes.FormattingOptions, token: CancellationToken): Promise { const document = this._documents.getDocument(resource); const ran = typeConvert.Range.to(range); @@ -412,7 +412,7 @@ class OnTypeFormattingAdapter { autoFormatTriggerCharacters: string[] = []; // not here - provideOnTypeFormattingEdits(resource: URI, position: IPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise { + provideOnTypeFormattingEdits(resource: URI, position: IPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise { const document = this._documents.getDocument(resource); const pos = typeConvert.Position.to(position); @@ -450,7 +450,7 @@ class NavigateTypeAdapter { continue; } const symbol = IdObject.mixin(typeConvert.WorkspaceSymbol.from(item)); - this._symbolCache[symbol._id] = item; + this._symbolCache[symbol._id!] = item; result.symbols.push(symbol); } } @@ -462,19 +462,19 @@ class NavigateTypeAdapter { }); } - resolveWorkspaceSymbol(symbol: WorkspaceSymbolDto, token: CancellationToken): Promise { + resolveWorkspaceSymbol(symbol: WorkspaceSymbolDto, token: CancellationToken): Promise { if (typeof this._provider.resolveWorkspaceSymbol !== 'function') { return Promise.resolve(symbol); } - const item = this._symbolCache[symbol._id]; + const item = this._symbolCache[symbol._id!]; if (item) { - return asPromise(() => this._provider.resolveWorkspaceSymbol(item, token)).then(value => { + return asPromise(() => this._provider.resolveWorkspaceSymbol!(item, token)).then(value => { return value && mixin(symbol, typeConvert.WorkspaceSymbol.from(value), true); }); } - return undefined; + return Promise.resolve(undefined); } releaseWorkspaceSymbols(id: number): any { @@ -512,7 +512,7 @@ class RenameAdapter { }, err => { let rejectReason = RenameAdapter._asMessage(err); if (rejectReason) { - return { rejectReason, edits: undefined }; + return { rejectReason, edits: undefined! }; } else { // generic error return Promise.reject(err); @@ -552,14 +552,14 @@ class RenameAdapter { }, err => { let rejectReason = RenameAdapter._asMessage(err); if (rejectReason) { - return { rejectReason, range: undefined, text: undefined }; + return { rejectReason, range: undefined!, text: undefined! }; } else { return Promise.reject(err); } }); } - private static _asMessage(err: any): string { + private static _asMessage(err: any): string | undefined { if (typeof err === 'string') { return err; } else if (err instanceof Error && typeof err.message === 'string') { @@ -643,12 +643,12 @@ class SuggestAdapter { } const { _parentId, _id } = (suggestion); - const item = this._cache.has(_parentId) && this._cache.get(_parentId)[_id]; + const item = this._cache.has(_parentId) ? this._cache.get(_parentId)![_id] : undefined; if (!item) { return Promise.resolve(suggestion); } - return asPromise(() => this._provider.resolveCompletionItem(item, token)).then(resolvedItem => { + return asPromise(() => this._provider.resolveCompletionItem!(item, token)).then(resolvedItem => { if (!resolvedItem) { return suggestion; @@ -684,7 +684,7 @@ class SuggestAdapter { label: item.label, kind: typeConvert.CompletionItemKind.from(item.kind), detail: item.detail, - documentation: typeConvert.MarkdownString.fromStrict(item.documentation), + documentation: typeof item.documentation === 'undefined' ? undefined : typeConvert.MarkdownString.fromStrict(item.documentation), filterText: item.filterText, sortText: item.sortText, preselect: item.preselect, @@ -740,7 +740,7 @@ class SignatureHelpAdapter { private readonly _heap: ExtHostHeapService, ) { } - provideSignatureHelp(resource: URI, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise { + provideSignatureHelp(resource: URI, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); const pos = typeConvert.Position.to(position); const vscodeContext = this.reviveContext(context); @@ -779,7 +779,7 @@ class LinkProviderAdapter { private readonly _provider: vscode.DocumentLinkProvider ) { } - provideLinks(resource: URI, token: CancellationToken): Promise { + provideLinks(resource: URI, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); return asPromise(() => this._provider.provideDocumentLinks(doc, token)).then(links => { @@ -796,18 +796,18 @@ class LinkProviderAdapter { }); } - resolveLink(link: LinkDto, token: CancellationToken): Promise { + resolveLink(link: LinkDto, token: CancellationToken): Promise { if (typeof this._provider.resolveDocumentLink !== 'function') { - return undefined; + return Promise.resolve(undefined); } const id = ObjectIdentifier.of(link); const item = this._heapService.get(id); if (!item) { - return undefined; + return Promise.resolve(undefined); } - return asPromise(() => this._provider.resolveDocumentLink(item, token)).then(value => { + return asPromise(() => this._provider.resolveDocumentLink!(item, token)).then(value => { if (value) { return typeConvert.DocumentLink.from(value); } @@ -841,11 +841,14 @@ class ColorProviderAdapter { }); } - provideColorPresentations(resource: URI, raw: IRawColorInfo, token: CancellationToken): Promise { + provideColorPresentations(resource: URI, raw: IRawColorInfo, token: CancellationToken): Promise { const document = this._documents.getDocument(resource); const range = typeConvert.Range.to(raw.range); const color = typeConvert.Color.to(raw.color); return asPromise(() => this._provider.provideColorPresentations(color, { document, range }, token)).then(value => { + if (!Array.isArray(value)) { + return undefined; + } return value.map(typeConvert.ColorPresentation.from); }); } @@ -858,7 +861,7 @@ class FoldingProviderAdapter { private _provider: vscode.FoldingRangeProvider ) { } - provideFoldingRanges(resource: URI, context: modes.FoldingContext, token: CancellationToken): Promise { + provideFoldingRanges(resource: URI, context: modes.FoldingContext, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); return asPromise(() => this._provider.provideFoldingRanges(doc, context, token)).then(ranges => { if (!Array.isArray(ranges)) { @@ -965,7 +968,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return [this._doTransformDocumentSelector(selector)]; } - private _doTransformDocumentSelector(selector: string | vscode.DocumentFilter): ISerializedDocumentFilter { + private _doTransformDocumentSelector(selector: string | vscode.DocumentFilter): ISerializedDocumentFilter | undefined { if (typeof selector === 'string') { return { $serialized: true, @@ -1005,7 +1008,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { } private _withAdapter(handle: number, ctor: { new(...args: any[]): A }, callback: (adapter: A) => Promise): Promise { - let data = this._adapter.get(handle); + const data = this._adapter.get(handle); + if (!data) { + return Promise.reject(new Error('no adapter found')); + } + if (data.adapter instanceof ctor) { let t1: number; if (data.extension) { @@ -1013,11 +1020,12 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { this._logService.trace(`[${data.extension.identifier.value}] INVOKE provider '${(ctor as any).name}'`); } let p = callback(data.adapter); - if (data.extension) { + const extension = data.extension; + if (extension) { Promise.resolve(p).then( - () => this._logService.trace(`[${data.extension.identifier.value}] provider DONE after ${Date.now() - t1}ms`), + () => this._logService.trace(`[${extension.identifier.value}] provider DONE after ${Date.now() - t1}ms`), err => { - this._logService.error(`[${data.extension.identifier.value}] provider FAILED`); + this._logService.error(`[${extension.identifier.value}] provider FAILED`); this._logService.error(err); } ); @@ -1046,7 +1054,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise { + $provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise { return this._withAdapter(handle, DocumentSymbolAdapter, adapter => adapter.provideDocumentSymbols(URI.revive(resource), token)); } @@ -1061,7 +1069,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { let result = this._createDisposable(handle); if (eventHandle !== undefined) { - const subscription = provider.onDidChangeCodeLenses(_ => this._proxy.$emitCodeLensEvent(eventHandle)); + const subscription = provider.onDidChangeCodeLenses!(_ => this._proxy.$emitCodeLensEvent(eventHandle)); result = Disposable.from(result, subscription); } @@ -1126,7 +1134,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideHover(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise { + $provideHover(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise { return this._withAdapter(handle, HoverAdapter, adapter => adapter.provideHover(URI.revive(resource), position, token)); } @@ -1138,7 +1146,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise { + $provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise { return this._withAdapter(handle, DocumentHighlightAdapter, adapter => adapter.provideDocumentHighlights(URI.revive(resource), position, token)); } @@ -1150,7 +1158,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise { + $provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise { return this._withAdapter(handle, ReferenceAdapter, adapter => adapter.provideReferences(URI.revive(resource), position, context, token)); } @@ -1158,12 +1166,12 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { registerCodeActionProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider, metadata?: vscode.CodeActionProviderMetadata): vscode.Disposable { const handle = this._addNewAdapter(new CodeActionAdapter(this._documents, this._commands.converter, this._diagnostics, provider, this._logService, extension.identifier), extension); - this._proxy.$registerQuickFixSupport(handle, this._transformDocumentSelector(selector), metadata && metadata.providedCodeActionKinds ? metadata.providedCodeActionKinds.map(kind => kind.value) : undefined); + this._proxy.$registerQuickFixSupport(handle, this._transformDocumentSelector(selector), (metadata && metadata.providedCodeActionKinds) ? metadata.providedCodeActionKinds.map(kind => kind.value) : undefined); return this._createDisposable(handle); } - $provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise { + $provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise { return this._withAdapter(handle, CodeActionAdapter, adapter => adapter.provideCodeActions(URI.revive(resource), rangeOrSelection, context, token)); } @@ -1175,7 +1183,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: modes.FormattingOptions, token: CancellationToken): Promise { + $provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: modes.FormattingOptions, token: CancellationToken): Promise { return this._withAdapter(handle, DocumentFormattingAdapter, adapter => adapter.provideDocumentFormattingEdits(URI.revive(resource), options, token)); } @@ -1185,7 +1193,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: modes.FormattingOptions, token: CancellationToken): Promise { + $provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: modes.FormattingOptions, token: CancellationToken): Promise { return this._withAdapter(handle, RangeFormattingAdapter, adapter => adapter.provideDocumentRangeFormattingEdits(URI.revive(resource), range, options, token)); } @@ -1195,7 +1203,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise { + $provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise { return this._withAdapter(handle, OnTypeFormattingAdapter, adapter => adapter.provideOnTypeFormattingEdits(URI.revive(resource), position, ch, options, token)); } @@ -1211,7 +1219,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.provideWorkspaceSymbols(search, token)); } - $resolveWorkspaceSymbol(handle: number, symbol: WorkspaceSymbolDto, token: CancellationToken): Promise { + $resolveWorkspaceSymbol(handle: number, symbol: WorkspaceSymbolDto, token: CancellationToken): Promise { return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.resolveWorkspaceSymbol(symbol, token)); } @@ -1227,11 +1235,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Promise { + $provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Promise { return this._withAdapter(handle, RenameAdapter, adapter => adapter.provideRenameEdits(URI.revive(resource), position, newName, token)); } - $resolveRenameLocation(handle: number, resource: URI, position: IPosition, token: CancellationToken): Promise { + $resolveRenameLocation(handle: number, resource: URI, position: IPosition, token: CancellationToken): Promise { return this._withAdapter(handle, RenameAdapter, adapter => adapter.resolveRenameLocation(URI.revive(resource), position, token)); } @@ -1257,8 +1265,8 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { // --- parameter hints - registerSignatureHelpProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, metadataOrTriggerChars?: string[] | vscode.SignatureHelpProviderMetadata): vscode.Disposable { - const metadata: ISerializedSignatureHelpProviderMetadata = Array.isArray(metadataOrTriggerChars) + registerSignatureHelpProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, metadataOrTriggerChars: string[] | vscode.SignatureHelpProviderMetadata): vscode.Disposable { + const metadata: ISerializedSignatureHelpProviderMetadata | undefined = Array.isArray(metadataOrTriggerChars) ? { triggerCharacters: metadataOrTriggerChars, retriggerCharacters: [] } : metadataOrTriggerChars; @@ -1267,7 +1275,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise { + $provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise { return this._withAdapter(handle, SignatureHelpAdapter, adapter => adapter.provideSignatureHelp(URI.revive(resource), position, context, token)); } @@ -1279,11 +1287,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return this._createDisposable(handle); } - $provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise { + $provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise { return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.provideLinks(URI.revive(resource), token)); } - $resolveDocumentLink(handle: number, link: modes.ILink, token: CancellationToken): Promise { + $resolveDocumentLink(handle: number, link: modes.ILink, token: CancellationToken): Promise { return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.resolveLink(link, token)); } @@ -1362,7 +1370,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { }; } - private static _serializeOnEnterRules(onEnterRules: vscode.OnEnterRule[]): ISerializedOnEnterRule[] { + private static _serializeOnEnterRules(onEnterRules: vscode.OnEnterRule[]): ISerializedOnEnterRule[] | undefined | null { if (typeof onEnterRules === 'undefined') { return undefined; } @@ -1384,7 +1392,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { if (wordPattern) { this._documents.setWordDefinitionFor(languageId, wordPattern); } else { - this._documents.setWordDefinitionFor(languageId, null); + this._documents.setWordDefinitionFor(languageId, undefined); } const handle = this._nextHandle(); diff --git a/src/vs/workbench/api/node/extHostTypeConverters.ts b/src/vs/workbench/api/node/extHostTypeConverters.ts index 83786a14276..cfe6b70e50f 100644 --- a/src/vs/workbench/api/node/extHostTypeConverters.ts +++ b/src/vs/workbench/api/node/extHostTypeConverters.ts @@ -659,7 +659,7 @@ export namespace CompletionContext { export namespace CompletionItemKind { - export function from(kind: types.CompletionItemKind): modes.CompletionItemKind { + export function from(kind: types.CompletionItemKind | undefined): modes.CompletionItemKind { switch (kind) { case types.CompletionItemKind.Method: return modes.CompletionItemKind.Method; case types.CompletionItemKind.Function: return modes.CompletionItemKind.Function; @@ -812,7 +812,7 @@ export namespace DocumentLink { } export function to(link: modes.ILink): vscode.DocumentLink { - return new types.DocumentLink(Range.to(link.range), link.url && URI.parse(link.url)); + return new types.DocumentLink(Range.to(link.range), link.url ? URI.parse(link.url) : undefined); } } diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index f9d1658215e..6fd5b4064d4 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -1365,9 +1365,9 @@ export class DocumentLink { range: Range; - target: URI; + target?: URI; - constructor(range: Range, target: URI) { + constructor(range: Range, target: URI | undefined) { if (target && !(target instanceof URI)) { throw illegalArgument('target'); } From 6d973fef893ca8bd8be8354ab02edbb2f90f55ce Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Sun, 10 Feb 2019 10:42:46 -0800 Subject: [PATCH 144/207] Strict null work on main thread --- .../browser/services/bulkEditService.ts | 2 +- .../standalone/browser/simpleServices.ts | 2 +- src/vs/platform/files/common/files.ts | 2 +- .../electron-browser/mainThreadDecorations.ts | 12 ++++++---- .../electron-browser/mainThreadDocuments.ts | 4 ++-- .../mainThreadDocumentsAndEditors.ts | 24 +++++++++---------- .../api/electron-browser/mainThreadEditor.ts | 7 +++--- .../api/electron-browser/mainThreadEditors.ts | 8 +++---- .../mainThreadLanguageFeatures.ts | 14 +++++------ .../electron-browser/mainThreadTreeViews.ts | 7 ++++-- .../api/electron-browser/mainThreadWebview.ts | 12 +++++----- .../api/node/extHostTypeConverters.ts | 9 ++++--- src/vs/workbench/api/node/extHostTypes.ts | 4 ++-- .../browser/parts/editor/resourceViewer.ts | 2 +- .../common/editor/binaryEditorModel.ts | 4 ++-- .../decorations/browser/decorations.ts | 2 +- .../decorations/browser/decorationsService.ts | 2 +- .../electron-browser/extensionService.ts | 10 ++++---- .../node/extensionDescriptionRegistry.ts | 4 ++-- 19 files changed, 70 insertions(+), 61 deletions(-) diff --git a/src/vs/editor/browser/services/bulkEditService.ts b/src/vs/editor/browser/services/bulkEditService.ts index 33927be7765..9411568fc79 100644 --- a/src/vs/editor/browser/services/bulkEditService.ts +++ b/src/vs/editor/browser/services/bulkEditService.ts @@ -23,6 +23,6 @@ export interface IBulkEditResult { export interface IBulkEditService { _serviceBrand: any; - apply(edit: WorkspaceEdit, options: IBulkEditOptions): Promise; + apply(edit: WorkspaceEdit, options?: IBulkEditOptions): Promise; } diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index e92924064ef..5ef55afae51 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -576,7 +576,7 @@ export class SimpleBulkEditService implements IBulkEditService { // } - apply(workspaceEdit: WorkspaceEdit, options: IBulkEditOptions): Promise { + apply(workspaceEdit: WorkspaceEdit, options?: IBulkEditOptions): Promise { let edits = new Map(); diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index fce0e320b86..9797cae2147 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -419,7 +419,7 @@ export interface IBaseStat { * A unique identifier thet represents the * current state of the file or directory. */ - etag: string; + etag?: string; /** * The resource is readonly. diff --git a/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts b/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts index 37cd9749381..8847d97283a 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDecorations.ts @@ -109,13 +109,17 @@ export class MainThreadDecorations implements MainThreadDecorationsShape { } $onDidChange(handle: number, resources: UriComponents[]): void { - const [emitter] = this._provider.get(handle); - emitter.fire(resources && resources.map(URI.revive)); + const provider = this._provider.get(handle); + if (provider) { + const [emitter] = provider; + emitter.fire(resources && resources.map(URI.revive)); + } } $unregisterDecorationProvider(handle: number): void { - if (this._provider.has(handle)) { - dispose(this._provider.get(handle)); + const provider = this._provider.get(handle); + if (provider) { + dispose(provider); this._provider.delete(handle); } } diff --git a/src/vs/workbench/api/electron-browser/mainThreadDocuments.ts b/src/vs/workbench/api/electron-browser/mainThreadDocuments.ts index 325d34af088..7780708d837 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDocuments.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDocuments.ts @@ -130,14 +130,14 @@ export class MainThreadDocuments implements MainThreadDocumentsShape { private _shouldHandleFileEvent(e: TextFileModelChangeEvent): boolean { const model = this._modelService.getModel(e.resource); - return model && shouldSynchronizeModel(model); + return !!model && shouldSynchronizeModel(model); } private _onModelAdded(model: ITextModel): void { // Same filter as in mainThreadEditorsTracker if (!shouldSynchronizeModel(model)) { // don't synchronize too large models - return null; + return; } let modelUrl = model.uri; this._modelIsSynced[modelUrl.toString()] = true; diff --git a/src/vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors.ts b/src/vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors.ts index 1a51bf7f504..63273dd9aba 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors.ts @@ -7,7 +7,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { IDisposable, combinedDisposable, dispose } from 'vs/base/common/lifecycle'; import { values } from 'vs/base/common/map'; import { URI } from 'vs/base/common/uri'; -import { ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor, isCodeEditor, isDiffEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IEditor } from 'vs/editor/common/editorCommon'; @@ -70,7 +70,7 @@ class TextEditorSnapshot { readonly id: string; constructor( - readonly editor: ICodeEditor, + readonly editor: IActiveCodeEditor, ) { this.id = `${editor.getId()},${editor.getModel().id}`; } @@ -85,8 +85,8 @@ class DocumentAndEditorStateDelta { readonly addedDocuments: ITextModel[], readonly removedEditors: TextEditorSnapshot[], readonly addedEditors: TextEditorSnapshot[], - readonly oldActiveEditor: string, - readonly newActiveEditor: string, + readonly oldActiveEditor: string | undefined, + readonly newActiveEditor: string | undefined, ) { this.isEmpty = this.removedDocuments.length === 0 && this.addedDocuments.length === 0 @@ -131,7 +131,7 @@ class DocumentAndEditorState { constructor( readonly documents: Set, readonly textEditors: Map, - readonly activeEditor: string, + readonly activeEditor: string | undefined, ) { // } @@ -230,14 +230,14 @@ class MainThreadDocumentAndEditorStateComputer { // editor: only take those that have a not too large model const editors = new Map(); - let activeEditor: string | null = null; + let activeEditor: string | undefined = undefined; for (const editor of this._codeEditorService.listCodeEditors()) { if (editor.isSimpleWidget) { continue; } const model = editor.getModel(); - if (model && shouldSynchronizeModel(model) + if (editor.hasModel() && model && shouldSynchronizeModel(model) && !model.isDisposed() // model disposed && Boolean(this._modelService.getModel(model.uri)) // model disposing, the flag didn't flip yet but the model service already removed it ) { @@ -282,7 +282,7 @@ class MainThreadDocumentAndEditorStateComputer { } } - private _getActiveEditorFromPanel(): IEditor { + private _getActiveEditorFromPanel(): IEditor | undefined { let panel = this._panelService.getActivePanel(); if (panel instanceof BaseTextEditor && isCodeEditor(panel.getControl())) { return panel.getControl(); @@ -444,8 +444,8 @@ export class MainThreadDocumentsAndEditors { }; } - private _findEditorPosition(editor: MainThreadTextEditor): EditorViewColumn { - for (let workbenchEditor of this._editorService.visibleControls) { + private _findEditorPosition(editor: MainThreadTextEditor): EditorViewColumn | undefined { + for (const workbenchEditor of this._editorService.visibleControls) { if (editor.matches(workbenchEditor)) { return editorGroupToViewColumn(this._editorGroupService, workbenchEditor.group); } @@ -453,8 +453,8 @@ export class MainThreadDocumentsAndEditors { return undefined; } - findTextEditorIdFor(editor: IWorkbenchEditor): string { - for (let id in this._textEditors) { + findTextEditorIdFor(editor: IWorkbenchEditor): string | undefined { + for (const id in this._textEditors) { if (this._textEditors[id].matches(editor)) { return id; } diff --git a/src/vs/workbench/api/electron-browser/mainThreadEditor.ts b/src/vs/workbench/api/electron-browser/mainThreadEditor.ts index a5f9775cb68..672b53ed6b9 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadEditor.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadEditor.ts @@ -187,7 +187,7 @@ export class MainThreadTextEditor { private _focusTracker: IFocusTracker; private _codeEditorListeners: IDisposable[]; - private _properties: MainThreadTextEditorProperties | null; + private _properties: MainThreadTextEditorProperties; private readonly _onPropertiesChanged: Emitter; constructor( @@ -204,7 +204,6 @@ export class MainThreadTextEditor { this._modelService = modelService; this._codeEditorListeners = []; - this._properties = null; this._onPropertiesChanged = new Emitter(); this._modelListeners = []; @@ -300,7 +299,7 @@ export class MainThreadTextEditor { return !!this._codeEditor; } - public getProperties(): MainThreadTextEditorProperties | null { + public getProperties(): MainThreadTextEditorProperties { return this._properties; } @@ -316,7 +315,7 @@ export class MainThreadTextEditor { const newSelections = selections.map(Selection.liftSelection); this._setProperties( - new MainThreadTextEditorProperties(newSelections, this._properties!.options, this._properties!.visibleRanges), + new MainThreadTextEditorProperties(newSelections, this._properties.options, this._properties.visibleRanges), null ); } diff --git a/src/vs/workbench/api/electron-browser/mainThreadEditors.ts b/src/vs/workbench/api/electron-browser/mainThreadEditors.ts index d35dda26fd8..1f9bff1a2cb 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadEditors.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadEditors.ts @@ -36,7 +36,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { private _documentsAndEditors: MainThreadDocumentsAndEditors; private _toDispose: IDisposable[]; private _textEditorsListenersMap: { [editorId: string]: IDisposable[]; }; - private _editorPositionData: ITextEditorPositionData; + private _editorPositionData: ITextEditorPositionData | null; private _registeredDecorationTypes: { [decorationType: string]: boolean; }; constructor( @@ -145,7 +145,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { options: { preserveFocus: false } }, viewColumnToEditorGroup(this._editorGroupService, position)).then(() => { return; }); } - return undefined; + return Promise.resolve(); } $tryHideEditor(id: string): Promise { @@ -158,7 +158,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { } } } - return undefined; + return Promise.resolve(); } $trySetSelections(id: string, selections: ISelection[]): Promise { @@ -192,7 +192,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { return Promise.reject(disposed(`TextEditor(${id})`)); } this._documentsAndEditors.getEditor(id).revealRange(range, revealType); - return undefined; + return Promise.resolve(); } $trySetOptions(id: string, options: ITextEditorConfigurationUpdate): Promise { diff --git a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts index 009f0323c6e..48f55cbce28 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts @@ -198,7 +198,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha $registerHoverProvider(handle: number, selector: ISerializedDocumentFilter[]): void { this._registrations[handle] = modes.HoverProviderRegistry.register(typeConverters.LanguageSelector.from(selector), { - provideHover: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise => { + provideHover: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise => { return this._proxy.$provideHover(handle, model.uri, position, token); } }); @@ -208,7 +208,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha $registerDocumentHighlightProvider(handle: number, selector: ISerializedDocumentFilter[]): void { this._registrations[handle] = modes.DocumentHighlightProviderRegistry.register(typeConverters.LanguageSelector.from(selector), { - provideDocumentHighlights: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise => { + provideDocumentHighlights: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise => { return this._proxy.$provideDocumentHighlights(handle, model.uri, position, token); } }); @@ -243,7 +243,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha $registerDocumentFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], displayName: string): void { this._registrations[handle] = modes.DocumentFormattingEditProviderRegistry.register(typeConverters.LanguageSelector.from(selector), { displayName, - provideDocumentFormattingEdits: (model: ITextModel, options: modes.FormattingOptions, token: CancellationToken): Promise => { + provideDocumentFormattingEdits: (model: ITextModel, options: modes.FormattingOptions, token: CancellationToken): Promise => { return this._proxy.$provideDocumentFormattingEdits(handle, model.uri, options, token); } }); @@ -252,7 +252,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha $registerRangeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], displayName: string): void { this._registrations[handle] = modes.DocumentRangeFormattingEditProviderRegistry.register(typeConverters.LanguageSelector.from(selector), { displayName, - provideDocumentRangeFormattingEdits: (model: ITextModel, range: EditorRange, options: modes.FormattingOptions, token: CancellationToken): Promise => { + provideDocumentRangeFormattingEdits: (model: ITextModel, range: EditorRange, options: modes.FormattingOptions, token: CancellationToken): Promise => { return this._proxy.$provideDocumentRangeFormattingEdits(handle, model.uri, range, options, token); } }); @@ -263,7 +263,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha autoFormatTriggerCharacters, - provideOnTypeFormattingEdits: (model: ITextModel, position: EditorPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise => { + provideOnTypeFormattingEdits: (model: ITextModel, position: EditorPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise => { return this._proxy.$provideOnTypeFormattingEdits(handle, model.uri, position, ch, options, token); } }); @@ -272,7 +272,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha // --- navigate type $registerNavigateTypeSupport(handle: number): void { - let lastResultId: number; + let lastResultId: number | undefined; this._registrations[handle] = search.WorkspaceSymbolProviderRegistry.register({ provideWorkspaceSymbols: (search: string, token: CancellationToken): Promise => { return this._proxy.$provideWorkspaceSymbols(handle, search, token).then(result => { @@ -298,7 +298,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha return this._proxy.$provideRenameEdits(handle, model.uri, position, newName, token).then(reviveWorkspaceEditDto); }, resolveRenameLocation: supportResolveLocation - ? (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise => this._proxy.$resolveRenameLocation(handle, model.uri, position, token) + ? (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise => this._proxy.$resolveRenameLocation(handle, model.uri, position, token) : undefined }); } diff --git a/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts b/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts index 84b444bb19e..2d6da3314f5 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadTreeViews.ts @@ -45,7 +45,10 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie return this.viewsService.openView(treeViewId, options.focus) .then(() => { const viewer = this.getTreeView(treeViewId); - return this.reveal(viewer, this._dataProviders.get(treeViewId), item, parentChain, options); + if (viewer) { + return this.reveal(viewer, this._dataProviders.get(treeViewId)!, item, parentChain, options); + } + return undefined; }); } @@ -56,7 +59,7 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie const itemsToRefresh = dataProvider.getItemsToRefresh(itemsToRefreshByHandle); return viewer.refresh(itemsToRefresh.length ? itemsToRefresh : undefined); } - return null; + return Promise.resolve(); } $setMessage(treeViewId: string, message: string | IMarkdownString): void { diff --git a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts index cc68e778185..f1c8f61a6f5 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts @@ -68,14 +68,14 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv handle: WebviewPanelHandle, viewType: string, title: string, - showOptions: { viewColumn: EditorViewColumn | null, preserveFocus: boolean }, + showOptions: { viewColumn?: EditorViewColumn, preserveFocus?: boolean }, options: WebviewInputOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents ): void { const mainThreadShowOptions: ICreateWebViewShowOptions = Object.create(null); if (showOptions) { - mainThreadShowOptions.preserveFocus = showOptions.preserveFocus; + mainThreadShowOptions.preserveFocus = !!showOptions.preserveFocus; mainThreadShowOptions.group = viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn); } @@ -129,7 +129,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv const targetGroup = this._editorGroupService.getGroup(viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn)); - this._webviewService.revealWebview(webview, targetGroup || this._editorGroupService.activeGroup, showOptions.preserveFocus); + this._webviewService.revealWebview(webview, targetGroup || this._editorGroupService.activeGroup, !!showOptions.preserveFocus); } public $postMessage(handle: WebviewPanelHandle, message: any): Promise { @@ -137,7 +137,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv const editors = this._editorService.visibleControls .filter(e => e instanceof WebviewEditor) .map(e => e as WebviewEditor) - .filter(e => e.input.matches(webview)); + .filter(e => e.input!.matches(webview)); for (const editor of editors) { editor.sendMessage(message); @@ -216,7 +216,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv let newActiveWebview: { input: WebviewEditorInput, handle: WebviewPanelHandle } | undefined = undefined; if (activeEditor && activeEditor.input instanceof WebviewEditorInput) { for (const handle of map.keys(this._webviews)) { - const input = this._webviews.get(handle); + const input = this._webviews.get(handle)!; if (input.matches(activeEditor.input)) { newActiveWebview = { input, handle }; break; @@ -240,7 +240,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv if (oldActiveWebview) { this._proxy.$onDidChangeWebviewPanelViewState(this._activeWebview, { active: false, - visible: this._editorService.visibleControls.some(editor => editor.input && editor.input.matches(oldActiveWebview)), + visible: this._editorService.visibleControls.some(editor => !!editor.input && editor.input.matches(oldActiveWebview)), position: editorGroupToViewColumn(this._editorGroupService, oldActiveWebview.group), }); } diff --git a/src/vs/workbench/api/node/extHostTypeConverters.ts b/src/vs/workbench/api/node/extHostTypeConverters.ts index cfe6b70e50f..00c9c120a02 100644 --- a/src/vs/workbench/api/node/extHostTypeConverters.ts +++ b/src/vs/workbench/api/node/extHostTypeConverters.ts @@ -443,7 +443,7 @@ export namespace TextEdit { export function to(edit: modes.TextEdit): types.TextEdit { const result = new types.TextEdit(Range.to(edit.range), edit.text); - result.newEol = typeof edit.eol === 'undefined' ? undefined : EndOfLine.to(edit.eol); + result.newEol = (typeof edit.eol === 'undefined' ? undefined : EndOfLine.to(edit.eol))!; return result; } } @@ -457,7 +457,7 @@ export namespace WorkspaceEdit { const [uri, uriOrEdits] = entry; if (Array.isArray(uriOrEdits)) { // text edits - const doc = documents ? documents.getDocument(uri.toString()) : undefined; + const doc = documents && uri ? documents.getDocument(uri.toString()) : undefined; result.edits.push({ resource: uri, modelVersionId: doc && doc.version, edits: uriOrEdits.map(TextEdit.from) }); } else { // resource edits @@ -986,6 +986,9 @@ export namespace GlobPattern { export namespace LanguageSelector { + export function from(selector: undefined): undefined; + export function from(selector: vscode.DocumentSelector): languageSelector.LanguageSelector; + export function from(selector: vscode.DocumentSelector | undefined): languageSelector.LanguageSelector | undefined; export function from(selector: vscode.DocumentSelector | undefined): languageSelector.LanguageSelector | undefined { if (!selector) { return undefined; @@ -997,7 +1000,7 @@ export namespace LanguageSelector { return { language: selector.language, scheme: selector.scheme, - pattern: GlobPattern.from(selector.pattern), + pattern: typeof selector.pattern === 'undefined' ? undefined : GlobPattern.from(selector.pattern), exclusive: selector.exclusive }; } diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index 6fd5b4064d4..917c9bedf4d 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -948,9 +948,9 @@ export class SymbolInformation { kind: SymbolKind; containerName: string | undefined; - constructor(name: string, kind: SymbolKind, containerName: string, location: Location); + constructor(name: string, kind: SymbolKind, containerName: string | undefined, location: Location); constructor(name: string, kind: SymbolKind, range: Range, uri?: URI, containerName?: string); - constructor(name: string, kind: SymbolKind, rangeOrContainer: string | Range, locationOrUri?: Location | URI, containerName?: string) { + constructor(name: string, kind: SymbolKind, rangeOrContainer: string | undefined | Range, locationOrUri?: Location | URI, containerName?: string) { this.name = name; this.kind = kind; this.containerName = containerName; diff --git a/src/vs/workbench/browser/parts/editor/resourceViewer.ts b/src/vs/workbench/browser/parts/editor/resourceViewer.ts index a0cc90b5735..73446c7b5cb 100644 --- a/src/vs/workbench/browser/parts/editor/resourceViewer.ts +++ b/src/vs/workbench/browser/parts/editor/resourceViewer.ts @@ -27,7 +27,7 @@ export interface IResourceDescriptor { readonly resource: URI; readonly name: string; readonly size: number; - readonly etag: string; + readonly etag?: string; readonly mime: string; } diff --git a/src/vs/workbench/common/editor/binaryEditorModel.ts b/src/vs/workbench/common/editor/binaryEditorModel.ts index 57f46840097..bb60951b8c1 100644 --- a/src/vs/workbench/common/editor/binaryEditorModel.ts +++ b/src/vs/workbench/common/editor/binaryEditorModel.ts @@ -16,7 +16,7 @@ export class BinaryEditorModel extends EditorModel { private name: string; private resource: URI; private size: number; - private etag: string; + private etag?: string; private mime: string; constructor( @@ -70,7 +70,7 @@ export class BinaryEditorModel extends EditorModel { /** * The etag of the binary resource if known. */ - getETag(): string { + getETag(): string | undefined { return this.etag; } diff --git a/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts index 73cfd4cce86..063ec4ee52b 100644 --- a/src/vs/workbench/services/decorations/browser/decorations.ts +++ b/src/vs/workbench/services/decorations/browser/decorations.ts @@ -31,7 +31,7 @@ export interface IDecoration { export interface IDecorationsProvider { readonly label: string; readonly onDidChange: Event; - provideDecorations(uri: URI, token: CancellationToken): IDecorationData | Promise | undefined; + provideDecorations(uri: URI, token: CancellationToken): IDecorationData | Promise | undefined; } export interface IResourceDecorationChangeEvent { diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 2e3b151afc9..e0ef2f3814f 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -301,7 +301,7 @@ class DecorationProviderWrapper { const source = new CancellationTokenSource(); const dataOrThenable = this._provider.provideDecorations(uri, source.token); - if (!isThenable(dataOrThenable)) { + if (!isThenable | undefined>(dataOrThenable)) { // sync -> we have a result now return this._keepItem(uri, dataOrThenable); diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 02e23141003..a668ec07907 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -37,13 +37,13 @@ const NO_OP_VOID_PROMISE = Promise.resolve(undefined); schema.properties.engines.properties.vscode.default = `^${pkg.version}`; -let productAllowProposedApi: Set = null; +let productAllowProposedApi: Set | null = null; function allowProposedApiFromProduct(id: ExtensionIdentifier): boolean { // create set if needed - if (productAllowProposedApi === null) { + if (!productAllowProposedApi) { productAllowProposedApi = new Set(); if (isNonEmptyArray(product.extensionAllowedProposedApi)) { - product.extensionAllowedProposedApi.forEach((id) => productAllowProposedApi.add(ExtensionIdentifier.toKey(id))); + product.extensionAllowedProposedApi.forEach((id) => productAllowProposedApi!.add(ExtensionIdentifier.toKey(id))); } } return productAllowProposedApi.has(ExtensionIdentifier.toKey(id)); @@ -167,7 +167,7 @@ export class ExtensionService extends Disposable implements IExtensionService { } while (this._deltaExtensionsQueue.length > 0) { - const item = this._deltaExtensionsQueue.shift(); + const item = this._deltaExtensionsQueue.shift()!; try { this._inHandleDeltaExtensions = true; await this._deltaExtensions(item.toAdd, item.toRemove); @@ -856,7 +856,7 @@ export class ExtensionService extends Disposable implements IExtensionService { if (!this._extensionsMessages.has(extensionKey)) { this._extensionsMessages.set(extensionKey, []); } - this._extensionsMessages.get(extensionKey).push({ + this._extensionsMessages.get(extensionKey)!.push({ type: severity, message: message, extensionId: null, diff --git a/src/vs/workbench/services/extensions/node/extensionDescriptionRegistry.ts b/src/vs/workbench/services/extensions/node/extensionDescriptionRegistry.ts index 6ad4cac017d..972c560d6b9 100644 --- a/src/vs/workbench/services/extensions/node/extensionDescriptionRegistry.ts +++ b/src/vs/workbench/services/extensions/node/extensionDescriptionRegistry.ts @@ -189,8 +189,8 @@ export class ExtensionDescriptionRegistry { return this._extensionsArr.slice(0); } - public getExtensionDescription(extensionId: ExtensionIdentifier | string): IExtensionDescription | null { + public getExtensionDescription(extensionId: ExtensionIdentifier | string): IExtensionDescription | undefined { const extension = this._extensionsMap.get(ExtensionIdentifier.toKey(extensionId)); - return extension ? extension : null; + return extension ? extension : undefined; } } From 31fbc68a94d824cda99e4f589747248e843aace7 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Sun, 10 Feb 2019 10:55:40 -0800 Subject: [PATCH 145/207] Strict null check resolver.test --- .../files/electron-browser/fileService.ts | 2 +- .../test/electron-browser/resolver.test.ts | 76 +++++++++---------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/vs/workbench/services/files/electron-browser/fileService.ts b/src/vs/workbench/services/files/electron-browser/fileService.ts index 1a66c56808e..05cc4b8979f 100644 --- a/src/vs/workbench/services/files/electron-browser/fileService.ts +++ b/src/vs/workbench/services/files/electron-browser/fileService.ts @@ -1142,7 +1142,7 @@ export class StatResolver { this.etag = etag(size, mtime); } - resolve(options: IResolveFileOptions): Promise { + resolve(options: IResolveFileOptions | undefined): Promise { // General Data const fileStat: IFileStat = { diff --git a/src/vs/workbench/services/files/test/electron-browser/resolver.test.ts b/src/vs/workbench/services/files/test/electron-browser/resolver.test.ts index 8d2af37c06f..d2e6c1a9667 100644 --- a/src/vs/workbench/services/files/test/electron-browser/resolver.test.ts +++ b/src/vs/workbench/services/files/test/electron-browser/resolver.test.ts @@ -32,13 +32,13 @@ suite('Stat Resolver', () => { test('resolve file', function () { let resolver = create('/index.html'); - return resolver.resolve(null).then(result => { + return resolver.resolve(undefined).then(result => { assert.ok(!result.isDirectory); assert.equal(result.name, 'index.html'); assert.ok(!!result.etag); resolver = create('examples'); - return resolver.resolve(null).then(result => { + return resolver.resolve(undefined).then(result => { assert.ok(result.isDirectory); }); }); @@ -49,20 +49,20 @@ suite('Stat Resolver', () => { let resolver = create('/'); - return resolver.resolve(null).then(result => { + return resolver.resolve(undefined).then(result => { assert.ok(result); assert.ok(result.children); - assert.ok(result.children.length > 0); - assert.ok(result.isDirectory); - assert.equal(result.children.length, testsElements.length); + assert.ok(result.children!.length > 0); + assert.ok(result!.isDirectory); + assert.equal(result.children!.length, testsElements.length); - assert.ok(result.children.every((entry) => { + assert.ok(result.children!.every((entry) => { return testsElements.some((name) => { return path.basename(entry.resource.fsPath) === name; }); })); - result.children.forEach((value) => { + result.children!.forEach((value) => { assert.ok(path.basename(value.resource.fsPath)); if (['examples', 'other'].indexOf(path.basename(value.resource.fsPath)) >= 0) { assert.ok(value.isDirectory); @@ -85,20 +85,20 @@ suite('Stat Resolver', () => { return resolver.resolve({ resolveTo: [toResource('other/deep')] }).then(result => { assert.ok(result); assert.ok(result.children); - assert.ok(result.children.length > 0); + assert.ok(result.children!.length > 0); assert.ok(result.isDirectory); - let children = result.children; + const children = result.children!; assert.equal(children.length, 4); - let other = utils.getByName(result, 'other'); + const other = utils.getByName(result, 'other'); assert.ok(other); - assert.ok(other.children.length > 0); + assert.ok(other!.children!.length > 0); - let deep = utils.getByName(other, 'deep'); + const deep = utils.getByName(other!, 'deep'); assert.ok(deep); - assert.ok(deep.children.length > 0); - assert.equal(deep.children.length, 4); + assert.ok(deep!.children!.length > 0); + assert.equal(deep!.children!.length, 4); }); }); @@ -108,24 +108,24 @@ suite('Stat Resolver', () => { return resolver.resolve({ resolveTo: [toResource('other/Deep')] }).then(result => { assert.ok(result); assert.ok(result.children); - assert.ok(result.children.length > 0); + assert.ok(result.children!.length > 0); assert.ok(result.isDirectory); - let children = result.children; - assert.equal(children.length, 4); + const children = result.children; + assert.equal(children!.length, 4); - let other = utils.getByName(result, 'other'); + const other = utils.getByName(result, 'other'); assert.ok(other); - assert.ok(other.children.length > 0); + assert.ok(other!.children!.length > 0); - let deep = utils.getByName(other, 'deep'); + const deep = utils.getByName(other!, 'deep'); if (isLinux) { // Linux has case sensitive file system assert.ok(deep); - assert.ok(!deep.children); // not resolved because we got instructed to resolve other/Deep with capital D + assert.ok(!deep!.children); // not resolved because we got instructed to resolve other/Deep with capital D } else { assert.ok(deep); - assert.ok(deep.children.length > 0); - assert.equal(deep.children.length, 4); + assert.ok(deep!.children!.length > 0); + assert.equal(deep!.children!.length, 4); } }); }); @@ -136,25 +136,25 @@ suite('Stat Resolver', () => { return resolver.resolve({ resolveTo: [toResource('other/deep'), toResource('examples')] }).then(result => { assert.ok(result); assert.ok(result.children); - assert.ok(result.children.length > 0); + assert.ok(result.children!.length > 0); assert.ok(result.isDirectory); - let children = result.children; + const children = result.children!; assert.equal(children.length, 4); - let other = utils.getByName(result, 'other'); + const other = utils.getByName(result, 'other'); assert.ok(other); - assert.ok(other.children.length > 0); + assert.ok(other!.children!.length > 0); - let deep = utils.getByName(other, 'deep'); + const deep = utils.getByName(other!, 'deep'); assert.ok(deep); - assert.ok(deep.children.length > 0); - assert.equal(deep.children.length, 4); + assert.ok(deep!.children!.length > 0); + assert.equal(deep!.children!.length, 4); - let examples = utils.getByName(result, 'examples'); + const examples = utils.getByName(result, 'examples'); assert.ok(examples); - assert.ok(examples.children.length > 0); - assert.equal(examples.children.length, 4); + assert.ok(examples!.children!.length > 0); + assert.equal(examples!.children!.length, 4); }); }); @@ -164,16 +164,16 @@ suite('Stat Resolver', () => { return resolver.resolve({ resolveSingleChildDescendants: true }).then(result => { assert.ok(result); assert.ok(result.children); - assert.ok(result.children.length > 0); + assert.ok(result.children!.length > 0); assert.ok(result.isDirectory); - let children = result.children; + const children = result.children!; assert.equal(children.length, 1); let deep = utils.getByName(result, 'deep'); assert.ok(deep); - assert.ok(deep.children.length > 0); - assert.equal(deep.children.length, 4); + assert.ok(deep!.children!.length > 0); + assert.equal(deep!.children!.length, 4); }); }); }); From d0d773eddcada673d288f125d3fa5a100198f32b Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Sun, 10 Feb 2019 11:03:29 -0800 Subject: [PATCH 146/207] Strict null supressions in test files --- .../configurationResolverService.test.ts | 55 +++++++++---------- .../test/browser/editorGroupsService.test.ts | 2 +- .../editor/test/browser/editorService.test.ts | 6 +- .../textfile/test/textFileEditorModel.test.ts | 20 +++---- .../test/textModelResolverService.test.ts | 2 +- 5 files changed, 42 insertions(+), 43 deletions(-) diff --git a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts index 2d6bf3ad7f5..9dd5e6f18ad 100644 --- a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts @@ -19,7 +19,7 @@ import { CancellationToken } from 'vscode'; import * as Types from 'vs/base/common/types'; suite('Configuration Resolver Service', () => { - let configurationResolverService: IConfigurationResolverService; + let configurationResolverService: IConfigurationResolverService | null; let envVariables: { [key: string]: string } = { key1: 'Value for key1', key2: 'Value for key2' }; let mockCommandService: MockCommandService; let editorService: TestEditorService; @@ -45,46 +45,46 @@ suite('Configuration Resolver Service', () => { test('substitute one', () => { if (platform.isWindows) { - assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${workspaceFolder} xyz'), 'abc \\VSCode\\workspaceLocation xyz'); + assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${workspaceFolder} xyz'), 'abc \\VSCode\\workspaceLocation xyz'); } else { - assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${workspaceFolder} xyz'), 'abc /VSCode/workspaceLocation xyz'); + assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${workspaceFolder} xyz'), 'abc /VSCode/workspaceLocation xyz'); } }); test('workspace root folder name', () => { - assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${workspaceRootFolderName} xyz'), 'abc workspaceLocation xyz'); + assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${workspaceRootFolderName} xyz'), 'abc workspaceLocation xyz'); }); // TODO@isidor mock the editor service properly // test('current selected line number', () => { - // assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${lineNumber} xyz'), `abc ${editorService.mockLineNumber} xyz`); + // assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${lineNumber} xyz'), `abc ${editorService.mockLineNumber} xyz`); // }); // test('current selected text', () => { - // assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${selectedText} xyz'), `abc ${editorService.mockSelectedText} xyz`); + // assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${selectedText} xyz'), `abc ${editorService.mockSelectedText} xyz`); // }); test('substitute many', () => { if (platform.isWindows) { - assert.strictEqual(configurationResolverService.resolve(workspace, '${workspaceFolder} - ${workspaceFolder}'), '\\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation'); + assert.strictEqual(configurationResolverService!.resolve(workspace, '${workspaceFolder} - ${workspaceFolder}'), '\\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation'); } else { - assert.strictEqual(configurationResolverService.resolve(workspace, '${workspaceFolder} - ${workspaceFolder}'), '/VSCode/workspaceLocation - /VSCode/workspaceLocation'); + assert.strictEqual(configurationResolverService!.resolve(workspace, '${workspaceFolder} - ${workspaceFolder}'), '/VSCode/workspaceLocation - /VSCode/workspaceLocation'); } }); test('substitute one env variable', () => { if (platform.isWindows) { - assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${workspaceFolder} ${env:key1} xyz'), 'abc \\VSCode\\workspaceLocation Value for key1 xyz'); + assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${workspaceFolder} ${env:key1} xyz'), 'abc \\VSCode\\workspaceLocation Value for key1 xyz'); } else { - assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${workspaceFolder} ${env:key1} xyz'), 'abc /VSCode/workspaceLocation Value for key1 xyz'); + assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${workspaceFolder} ${env:key1} xyz'), 'abc /VSCode/workspaceLocation Value for key1 xyz'); } }); test('substitute many env variable', () => { if (platform.isWindows) { - assert.strictEqual(configurationResolverService.resolve(workspace, '${workspaceFolder} - ${workspaceFolder} ${env:key1} - ${env:key2}'), '\\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation Value for key1 - Value for key2'); + assert.strictEqual(configurationResolverService!.resolve(workspace, '${workspaceFolder} - ${workspaceFolder} ${env:key1} - ${env:key2}'), '\\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation Value for key1 - Value for key2'); } else { - assert.strictEqual(configurationResolverService.resolve(workspace, '${workspaceFolder} - ${workspaceFolder} ${env:key1} - ${env:key2}'), '/VSCode/workspaceLocation - /VSCode/workspaceLocation Value for key1 - Value for key2'); + assert.strictEqual(configurationResolverService!.resolve(workspace, '${workspaceFolder} - ${workspaceFolder} ${env:key1} - ${env:key2}'), '/VSCode/workspaceLocation - /VSCode/workspaceLocation Value for key1 - Value for key2'); } }); @@ -93,7 +93,7 @@ suite('Configuration Resolver Service', () => { // '${workspaceRootFolderName}': '${lineNumber}', // 'hey ${env:key1} ': '${workspaceRootFolderName}' // }; - // assert.deepEqual(configurationResolverService.resolve(workspace, myObject), { + // assert.deepEqual(configurationResolverService!.resolve(workspace, myObject), { // 'workspaceLocation': `${editorService.mockLineNumber}`, // 'hey Value for key1 ': 'workspaceLocation' // }); @@ -102,15 +102,14 @@ suite('Configuration Resolver Service', () => { test('substitute one env variable using platform case sensitivity', () => { if (platform.isWindows) { - assert.strictEqual(configurationResolverService.resolve(workspace, '${env:key1} - ${env:Key1}'), 'Value for key1 - Value for key1'); + assert.strictEqual(configurationResolverService!.resolve(workspace, '${env:key1} - ${env:Key1}'), 'Value for key1 - Value for key1'); } else { - assert.strictEqual(configurationResolverService.resolve(workspace, '${env:key1} - ${env:Key1}'), 'Value for key1 - '); + assert.strictEqual(configurationResolverService!.resolve(workspace, '${env:key1} - ${env:Key1}'), 'Value for key1 - '); } }); test('substitute one configuration variable', () => { - let configurationService: IConfigurationService; - configurationService = new MockConfigurationService({ + let configurationService: IConfigurationService = new MockConfigurationService({ editor: { fontFamily: 'foo' }, @@ -256,7 +255,7 @@ suite('Configuration Resolver Service', () => { 'outDir': null }; - return configurationResolverService.resolveWithInteractionReplace(undefined, configuration).then(result => { + return configurationResolverService!.resolveWithInteractionReplace(undefined, configuration).then(result => { assert.deepEqual(result, { 'name': 'Attach to Process', @@ -285,7 +284,7 @@ suite('Configuration Resolver Service', () => { const commandVariables = Object.create(null); commandVariables['commandVariable1'] = 'command1'; - return configurationResolverService.resolveWithInteractionReplace(undefined, configuration, undefined, commandVariables).then(result => { + return configurationResolverService!.resolveWithInteractionReplace(undefined, configuration, undefined, commandVariables).then(result => { assert.deepEqual(result, { 'name': 'Attach to Process', @@ -318,7 +317,7 @@ suite('Configuration Resolver Service', () => { const commandVariables = Object.create(null); commandVariables['commandVariable1'] = 'command1'; - return configurationResolverService.resolveWithInteractionReplace(undefined, configuration, undefined, commandVariables).then(result => { + return configurationResolverService!.resolveWithInteractionReplace(undefined, configuration, undefined, commandVariables).then(result => { assert.deepEqual(result, { 'name': 'Attach to Process', @@ -349,7 +348,7 @@ suite('Configuration Resolver Service', () => { const commandVariables = Object.create(null); commandVariables['commandVariable1'] = 'command1'; - return configurationResolverService.resolveWithInteractionReplace(undefined, configuration, undefined, commandVariables).then(result => { + return configurationResolverService!.resolveWithInteractionReplace(undefined, configuration, undefined, commandVariables).then(result => { assert.deepEqual(result, { 'name': 'Attach to Process', @@ -374,7 +373,7 @@ suite('Configuration Resolver Service', () => { 'outDir': null }; - return configurationResolverService.resolveWithInteractionReplace(workspace, configuration, 'tasks').then(result => { + return configurationResolverService!.resolveWithInteractionReplace(workspace, configuration, 'tasks').then(result => { assert.deepEqual(result, { 'name': 'Attach to Process', @@ -401,7 +400,7 @@ suite('Configuration Resolver Service', () => { 'outDir': null }; - return configurationResolverService.resolveWithInteractionReplace(workspace, configuration, 'tasks').then(result => { + return configurationResolverService!.resolveWithInteractionReplace(workspace, configuration, 'tasks').then(result => { assert.deepEqual(result, { 'name': 'Attach to Process', @@ -428,7 +427,7 @@ suite('Configuration Resolver Service', () => { 'outDir': null }; - return configurationResolverService.resolveWithInteractionReplace(workspace, configuration, 'tasks').then(result => { + return configurationResolverService!.resolveWithInteractionReplace(workspace, configuration, 'tasks').then(result => { assert.deepEqual(result, { 'name': 'Attach to Process', @@ -456,7 +455,7 @@ suite('Configuration Resolver Service', () => { 'outDir': null }; - return configurationResolverService.resolveWithInteractionReplace(workspace, configuration, 'tasks').then(result => { + return configurationResolverService!.resolveWithInteractionReplace(workspace, configuration, 'tasks').then(result => { assert.deepEqual(result, { 'name': 'resolvedEnterinput3', @@ -490,15 +489,15 @@ class MockConfigurationService implements IConfigurationService { const valuePath = (value).split('.'); let object = this.configuration; while (valuePath.length && object) { - object = object[valuePath.shift()]; + object = object[valuePath.shift()!]; } return object; } - public updateValue(): Promise { return null; } + public updateValue(): Promise { return Promise.resolve(); } public getConfigurationData(): any { return null; } public onDidChangeConfiguration() { return { dispose() { } }; } - public reloadConfiguration() { return null; } + public reloadConfiguration() { return Promise.resolve(); } } class MockCommandService implements ICommandService { diff --git a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts index ef4e6423cb7..ca549547ab7 100644 --- a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts @@ -41,7 +41,7 @@ export class TestEditorInput extends EditorInput implements IFileEditorInput { constructor(private resource: URI) { super(); } getTypeId() { return 'testEditorInputForEditorGroupService'; } - resolve(): Promise { return Promise.resolve(undefined); } + resolve(): Promise { return Promise.resolve(null); } matches(other: TestEditorInput): boolean { return other && this.resource.toString() === other.resource.toString() && other instanceof TestEditorInput; } setEncoding(encoding: string) { } getEncoding(): string { return null!; } diff --git a/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts index 7f2c1932568..467ec82f69d 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -120,7 +120,7 @@ suite('Editor service', () => { assert.equal(visibleEditorChangeEventCounter, 1); // Close input - return editor.group.closeEditor(input).then(() => { + return editor.group!.closeEditor(input).then(() => { assert.equal(didCloseEditorListenerCounter, 1); assert.equal(activeEditorChangeEventCounter, 2); assert.equal(visibleEditorChangeEventCounter, 2); @@ -260,7 +260,7 @@ suite('Editor service', () => { class MyEditor extends BaseEditor { constructor(id: string) { - super(id, null, new TestThemeService(), new TestStorageService()); + super(id, undefined, new TestThemeService(), new TestStorageService()); } getId(): string { @@ -403,7 +403,7 @@ suite('Editor service', () => { // 1.) open, open same, open other, close let editor = await service.openEditor(input, { pinned: true }); - const group = editor.group; + const group = editor.group!; assertActiveEditorChangedEvent(true); assertVisibleEditorsChangedEvent(true); diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts index 680eab70090..33fa05d3021 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts @@ -264,7 +264,7 @@ suite('Files - TextFileEditorModel', () => { model.onDidStateChange(e => { if (e === StateChange.SAVED) { - assert.equal(snapshotToString(model.createSnapshot()), 'bar'); + assert.equal(snapshotToString(model.createSnapshot()!), 'bar'); assert.ok(!model.isDirty()); eventCounter++; } @@ -337,7 +337,7 @@ suite('Files - TextFileEditorModel', () => { assert.ok(!sequentializer.pendingSave); // pending removes itself after done - return sequentializer.setPending(1, Promise.resolve(null)).then(() => { + return sequentializer.setPending(1, Promise.resolve()).then(() => { assert.ok(!sequentializer.hasPendingSave()); assert.ok(!sequentializer.hasPendingSave(1)); assert.ok(!sequentializer.pendingSave); @@ -361,11 +361,11 @@ suite('Files - TextFileEditorModel', () => { const sequentializer = new SaveSequentializer(); let pendingDone = false; - sequentializer.setPending(1, timeout(1).then(() => { pendingDone = true; return null; })); + sequentializer.setPending(1, timeout(1).then(() => { pendingDone = true; return; })); // next finishes instantly let nextDone = false; - const res = sequentializer.setNext(() => Promise.resolve(null).then(() => { nextDone = true; return null; })); + const res = sequentializer.setNext(() => Promise.resolve(null).then(() => { nextDone = true; return; })); return res.then(() => { assert.ok(pendingDone); @@ -377,11 +377,11 @@ suite('Files - TextFileEditorModel', () => { const sequentializer = new SaveSequentializer(); let pendingDone = false; - sequentializer.setPending(1, timeout(1).then(() => { pendingDone = true; return null; })); + sequentializer.setPending(1, timeout(1).then(() => { pendingDone = true; return; })); // next finishes after timeout let nextDone = false; - const res = sequentializer.setNext(() => timeout(1).then(() => { nextDone = true; return null; })); + const res = sequentializer.setNext(() => timeout(1).then(() => { nextDone = true; return; })); return res.then(() => { assert.ok(pendingDone); @@ -393,17 +393,17 @@ suite('Files - TextFileEditorModel', () => { const sequentializer = new SaveSequentializer(); let pendingDone = false; - sequentializer.setPending(1, timeout(1).then(() => { pendingDone = true; return null; })); + sequentializer.setPending(1, timeout(1).then(() => { pendingDone = true; return; })); // next finishes after timeout let firstDone = false; - let firstRes = sequentializer.setNext(() => timeout(2).then(() => { firstDone = true; return null; })); + let firstRes = sequentializer.setNext(() => timeout(2).then(() => { firstDone = true; return; })); let secondDone = false; - let secondRes = sequentializer.setNext(() => timeout(3).then(() => { secondDone = true; return null; })); + let secondRes = sequentializer.setNext(() => timeout(3).then(() => { secondDone = true; return; })); let thirdDone = false; - let thirdRes = sequentializer.setNext(() => timeout(4).then(() => { thirdDone = true; return null; })); + let thirdRes = sequentializer.setNext(() => timeout(4).then(() => { thirdDone = true; return; })); return Promise.all([firstRes, secondRes, thirdRes]).then(() => { assert.ok(pendingDone); diff --git a/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts b/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts index 11847180005..c05d512145c 100644 --- a/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts +++ b/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts @@ -72,7 +72,7 @@ suite('Workbench - TextModelResolverService', () => { return input.resolve().then(async model => { assert.ok(model); - assert.equal(snapshotToString((model as ResourceEditorModel).createSnapshot()), 'Hello Test'); + assert.equal(snapshotToString((model as ResourceEditorModel).createSnapshot()!), 'Hello Test'); let disposed = false; let disposedPromise = new Promise(resolve => { From 8b367f97f4c8a4984001aa2fdfcd21c4e99e4502 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Sun, 10 Feb 2019 15:46:41 -0800 Subject: [PATCH 147/207] Fix failing test --- .../api/electron-browser/mainThreadDocumentsAndEditors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors.ts b/src/vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors.ts index 63273dd9aba..7801fcbf337 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors.ts @@ -230,7 +230,7 @@ class MainThreadDocumentAndEditorStateComputer { // editor: only take those that have a not too large model const editors = new Map(); - let activeEditor: string | undefined = undefined; + let activeEditor: string | null = null; // Strict null work. This doesn't like being undefined! for (const editor of this._codeEditorService.listCodeEditors()) { if (editor.isSimpleWidget) { From 7ca2c0a7b27234d2d6f4ebc75f0282dd314836be Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Sun, 10 Feb 2019 15:51:59 -0800 Subject: [PATCH 148/207] Strict null work in list commands --- src/vs/workbench/browser/actions/listCommands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/actions/listCommands.ts b/src/vs/workbench/browser/actions/listCommands.ts index 94a19170266..d47aa860d21 100644 --- a/src/vs/workbench/browser/actions/listCommands.ts +++ b/src/vs/workbench/browser/actions/listCommands.ts @@ -18,7 +18,7 @@ import { DataTree } from 'vs/base/browser/ui/tree/dataTree'; import { ITreeNode } from 'vs/base/browser/ui/tree/tree'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -function ensureDOMFocus(widget: ListWidget): void { +function ensureDOMFocus(widget: ListWidget | undefined): void { // it can happen that one of the commands is executed while // DOM focus is within another focusable control within the // list/tree item. therefor we should ensure that the From bdfb6157618d523cf9b57d9100afcf2800b2fbd5 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Sun, 10 Feb 2019 15:54:17 -0800 Subject: [PATCH 149/207] Define IActiveEditor that always has group set This is similar to the IActiveCodeEditor class --- src/vs/workbench/browser/parts/editor/editorCommands.ts | 6 +++--- src/vs/workbench/services/editor/common/editorService.ts | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorCommands.ts b/src/vs/workbench/browser/parts/editor/editorCommands.ts index 9a22dbc334b..462b964ee5c 100644 --- a/src/vs/workbench/browser/parts/editor/editorCommands.ts +++ b/src/vs/workbench/browser/parts/editor/editorCommands.ts @@ -8,7 +8,7 @@ import * as types from 'vs/base/common/types'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { TextCompareEditorVisibleContext, EditorInput, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IEditor, IEditorInput } from 'vs/workbench/common/editor'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IEditorService, IActiveEditor } from 'vs/workbench/services/editor/common/editorService'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor'; import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes'; @@ -113,7 +113,7 @@ function moveActiveEditor(args: ActiveEditorMoveArguments = Object.create(null), } } -function moveActiveTab(args: ActiveEditorMoveArguments, control: IEditor, accessor: ServicesAccessor): void { +function moveActiveTab(args: ActiveEditorMoveArguments, control: IActiveEditor, accessor: ServicesAccessor): void { const group = control.group; let index = group.getIndexOfEditor(control.input); switch (args.to) { @@ -141,7 +141,7 @@ function moveActiveTab(args: ActiveEditorMoveArguments, control: IEditor, access group.moveEditor(control.input, group, { index }); } -function moveActiveEditorToGroup(args: ActiveEditorMoveArguments, control: IEditor, accessor: ServicesAccessor): void { +function moveActiveEditorToGroup(args: ActiveEditorMoveArguments, control: IActiveEditor, accessor: ServicesAccessor): void { const editorGroupService = accessor.get(IEditorGroupsService); const configurationService = accessor.get(IConfigurationService); diff --git a/src/vs/workbench/services/editor/common/editorService.ts b/src/vs/workbench/services/editor/common/editorService.ts index 462dd7f33a0..9fe2e5df047 100644 --- a/src/vs/workbench/services/editor/common/editorService.ts +++ b/src/vs/workbench/services/editor/common/editorService.ts @@ -39,6 +39,11 @@ export interface IOpenEditorOverride { override?: Promise; } +export interface IActiveEditor extends IEditor { + input: IEditorInput; + group: IEditorGroup; +} + export interface IEditorService { _serviceBrand: ServiceIdentifier; @@ -69,7 +74,7 @@ export interface IEditorService { * * @see `IEditorService.activeEditor` */ - readonly activeControl: IEditor; + readonly activeControl: IActiveEditor; /** * The currently active text editor widget or `undefined` if there is currently no active From bcf5339ff5fabf8b7bb29def5edd1679485551b7 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Sun, 10 Feb 2019 16:08:47 -0800 Subject: [PATCH 150/207] Strict null work in editorStatus --- .../browser/parts/editor/editorCommands.ts | 6 +- .../browser/parts/editor/editorStatus.ts | 60 ++++++++++--------- .../browser/parts/views/customView.ts | 6 +- 3 files changed, 37 insertions(+), 35 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorCommands.ts b/src/vs/workbench/browser/parts/editor/editorCommands.ts index 462b964ee5c..5e7607047e2 100644 --- a/src/vs/workbench/browser/parts/editor/editorCommands.ts +++ b/src/vs/workbench/browser/parts/editor/editorCommands.ts @@ -642,7 +642,7 @@ function registerCloseEditorCommands() { }); } -function getCommandsContext(resourceOrContext: URI | IEditorCommandsContext, context?: IEditorCommandsContext): IEditorCommandsContext { +function getCommandsContext(resourceOrContext: URI | IEditorCommandsContext, context?: IEditorCommandsContext): IEditorCommandsContext | undefined { if (URI.isUri(resourceOrContext)) { return context; } @@ -662,7 +662,7 @@ function resolveCommandsContext(editorGroupService: IEditorGroupsService, contex // Resolve from context let group = context && typeof context.groupId === 'number' ? editorGroupService.getGroup(context.groupId) : undefined; - let editor = group && typeof context.editorIndex === 'number' ? group.getEditor(context.editorIndex) : undefined; + let editor = group && context && typeof context.editorIndex === 'number' ? group.getEditor(context.editorIndex) : undefined; let control = group ? group.activeControl : undefined; // Fallback to active group as needed @@ -675,7 +675,7 @@ function resolveCommandsContext(editorGroupService: IEditorGroupsService, contex return { group, editor, control }; } -export function getMultiSelectedEditorContexts(editorContext: IEditorCommandsContext, listService: IListService, editorGroupService: IEditorGroupsService): IEditorCommandsContext[] { +export function getMultiSelectedEditorContexts(editorContext: IEditorCommandsContext | undefined, listService: IListService, editorGroupService: IEditorGroupsService): IEditorCommandsContext[] { // First check for a focused list to return the selected items from const list = listService.lastFocusedList; diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index d0e97f06e7e..510422eb7cc 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -64,7 +64,7 @@ class SideBySideEditorEncodingSupport implements IEncodingSupport { } } -function toEditorWithEncodingSupport(input: IEditorInput): IEncodingSupport { +function toEditorWithEncodingSupport(input: IEditorInput): IEncodingSupport | null { // Untitled Editor if (input instanceof UntitledEditorInput) { @@ -179,7 +179,7 @@ class State { this._metadata = null; } - update(update: StateDelta): StateChange { + update(update: StateDelta): StateChange | null { const e = new StateChange(); let somethingChanged = false; @@ -282,9 +282,9 @@ export class EditorStatus implements IStatusbarItem { private metadataElement: HTMLElement; private toDispose: IDisposable[]; private activeEditorListeners: IDisposable[]; - private delayedRender: IDisposable; - private toRender: StateChange; - private screenReaderNotification: INotificationHandle; + private delayedRender: IDisposable | null; + private toRender: StateChange | null; + private screenReaderNotification: INotificationHandle | null; constructor( @IEditorService private readonly editorService: IEditorService, @@ -379,7 +379,9 @@ export class EditorStatus implements IStatusbarItem { this.delayedRender = null; const toRender = this.toRender; this.toRender = null; - this._renderNow(toRender); + if (toRender) { + this._renderNow(toRender); + } }); } else { this.toRender.combine(changed); @@ -458,9 +460,9 @@ export class EditorStatus implements IStatusbarItem { } } - private getSelectionLabel(info: IEditorSelectionStatus): string { + private getSelectionLabel(info: IEditorSelectionStatus): string | undefined { if (!info || !info.selections) { - return null; + return undefined; } if (info.selections.length === 1) { @@ -479,7 +481,7 @@ export class EditorStatus implements IStatusbarItem { return strings.format(nlsMultiSelection, info.selections.length); } - return null; + return undefined; } private onModeClick(): void { @@ -544,7 +546,7 @@ export class EditorStatus implements IStatusbarItem { private updateStatusBar(): void { const activeControl = this.editorService.activeControl; - const activeCodeEditor = activeControl ? getCodeEditor(activeControl.getControl()) : undefined; + const activeCodeEditor = activeControl ? getCodeEditor(activeControl.getControl()) || undefined : undefined; // Update all states this.onScreenReaderModeChange(activeCodeEditor); @@ -582,7 +584,7 @@ export class EditorStatus implements IStatusbarItem { this.activeEditorListeners.push(activeCodeEditor.onDidChangeModelContent((e) => { this.onEOLChange(activeCodeEditor); - let selections = activeCodeEditor.getSelections(); + const selections = activeCodeEditor.getSelections(); for (const change of e.changes) { if (selections.some(selection => Range.areIntersecting(selection, change.range))) { this.onSelectionChange(activeCodeEditor); @@ -626,8 +628,8 @@ export class EditorStatus implements IStatusbarItem { } } - private onModeChange(editorWidget: ICodeEditor): void { - let info: StateDelta = { mode: null }; + private onModeChange(editorWidget: ICodeEditor | undefined): void { + let info: StateDelta = { mode: undefined }; // We only support text based editors if (editorWidget) { @@ -635,15 +637,15 @@ export class EditorStatus implements IStatusbarItem { if (textModel) { // Compute mode const modeId = textModel.getLanguageIdentifier().language; - info = { mode: this.modeService.getLanguageName(modeId) }; + info = { mode: this.modeService.getLanguageName(modeId) || undefined }; } } this.updateState(info); } - private onIndentationChange(editorWidget: ICodeEditor): void { - const update: StateDelta = { indentation: null }; + private onIndentationChange(editorWidget: ICodeEditor | undefined): void { + const update: StateDelta = { indentation: undefined }; if (editorWidget) { const model = editorWidget.getModel(); @@ -661,10 +663,10 @@ export class EditorStatus implements IStatusbarItem { } private onMetadataChange(editor: IBaseEditor): void { - const update: StateDelta = { metadata: null }; + const update: StateDelta = { metadata: undefined }; if (editor instanceof BaseBinaryResourceEditor || editor instanceof BinaryResourceDiffEditor) { - update.metadata = editor.getMetadata(); + update.metadata = editor.getMetadata() || undefined; } this.updateState(update); @@ -672,7 +674,7 @@ export class EditorStatus implements IStatusbarItem { private _promptedScreenReader: boolean = false; - private onScreenReaderModeChange(editorWidget: ICodeEditor): void { + private onScreenReaderModeChange(editorWidget: ICodeEditor | undefined): void { let screenReaderMode = false; // We only support text based editors @@ -701,7 +703,7 @@ export class EditorStatus implements IStatusbarItem { this.updateState({ screenReaderMode: screenReaderMode }); } - private onSelectionChange(editorWidget: ICodeEditor): void { + private onSelectionChange(editorWidget: ICodeEditor | undefined): void { const info: IEditorSelectionStatus = {}; // We only support text based editors @@ -715,7 +717,7 @@ export class EditorStatus implements IStatusbarItem { const textModel = editorWidget.getModel(); if (textModel) { info.selections.forEach(selection => { - info.charactersSelected += textModel.getValueLengthInRange(selection); + info.charactersSelected! += textModel.getValueLengthInRange(selection); }); } @@ -738,8 +740,8 @@ export class EditorStatus implements IStatusbarItem { this.updateState({ selectionStatus: this.getSelectionLabel(info) }); } - private onEOLChange(editorWidget: ICodeEditor): void { - const info: StateDelta = { EOL: null }; + private onEOLChange(editorWidget: ICodeEditor | undefined): void { + const info: StateDelta = { EOL: undefined }; if (editorWidget && !editorWidget.getConfiguration().readOnly) { const codeEditorModel = editorWidget.getModel(); @@ -756,7 +758,7 @@ export class EditorStatus implements IStatusbarItem { return; } - const info: StateDelta = { encoding: null }; + const info: StateDelta = { encoding: undefined }; // We only support text based editors if (e && (isCodeEditor(e.getControl()) || isDiffEditor(e.getControl()))) { @@ -798,7 +800,7 @@ export class EditorStatus implements IStatusbarItem { } } -function isWritableCodeEditor(codeEditor: ICodeEditor): boolean { +function isWritableCodeEditor(codeEditor: ICodeEditor | undefined): boolean { if (!codeEditor) { return false; } @@ -807,7 +809,7 @@ function isWritableCodeEditor(codeEditor: ICodeEditor): boolean { } function isWritableBaseEditor(e: IBaseEditor): boolean { - return e && isWritableCodeEditor(getCodeEditor(e.getControl())); + return e && isWritableCodeEditor(getCodeEditor(e.getControl()) || undefined); } export class ShowLanguageExtensionsAction extends Action { @@ -882,7 +884,7 @@ export class ChangeModeAction extends Action { } // construct a fake resource to be able to show nice icons if any - let fakeResource: uri; + let fakeResource: uri | undefined; const extensions = this.modeService.getExtensions(lang); if (extensions && extensions.length) { fakeResource = uri.file(extensions[0]); @@ -1077,7 +1079,7 @@ class ChangeIndentationAction extends Action { return { id: a.id, label: a.label, - detail: (language === LANGUAGE_DEFAULT) ? null : a.alias, + detail: (language === LANGUAGE_DEFAULT) ? undefined : a.alias, run: () => { activeTextEditorWidget.focus(); a.run(); @@ -1203,7 +1205,7 @@ export class ChangeEncodingAction extends Action { const configuredEncoding = this.textResourceConfigurationService.getValue(resource, 'files.encoding'); - let directMatchIndex: number; + let directMatchIndex: number | undefined; let aliasMatchIndex: number; // All encodings are valid picks diff --git a/src/vs/workbench/browser/parts/views/customView.ts b/src/vs/workbench/browser/parts/views/customView.ts index 960d8631a52..73cb594d7a8 100644 --- a/src/vs/workbench/browser/parts/views/customView.ts +++ b/src/vs/workbench/browser/parts/views/customView.ts @@ -87,8 +87,8 @@ export class CustomTreeViewPanel extends ViewletPanel { return [...this.treeView.getSecondaryActions()]; } - getActionItem(action: IAction): IActionItem { - return action instanceof MenuItemAction ? new ContextAwareMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService) : undefined; + getActionItem(action: IAction): IActionItem | null { + return action instanceof MenuItemAction ? new ContextAwareMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService) : null; } getOptimalWidth(): number { @@ -758,7 +758,7 @@ class Aligner extends Disposable { if (this.hasIcon(parent)) { return false; } - return parent.children && parent.children.every(c => c.collapsibleState === TreeItemCollapsibleState.None || !this.hasIcon(c)); + return !!parent.children && parent.children.every(c => c.collapsibleState === TreeItemCollapsibleState.None || !this.hasIcon(c)); } private hasIcon(node: ITreeItem): boolean { From 4dbd042325e9724d4a35f2c7150c0c9784860e61 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Feb 2019 08:06:31 -0800 Subject: [PATCH 151/207] Strict null work in tabsTitleControl --- .../browser/parts/editor/tabsTitleControl.ts | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index a9802ce7ea3..d455c6346f3 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -62,7 +62,7 @@ export class TabsTitleControl extends TitleControl { private tabDisposeables: IDisposable[] = []; private dimension: Dimension; - private layoutScheduled: IDisposable; + private layoutScheduled?: IDisposable; private blockRevealActiveTab: boolean; constructor( @@ -203,7 +203,7 @@ export class TabsTitleControl extends TitleControl { // Return if transfer is unsupported if (!this.isSupportedDropTransfer(e)) { - e.dataTransfer.dropEffect = 'none'; + e.dataTransfer!.dropEffect = 'none'; return; } @@ -214,7 +214,7 @@ export class TabsTitleControl extends TitleControl { const localDraggedEditor = this.editorTransfer.getData(DraggedEditorIdentifier.prototype)[0].identifier; if (this.group.id === localDraggedEditor.groupId && this.group.getIndexOfEditor(localDraggedEditor.editor) === this.group.count - 1) { - e.dataTransfer.dropEffect = 'none'; + e.dataTransfer!.dropEffect = 'none'; return; } } @@ -222,7 +222,7 @@ export class TabsTitleControl extends TitleControl { // Update the dropEffect to "copy" if there is no local data to be dragged because // in that case we can only copy the data into and not move it from its source if (!isLocalDragAndDrop) { - e.dataTransfer.dropEffect = 'copy'; + e.dataTransfer!.dropEffect = 'copy'; } this.updateDropFeedback(this.tabsContainer, true); @@ -298,7 +298,7 @@ export class TabsTitleControl extends TitleControl { (this.tabsContainer.lastChild as HTMLElement).remove(); // Remove associated tab label and widget - this.tabDisposeables.pop().dispose(); + this.tabDisposeables.pop()!.dispose(); } // A removal of a label requires to recompute all labels @@ -577,7 +577,7 @@ export class TabsTitleControl extends TitleControl { const editor = this.group.getEditor(index); this.editorTransfer.setData([new DraggedEditorIdentifier({ editor, groupId: this.group.id })], DraggedEditorIdentifier.prototype); - e.dataTransfer.effectAllowed = 'copyMove'; + e.dataTransfer!.effectAllowed = 'copyMove'; // Apply some datatransfer types to allow for dragging the element outside of the application const resource = toResource(editor, { supportSideBySide: true }); @@ -599,7 +599,7 @@ export class TabsTitleControl extends TitleControl { // Return if transfer is unsupported if (!this.isSupportedDropTransfer(e)) { - e.dataTransfer.dropEffect = 'none'; + e.dataTransfer!.dropEffect = 'none'; return; } @@ -610,7 +610,7 @@ export class TabsTitleControl extends TitleControl { const localDraggedEditor = this.editorTransfer.getData(DraggedEditorIdentifier.prototype)[0].identifier; if (localDraggedEditor.editor === this.group.getEditor(index) && localDraggedEditor.groupId === this.group.id) { - e.dataTransfer.dropEffect = 'none'; + e.dataTransfer!.dropEffect = 'none'; return; } } @@ -618,7 +618,7 @@ export class TabsTitleControl extends TitleControl { // Update the dropEffect to "copy" if there is no local data to be dragged because // in that case we can only copy the data into and not move it from its source if (!isLocalDragAndDrop) { - e.dataTransfer.dropEffect = 'copy'; + e.dataTransfer!.dropEffect = 'copy'; } this.updateDropFeedback(tab, true, index); @@ -661,7 +661,7 @@ export class TabsTitleControl extends TitleControl { return true; // (local) editors can always be dropped } - if (e.dataTransfer.types.length > 0) { + if (e.dataTransfer && e.dataTransfer.types.length > 0) { return true; // optimistically allow external data (// see https://github.com/Microsoft/vscode/issues/25789) } @@ -698,9 +698,9 @@ export class TabsTitleControl extends TitleControl { // Build labels and descriptions for each editor const labels = this.group.editors.map(editor => ({ editor, - name: editor.getName(), - description: editor.getDescription(verbosity), - title: editor.getTitle(Verbosity.LONG) + name: editor.getName()!, + description: editor.getDescription(verbosity) || undefined, + title: editor.getTitle(Verbosity.LONG) || undefined })); // Shorten labels as needed @@ -752,7 +752,7 @@ export class TabsTitleControl extends TitleControl { if (useLongDescriptions) { mapDescriptionToDuplicates.clear(); duplicateTitles.forEach(label => { - label.description = label.editor.getDescription(Verbosity.LONG); + label.description = label.editor.getDescription(Verbosity.LONG) || undefined; getOrSet(mapDescriptionToDuplicates, label.description, []).push(label); }); } @@ -780,7 +780,7 @@ export class TabsTitleControl extends TitleControl { }); } - private getLabelConfigFlags(value: string) { + private getLabelConfigFlags(value: string | undefined) { switch (value) { case 'short': return { verbosity: Verbosity.SHORT, shortenDuplicates: false }; @@ -925,7 +925,7 @@ export class TabsTitleControl extends TitleControl { // Highlight modified tabs with a border if configured if (this.accessor.partOptions.highlightModifiedTabs) { - let modifiedBorderColor: string; + let modifiedBorderColor: string | null; if (isGroupActive && isTabActive) { modifiedBorderColor = this.getColor(TAB_ACTIVE_MODIFIED_BORDER); } else if (isGroupActive && !isTabActive) { From ebf55c18b8002684212960c5c9807894422f25ce Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 11 Feb 2019 18:33:41 +0100 Subject: [PATCH 152/207] debt - move search history service to common --- src/tsconfig.strictNullChecks.json | 2 +- src/vs/workbench/electron-browser/shell.ts | 2 +- .../services/search/{node => common}/searchHistoryService.ts | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/vs/workbench/services/search/{node => common}/searchHistoryService.ts (100%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 7b4b9f867cd..ce3c562fc7d 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -729,6 +729,7 @@ "./vs/workbench/services/search/common/searchHelpers.ts", "./vs/workbench/services/search/common/replace.ts", "./vs/workbench/services/search/common/search.ts", + "./vs/workbench/services/search/common/searchHistoryService.ts", "./vs/workbench/services/search/node/fileSearch.ts", "./vs/workbench/services/search/node/fileSearchManager.ts", "./vs/workbench/services/search/node/rawSearchService.ts", @@ -738,7 +739,6 @@ "./vs/workbench/services/search/node/ripgrepTextSearchEngine.ts", "./vs/workbench/services/search/node/search.ts", "./vs/workbench/services/search/node/searchApp.ts", - "./vs/workbench/services/search/node/searchHistoryService.ts", "./vs/workbench/services/search/node/searchIpc.ts", "./vs/workbench/services/search/node/textSearchAdapter.ts", "./vs/workbench/services/search/node/textSearchManager.ts", diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index c28fe9ca74f..a20c43c0c3a 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -83,7 +83,7 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/node/remoteAge import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { OpenerService } from 'vs/editor/browser/services/openerService'; -import { SearchHistoryService } from 'vs/workbench/services/search/node/searchHistoryService'; +import { SearchHistoryService } from 'vs/workbench/services/search/common/searchHistoryService'; import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/node/extensionManagementServerService'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; import { LogLevelSetterChannel } from 'vs/platform/log/node/logIpc'; diff --git a/src/vs/workbench/services/search/node/searchHistoryService.ts b/src/vs/workbench/services/search/common/searchHistoryService.ts similarity index 100% rename from src/vs/workbench/services/search/node/searchHistoryService.ts rename to src/vs/workbench/services/search/common/searchHistoryService.ts From dbce60b083754e39b55f060b01f72f09c20339d8 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 11 Feb 2019 23:03:24 +0100 Subject: [PATCH 153/207] Fix #68408 --- .../electron-browser/extensionEditor.ts | 4 +- .../electron-browser/extensionsActions.ts | 172 +++++++++++++++--- .../media/extensionActions.css | 1 + .../themes/common/workbenchThemeService.ts | 2 +- .../electron-browser/workbenchThemeService.ts | 5 +- 5 files changed, 157 insertions(+), 27 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts index 0e03b0890ce..fcf2068e3ac 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts @@ -28,7 +28,7 @@ import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, IExtension import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets'; import { EditorOptions } from 'vs/workbench/common/editor'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; -import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions'; +import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions'; import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; @@ -367,6 +367,8 @@ export class ExtensionEditor extends BaseEditor { reloadAction, this.instantiationService.createInstance(StatusLabelAction), this.instantiationService.createInstance(UpdateAction), + this.instantiationService.createInstance(SetColorThemeAction), + this.instantiationService.createInstance(SetFileIconThemeAction), this.instantiationService.createInstance(EnableDropDownAction), this.instantiationService.createInstance(DisableDropDownAction, runningExtensions), this.instantiationService.createInstance(CombinedInstallAction), diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts index e5fc6a2016c..0025d474609 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts @@ -55,7 +55,7 @@ import { clipboard } from 'electron'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { coalesce } from 'vs/base/common/arrays'; -import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { IWorkbenchThemeService, COLOR_THEME_SETTING } from 'vs/workbench/services/themes/common/workbenchThemeService'; function toExtensionDescription(local: ILocalExtension): IExtensionDescription { return { @@ -147,7 +147,6 @@ export class InstallAction extends ExtensionAction { @IInstantiationService private readonly instantiationService: IInstantiationService, @INotificationService private readonly notificationService: INotificationService, @IOpenerService private readonly openerService: IOpenerService, - @IQuickInputService private readonly quickInputService: IQuickInputService, @IExtensionService private readonly runtimeExtensionService: IExtensionService, @IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService ) { @@ -183,8 +182,22 @@ export class InstallAction extends ExtensionAction { const extension = await this.install(this.extension); - if (extension.local && extension.local.manifest.contributes && extension.local.manifest.contributes.themes && extension.local.manifest.contributes.themes.length) { - return this.applyInstalledTheme(extension.local); + if (extension.local) { + const runningExtension = await this.getRunningExtension(extension.local); + if (runningExtension) { + const colorThemes = await this.workbenchThemeService.getColorThemes(runningExtension.identifier); + const fileIconThemes = await this.workbenchThemeService.getFileIconThemes(runningExtension.identifier); + if (colorThemes.length && !fileIconThemes.length) { + const action = this.instantiationService.createInstance(SetColorThemeAction); + action.extension = extension; + return action.run(true); + } + if (!colorThemes.length && fileIconThemes.length) { + const action = this.instantiationService.createInstance(SetFileIconThemeAction); + action.extension = extension; + return action.run(true); + } + } } } @@ -202,25 +215,6 @@ export class InstallAction extends ExtensionAction { }); } - private async applyInstalledTheme(extension: ILocalExtension): Promise { - const runningExtension = await this.getRunningExtension(extension); - if (runningExtension) { - const currentTheme = this.workbenchThemeService.getColorTheme(); - const themes = await this.workbenchThemeService.getColorThemes(runningExtension.identifier); - const delayer = new Delayer(100); - const picks: (IQuickPickItem | IQuickPickSeparator)[] = themes.map(theme => ({ label: theme.label, id: theme.id })); - picks.push({ type: 'separator' }); - picks.push({ label: localize('stay with current theme', "Stay with current theme ({0})", currentTheme.label), id: currentTheme.id }); - const pickedTheme = await this.quickInputService.pick( - picks, - { - placeHolder: localize('apply installed theme', "Apply installed theme or press Escape to cancel."), - onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setColorTheme(item.id, ConfigurationTarget.MEMORY).then(() => undefined)) - }); - this.workbenchThemeService.setColorTheme(pickedTheme ? pickedTheme.id : currentTheme.id, undefined); - } - } - private async getRunningExtension(extension: ILocalExtension): Promise { const runningExtension = await this.runtimeExtensionService.getExtension(extension.identifier.id); if (runningExtension) { @@ -1111,6 +1105,138 @@ export class ReloadAction extends ExtensionAction { } } +export class SetColorThemeAction extends ExtensionAction { + + private static readonly EnabledClass = 'extension-action theme'; + private static readonly DisabledClass = `${SetColorThemeAction.EnabledClass} disabled`; + + private disposables: IDisposable[] = []; + + constructor( + @IExtensionService extensionService: IExtensionService, + @IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService, + @IQuickInputService private readonly quickInputService: IQuickInputService, + @IConfigurationService private readonly configurationService: IConfigurationService + ) { + super(`extensions.colorTheme`, localize('color theme', "Set Color Theme"), SetColorThemeAction.DisabledClass, false); + Event.any(extensionService.onDidChangeExtensions, workbenchThemeService.onDidColorThemeChange)(() => this.update(), this, this.disposables); + this.update(); + } + + async update(): Promise { + this.enabled = false; + if (this.extension) { + const isInstalled = this.extension.state === ExtensionState.Installed; + if (isInstalled) { + const colorThemes = await this.workbenchThemeService.getColorThemes(new ExtensionIdentifier(this.extension.identifier.id)); + this.enabled = colorThemes.length > 0; + } + } + this.class = this.enabled ? SetColorThemeAction.EnabledClass : SetColorThemeAction.DisabledClass; + } + + async run(showCurrentTheme: boolean): Promise { + await this.update(); + if (!this.enabled) { + return; + } + let colorThemes = await this.workbenchThemeService.getColorThemes(new ExtensionIdentifier(this.extension.identifier.id)); + const currentTheme = this.workbenchThemeService.getColorTheme(); + showCurrentTheme = showCurrentTheme || colorThemes.some(t => t.id === currentTheme.id); + if (showCurrentTheme) { + colorThemes = colorThemes.filter(t => t.id !== currentTheme.id); + } + + const delayer = new Delayer(100); + const picks: (IQuickPickItem | IQuickPickSeparator)[] = []; + picks.push(...colorThemes.map(theme => ({ label: theme.label, id: theme.id }))); + if (showCurrentTheme) { + picks.push({ type: 'separator', label: localize('current', "Current") }); + picks.push({ label: currentTheme.label, id: currentTheme.id }); + } + const pickedTheme = await this.quickInputService.pick( + picks, + { + placeHolder: localize('select color theme', "Select Color Theme"), + onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setColorTheme(item.id, undefined)) + }); + let confValue = this.configurationService.inspect(COLOR_THEME_SETTING); + const target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER; + return this.workbenchThemeService.setColorTheme(pickedTheme ? pickedTheme.id : currentTheme.id, target); + } + + dispose() { + this.disposables = dispose(this.disposables); + super.dispose(); + } +} + +export class SetFileIconThemeAction extends ExtensionAction { + + private static readonly EnabledClass = 'extension-action theme'; + private static readonly DisabledClass = `${SetFileIconThemeAction.EnabledClass} disabled`; + + private disposables: IDisposable[] = []; + + constructor( + @IExtensionService extensionService: IExtensionService, + @IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService, + @IQuickInputService private readonly quickInputService: IQuickInputService, + @IConfigurationService private readonly configurationService: IConfigurationService + ) { + super(`extensions.fileIconTheme`, localize('file icon theme', "Set File Icon Theme"), SetFileIconThemeAction.DisabledClass, false); + Event.any(extensionService.onDidChangeExtensions, workbenchThemeService.onDidFileIconThemeChange)(() => this.update(), this, this.disposables); + this.update(); + } + + async update(): Promise { + this.enabled = false; + if (this.extension) { + const isInstalled = this.extension.state === ExtensionState.Installed; + if (isInstalled) { + const fileIconThemes = await this.workbenchThemeService.getFileIconThemes(new ExtensionIdentifier(this.extension.identifier.id)); + this.enabled = fileIconThemes.length > 0; + } + } + this.class = this.enabled ? SetFileIconThemeAction.EnabledClass : SetFileIconThemeAction.DisabledClass; + } + + async run(showCurrentTheme: boolean): Promise { + await this.update(); + if (!this.enabled) { + return; + } + let fileIconThemes = await this.workbenchThemeService.getFileIconThemes(new ExtensionIdentifier(this.extension.identifier.id)); + const currentTheme = this.workbenchThemeService.getFileIconTheme(); + showCurrentTheme = showCurrentTheme || fileIconThemes.some(t => t.id === currentTheme.id); + if (showCurrentTheme) { + fileIconThemes = fileIconThemes.filter(t => t.id !== currentTheme.id); + } + + const delayer = new Delayer(100); + const picks: (IQuickPickItem | IQuickPickSeparator)[] = []; + picks.push(...fileIconThemes.map(theme => ({ label: theme.label, id: theme.id }))); + if (showCurrentTheme) { + picks.push({ type: 'separator', label: localize('current', "Current") }); + picks.push({ label: currentTheme.label, id: currentTheme.id }); + } + const pickedTheme = await this.quickInputService.pick( + picks, + { + placeHolder: localize('select file icon theme', "Select File Icon Theme"), + onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setFileIconTheme(item.id, undefined)) + }); + let confValue = this.configurationService.inspect(COLOR_THEME_SETTING); + const target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER; + return this.workbenchThemeService.setFileIconTheme(pickedTheme ? pickedTheme.id : currentTheme.id, target); + } + + dispose() { + this.disposables = dispose(this.disposables); + super.dispose(); + } +} + export class OpenExtensionsViewletAction extends ShowViewletAction { static ID = VIEWLET_ID; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/extensionActions.css b/src/vs/workbench/contrib/extensions/electron-browser/media/extensionActions.css index d2bea0aecb4..3bf716270cc 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/media/extensionActions.css +++ b/src/vs/workbench/contrib/extensions/electron-browser/media/extensionActions.css @@ -31,6 +31,7 @@ .monaco-action-bar .action-item.disabled .action-label.extension-action.install:not(.installing), .monaco-action-bar .action-item.disabled .action-label.extension-action.uninstall:not(.uninstalling), .monaco-action-bar .action-item.disabled .action-label.extension-action.update, +.monaco-action-bar .action-item.disabled .action-label.extension-action.theme, .monaco-action-bar .action-item.disabled .action-label.extension-action.extension-editor-dropdown-action, .monaco-action-bar .action-item.disabled .action-label.extension-action.reload, .monaco-action-bar .action-item.disabled .action-label.disable-status.hide, diff --git a/src/vs/workbench/services/themes/common/workbenchThemeService.ts b/src/vs/workbench/services/themes/common/workbenchThemeService.ts index 9e386c7960c..4da012b7901 100644 --- a/src/vs/workbench/services/themes/common/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/common/workbenchThemeService.ts @@ -61,7 +61,7 @@ export interface IWorkbenchThemeService extends IThemeService { setFileIconTheme(iconThemeId: string | undefined, settingsTarget: ConfigurationTarget | undefined): Promise; getFileIconTheme(): IFileIconTheme; - getFileIconThemes(): Promise; + getFileIconThemes(extensionId?: ExtensionIdentifier): Promise; onDidFileIconThemeChange: Event; } diff --git a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts index d4b2043c48d..099a3ca61be 100644 --- a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts @@ -460,8 +460,9 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } } - public getFileIconThemes(): Promise { - return this.iconThemeStore.getFileIconThemes(); + public async getFileIconThemes(extensionId?: ExtensionIdentifier): Promise { + const filIconThemes = await this.iconThemeStore.getFileIconThemes(); + return extensionId ? filIconThemes.filter(c => c.extensionData && ExtensionIdentifier.equals(new ExtensionIdentifier(c.extensionData.extensionId), extensionId)) : filIconThemes; } public getFileIconTheme() { From 233c9b85f54870b59dcdf78a3ddbb0e6b124a355 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 11 Feb 2019 23:20:50 +0100 Subject: [PATCH 154/207] #68408 get the current theme from setting --- .../extensions/electron-browser/extensionsActions.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts index 0025d474609..4052760efdb 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts @@ -55,7 +55,7 @@ import { clipboard } from 'electron'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { coalesce } from 'vs/base/common/arrays'; -import { IWorkbenchThemeService, COLOR_THEME_SETTING } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { IWorkbenchThemeService, COLOR_THEME_SETTING, ICON_THEME_SETTING } from 'vs/workbench/services/themes/common/workbenchThemeService'; function toExtensionDescription(local: ILocalExtension): IExtensionDescription { return { @@ -1141,7 +1141,8 @@ export class SetColorThemeAction extends ExtensionAction { return; } let colorThemes = await this.workbenchThemeService.getColorThemes(new ExtensionIdentifier(this.extension.identifier.id)); - const currentTheme = this.workbenchThemeService.getColorTheme(); + const allThemes = await this.workbenchThemeService.getColorThemes(); + const currentTheme = allThemes.filter(t => t.settingsId === this.configurationService.getValue(COLOR_THEME_SETTING))[0]; showCurrentTheme = showCurrentTheme || colorThemes.some(t => t.id === currentTheme.id); if (showCurrentTheme) { colorThemes = colorThemes.filter(t => t.id !== currentTheme.id); @@ -1207,7 +1208,8 @@ export class SetFileIconThemeAction extends ExtensionAction { return; } let fileIconThemes = await this.workbenchThemeService.getFileIconThemes(new ExtensionIdentifier(this.extension.identifier.id)); - const currentTheme = this.workbenchThemeService.getFileIconTheme(); + const allThemes = await this.workbenchThemeService.getFileIconThemes(); + const currentTheme = allThemes.filter(t => t.settingsId === this.configurationService.getValue(ICON_THEME_SETTING))[0]; showCurrentTheme = showCurrentTheme || fileIconThemes.some(t => t.id === currentTheme.id); if (showCurrentTheme) { fileIconThemes = fileIconThemes.filter(t => t.id !== currentTheme.id); @@ -1226,7 +1228,7 @@ export class SetFileIconThemeAction extends ExtensionAction { placeHolder: localize('select file icon theme', "Select File Icon Theme"), onDidFocus: item => delayer.trigger(() => this.workbenchThemeService.setFileIconTheme(item.id, undefined)) }); - let confValue = this.configurationService.inspect(COLOR_THEME_SETTING); + let confValue = this.configurationService.inspect(ICON_THEME_SETTING); const target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER; return this.workbenchThemeService.setFileIconTheme(pickedTheme ? pickedTheme.id : currentTheme.id, target); } From 1f5b3988d853323f04980fa636cbd5e7f94cab70 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 11 Feb 2019 23:41:24 +0100 Subject: [PATCH 155/207] #68408 Consider null fle icon theme --- .../contrib/extensions/electron-browser/extensionsActions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts index 4052760efdb..ed5b9503d7c 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts @@ -1209,7 +1209,7 @@ export class SetFileIconThemeAction extends ExtensionAction { } let fileIconThemes = await this.workbenchThemeService.getFileIconThemes(new ExtensionIdentifier(this.extension.identifier.id)); const allThemes = await this.workbenchThemeService.getFileIconThemes(); - const currentTheme = allThemes.filter(t => t.settingsId === this.configurationService.getValue(ICON_THEME_SETTING))[0]; + const currentTheme = allThemes.filter(t => t.settingsId === this.configurationService.getValue(ICON_THEME_SETTING))[0] || this.workbenchThemeService.getFileIconTheme(); showCurrentTheme = showCurrentTheme || fileIconThemes.some(t => t.id === currentTheme.id); if (showCurrentTheme) { fileIconThemes = fileIconThemes.filter(t => t.id !== currentTheme.id); @@ -1218,7 +1218,7 @@ export class SetFileIconThemeAction extends ExtensionAction { const delayer = new Delayer(100); const picks: (IQuickPickItem | IQuickPickSeparator)[] = []; picks.push(...fileIconThemes.map(theme => ({ label: theme.label, id: theme.id }))); - if (showCurrentTheme) { + if (showCurrentTheme && currentTheme.label) { picks.push({ type: 'separator', label: localize('current', "Current") }); picks.push({ label: currentTheme.label, id: currentTheme.id }); } From b7bedc41be2d54956ef095d1fa2f85c7c1e9fce9 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 12 Feb 2019 00:04:29 +0100 Subject: [PATCH 156/207] set color themes always if exist --- .../contrib/extensions/electron-browser/extensionsActions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts index ed5b9503d7c..5d2b234fa75 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts @@ -187,12 +187,12 @@ export class InstallAction extends ExtensionAction { if (runningExtension) { const colorThemes = await this.workbenchThemeService.getColorThemes(runningExtension.identifier); const fileIconThemes = await this.workbenchThemeService.getFileIconThemes(runningExtension.identifier); - if (colorThemes.length && !fileIconThemes.length) { + if (colorThemes.length) { const action = this.instantiationService.createInstance(SetColorThemeAction); action.extension = extension; return action.run(true); } - if (!colorThemes.length && fileIconThemes.length) { + if (fileIconThemes.length) { const action = this.instantiationService.createInstance(SetFileIconThemeAction); action.extension = extension; return action.run(true); From d50c9d8609a284035c1233316ba238c1a247d803 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Mon, 11 Feb 2019 16:32:24 -0800 Subject: [PATCH 157/207] check if users can operate on reactions --- src/vs/editor/common/modes.ts | 1 + src/vs/workbench/api/node/extHostComments.ts | 11 ++++++++++- .../contrib/comments/electron-browser/commentNode.ts | 2 +- .../electron-browser/commentsEditorContribution.ts | 4 ++-- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 0e9fdec3f13..6126701924d 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1235,6 +1235,7 @@ export interface NewCommentAction { export interface CommentReaction { readonly label?: string; readonly hasReacted?: boolean; + readonly canEdit?: boolean; } /** diff --git a/src/vs/workbench/api/node/extHostComments.ts b/src/vs/workbench/api/node/extHostComments.ts index 547da7fe41f..506b4a0e189 100644 --- a/src/vs/workbench/api/node/extHostComments.ts +++ b/src/vs/workbench/api/node/extHostComments.ts @@ -258,6 +258,9 @@ function convertToComment(provider: vscode.DocumentCommentProvider | vscode.Work const canEdit = !!(provider as vscode.DocumentCommentProvider).editComment && vscodeComment.canEdit; const canDelete = !!(provider as vscode.DocumentCommentProvider).deleteComment && vscodeComment.canDelete; const iconPath = vscodeComment.userIconPath ? vscodeComment.userIconPath.toString() : vscodeComment.gravatar; + const providerCanDeleteReaction = !!(provider as vscode.DocumentCommentProvider).deleteReaction; + const providerCanAddReaction = !!(provider as vscode.DocumentCommentProvider).addReaction; + return { commentId: vscodeComment.commentId, body: extHostTypeConverter.MarkdownString.from(vscodeComment.body), @@ -267,6 +270,12 @@ function convertToComment(provider: vscode.DocumentCommentProvider | vscode.Work canDelete: canDelete, command: vscodeComment.command ? commandsConverter.toInternal(vscodeComment.command) : null, isDraft: vscodeComment.isDraft, - commentReactions: vscodeComment.commentReactions + commentReactions: vscodeComment.commentReactions.map(reaction => { + return { + label: reaction.label, + hasReacted: reaction.hasReacted, + canEdit: (reaction.hasReacted && providerCanDeleteReaction) || (!reaction.hasReacted && providerCanAddReaction) + }; + }) }; } diff --git a/src/vs/workbench/contrib/comments/electron-browser/commentNode.ts b/src/vs/workbench/contrib/comments/electron-browser/commentNode.ts index 6c61815bdb2..85161998a60 100644 --- a/src/vs/workbench/contrib/comments/electron-browser/commentNode.ts +++ b/src/vs/workbench/contrib/comments/electron-browser/commentNode.ts @@ -180,7 +180,7 @@ export class CommentNode extends Disposable { this._toDispose.push(this._reactionsActionBar); let reactionActions = this.comment.commentReactions!.map(reaction => { - return new Action(`reaction.${reaction.label}`, `${reaction.label}`, reaction.hasReacted ? 'active' : '', true, async () => { + return new Action(`reaction.${reaction.label}`, `${reaction.label}`, reaction.hasReacted && reaction.canEdit ? 'active' : '', reaction.canEdit, async () => { try { if (reaction.hasReacted) { await this.commentService.deleteReaction(this.owner, this.resource, this.comment, reaction); diff --git a/src/vs/workbench/contrib/comments/electron-browser/commentsEditorContribution.ts b/src/vs/workbench/contrib/comments/electron-browser/commentsEditorContribution.ts index 467d81e927d..6b67c55dace 100644 --- a/src/vs/workbench/contrib/comments/electron-browser/commentsEditorContribution.ts +++ b/src/vs/workbench/contrib/comments/electron-browser/commentsEditorContribution.ts @@ -748,13 +748,13 @@ registerThemingParticipant((theme, collector) => { const statusBarItemHoverBackground = theme.getColor(STATUS_BAR_ITEM_HOVER_BACKGROUND); if (statusBarItemHoverBackground) { - collector.addRule(`.monaco-editor .review-widget .body .review-comment .review-comment-contents .comment-reactions .action-item a.action-label:hover { background-color: ${statusBarItemHoverBackground}; border: 1px solid grey; + collector.addRule(`.monaco-editor .review-widget .body .review-comment .review-comment-contents .comment-reactions .action-item a.action-label.active:hover { background-color: ${statusBarItemHoverBackground}; border: 1px solid grey; border-radius: 3px; }`); } const statusBarItemActiveBackground = theme.getColor(STATUS_BAR_ITEM_ACTIVE_BACKGROUND); if (statusBarItemActiveBackground) { - collector.addRule(`.monaco-editor .review-widget .body .review-comment .review-comment-contents .comment-reactions .action-item a.action-label:active { background-color: ${statusBarItemActiveBackground}; border: 1px solid grey; + collector.addRule(`.monaco-editor .review-widget .body .review-comment .review-comment-contents .comment-reactions .action-item a.action-label.active:active { background-color: ${statusBarItemActiveBackground}; border: 1px solid grey; border-radius: 3px;}`); } }); From 24a42d3a4ba6aaa551ef291a3e5d15676a3a9ee7 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Feb 2019 12:00:58 -0800 Subject: [PATCH 158/207] Strict null auto add --- src/tsconfig.strictNullChecks.json | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index ce3c562fc7d..0607ea796ff 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -213,6 +213,7 @@ "./vs/platform/actions/test/common/menuService.test.ts", "./vs/platform/backup/common/backup.ts", "./vs/platform/backup/electron-main/backupMainService.ts", + "./vs/platform/browser/contextScopedHistoryWidget.ts", "./vs/platform/clipboard/common/clipboardService.ts", "./vs/platform/clipboard/electron-browser/clipboardService.ts", "./vs/platform/commands/common/commands.ts", @@ -371,7 +372,6 @@ "./vs/platform/url/common/urlService.ts", "./vs/platform/url/electron-main/electronUrlListener.ts", "./vs/platform/url/node/urlIpc.ts", - "./vs/platform/browser/contextScopedHistoryWidget.ts", "./vs/platform/windows/common/windows.ts", "./vs/platform/windows/electron-browser/windowService.ts", "./vs/platform/windows/electron-main/windows.ts", @@ -387,14 +387,15 @@ "./vs/vscode.d.ts", "./vs/vscode.proposed.d.ts", "./vs/workbench/api/common/configurationExtensionPoint.ts", - "./vs/workbench/api/common/menusExtensionPoint.ts", "./vs/workbench/api/common/jsonValidationExtensionPoint.ts", + "./vs/workbench/api/common/menusExtensionPoint.ts", "./vs/workbench/api/electron-browser/extHostCustomers.ts", "./vs/workbench/api/electron-browser/mainThreadClipboard.ts", "./vs/workbench/api/electron-browser/mainThreadCommands.ts", "./vs/workbench/api/electron-browser/mainThreadConfiguration.ts", "./vs/workbench/api/electron-browser/mainThreadConsole.ts", "./vs/workbench/api/electron-browser/mainThreadDebugService.ts", + "./vs/workbench/api/electron-browser/mainThreadDecorations.ts", "./vs/workbench/api/electron-browser/mainThreadDiagnostics.ts", "./vs/workbench/api/electron-browser/mainThreadDialogs.ts", "./vs/workbench/api/electron-browser/mainThreadDocumentContentProviders.ts", @@ -414,6 +415,7 @@ "./vs/workbench/api/electron-browser/mainThreadStorage.ts", "./vs/workbench/api/electron-browser/mainThreadTelemetry.ts", "./vs/workbench/api/electron-browser/mainThreadTerminalService.ts", + "./vs/workbench/api/electron-browser/mainThreadTreeViews.ts", "./vs/workbench/api/electron-browser/mainThreadUrls.ts", "./vs/workbench/api/electron-browser/mainThreadWindow.ts", "./vs/workbench/api/electron-browser/mainThreadWorkspace.ts", @@ -468,6 +470,7 @@ "./vs/workbench/browser/parts/views/views.ts", "./vs/workbench/browser/parts/views/viewsViewlet.ts", "./vs/workbench/browser/quickopen.ts", + "./vs/workbench/browser/style.ts", "./vs/workbench/browser/viewlet.ts", "./vs/workbench/browser/workbench.contribution.ts", "./vs/workbench/common/actions.ts", @@ -726,9 +729,9 @@ "./vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts", "./vs/workbench/services/remote/node/remoteAgentEnvironmentChannel.ts", "./vs/workbench/services/remote/node/remoteAgentService.ts", - "./vs/workbench/services/search/common/searchHelpers.ts", "./vs/workbench/services/search/common/replace.ts", "./vs/workbench/services/search/common/search.ts", + "./vs/workbench/services/search/common/searchHelpers.ts", "./vs/workbench/services/search/common/searchHistoryService.ts", "./vs/workbench/services/search/node/fileSearch.ts", "./vs/workbench/services/search/node/fileSearchManager.ts", @@ -742,14 +745,14 @@ "./vs/workbench/services/search/node/searchIpc.ts", "./vs/workbench/services/search/node/textSearchAdapter.ts", "./vs/workbench/services/search/node/textSearchManager.ts", + "./vs/workbench/services/search/test/common/replace.test.ts", + "./vs/workbench/services/search/test/common/search.test.ts", "./vs/workbench/services/search/test/common/searchHelpers.test.ts", "./vs/workbench/services/search/test/node/ripgrepFileSearch.test.ts", "./vs/workbench/services/search/test/node/ripgrepTextSearchEngine.test.ts", "./vs/workbench/services/search/test/node/search.test.ts", "./vs/workbench/services/search/test/node/textSearch.integrationTest.ts", "./vs/workbench/services/search/test/node/textSearchManager.test.ts", - "./vs/workbench/services/search/test/common/replace.test.ts", - "./vs/workbench/services/search/test/common/search.test.ts", "./vs/workbench/services/textMate/electron-browser/TMGrammars.ts", "./vs/workbench/services/textMate/electron-browser/TMHelper.ts", "./vs/workbench/services/textMate/electron-browser/TMSyntax.ts", From ea0d487dbe0ccc8a4af9bdb57f9bf2516695cfbc Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Feb 2019 12:24:55 -0800 Subject: [PATCH 159/207] Strict null check quickOpenController --- src/tsconfig.strictNullChecks.json | 2 + .../quickopen/browser/quickOpenWidget.ts | 6 +- .../parts/quickopen/quickOpenController.ts | 62 ++++++++++--------- 3 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 0607ea796ff..99c003b1d1d 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -462,6 +462,8 @@ "./vs/workbench/browser/parts/quickinput/quickInputBox.ts", "./vs/workbench/browser/parts/quickinput/quickInputList.ts", "./vs/workbench/browser/parts/quickinput/quickInputUtils.ts", + "./vs/workbench/browser/parts/quickopen/quickOpenActions.ts", + "./vs/workbench/browser/parts/quickopen/quickOpenController.ts", "./vs/workbench/browser/parts/quickopen/quickopen.ts", "./vs/workbench/browser/parts/sidebar/sidebarPart.ts", "./vs/workbench/browser/parts/statusbar/statusbar.ts", diff --git a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts index ed4b43d2680..74148e4a0fd 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts @@ -639,7 +639,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { this.setInput(input, autoFocus); } - private setInputAndLayout(input: IModel, autoFocus: IAutoFocus): void { + private setInputAndLayout(input: IModel, autoFocus?: IAutoFocus): void { this.treeContainer.style.height = `${this.getHeight(input)}px`; this.tree.setInput(null).then(() => { @@ -873,7 +873,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { } } - setInput(input: IModel, autoFocus: IAutoFocus, ariaLabel?: string): void { + setInput(input: IModel, autoFocus?: IAutoFocus, ariaLabel?: string): void { if (!this.isVisible()) { return; } @@ -945,7 +945,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { return this.inputBox; } - setExtraClass(clazz: string): void { + setExtraClass(clazz: string | null): void { const previousClass = this.element.getAttribute('quick-open-extra-class'); if (previousClass) { DOM.removeClasses(this.element, previousClass); diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 9b4f8f54995..f16ee0b235a 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -78,12 +78,12 @@ export class QuickOpenController extends Component implements IQuickOpenService private mapContextKeyToContext: { [id: string]: IContextKey; } = Object.create(null); private handlerOnOpenCalled: { [prefix: string]: boolean; } = Object.create(null); private promisesToCompleteOnHide: ValueCallback[] = []; - private previousActiveHandlerDescriptor: QuickOpenHandlerDescriptor; + private previousActiveHandlerDescriptor: QuickOpenHandlerDescriptor | null; private actionProvider = new ContributableActionProvider(); private closeOnFocusLost: boolean; private searchInEditorHistory: boolean; private editorHistoryHandler: EditorHistoryHandler; - private pendingGetResultsInvocation: CancellationTokenSource; + private pendingGetResultsInvocation: CancellationTokenSource | null; constructor( @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService, @@ -165,7 +165,7 @@ export class QuickOpenController extends Component implements IQuickOpenService // Telemetry: log that quick open is shown and log the mode const registry = Registry.as(Extensions.Quickopen); - const handlerDescriptor = registry.getQuickOpenHandler(prefix) || registry.getDefaultQuickOpenHandler(); + const handlerDescriptor = (prefix ? registry.getQuickOpenHandler(prefix) : undefined) || registry.getDefaultQuickOpenHandler(); // Trigger onOpen this.resolveHandler(handlerDescriptor); @@ -206,7 +206,7 @@ export class QuickOpenController extends Component implements IQuickOpenService } else { const editorHistory = this.getEditorHistoryWithGroupLabel(); if (editorHistory.getEntries().length < 2) { - quickNavigateConfiguration = null; // If no entries can be shown, default to normal quick open mode + quickNavigateConfiguration = undefined; // If no entries can be shown, default to normal quick open mode } // Compute auto focus @@ -270,7 +270,10 @@ export class QuickOpenController extends Component implements IQuickOpenService // Complete promises that are waiting while (this.promisesToCompleteOnHide.length) { - this.promisesToCompleteOnHide.pop()(true); + const callback = this.promisesToCompleteOnHide.pop(); + if (callback) { + callback(true); + } } if (reason !== HideReason.FOCUS_LOST) { @@ -297,7 +300,7 @@ export class QuickOpenController extends Component implements IQuickOpenService } private setQuickOpenContextKey(id?: string): void { - let key: IContextKey; + let key: IContextKey | undefined; if (id) { key = this.mapContextKeyToContext[id]; if (!key) { @@ -479,13 +482,13 @@ export class QuickOpenController extends Component implements IQuickOpenService // merge history and default handler results const handlerResults = (result && result.entries) || []; - this.mergeResults(quickOpenModel, handlerResults, resolvedHandler.getGroupLabel()); + this.mergeResults(quickOpenModel, handlerResults, resolvedHandler.getGroupLabel() || undefined); } }); }); } - private mergeResults(quickOpenModel: QuickOpenModel, handlerResults: QuickOpenEntry[], groupLabel: string): void { + private mergeResults(quickOpenModel: QuickOpenModel, handlerResults: QuickOpenEntry[], groupLabel: string | undefined): void { // Remove results already showing by checking for a "resource" property const mapEntryToResource = this.mapEntriesToResource(quickOpenModel); @@ -526,7 +529,7 @@ export class QuickOpenController extends Component implements IQuickOpenService const placeHolderLabel = (typeof canRun === 'string') ? canRun : nls.localize('canNotRunPlaceholder', "This quick open handler can not be used in the current context"); const model = new QuickOpenModel([new PlaceholderQuickOpenEntry(placeHolderLabel)], this.actionProvider); - this.showModel(model, resolvedHandler.getAutoFocus(value, { model, quickNavigateConfiguration: this.quickOpenWidget.getQuickNavigateConfiguration() }), resolvedHandler.getAriaLabel()); + this.showModel(model, resolvedHandler.getAutoFocus(value, { model, quickNavigateConfiguration: this.quickOpenWidget.getQuickNavigateConfiguration() }), resolvedHandler.getAriaLabel() || undefined); return Promise.resolve(undefined); } @@ -547,9 +550,9 @@ export class QuickOpenController extends Component implements IQuickOpenService if (!token.isCancellationRequested) { if (!result || !result.entries.length) { const model = new QuickOpenModel([new PlaceholderQuickOpenEntry(resolvedHandler.getEmptyLabel(value))]); - this.showModel(model, resolvedHandler.getAutoFocus(value, { model, quickNavigateConfiguration: this.quickOpenWidget.getQuickNavigateConfiguration() }), resolvedHandler.getAriaLabel()); + this.showModel(model, resolvedHandler.getAutoFocus(value, { model, quickNavigateConfiguration: this.quickOpenWidget.getQuickNavigateConfiguration() }), resolvedHandler.getAriaLabel() || undefined); } else { - this.showModel(result, resolvedHandler.getAutoFocus(value, { model: result, quickNavigateConfiguration: this.quickOpenWidget.getQuickNavigateConfiguration() }), resolvedHandler.getAriaLabel()); + this.showModel(result, resolvedHandler.getAutoFocus(value, { model: result, quickNavigateConfiguration: this.quickOpenWidget.getQuickNavigateConfiguration() }), resolvedHandler.getAriaLabel() || undefined); } } }); @@ -570,15 +573,16 @@ export class QuickOpenController extends Component implements IQuickOpenService } private clearModel(): void { - this.showModel(new QuickOpenModel(), null); + this.showModel(new QuickOpenModel(), undefined); } private mapEntriesToResource(model: QuickOpenModel): { [resource: string]: QuickOpenEntry; } { const entries = model.getEntries(); const mapEntryToPath: { [path: string]: QuickOpenEntry; } = {}; entries.forEach((entry: QuickOpenEntry) => { - if (entry.getResource()) { - mapEntryToPath[entry.getResource().toString()] = entry; + const resource = entry.getResource(); + if (resource) { + mapEntryToPath[resource.toString()] = entry; } }); @@ -655,7 +659,7 @@ class EditorHistoryHandler { getResults(searchValue?: string, token?: CancellationToken): QuickOpenEntry[] { // Massage search for scoring - const query = prepareQuery(searchValue); + const query = prepareQuery(searchValue || ''); // Just return all if we are not searching const history = this.historyService.getHistory(); @@ -670,7 +674,7 @@ class EditorHistoryHandler { // For now, only support to match on inputs that provide resource information .filter(input => { - let resource: URI; + let resource: URI | undefined; if (input instanceof EditorInput) { resource = resourceForEditorHistory(input, this.fileService); } else { @@ -690,7 +694,7 @@ class EditorHistoryHandler { return false; } - e.setHighlights(itemScore.labelMatch, itemScore.descriptionMatch); + e.setHighlights(itemScore.labelMatch || [], itemScore.descriptionMatch); return true; }) @@ -707,8 +711,8 @@ class EditorHistoryItemAccessorClass extends QuickOpenItemAccessorClass { super(); } - getItemDescription(entry: QuickOpenEntry): string { - return this.allowMatchOnDescription ? entry.getDescription() : undefined; + getItemDescription(entry: QuickOpenEntry): string | null { + return this.allowMatchOnDescription ? entry.getDescription() : null; } } @@ -721,9 +725,9 @@ export class EditorHistoryEntryGroup extends QuickOpenEntryGroup { export class EditorHistoryEntry extends EditorQuickOpenEntry { private input: IEditorInput | IResourceInput; - private resource: URI; - private label: string; - private description: string; + private resource: URI | undefined; + private label: string | null; + private description: string | null; private dirty: boolean; constructor( @@ -749,7 +753,7 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { const resourceInput = input as IResourceInput; this.resource = resourceInput.resource; this.label = resources.basenameOrAuthority(resourceInput.resource); - this.description = labelService.getUriLabel(resources.dirname(this.resource), { relative: true }); + this.description = labelService.getUriLabel(resources.dirname(this.resource)!, { relative: true }); this.dirty = this.resource && this.textFileService.isDirty(this.resource); if (this.dirty && this.textFileService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { @@ -762,7 +766,7 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { return this.dirty ? 'dirty' : ''; } - getLabel(): string { + getLabel(): string | null { return this.label; } @@ -776,12 +780,12 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { return nls.localize('entryAriaLabel', "{0}, recently opened", this.getLabel()); } - getDescription(): string { + getDescription(): string | null { return this.description; } - getResource(): URI { - return this.resource; + getResource(): URI | null { + return this.resource || null; } getInput(): IEditorInput | IResourceInput { @@ -806,7 +810,7 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { } } -function resourceForEditorHistory(input: EditorInput, fileService: IFileService): URI { +function resourceForEditorHistory(input: EditorInput, fileService: IFileService): URI | undefined { const resource = input ? input.getResource() : undefined; // For the editor history we only prefer resources that are either untitled or @@ -846,7 +850,7 @@ export class RemoveFromEditorHistoryAction extends Action { return { input: h, - iconClasses: getIconClasses(this.modelService, this.modeService, entry.getResource()), + iconClasses: getIconClasses(this.modelService, this.modeService, entry.getResource() || undefined), label: entry.getLabel(), description: entry.getDescription() }; From 0f89a21a5b38eb4aa55cfc39ea06d963a0f4d955 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Feb 2019 12:29:53 -0800 Subject: [PATCH 160/207] Strict null check extensionsWidget --- src/tsconfig.strictNullChecks.json | 2 ++ .../contrib/extensions/electron-browser/extensionsWidgets.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 99c003b1d1d..bc8cf4fec68 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -545,7 +545,9 @@ "./vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts", "./vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts", "./vs/workbench/contrib/extensions/electron-browser/extensionsActivationProgress.ts", + "./vs/workbench/contrib/extensions/electron-browser/extensionsList.ts", "./vs/workbench/contrib/extensions/electron-browser/extensionsUtils.ts", + "./vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts", "./vs/workbench/contrib/extensions/node/extensionsWorkbenchService.ts", "./vs/workbench/contrib/extensions/test/common/extensionQuery.test.ts", "./vs/workbench/contrib/feedback/electron-browser/feedback.contribution.ts", diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts index 8cf034ebdb5..7e81d54db35 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts @@ -136,7 +136,7 @@ export class RatingsWidget extends ExtensionWidget { } } this.container.title = this.extension.ratingCount === 1 ? localize('ratedBySingleUser', "Rated by 1 user") - : this.extension.ratingCount > 1 ? localize('ratedByUsers', "Rated by {0} users", this.extension.ratingCount) : localize('noRating', "No rating"); + : typeof this.extension.ratingCount === 'number' && this.extension.ratingCount > 1 ? localize('ratedByUsers', "Rated by {0} users", this.extension.ratingCount) : localize('noRating', "No rating"); } } From cbdd9bddbaafc669fb40f6cb79872332a1aebb2e Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Feb 2019 12:36:45 -0800 Subject: [PATCH 161/207] Strict null work on extensions --- .../electron-browser/runtimeExtensionsEditor.ts | 8 ++++---- src/vs/workbench/services/extensions/common/extensions.ts | 2 +- .../extensions/electron-browser/extensionHostProfiler.ts | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts index b1c5250d2a3..609c33cb153 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts @@ -90,7 +90,7 @@ interface IRuntimeExtension { description: IExtensionDescription; marketplaceInfo: IExtension; status: IExtensionsStatus; - profileInfo: IExtensionProfileInformation; + profileInfo?: IExtensionProfileInformation; unresponsiveProfile?: IExtensionHostProfile; } @@ -214,7 +214,7 @@ export class RuntimeExtensionsEditor extends BaseEditor { description: extensionDescription, marketplaceInfo: marketplaceMap[ExtensionIdentifier.toKey(extensionDescription.identifier)], status: statusMap[extensionDescription.identifier.value], - profileInfo: profileInfo, + profileInfo: profileInfo || undefined, unresponsiveProfile: this._extensionHostProfileService.getUnresponsiveProfile(extensionDescription.identifier) }; } @@ -402,7 +402,7 @@ export class RuntimeExtensionsEditor extends BaseEditor { horizontalScrolling: false }) as WorkbenchList; - this._list.splice(0, this._list.length, this._elements); + this._list.splice(0, this._list.length, this._elements || undefined); this._list.onContextMenu((e) => { if (!e.element) { @@ -579,7 +579,7 @@ export class DebugExtensionHostAction extends Action { } } - return this._debugService.startDebugging(null, { + return this._debugService.startDebugging(undefined, { type: 'node', name: nls.localize('debugExtensionHost.launch.name', "Attach Extension Host"), request: 'attach', diff --git a/src/vs/workbench/services/extensions/common/extensions.ts b/src/vs/workbench/services/extensions/common/extensions.ts index fabecb6b379..d40c975542c 100644 --- a/src/vs/workbench/services/extensions/common/extensions.ts +++ b/src/vs/workbench/services/extensions/common/extensions.ts @@ -89,7 +89,7 @@ export interface IExtensionHostProfile { /** * Extension id or one of the four known program states. */ -export type ProfileSegmentId = string | 'idle' | 'program' | 'gc' | 'self' | null; +export type ProfileSegmentId = string | 'idle' | 'program' | 'gc' | 'self'; export class ActivationTimes { constructor( diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts index 852b3130a2e..16ebfa07804 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts @@ -33,12 +33,12 @@ export class ExtensionHostProfiler { let nodes = profile.nodes; let idsToNodes = new Map(); - let idsToSegmentId = new Map(); + let idsToSegmentId = new Map(); for (let node of nodes) { idsToNodes.set(node.id, node); } - function visit(node: ProfileNode, segmentId: ProfileSegmentId) { + function visit(node: ProfileNode, segmentId: ProfileSegmentId | null) { if (!segmentId) { switch (node.callFrame.functionName) { case '(root)': From 14e4835a550aa14c404f06c4bedfcaa6b3ec49f3 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Feb 2019 12:54:20 -0800 Subject: [PATCH 162/207] Strict null extHostWorkspace --- src/tsconfig.strictNullChecks.json | 1 + .../electron-browser/mainThreadWorkspace.ts | 4 +-- src/vs/workbench/api/node/extHost.protocol.ts | 2 +- src/vs/workbench/api/node/extHostWorkspace.ts | 32 +++++++++---------- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index bc8cf4fec68..a8c9d8f9849 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -434,6 +434,7 @@ "./vs/workbench/api/node/extHostTypes.ts", "./vs/workbench/api/node/extHostUrls.ts", "./vs/workbench/api/node/extHostWindow.ts", + "./vs/workbench/api/node/extHostWorkspace.ts", "./vs/workbench/api/shared/editor.ts", "./vs/workbench/api/shared/tasks.ts", "./vs/workbench/browser/actions.ts", diff --git a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts index feaf90bb3fd..81924fb4f52 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts @@ -119,11 +119,11 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { // --- search --- - $startFileSearch(includePattern: string, _includeFolder: UriComponents, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise | undefined { + $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { const includeFolder = URI.revive(_includeFolder); const workspace = this._contextService.getWorkspace(); if (!workspace.folders.length) { - return undefined; + return Promise.resolve(undefined); } const query = this._queryBuilder.file( diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index c64f2d0d430..a366eb27bda 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -509,7 +509,7 @@ export interface ExtHostUrlsShape { } export interface MainThreadWorkspaceShape extends IDisposable { - $startFileSearch(includePattern: string | undefined, includeFolder: URI, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise | undefined; + $startFileSearch(includePattern: string | undefined, includeFolder: URI | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise; $startTextSearch(query: IPatternInfo, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise; $checkExists(includes: string[], token: CancellationToken): Promise; $saveAll(includeUntitled?: boolean): Promise; diff --git a/src/vs/workbench/api/node/extHostWorkspace.ts b/src/vs/workbench/api/node/extHostWorkspace.ts index 202b9b6e84c..ba9ba71eaca 100644 --- a/src/vs/workbench/api/node/extHostWorkspace.ts +++ b/src/vs/workbench/api/node/extHostWorkspace.ts @@ -69,7 +69,7 @@ class ExtHostWorkspaceImpl extends Workspace { // data and update their properties. It could be that an extension stored them // for later use and we want to keep them "live" if they are still present. const oldWorkspace = previousConfirmedWorkspace; - if (oldWorkspace) { + if (previousConfirmedWorkspace) { folders.forEach((folderData, index) => { const folderUri = URI.revive(folderData.uri); const existingFolder = ExtHostWorkspaceImpl._findFolder(previousUnconfirmedWorkspace || previousConfirmedWorkspace, folderUri); @@ -128,15 +128,15 @@ class ExtHostWorkspaceImpl extends Workspace { return this._workspaceFolders.slice(0); } - getWorkspaceFolder(uri: URI, resolveParent?: boolean): vscode.WorkspaceFolder { + getWorkspaceFolder(uri: URI, resolveParent?: boolean): vscode.WorkspaceFolder | undefined { if (resolveParent && this._structure.get(uri.toString())) { // `uri` is a workspace folder so we check for its parent - uri = dirname(uri); + uri = dirname(uri)!; } return this._structure.findSubstr(uri.toString()); } - resolveWorkspaceFolder(uri: URI): vscode.WorkspaceFolder { + resolveWorkspaceFolder(uri: URI): vscode.WorkspaceFolder | undefined { return this._structure.get(uri.toString()); } } @@ -147,7 +147,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { private readonly _logService: ILogService; private readonly _requestIdProvider: Counter; private readonly _barrier: Barrier; - private _actual: ExtHostWorkspaceProvider; + private _actual: ExtHostWorkspaceProvider | null; constructor( mainContext: IMainContext, @@ -162,7 +162,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { } public getWorkspaceProvider(): Promise { - return this._barrier.wait().then(_ => this._actual); + return this._barrier.wait().then(_ => this._actual!); } $initializeWorkspace(data: IWorkspaceData): void { @@ -187,7 +187,7 @@ export class ExtHostWorkspaceProvider { private readonly _onDidChangeWorkspace = new Emitter(); - private _confirmedWorkspace: ExtHostWorkspaceImpl; + private _confirmedWorkspace?: ExtHostWorkspaceImpl; private _unconfirmedWorkspace?: ExtHostWorkspaceImpl; private readonly _proxy: MainThreadWorkspaceShape; @@ -205,12 +205,12 @@ export class ExtHostWorkspaceProvider { ) { this._proxy = mainContext.getProxy(MainContext.MainThreadWorkspace); this._messageService = mainContext.getProxy(MainContext.MainThreadMessageService); - this._confirmedWorkspace = ExtHostWorkspaceImpl.toExtHostWorkspace(data).workspace; + this._confirmedWorkspace = ExtHostWorkspaceImpl.toExtHostWorkspace(data).workspace || undefined; } // --- workspace --- - get workspace(): Workspace { + get workspace(): Workspace | undefined { return this._actualWorkspace; } @@ -218,7 +218,7 @@ export class ExtHostWorkspaceProvider { return this._actualWorkspace ? this._actualWorkspace.name : undefined; } - private get _actualWorkspace(): ExtHostWorkspaceImpl { + private get _actualWorkspace(): ExtHostWorkspaceImpl | undefined { return this._unconfirmedWorkspace || this._confirmedWorkspace; } @@ -258,7 +258,7 @@ export class ExtHostWorkspaceProvider { // Simulate the updateWorkspaceFolders method on our data to do more validation const newWorkspaceFolders = currentWorkspaceFolders.slice(0); - newWorkspaceFolders.splice(index, deleteCount, ...validatedDistinctWorkspaceFoldersToAdd.map(f => ({ uri: f.uri, name: f.name || basenameOrAuthority(f.uri), index: undefined }))); + newWorkspaceFolders.splice(index, deleteCount, ...validatedDistinctWorkspaceFoldersToAdd.map(f => ({ uri: f.uri, name: f.name || basenameOrAuthority(f.uri), index: undefined! /* fixed later */ }))); for (let i = 0; i < newWorkspaceFolders.length; i++) { const folder = newWorkspaceFolders[i]; @@ -293,7 +293,7 @@ export class ExtHostWorkspaceProvider { return true; } - getWorkspaceFolder(uri: vscode.Uri, resolveParent?: boolean): vscode.WorkspaceFolder { + getWorkspaceFolder(uri: vscode.Uri, resolveParent?: boolean): vscode.WorkspaceFolder | undefined { if (!this._actualWorkspace) { return undefined; } @@ -346,7 +346,7 @@ export class ExtHostWorkspaceProvider { return path; } - if (typeof includeWorkspace === 'undefined') { + if (typeof includeWorkspace === 'undefined' && this._actualWorkspace) { includeWorkspace = this._actualWorkspace.folders.length > 1; } @@ -367,7 +367,7 @@ export class ExtHostWorkspaceProvider { name: this._actualWorkspace.name, configuration: this._actualWorkspace.configuration, folders - } as IWorkspaceData, this._actualWorkspace).workspace; + } as IWorkspaceData, this._actualWorkspace).workspace || undefined; } } @@ -377,7 +377,7 @@ export class ExtHostWorkspaceProvider { // Update our workspace object. We have a confirmed workspace, so we drop our // unconfirmed workspace. - this._confirmedWorkspace = workspace; + this._confirmedWorkspace = workspace || undefined; this._unconfirmedWorkspace = undefined; // Events @@ -405,7 +405,7 @@ export class ExtHostWorkspaceProvider { } } - let excludePatternOrDisregardExcludes: string | false | undefined; + let excludePatternOrDisregardExcludes: string | false = false; if (exclude === null) { excludePatternOrDisregardExcludes = false; } else if (exclude) { From ebff3af5060ca71af1cfc81e5585ef70855ffa12 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Feb 2019 13:20:01 -0800 Subject: [PATCH 163/207] Strict null supressions in tests --- .../mainThreadConfiguration.ts | 6 +- .../debug/test/browser/baseDebugView.test.ts | 4 +- .../debug/test/browser/linkDetector.test.ts | 6 +- .../services/panel/common/panelService.ts | 2 +- .../api/extHostWorkspace.test.ts | 142 +++++++++--------- .../api/mainThreadDocumentsAndEditors.test.ts | 22 +-- .../workbench/test/workbenchTestServices.ts | 4 +- 7 files changed, 93 insertions(+), 93 deletions(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts index 265994c37dc..a219ce3dca3 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts @@ -46,17 +46,17 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape { this._configurationListener.dispose(); } - $updateConfigurationOption(target: ConfigurationTarget, key: string, value: any, resourceUriComponenets: UriComponents): Promise { + $updateConfigurationOption(target: ConfigurationTarget | null, key: string, value: any, resourceUriComponenets: UriComponents | null): Promise { const resource = resourceUriComponenets ? URI.revive(resourceUriComponenets) : null; return this.writeConfiguration(target, key, value, resource); } - $removeConfigurationOption(target: ConfigurationTarget, key: string, resourceUriComponenets: UriComponents): Promise { + $removeConfigurationOption(target: ConfigurationTarget | null, key: string, resourceUriComponenets: UriComponents | null): Promise { const resource = resourceUriComponenets ? URI.revive(resourceUriComponenets) : null; return this.writeConfiguration(target, key, undefined, resource); } - private writeConfiguration(target: ConfigurationTarget, key: string, value: any, resource: URI | null): Promise { + private writeConfiguration(target: ConfigurationTarget | null, key: string, value: any, resource: URI | null): Promise { target = target !== null && target !== undefined ? target : this.deriveConfigurationTarget(key, resource); return this.configurationService.updateValue(key, value, { resource }, target, true); } diff --git a/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts b/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts index d4549a65671..149b78269a8 100644 --- a/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts @@ -55,10 +55,10 @@ suite('Debug - Base Debug View', () => { test('render variable', () => { const session = new MockSession(); const thread = new Thread(session, 'mockthread', 1); - const stackFrame = new StackFrame(thread, 1, null, 'app.js', 'normal', { startLineNumber: 1, startColumn: 1, endLineNumber: undefined, endColumn: undefined }, 0); + const stackFrame = new StackFrame(thread, 1, null!, 'app.js', 'normal', { startLineNumber: 1, startColumn: 1, endLineNumber: undefined!, endColumn: undefined! }, 0); const scope = new Scope(stackFrame, 1, 'local', 1, false, 10, 10); - let variable = new Variable(session, scope, 2, 'foo', 'bar.foo', undefined, 0, 0, {}, 'string'); + let variable = new Variable(session, scope, 2, 'foo', 'bar.foo', undefined!, 0, 0, {}, 'string'); let expression = $('.'); let name = $('.'); let value = $('.'); diff --git a/src/vs/workbench/contrib/debug/test/browser/linkDetector.test.ts b/src/vs/workbench/contrib/debug/test/browser/linkDetector.test.ts index c164d37d9db..5f554b70daf 100644 --- a/src/vs/workbench/contrib/debug/test/browser/linkDetector.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/linkDetector.test.ts @@ -58,10 +58,10 @@ suite('Debug - Link Detector', () => { assert.equal(1, output.children.length); assert.equal('SPAN', output.tagName); - assert.equal('A', output.firstElementChild.tagName); + assert.equal('A', output.firstElementChild!.tagName); assert(expectedOutput.test(output.outerHTML)); - assertElementIsLink(output.firstElementChild); - assert.equal(isWindows ? 'C:/foo/bar.js:12:34' : '/Users/foo/bar.js:12:34', output.firstElementChild.textContent); + assertElementIsLink(output.firstElementChild!); + assert.equal(isWindows ? 'C:/foo/bar.js:12:34' : '/Users/foo/bar.js:12:34', output.firstElementChild!.textContent); }); test('relativeLink', () => { diff --git a/src/vs/workbench/services/panel/common/panelService.ts b/src/vs/workbench/services/panel/common/panelService.ts index 11732a0207a..f99cf3c813b 100644 --- a/src/vs/workbench/services/panel/common/panelService.ts +++ b/src/vs/workbench/services/panel/common/panelService.ts @@ -30,7 +30,7 @@ export interface IPanelService { /** * Returns the current active panel or null if none */ - getActivePanel(): IPanel; + getActivePanel(): IPanel | null; /** * * Returns all built-in panels following the default order (Problems - Output - Debug Console - Terminal) 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 de017d9d841..114f0f57a0f 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts @@ -109,16 +109,16 @@ suite('ExtHostWorkspace', function () { assert.equal(ws.getPath(), undefined); ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('Folder'), 0), aWorkspaceFolderData(URI.file('Another/Folder'), 1)] }, new NullLogService(), new Counter()); - assert.equal(ws.getPath().replace(/\\/g, '/'), '/Folder'); + assert.equal(ws.getPath()!.replace(/\\/g, '/'), '/Folder'); ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('/Folder'), 0)] }, new NullLogService(), new Counter()); - assert.equal(ws.getPath().replace(/\\/g, '/'), '/Folder'); + assert.equal(ws.getPath()!.replace(/\\/g, '/'), '/Folder'); }); test('WorkspaceFolder has name and index', function () { const ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter()); - const [one, two] = ws.getWorkspaceFolders(); + const [one, two] = ws.getWorkspaceFolders()!; assert.equal(one.name, 'One'); assert.equal(one.index, 0); @@ -140,37 +140,37 @@ suite('ExtHostWorkspace', function () { let folder = ws.getWorkspaceFolder(URI.file('/foo/bar')); assert.equal(folder, undefined); - folder = ws.getWorkspaceFolder(URI.file('/Coding/One/file/path.txt')); + folder = ws.getWorkspaceFolder(URI.file('/Coding/One/file/path.txt'))!; assert.equal(folder.name, 'One'); - folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/file/path.txt')); + folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/file/path.txt'))!; assert.equal(folder.name, 'Two'); - folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nest')); + folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nest'))!; assert.equal(folder.name, 'Two'); - folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/file')); + folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/file'))!; assert.equal(folder.name, 'Nested'); - folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/f')); + folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/f'))!; assert.equal(folder.name, 'Nested'); - folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested'), true); + folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested'), true)!; assert.equal(folder.name, 'Two'); - folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/'), true); + folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/'), true)!; assert.equal(folder.name, 'Two'); - folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested')); + folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested'))!; assert.equal(folder.name, 'Nested'); - folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/')); + folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/'))!; assert.equal(folder.name, 'Nested'); - folder = ws.getWorkspaceFolder(URI.file('/Coding/Two'), true); + folder = ws.getWorkspaceFolder(URI.file('/Coding/Two'), true)!; assert.equal(folder, undefined); - folder = ws.getWorkspaceFolder(URI.file('/Coding/Two'), false); + folder = ws.getWorkspaceFolder(URI.file('/Coding/Two'), false)!; assert.equal(folder.name, 'Two'); }); @@ -240,21 +240,21 @@ suite('ExtHostWorkspace', function () { test('Multiroot change keeps existing workspaces live', function () { let ws = new ExtHostWorkspaceProvider(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService(), new Counter()); - let firstFolder = ws.getWorkspaceFolders()[0]; + let firstFolder = ws.getWorkspaceFolders()![0]; ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar2'), 0), aWorkspaceFolderData(URI.parse('foo:bar'), 1, 'renamed')] }); - assert.equal(ws.getWorkspaceFolders()[1], firstFolder); + assert.equal(ws.getWorkspaceFolders()![1], firstFolder); assert.equal(firstFolder.index, 1); assert.equal(firstFolder.name, 'renamed'); ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar2'), 1), aWorkspaceFolderData(URI.parse('foo:bar'), 2)] }); - assert.equal(ws.getWorkspaceFolders()[2], firstFolder); + assert.equal(ws.getWorkspaceFolders()![2], firstFolder); assert.equal(firstFolder.index, 2); ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0)] }); ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar'), 1)] }); - assert.notEqual(firstFolder, ws.workspace.folders[0]); + assert.notEqual(firstFolder, ws.workspace!.folders[0]); }); test('updateWorkspaceFolders - invalid arguments', function () { @@ -296,10 +296,10 @@ suite('ExtHostWorkspace', function () { // assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar')))); - assert.equal(1, ws.workspace.folders.length); - assert.equal(ws.workspace.folders[0].uri.toString(), URI.parse('foo:bar').toString()); + assert.equal(1, ws.workspace!.folders.length); + assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString()); - const firstAddedFolder = ws.getWorkspaceFolders()[0]; + const firstAddedFolder = ws.getWorkspaceFolders()![0]; let gotEvent = false; let sub = ws.onDidChangeWorkspace(e => { @@ -316,20 +316,20 @@ suite('ExtHostWorkspace', function () { ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }); // simulate acknowledgement from main side assert.equal(gotEvent, true); sub.dispose(); - assert.equal(ws.getWorkspaceFolders()[0], firstAddedFolder); // verify object is still live + assert.equal(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live // // Add two more folders // assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 1, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar1')), asUpdateWorkspaceFolderData(URI.parse('foo:bar2')))); - assert.equal(3, ws.workspace.folders.length); - assert.equal(ws.workspace.folders[0].uri.toString(), URI.parse('foo:bar').toString()); - assert.equal(ws.workspace.folders[1].uri.toString(), URI.parse('foo:bar1').toString()); - assert.equal(ws.workspace.folders[2].uri.toString(), URI.parse('foo:bar2').toString()); + assert.equal(3, ws.workspace!.folders.length); + assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString()); + assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString()); + assert.equal(ws.workspace!.folders[2].uri.toString(), URI.parse('foo:bar2').toString()); - const secondAddedFolder = ws.getWorkspaceFolders()[1]; - const thirdAddedFolder = ws.getWorkspaceFolders()[2]; + const secondAddedFolder = ws.getWorkspaceFolders()![1]; + const thirdAddedFolder = ws.getWorkspaceFolders()![2]; gotEvent = false; sub = ws.onDidChangeWorkspace(e => { @@ -348,18 +348,18 @@ suite('ExtHostWorkspace', function () { ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar1'), 1), aWorkspaceFolderData(URI.parse('foo:bar2'), 2)] }); // simulate acknowledgement from main side assert.equal(gotEvent, true); sub.dispose(); - assert.equal(ws.getWorkspaceFolders()[0], firstAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()[1], secondAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()[2], thirdAddedFolder); // verify object is still live + assert.equal(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live + assert.equal(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live + assert.equal(ws.getWorkspaceFolders()![2], thirdAddedFolder); // verify object is still live // // Remove one folder // assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 2, 1)); - assert.equal(2, ws.workspace.folders.length); - assert.equal(ws.workspace.folders[0].uri.toString(), URI.parse('foo:bar').toString()); - assert.equal(ws.workspace.folders[1].uri.toString(), URI.parse('foo:bar1').toString()); + assert.equal(2, ws.workspace!.folders.length); + assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString()); + assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString()); gotEvent = false; sub = ws.onDidChangeWorkspace(e => { @@ -375,21 +375,21 @@ suite('ExtHostWorkspace', function () { ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar1'), 1)] }); // simulate acknowledgement from main side assert.equal(gotEvent, true); sub.dispose(); - assert.equal(ws.getWorkspaceFolders()[0], firstAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()[1], secondAddedFolder); // verify object is still live + assert.equal(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live + assert.equal(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live // // Rename folder // assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar'), 'renamed 1'), asUpdateWorkspaceFolderData(URI.parse('foo:bar1'), 'renamed 2'))); - assert.equal(2, ws.workspace.folders.length); - assert.equal(ws.workspace.folders[0].uri.toString(), URI.parse('foo:bar').toString()); - assert.equal(ws.workspace.folders[1].uri.toString(), URI.parse('foo:bar1').toString()); - assert.equal(ws.workspace.folders[0].name, 'renamed 1'); - assert.equal(ws.workspace.folders[1].name, 'renamed 2'); - assert.equal(ws.getWorkspaceFolders()[0].name, 'renamed 1'); - assert.equal(ws.getWorkspaceFolders()[1].name, 'renamed 2'); + assert.equal(2, ws.workspace!.folders.length); + assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString()); + assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString()); + assert.equal(ws.workspace!.folders[0].name, 'renamed 1'); + assert.equal(ws.workspace!.folders[1].name, 'renamed 2'); + assert.equal(ws.getWorkspaceFolders()![0].name, 'renamed 1'); + assert.equal(ws.getWorkspaceFolders()![1].name, 'renamed 2'); gotEvent = false; sub = ws.onDidChangeWorkspace(e => { @@ -404,24 +404,24 @@ suite('ExtHostWorkspace', function () { ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0, 'renamed 1'), aWorkspaceFolderData(URI.parse('foo:bar1'), 1, 'renamed 2')] }); // simulate acknowledgement from main side assert.equal(gotEvent, true); sub.dispose(); - assert.equal(ws.getWorkspaceFolders()[0], firstAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()[1], secondAddedFolder); // verify object is still live - assert.equal(ws.workspace.folders[0].name, 'renamed 1'); - assert.equal(ws.workspace.folders[1].name, 'renamed 2'); - assert.equal(ws.getWorkspaceFolders()[0].name, 'renamed 1'); - assert.equal(ws.getWorkspaceFolders()[1].name, 'renamed 2'); + assert.equal(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live + assert.equal(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live + assert.equal(ws.workspace!.folders[0].name, 'renamed 1'); + assert.equal(ws.workspace!.folders[1].name, 'renamed 2'); + assert.equal(ws.getWorkspaceFolders()![0].name, 'renamed 1'); + assert.equal(ws.getWorkspaceFolders()![1].name, 'renamed 2'); // // Add and remove folders // assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar3')), asUpdateWorkspaceFolderData(URI.parse('foo:bar4')))); - assert.equal(2, ws.workspace.folders.length); - assert.equal(ws.workspace.folders[0].uri.toString(), URI.parse('foo:bar3').toString()); - assert.equal(ws.workspace.folders[1].uri.toString(), URI.parse('foo:bar4').toString()); + assert.equal(2, ws.workspace!.folders.length); + assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar3').toString()); + assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar4').toString()); - const fourthAddedFolder = ws.getWorkspaceFolders()[0]; - const fifthAddedFolder = ws.getWorkspaceFolders()[1]; + const fourthAddedFolder = ws.getWorkspaceFolders()![0]; + const fifthAddedFolder = ws.getWorkspaceFolders()![1]; gotEvent = false; sub = ws.onDidChangeWorkspace(e => { @@ -440,20 +440,20 @@ suite('ExtHostWorkspace', function () { ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar4'), 1)] }); // simulate acknowledgement from main side assert.equal(gotEvent, true); sub.dispose(); - assert.equal(ws.getWorkspaceFolders()[0], fourthAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()[1], fifthAddedFolder); // verify object is still live + assert.equal(ws.getWorkspaceFolders()![0], fourthAddedFolder); // verify object is still live + assert.equal(ws.getWorkspaceFolders()![1], fifthAddedFolder); // verify object is still live // // Swap folders // assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar4')), asUpdateWorkspaceFolderData(URI.parse('foo:bar3')))); - assert.equal(2, ws.workspace.folders.length); - assert.equal(ws.workspace.folders[0].uri.toString(), URI.parse('foo:bar4').toString()); - assert.equal(ws.workspace.folders[1].uri.toString(), URI.parse('foo:bar3').toString()); + assert.equal(2, ws.workspace!.folders.length); + assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar4').toString()); + assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar3').toString()); - assert.equal(ws.getWorkspaceFolders()[0], fifthAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()[1], fourthAddedFolder); // verify object is still live + assert.equal(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live + assert.equal(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live gotEvent = false; sub = ws.onDidChangeWorkspace(e => { @@ -468,8 +468,8 @@ suite('ExtHostWorkspace', function () { ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar4'), 0), aWorkspaceFolderData(URI.parse('foo:bar3'), 1)] }); // simulate acknowledgement from main side assert.equal(gotEvent, true); sub.dispose(); - assert.equal(ws.getWorkspaceFolders()[0], fifthAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()[1], fourthAddedFolder); // verify object is still live + assert.equal(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live + assert.equal(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live assert.equal(fifthAddedFolder.index, 0); assert.equal(fourthAddedFolder.index, 1); @@ -479,12 +479,12 @@ suite('ExtHostWorkspace', function () { assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 2, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar5')))); - assert.equal(3, ws.workspace.folders.length); - assert.equal(ws.workspace.folders[0].uri.toString(), URI.parse('foo:bar4').toString()); - assert.equal(ws.workspace.folders[1].uri.toString(), URI.parse('foo:bar3').toString()); - assert.equal(ws.workspace.folders[2].uri.toString(), URI.parse('foo:bar5').toString()); + assert.equal(3, ws.workspace!.folders.length); + assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar4').toString()); + assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar3').toString()); + assert.equal(ws.workspace!.folders[2].uri.toString(), URI.parse('foo:bar5').toString()); - const sixthAddedFolder = ws.getWorkspaceFolders()[2]; + const sixthAddedFolder = ws.getWorkspaceFolders()![2]; gotEvent = false; sub = ws.onDidChangeWorkspace(e => { @@ -506,9 +506,9 @@ suite('ExtHostWorkspace', function () { assert.equal(gotEvent, true); sub.dispose(); - assert.equal(ws.getWorkspaceFolders()[0], fifthAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()[1], fourthAddedFolder); // verify object is still live - assert.equal(ws.getWorkspaceFolders()[2], sixthAddedFolder); // verify object is still live + assert.equal(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live + assert.equal(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live + assert.equal(ws.getWorkspaceFolders()![2], sixthAddedFolder); // verify object is still live finish(); }); diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts index 6b0abfd5d04..60dfeb7108d 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadDocumentsAndEditors.test.ts @@ -29,7 +29,7 @@ suite('MainThreadDocumentsAndEditors', () => { let deltas: IDocumentsAndEditorsDelta[] = []; const hugeModelString = new Array(2 + (50 * 1024 * 1024)).join('-'); - function myCreateTestCodeEditor(model: ITextModel): TestCodeEditor { + function myCreateTestCodeEditor(model: ITextModel | undefined): TestCodeEditor { return createTestCodeEditor({ model: model, serviceCollection: new ServiceCollection( @@ -68,12 +68,12 @@ suite('MainThreadDocumentsAndEditors', () => { textFileService, workbenchEditorService, codeEditorService, - null, + null!, fileService, - null, - null, + null!, + null!, editorGroupService, - null, + null!, new class extends mock() implements IPanelService { _serviceBrand: any; onDidPanelOpen = Event.None; @@ -95,7 +95,7 @@ suite('MainThreadDocumentsAndEditors', () => { assert.equal(deltas.length, 1); const [delta] = deltas; - assert.equal(delta.addedDocuments.length, 1); + assert.equal(delta.addedDocuments!.length, 1); assert.equal(delta.removedDocuments, undefined); assert.equal(delta.addedEditors, undefined); assert.equal(delta.removedEditors, undefined); @@ -146,7 +146,7 @@ suite('MainThreadDocumentsAndEditors', () => { }); test('ignore editor w/o model', () => { - const editor = myCreateTestCodeEditor(null); + const editor = myCreateTestCodeEditor(undefined); assert.equal(deltas.length, 1); const [delta] = deltas; assert.equal(delta.newActiveEditor, null); @@ -166,13 +166,13 @@ suite('MainThreadDocumentsAndEditors', () => { assert.equal(deltas.length, 2); const [first, second] = deltas; - assert.equal(first.addedDocuments.length, 1); + assert.equal(first.addedDocuments!.length, 1); assert.equal(first.newActiveEditor, null); assert.equal(first.removedDocuments, undefined); assert.equal(first.addedEditors, undefined); assert.equal(first.removedEditors, undefined); - assert.equal(second.addedEditors.length, 1); + assert.equal(second.addedEditors!.length, 1); assert.equal(second.addedDocuments, undefined); assert.equal(second.removedDocuments, undefined); assert.equal(second.removedEditors, undefined); @@ -194,8 +194,8 @@ suite('MainThreadDocumentsAndEditors', () => { const [first] = deltas; assert.equal(first.newActiveEditor, null); - assert.equal(first.removedEditors.length, 1); - assert.equal(first.removedDocuments.length, 1); + assert.equal(first.removedEditors!.length, 1); + assert.equal(first.removedDocuments!.length, 1); assert.equal(first.addedDocuments, undefined); assert.equal(first.addedEditors, undefined); diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index f7f05c56919..8b51c7ab149 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -62,7 +62,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IDecorationsService, IResourceDecorationChangeEvent, IDecoration, IDecorationData, IDecorationsProvider } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, toDisposable, Disposable } from 'vs/base/common/lifecycle'; import { IEditorGroupsService, IEditorGroup, GroupsOrder, GroupsArrangement, GroupDirection, IAddGroupOptions, IMergeGroupOptions, IMoveEditorOptions, ICopyEditorOptions, IEditorReplacement, IGroupChangeEvent, EditorsOrder, IFindGroupScope, EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { IEditorService, IOpenEditorOverrideHandler } from 'vs/workbench/services/editor/common/editorService'; +import { IEditorService, IOpenEditorOverrideHandler, IActiveEditor } from 'vs/workbench/services/editor/common/editorService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { IDecorationRenderOptions } from 'vs/editor/common/editorCommon'; @@ -730,7 +730,7 @@ export class TestEditorService implements EditorServiceImpl { onDidCloseEditor: Event = Event.None; onDidOpenEditorFail: Event = Event.None; - activeControl: IEditor; + activeControl: IActiveEditor; activeTextEditorWidget: any; activeEditor: IEditorInput; editors: ReadonlyArray = []; From a8216d42a4c12e072d26611b1281ae03cdee7f38 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Feb 2019 14:05:10 -0800 Subject: [PATCH 164/207] Make the typescript plugins contribution point dynamic Part of #67575 --- .../src/typescriptServiceClient.ts | 4 + .../src/utils/plugins.ts | 73 ++++++++++++++----- 2 files changed, 60 insertions(+), 17 deletions(-) diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index 134942e4696..3af65af48e0 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -166,6 +166,10 @@ export default class TypeScriptServiceClient extends Disposable implements IType this._register(this.pluginManager.onDidUpdateConfig(update => { this.configurePlugin(update.pluginId, update.config); })); + + this._register(this.pluginManager.onDidChangePlugins(() => { + this.restartTsServer(); + })); } public get configuration() { diff --git a/extensions/typescript-language-features/src/utils/plugins.ts b/extensions/typescript-language-features/src/utils/plugins.ts index 3b0cf217b92..71ce2430cb8 100644 --- a/extensions/typescript-language-features/src/utils/plugins.ts +++ b/extensions/typescript-language-features/src/utils/plugins.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; +import * as arrays from './arrays'; import { Disposable } from './dispose'; -import { memoize } from './memoize'; export interface TypeScriptServerPlugin { readonly path: string; @@ -14,28 +14,45 @@ export interface TypeScriptServerPlugin { readonly languages: ReadonlyArray; } +namespace TypeScriptServerPlugin { + export function equals(a: TypeScriptServerPlugin, b: TypeScriptServerPlugin): boolean { + return a.path === b.path + && a.name === b.name + && a.enableForWorkspaceTypeScriptVersions === b.enableForWorkspaceTypeScriptVersions + && arrays.equals(a.languages, b.languages); + } +} + export class PluginManager extends Disposable { private readonly _pluginConfigurations = new Map(); - @memoize - public get plugins(): ReadonlyArray { - const plugins: TypeScriptServerPlugin[] = []; - for (const extension of vscode.extensions.all) { - const pack = extension.packageJSON; - if (pack.contributes && Array.isArray(pack.contributes.typescriptServerPlugins)) { - for (const plugin of pack.contributes.typescriptServerPlugins) { - plugins.push({ - name: plugin.name, - enableForWorkspaceTypeScriptVersions: !!plugin.enableForWorkspaceTypeScriptVersions, - path: extension.extensionPath, - languages: Array.isArray(plugin.languages) ? plugin.languages : [], - }); - } + private _plugins: Map> | undefined; + + constructor() { + super(); + + vscode.extensions.onDidChange(() => { + if (!this._plugins) { + return; } - } - return plugins; + const newPlugins = this.readPlugins(); + if (!arrays.equals(arrays.flatten(Array.from(this._plugins.values())), arrays.flatten(Array.from(newPlugins.values())), TypeScriptServerPlugin.equals)) { + this._plugins = newPlugins; + this._onDidUpdatePlugins.fire(this); + } + }, undefined, this._disposables); } + public get plugins(): ReadonlyArray { + if (!this._plugins) { + this._plugins = this.readPlugins(); + } + return arrays.flatten(Array.from(this._plugins.values())); + } + + private readonly _onDidUpdatePlugins = this._register(new vscode.EventEmitter()); + public readonly onDidChangePlugins = this._onDidUpdatePlugins.event; + private readonly _onDidUpdateConfig = this._register(new vscode.EventEmitter<{ pluginId: string, config: {} }>()); public readonly onDidUpdateConfig = this._onDidUpdateConfig.event; @@ -47,4 +64,26 @@ export class PluginManager extends Disposable { public configurations(): IterableIterator<[string, {}]> { return this._pluginConfigurations.entries(); } + + private readPlugins() { + const pluginMap = new Map>(); + for (const extension of vscode.extensions.all) { + const pack = extension.packageJSON; + if (pack.contributes && Array.isArray(pack.contributes.typescriptServerPlugins)) { + const plugins: TypeScriptServerPlugin[] = []; + for (const plugin of pack.contributes.typescriptServerPlugins) { + plugins.push({ + name: plugin.name, + enableForWorkspaceTypeScriptVersions: !!plugin.enableForWorkspaceTypeScriptVersions, + path: extension.extensionPath, + languages: Array.isArray(plugin.languages) ? plugin.languages : [], + }); + } + if (plugins.length) { + pluginMap.set(extension.id, plugins); + } + } + } + return pluginMap; + } } \ No newline at end of file From 8d0777697e03a05bef85d22a8a6d0e021d5e6690 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Feb 2019 16:41:41 -0800 Subject: [PATCH 165/207] Fix potential exception --- src/vs/workbench/api/node/extHostDocumentsAndEditors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts b/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts index 1cf6b396280..3aa410ad1e1 100644 --- a/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts +++ b/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts @@ -101,7 +101,7 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha data.selections.map(typeConverters.Selection.to), data.options, data.visibleRanges.map(typeConverters.Range.to), - typeConverters.ViewColumn.to(data.editorPosition) + typeof data.editorPosition === 'undefined' ? undefined : typeConverters.ViewColumn.to(data.editorPosition) ); this._editors.set(data.id, editor); } From a7ef42a93cbca59a2be1e7663f2fc3a57840149c Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Feb 2019 16:56:17 -0800 Subject: [PATCH 166/207] Fix strict null errors related to getActivePanel --- src/vs/workbench/browser/actions/navigationActions.ts | 2 +- src/vs/workbench/browser/panel.ts | 2 +- .../contrib/terminal/electron-browser/terminalInstance.ts | 2 +- .../workbench/services/timer/electron-browser/timerService.ts | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/browser/actions/navigationActions.ts b/src/vs/workbench/browser/actions/navigationActions.ts index 5e80d459df0..bc0bc3a7ada 100644 --- a/src/vs/workbench/browser/actions/navigationActions.ts +++ b/src/vs/workbench/browser/actions/navigationActions.ts @@ -68,7 +68,7 @@ abstract class BaseNavigationAction extends Action { return false; } - const activePanelId = this.panelService.getActivePanel().getId(); + const activePanelId = this.panelService.getActivePanel()!.getId(); return this.panelService.openPanel(activePanelId, true); } diff --git a/src/vs/workbench/browser/panel.ts b/src/vs/workbench/browser/panel.ts index 4cd74b0ebbe..f91feedc0d1 100644 --- a/src/vs/workbench/browser/panel.ts +++ b/src/vs/workbench/browser/panel.ts @@ -95,7 +95,7 @@ export abstract class TogglePanelAction extends Action { private isPanelActive(): boolean { const activePanel = this.panelService.getActivePanel(); - return activePanel && activePanel.getId() === this.panelId; + return !!activePanel && activePanel.getId() === this.panelId; } private isPanelFocused(): boolean { diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts index b9ca8a82b51..0a38e48b7fd 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstance.ts @@ -924,7 +924,7 @@ export class TerminalInstance implements ITerminalInstance { private _refreshSelectionContextKey() { const activePanel = this._panelService.getActivePanel(); - const isActive = activePanel && activePanel.getId() === TERMINAL_PANEL_ID; + const isActive = !!activePanel && activePanel.getId() === TERMINAL_PANEL_ID; this._terminalHasTextContextKey.set(isActive && this.hasSelection()); } diff --git a/src/vs/workbench/services/timer/electron-browser/timerService.ts b/src/vs/workbench/services/timer/electron-browser/timerService.ts index c8a35127665..be1ba98ee64 100644 --- a/src/vs/workbench/services/timer/electron-browser/timerService.ts +++ b/src/vs/workbench/services/timer/electron-browser/timerService.ts @@ -378,6 +378,7 @@ class TimerService implements ITimerService { } const activeViewlet = this._viewletService.getActiveViewlet(); + const activePanel = this._panelService.getActivePanel(); return { version: 2, ellapsed: perf.getDuration(startMark, 'didStartWorkbench'), @@ -389,7 +390,7 @@ class TimerService implements ITimerService { windowCount: await this._windowsService.getWindowCount(), viewletId: activeViewlet ? activeViewlet.getId() : undefined, editorIds: this._editorService.visibleEditors.map(input => input.getTypeId()), - panelId: this._panelService.getActivePanel() ? this._panelService.getActivePanel().getId() : undefined, + panelId: activePanel ? activePanel.getId() : undefined, // timers timers: { From 614ad268cb7553d97f24296fe383cac4de1ebc8f Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Feb 2019 17:24:26 -0800 Subject: [PATCH 167/207] Fix another case where typeConverters.ViewColumn.to could be passed undefined --- src/vs/workbench/api/node/extHostDocumentsAndEditors.ts | 2 +- src/vs/workbench/api/node/extHostWebview.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts b/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts index 3aa410ad1e1..4048e3a936b 100644 --- a/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts +++ b/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts @@ -101,7 +101,7 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha data.selections.map(typeConverters.Selection.to), data.options, data.visibleRanges.map(typeConverters.Range.to), - typeof data.editorPosition === 'undefined' ? undefined : typeConverters.ViewColumn.to(data.editorPosition) + typeof data.editorPosition === 'number' ? typeConverters.ViewColumn.to(data.editorPosition) : undefined ); this._editors.set(data.id, editor); } diff --git a/src/vs/workbench/api/node/extHostWebview.ts b/src/vs/workbench/api/node/extHostWebview.ts index 0906dd92aad..f3851ed6088 100644 --- a/src/vs/workbench/api/node/extHostWebview.ts +++ b/src/vs/workbench/api/node/extHostWebview.ts @@ -333,7 +333,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { } const webview = new ExtHostWebview(webviewHandle, this._proxy, options); - const revivedPanel = new ExtHostWebviewPanel(webviewHandle, this._proxy, viewType, title, typeConverters.ViewColumn.to(position), options, webview); + const revivedPanel = new ExtHostWebviewPanel(webviewHandle, this._proxy, viewType, title, typeof position === 'number' ? typeConverters.ViewColumn.to(position) : undefined, options, webview); this._webviewPanels.set(webviewHandle, revivedPanel); return Promise.resolve(serializer.deserializeWebviewPanel(revivedPanel, state)); } From b735cd16b2047c1347bd55b156c549b04df153a9 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 11 Feb 2019 17:45:32 -0800 Subject: [PATCH 168/207] Webview.reveal(undefined) should reveal in current column, not in the active column Fixes #67691 --- src/vs/workbench/api/electron-browser/mainThreadWebview.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts index f1c8f61a6f5..d88f7ee8162 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWebview.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts @@ -129,7 +129,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv const targetGroup = this._editorGroupService.getGroup(viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn)); - this._webviewService.revealWebview(webview, targetGroup || this._editorGroupService.activeGroup, !!showOptions.preserveFocus); + this._webviewService.revealWebview(webview, targetGroup || this._editorGroupService.getGroup(webview.group), !!showOptions.preserveFocus); } public $postMessage(handle: WebviewPanelHandle, message: any): Promise { From 621163d300e04489d7e24ff20ca19e974ac04112 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Sat, 9 Feb 2019 16:02:31 -0800 Subject: [PATCH 169/207] Fix #68168 --- src/vs/workbench/contrib/search/browser/searchActions.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/search/browser/searchActions.ts b/src/vs/workbench/contrib/search/browser/searchActions.ts index e1bd450dac3..ffac4eec71a 100644 --- a/src/vs/workbench/contrib/search/browser/searchActions.ts +++ b/src/vs/workbench/contrib/search/browser/searchActions.ts @@ -54,7 +54,7 @@ export function openSearchView(viewletService: IViewletService, panelService: IP return Promise.resolve(panelService.openPanel(VIEW_ID, focus) as SearchView); } -export function getSearchView(viewletService: IViewletService, panelService: IPanelService): SearchView { +export function getSearchView(viewletService: IViewletService, panelService: IPanelService): SearchView | null { const activeViewlet = viewletService.getActiveViewlet(); if (activeViewlet && activeViewlet.getId() === VIEW_ID) { return activeViewlet; @@ -65,7 +65,7 @@ export function getSearchView(viewletService: IViewletService, panelService: IPa return activePanel; } - return undefined; + return null; } function doAppendKeyBindingLabel(label: string, keyBinding: ResolvedKeybinding): string { @@ -230,7 +230,7 @@ export class RefreshAction extends Action { } get enabled(): boolean { - return this.searchView.isSearchSubmitted(); + return this.searchView && this.searchView.isSearchSubmitted(); } update(): void { @@ -242,6 +242,7 @@ export class RefreshAction extends Action { if (searchView) { searchView.onQueryChanged(); } + return Promise.resolve(null); } } From cbff3636412c99fe54c26c2cf957dc427117bd1a Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Sat, 9 Feb 2019 16:18:02 -0800 Subject: [PATCH 170/207] Strict null check extHostSearch.ts --- src/tsconfig.strictNullChecks.json | 1 + src/vs/workbench/api/node/extHostSearch.ts | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index a8c9d8f9849..385730e03cc 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -430,6 +430,7 @@ "./vs/workbench/api/node/extHostMessageService.ts", "./vs/workbench/api/node/extHostOutputService.ts", "./vs/workbench/api/node/extHostSearch.fileIndex.ts", + "./vs/workbench/api/node/extHostSearch.ts", "./vs/workbench/api/node/extHostStorage.ts", "./vs/workbench/api/node/extHostTypes.ts", "./vs/workbench/api/node/extHostUrls.ts", diff --git a/src/vs/workbench/api/node/extHostSearch.ts b/src/vs/workbench/api/node/extHostSearch.ts index d5a17a18809..82c7aa8769a 100644 --- a/src/vs/workbench/api/node/extHostSearch.ts +++ b/src/vs/workbench/api/node/extHostSearch.ts @@ -124,6 +124,10 @@ export class ExtHostSearch implements ExtHostSearchShape { }, token); } else { const indexProvider = this._fileIndexProvider.get(handle); + if (!indexProvider) { + throw new Error('unknown provider: ' + handle); + } + return this._fileIndexSearchManager.fileSearch(query, indexProvider, batch => { this._proxy.$handleFileMatch(handle, session, batch.map(p => p.resource)); }, token); @@ -147,7 +151,11 @@ export class ExtHostSearch implements ExtHostSearchShape { } }; - return this._internalFileSearchProvider.doFileSearch(rawQuery, onResult, token); + if (!this._internalFileSearchProvider) { + throw new Error('No internal file search handler'); + } + + return >this._internalFileSearchProvider.doFileSearch(rawQuery, onResult, token); } $clearCache(cacheKey: string): Promise { @@ -163,8 +171,8 @@ export class ExtHostSearch implements ExtHostSearchShape { $provideTextSearchResults(handle: number, session: number, rawQuery: IRawTextQuery, token: CancellationToken): Promise { const provider = this._textSearchProvider.get(handle); - if (!provider.provideTextSearchResults) { - return Promise.resolve(undefined); + if (!provider || !provider.provideTextSearchResults) { + throw new Error(`Unknown provider ${handle}`); } const query = reviveQuery(rawQuery); From 9441f43636a639aaffa28a9c7e6e36151944c8b3 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Mon, 11 Feb 2019 22:35:00 +0000 Subject: [PATCH 171/207] Fix #68464 - bump node2 --- build/builtInExtensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index d0d0107677b..9c463209c2f 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -16,7 +16,7 @@ }, { "name": "ms-vscode.node-debug2", - "version": "1.31.5", + "version": "1.31.6", "repo": "https://github.com/Microsoft/vscode-node-debug2", "metadata": { "id": "36d19e17-7569-4841-a001-947eb18602b2", From 0ad1c5bce2e979b2c85f950f9d82659764753c42 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Feb 2019 07:23:01 +0100 Subject: [PATCH 172/207] fix #68461 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0a2f69dc996..ecfa099e064 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.32.0", - "distro": "7b752ca3a77088fd367b62bfcce2e437c99030b7", + "distro": "6f5d9db8821add003be71e726b4ef49df83a51b4", "author": { "name": "Microsoft Corporation" }, From 0f5d764111666b1810a1c77255df391a53091d01 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Feb 2019 07:31:34 +0100 Subject: [PATCH 173/207] bootstrap - move zoom setting up --- src/bootstrap-window.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bootstrap-window.js b/src/bootstrap-window.js index c41965b30ae..80145240039 100644 --- a/src/bootstrap-window.js +++ b/src/bootstrap-window.js @@ -32,6 +32,12 @@ exports.load = function (modulePaths, resultCallback, options) { const args = parseURLQueryArgs(); const configuration = JSON.parse(args['config'] || '{}') || {}; + // Apply zoom level early to avoid glitches + const zoomLevel = configuration.zoomLevel; + if (typeof zoomLevel === 'number' && zoomLevel !== 0) { + webFrame.setZoomLevel(zoomLevel); + } + // Error handler // @ts-ignore process.on('uncaughtException', function (error) { @@ -51,12 +57,6 @@ exports.load = function (modulePaths, resultCallback, options) { // Enable ASAR support bootstrap.enableASARSupport(path.join(configuration.appRoot, 'node_modules')); - // Apply zoom level early to avoid glitches - const zoomLevel = configuration.zoomLevel; - if (typeof zoomLevel === 'number' && zoomLevel !== 0) { - webFrame.setZoomLevel(zoomLevel); - } - if (options && typeof options.canModifyDOM === 'function') { options.canModifyDOM(configuration); } From 4e583c455ad8fd99d482f7502cacb070ee0f8c67 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Feb 2019 10:01:36 +0100 Subject: [PATCH 174/207] debt - reduce shell.ts to its services --- src/vs/workbench/electron-browser/main.ts | 2 +- src/vs/workbench/electron-browser/shell.ts | 225 ++------------- .../workbench/electron-browser/workbench.ts | 273 ++++++++++++++---- 3 files changed, 233 insertions(+), 267 deletions(-) diff --git a/src/vs/workbench/electron-browser/main.ts b/src/vs/workbench/electron-browser/main.ts index e5d78340abc..86622a111a7 100644 --- a/src/vs/workbench/electron-browser/main.ts +++ b/src/vs/workbench/electron-browser/main.ts @@ -150,7 +150,7 @@ function openWorkbench(configuration: IWindowConfiguration): Promise { (self).require.config({ onError: err => { if (err.errorCode === 'load') { - shell.onUnexpectedError(new Error(nls.localize('loaderErrorNative', "Failed to load a required file. Please restart the application to try again. Details: {0}", JSON.stringify(err)))); + onUnexpectedError(new Error(nls.localize('loaderErrorNative', "Failed to load a required file. Please restart the application to try again. Details: {0}", JSON.stringify(err)))); } } }); diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index a20c43c0c3a..3f825444640 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -3,16 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as platform from 'vs/base/common/platform'; -import * as perf from 'vs/base/common/performance'; -import * as aria from 'vs/base/browser/ui/aria/aria'; import { Disposable } from 'vs/base/common/lifecycle'; -import * as errors from 'vs/base/common/errors'; -import { toErrorMessage } from 'vs/base/common/errorMessage'; import product from 'vs/platform/node/product'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import pkg from 'vs/platform/node/package'; -import { Workbench, IWorkbenchStartedInfo } from 'vs/workbench/electron-browser/workbench'; +import { Workbench } from 'vs/workbench/electron-browser/workbench'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService, configurationTelemetry, combinedAppender, LogAppender } from 'vs/platform/telemetry/common/telemetryUtils'; import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc'; @@ -40,13 +35,13 @@ import { ExtensionService } from 'vs/workbench/services/extensions/electron-brow import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { InstantiationService } from 'vs/platform/instantiation/node/instantiationService'; -import { ILifecycleService, LifecyclePhase, WillShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle'; +import { ILifecycleService, WillShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle'; import { IMarkerService } from 'vs/platform/markers/common/markers'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ISearchService, ISearchHistoryService } from 'vs/workbench/services/search/common/search'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { CommandService } from 'vs/workbench/services/commands/common/commandService'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { WorkbenchModeServiceImpl } from 'vs/workbench/services/mode/common/workbenchModeService'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -56,9 +51,6 @@ import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net'; import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/node/extensionManagementIpc'; import { IExtensionManagementService, IExtensionEnablementService, IExtensionManagementServerService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService'; -import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; -import { restoreFontInfo, readFontInfo, saveFontInfo } from 'vs/editor/browser/config/configuration'; -import * as browser from 'vs/base/browser/browser'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { WorkbenchThemeService } from 'vs/workbench/services/themes/electron-browser/workbenchThemeService'; import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; @@ -78,7 +70,6 @@ import { NotificationService } from 'vs/workbench/services/notification/common/n import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { DialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService'; import { DialogChannel } from 'vs/platform/dialogs/node/dialogIpc'; -import { EventType, addDisposableListener, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; import { IRemoteAgentService } from 'vs/workbench/services/remote/node/remoteAgentService'; import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import { IOpenerService } from 'vs/platform/opener/common/opener'; @@ -128,26 +119,25 @@ export class Shell extends Disposable { private broadcastService: IBroadcastService; private themeService: WorkbenchThemeService; private lifecycleService: LifecycleService; - private mainProcessServices: ServiceCollection; private notificationService: INotificationService; private container: HTMLElement; - private previousErrorValue: string; - private previousErrorTime: number; + private mainProcessClient: IPCClient; + private mainProcessServices: ServiceCollection; private configuration: IWindowConfiguration; - private workbench: Workbench; constructor( container: HTMLElement, coreServices: ICoreServices, mainProcessServices: ServiceCollection, - private mainProcessClient: IPCClient, + mainProcessClient: IPCClient, configuration: IWindowConfiguration ) { super(); this.container = container; + this.mainProcessClient = this._register(mainProcessClient); this.configuration = configuration; @@ -158,114 +148,29 @@ export class Shell extends Disposable { this.storageService = coreServices.storageService; this.mainProcessServices = mainProcessServices; - - this.previousErrorTime = 0; } - private renderContents(): void { - - // ARIA - aria.setARIAContainer(document.body); + open(): void { // Instantiation service with services - const [instantiationService, serviceCollection] = this.initServiceCollection(this.container); - - // Warm up font cache information before building up too many dom elements - restoreFontInfo(this.storageService); - readFontInfo(BareFontInfo.createFromRawSettings(this.configurationService.getValue('editor'), browser.getZoomLevel())); - this._register(this.storageService.onWillSaveState(() => { - saveFontInfo(this.storageService); // Keep font info for next startup around - })); + const [instantiationService, serviceCollection] = this.initServiceCollection(); // Workbench - this.workbench = this.createWorkbench(instantiationService, serviceCollection, this.container); + const workbench = this._register(instantiationService.createInstance( + Workbench, + this.container, + this.configuration, + serviceCollection, + this.lifecycleService, + this.mainProcessClient + )); + workbench.startup(); // Window - this.workbench.getInstantiationService().createInstance(ElectronWindow); - - // Handle case where workbench is not starting up properly - const timeoutHandle = setTimeout(() => { - this.logService.warn('Workbench did not finish loading in 10 seconds, that might be a problem that should be reported.'); - }, 10000); - - this.lifecycleService.when(LifecyclePhase.Restored).then(() => { - clearTimeout(timeoutHandle); - }); + workbench.getInstantiationService().createInstance(ElectronWindow); } - private createWorkbench(instantiationService: IInstantiationService, serviceCollection: ServiceCollection, container: HTMLElement): Workbench { - - function handleStartupError(logService: ILogService, error: Error): void { - - // Log it - logService.error(toErrorMessage(error, true)); - - // Rethrow - throw error; - } - - try { - const workbench = instantiationService.createInstance(Workbench, container, this.configuration, serviceCollection, this.lifecycleService, this.mainProcessClient); - - // Startup Workbench - workbench.startup().then(startupInfos => { - - // Startup Telemetry - this.logStartupTelemetry(startupInfos); - }, error => handleStartupError(this.logService, error)); - - return workbench; - } catch (error) { - handleStartupError(this.logService, error); - - return undefined; - } - } - - private logStartupTelemetry(info: IWorkbenchStartedInfo): void { - const { filesToOpen, filesToCreate, filesToDiff } = this.configuration; - /* __GDPR__ - "workspaceLoad" : { - "userAgent" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "windowSize.innerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "windowSize.innerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "windowSize.outerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "windowSize.outerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "emptyWorkbench": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workbench.filesToOpen": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workbench.filesToCreate": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "workbench.filesToDiff": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "customKeybindingsCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "theme": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "language": { "classification": "SystemMetaData", "purpose": "BusinessInsight" }, - "pinnedViewlets": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "restoredViewlet": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "restoredEditors": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "pinnedViewlets": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "startupKind": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('workspaceLoad', { - userAgent: navigator.userAgent, - windowSize: { innerHeight: window.innerHeight, innerWidth: window.innerWidth, outerHeight: window.outerHeight, outerWidth: window.outerWidth }, - emptyWorkbench: this.contextService.getWorkbenchState() === WorkbenchState.EMPTY, - 'workbench.filesToOpen': filesToOpen && filesToOpen.length || 0, - 'workbench.filesToCreate': filesToCreate && filesToCreate.length || 0, - 'workbench.filesToDiff': filesToDiff && filesToDiff.length || 0, - customKeybindingsCount: info.customKeybindingsCount, - theme: this.themeService.getColorTheme().id, - language: platform.language, - pinnedViewlets: info.pinnedViewlets, - restoredViewlet: info.restoredViewlet, - restoredEditors: info.restoredEditorsCount, - startupKind: this.lifecycleService.startupKind - }); - - // Telemetry: startup metrics - perf.mark('didStartWorkbench'); - } - - private initServiceCollection(container: HTMLElement): [IInstantiationService, ServiceCollection] { + private initServiceCollection(): [IInstantiationService, ServiceCollection] { const serviceCollection = new ServiceCollection(); serviceCollection.set(IWorkspaceContextService, this.contextService); serviceCollection.set(IConfigurationService, this.configurationService); @@ -390,94 +295,4 @@ export class Shell extends Disposable { return [instantiationService, serviceCollection]; } - - open(): void { - - // Listen on unhandled rejection events - window.addEventListener('unhandledrejection', (event: PromiseRejectionEvent) => { - - // See https://developer.mozilla.org/en-US/docs/Web/API/PromiseRejectionEvent - errors.onUnexpectedError(event.reason); - - // Prevent the printing of this event to the console - event.preventDefault(); - }); - - // Listen on unexpected errors - errors.setUnexpectedErrorHandler((error: any) => { - this.onUnexpectedError(error); - }); - - // Create Contents - this.renderContents(); - - // Layout - this.layout(); - - // Listeners - this.registerListeners(); - - // Set lifecycle phase to `Ready` - this.lifecycleService.phase = LifecyclePhase.Ready; - } - - private registerListeners(): void { - this._register(addDisposableListener(window, EventType.RESIZE, e => this.onWindowResize(e, true))); - } - - private onWindowResize(e: any, retry: boolean): void { - if (e.target === window) { - if (window.document && window.document.body && window.document.body.clientWidth === 0) { - // TODO@Ben this is an electron issue on macOS when simple fullscreen is enabled - // where for some reason the window clientWidth is reported as 0 when switching - // between simple fullscreen and normal screen. In that case we schedule the layout - // call at the next animation frame once, in the hope that the dimensions are - // proper then. - if (retry) { - scheduleAtNextAnimationFrame(() => this.onWindowResize(e, false)); - } - return; - } - - this.layout(); - } - } - - onUnexpectedError(error: any): void { - const errorMsg = toErrorMessage(error, true); - if (!errorMsg) { - return; - } - - const now = Date.now(); - if (errorMsg === this.previousErrorValue && now - this.previousErrorTime <= 1000) { - return; // Return if error message identical to previous and shorter than 1 second - } - - this.previousErrorTime = now; - this.previousErrorValue = errorMsg; - - // Log it - this.logService.error(errorMsg); - - // Show to user if friendly message provided - if (error && error.friendlyMessage && this.notificationService) { - this.notificationService.error(error.friendlyMessage); - } - } - - private layout(): void { - this.workbench.layout(); - } - - dispose(): void { - super.dispose(); - - // Dispose Workbench - if (this.workbench) { - this.workbench.dispose(); - } - - this.mainProcessClient.dispose(); - } } diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index cb0f4ed466d..e11d491f04c 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -8,15 +8,15 @@ import 'vs/workbench/browser/style'; import { localize } from 'vs/nls'; import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; -import * as DOM from 'vs/base/browser/dom'; +import { EventType, addDisposableListener, addClasses, scheduleAtNextAnimationFrame, addClass, removeClass, trackFocus, isAncestor, getClientArea, position, size } from 'vs/base/browser/dom'; import { RunOnceScheduler, runWhenIdle } from 'vs/base/common/async'; -import * as browser from 'vs/base/browser/browser'; -import * as perf from 'vs/base/common/performance'; -import * as errors from 'vs/base/common/errors'; +import { getZoomLevel, onDidChangeFullscreen, isFullscreen, getZoomFactor } from 'vs/base/browser/browser'; +import { mark } from 'vs/base/common/performance'; +import { onUnexpectedError, setUnexpectedErrorHandler } from 'vs/base/common/errors'; import { BackupFileService, InMemoryBackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { Registry } from 'vs/platform/registry/common/platform'; -import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform'; +import { isWindows, isLinux, isMacintosh, language } from 'vs/base/common/platform'; import { IResourceInput } from 'vs/platform/editor/common/editor'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IEditorInputFactoryRegistry, Extensions as EditorExtensions, TextCompareEditorVisibleContext, TEXT_DIFF_EDITOR_ID, EditorsVisibleContext, InEditorZenModeContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, IUntitledResourceInput, IResourceDiffInput, SplitEditorsVertically, TextCompareEditorActiveContext, ActiveEditorContext } from 'vs/workbench/common/editor'; @@ -114,6 +114,12 @@ import { LogStorageAction } from 'vs/platform/storage/node/storageService'; import { Sizing, Direction, Grid, View } from 'vs/base/browser/ui/grid/grid'; import { IEditor } from 'vs/editor/common/editorCommon'; import { WorkbenchLayout } from 'vs/workbench/browser/layout'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { setARIAContainer } from 'vs/base/browser/ui/aria/aria'; +import { restoreFontInfo, readFontInfo, saveFontInfo } from 'vs/editor/browser/config/configuration'; +import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; +import { ILogService } from 'vs/platform/log/common/log'; +import { toErrorMessage } from 'vs/base/common/errorMessage'; interface WorkbenchParams { configuration: IWindowConfiguration; @@ -130,13 +136,12 @@ interface IZenModeSettings { restore: boolean; } -export interface IWorkbenchStartedInfo { +interface IWorkbenchStartedInfo { customKeybindingsCount: number; pinnedViewlets: string[]; restoredViewlet: string; restoredEditorsCount: number; } - type FontAliasingOption = 'default' | 'antialiased' | 'none' | 'auto'; const fontAliasingValues: FontAliasingOption[] = ['antialiased', 'none', 'auto']; @@ -191,6 +196,9 @@ export class Workbench extends Disposable implements IPartService { _serviceBrand: any; + private previousErrorValue: string; + private previousErrorTime: number = 0; + private workbenchParams: WorkbenchParams; private workbench: HTMLElement; private workbenchStarted: boolean; @@ -263,7 +271,9 @@ export class Workbench extends Disposable implements IPartService { @IWorkbenchThemeService private readonly themeService: WorkbenchThemeService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @IWindowService private readonly windowService: IWindowService, - @INotificationService private readonly notificationService: NotificationService + @INotificationService private readonly notificationService: NotificationService, + @ITelemetryService private readonly telemetryService: ITelemetryService, + @ILogService private readonly logService: ILogService ) { super(); @@ -273,11 +283,75 @@ export class Workbench extends Disposable implements IPartService { (configuration.filesToCreate && configuration.filesToCreate.length > 0) || (configuration.filesToOpen && configuration.filesToOpen.length > 0) || (configuration.filesToDiff && configuration.filesToDiff.length > 0); + + this.registerErrorHandler(); } - startup(): Promise { + private registerErrorHandler(): void { + + // Listen on unhandled rejection events + window.addEventListener('unhandledrejection', (event: PromiseRejectionEvent) => { + + // See https://developer.mozilla.org/en-US/docs/Web/API/PromiseRejectionEvent + onUnexpectedError(event.reason); + + // Prevent the printing of this event to the console + event.preventDefault(); + }); + + // Install handler for unexpected errors + setUnexpectedErrorHandler(error => this.handleUnexpectedError(error)); + } + + private handleUnexpectedError(error: any): void { + const errorMsg = toErrorMessage(error, true); + if (!errorMsg) { + return; + } + + const now = Date.now(); + if (errorMsg === this.previousErrorValue && now - this.previousErrorTime <= 1000) { + return; // Return if error message identical to previous and shorter than 1 second + } + + this.previousErrorTime = now; + this.previousErrorValue = errorMsg; + + // Log it + this.logService.error(errorMsg); + + // Show to user if friendly message provided + if (error && error.friendlyMessage && this.notificationService) { + this.notificationService.error(error.friendlyMessage); + } + } + + startup(): Promise { + try { + return this.doStartup().then(undefined, error => this.logService.error(toErrorMessage(error, true))); + } catch (error) { + this.logService.error(toErrorMessage(error, true)); + + throw error; // rethrow because this is a critical issue we cannot handle properly here + } + } + + private doStartup(): Promise { this.workbenchStarted = true; + // Set lifecycle phase to `Ready` + this.lifecycleService.phase = LifecyclePhase.Ready; + + // ARIA + setARIAContainer(document.body); + + // Warm up font cache information before building up too many dom elements + restoreFontInfo(this.storageService); + readFontInfo(BareFontInfo.createFromRawSettings(this.configurationService.getValue('editor'), getZoomLevel())); + this._register(this.storageService.onWillSaveState(() => { + saveFontInfo(this.storageService); // Keep font info for next startup around + })); + // Create Workbench Container this.createWorkbench(); @@ -302,11 +376,23 @@ export class Workbench extends Disposable implements IPartService { // Workbench Layout this.createWorkbenchLayout(); + // Layout + this.layout(); + // Driver if (this.environmentService.driverHandle) { registerWindowDriver(this.mainProcessClient, this.configuration.windowId, this.instantiationService).then(disposable => this._register(disposable)); } + // Handle case where workbench is not starting up properly + const timeoutHandle = setTimeout(() => { + this.logService.warn('Workbench did not finish loading in 10 seconds, that might be a problem that should be reported.'); + }, 10000); + + this.lifecycleService.when(LifecyclePhase.Restored).then(() => { + clearTimeout(timeoutHandle); + }); + // Restore Parts return this.restoreParts(); } @@ -315,11 +401,7 @@ export class Workbench extends Disposable implements IPartService { this.workbench = document.createElement('div'); this.workbench.id = Identifiers.WORKBENCH_CONTAINER; - DOM.addClasses(this.workbench, 'monaco-workbench', isWindows ? 'windows' : isLinux ? 'linux' : 'mac'); - - this._register(DOM.addDisposableListener(this.workbench, DOM.EventType.SCROLL, () => { - this.workbench.scrollTop = 0; // Prevent workbench from scrolling #55456 - })); + addClasses(this.workbench, 'monaco-workbench', isWindows ? 'windows' : isLinux ? 'linux' : 'mac'); } private createGlobalActions(): void { @@ -515,21 +597,46 @@ export class Workbench extends Disposable implements IPartService { this._register(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration())); // Fullscreen changes - this._register(browser.onDidChangeFullscreen(() => this.onFullscreenChanged())); + this._register(onDidChangeFullscreen(() => this.onFullscreenChanged())); // Group changes this._register(this.editorGroupService.onDidAddGroup(() => this.centerEditorLayout(this.shouldCenterLayout))); this._register(this.editorGroupService.onDidRemoveGroup(() => this.centerEditorLayout(this.shouldCenterLayout))); + + // Layout + this._register(addDisposableListener(window, EventType.RESIZE, e => this.onWindowResize(e, true))); + + // Prevent workbench from scrolling #55456 + this._register(addDisposableListener(this.workbench, EventType.SCROLL, () => { + this.workbench.scrollTop = 0; + })); + } + + private onWindowResize(e: any, retry: boolean): void { + if (e.target === window) { + if (window.document && window.document.body && window.document.body.clientWidth === 0) { + // TODO@Ben this is an electron issue on macOS when simple fullscreen is enabled + // where for some reason the window clientWidth is reported as 0 when switching + // between simple fullscreen and normal screen. In that case we schedule the layout + // call at the next animation frame once, in the hope that the dimensions are + // proper then. + if (retry) { + scheduleAtNextAnimationFrame(() => this.onWindowResize(e, false)); + } + return; + } + + this.layout(); + } } private onFullscreenChanged(): void { // Apply as CSS class - const isFullscreen = browser.isFullscreen(); - if (isFullscreen) { - DOM.addClass(this.workbench, 'fullscreen'); + if (isFullscreen()) { + addClass(this.workbench, 'fullscreen'); } else { - DOM.removeClass(this.workbench, 'fullscreen'); + removeClass(this.workbench, 'fullscreen'); if (this.zenMode.transitionedToFullScreen && this.zenMode.active) { this.toggleZenMode(); @@ -547,7 +654,7 @@ export class Workbench extends Disposable implements IPartService { if (visible !== this.menubarToggled) { this.menubarToggled = visible; - if (browser.isFullscreen() && (this.menubarVisibility === 'toggle' || this.menubarVisibility === 'default')) { + if (isFullscreen() && (this.menubarVisibility === 'toggle' || this.menubarVisibility === 'default')) { this._onTitleBarVisibilityChange.fire(); this.layout(); } @@ -694,7 +801,7 @@ export class Workbench extends Disposable implements IPartService { inputFocused.set(isInputFocused); if (isInputFocused) { - const tracker = DOM.trackFocus(document.activeElement as HTMLElement); + const tracker = trackFocus(document.activeElement as HTMLElement); Event.once(tracker.onDidBlur)(() => { inputFocused.set(activeElementIsInput()); @@ -703,7 +810,7 @@ export class Workbench extends Disposable implements IPartService { } } - this._register(DOM.addDisposableListener(window, 'focusin', () => trackInputFocus(), true)); + this._register(addDisposableListener(window, 'focusin', () => trackInputFocus(), true)); const workbenchStateRawContext = new RawContextKey('workbenchState', getWorkbenchStateString(this.configurationService.getWorkbenchState())); const workbenchStateContext = workbenchStateRawContext.bindTo(this.contextKeyService); @@ -733,11 +840,11 @@ export class Workbench extends Disposable implements IPartService { updateSplitEditorsVerticallyContext(); } - private restoreParts(): Promise { + private restoreParts(): Promise { const restorePromises: Promise[] = []; // Restore Editorpart - perf.mark('willRestoreEditors'); + mark('willRestoreEditors'); restorePromises.push(this.editorPart.whenRestored.then(() => { function openEditors(editors: IResourceEditor[], editorService: IEditorService) { @@ -755,7 +862,7 @@ export class Workbench extends Disposable implements IPartService { } return editorsToOpen.then(editors => openEditors(editors, this.editorService)); - }).then(() => perf.mark('didRestoreEditors'))); + }).then(() => mark('didRestoreEditors'))); // Restore Sidebar let viewletIdToRestore: string; @@ -770,21 +877,21 @@ export class Workbench extends Disposable implements IPartService { viewletIdToRestore = this.sidebarPart.getDefaultViewletId(); } - perf.mark('willRestoreViewlet'); + mark('willRestoreViewlet'); restorePromises.push(this.sidebarPart.openViewlet(viewletIdToRestore) .then(viewlet => viewlet || this.sidebarPart.openViewlet(this.sidebarPart.getDefaultViewletId())) - .then(() => perf.mark('didRestoreViewlet'))); + .then(() => mark('didRestoreViewlet'))); } // Restore Panel const panelRegistry = Registry.as(PanelExtensions.Panels); const panelId = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId()); if (!this.panelHidden && !!panelId) { - perf.mark('willRestorePanel'); + mark('willRestorePanel'); const isPanelToRestoreEnabled = !!this.panelPart.getPanels().filter(p => p.id === panelId).length; const panelIdToRestore = isPanelToRestoreEnabled ? panelId : panelRegistry.getDefaultPanelId(); this.panelPart.openPanel(panelIdToRestore, false); - perf.mark('didRestorePanel'); + mark('didRestorePanel'); } // Restore Zen Mode if active and supported for restore on startup @@ -799,7 +906,7 @@ export class Workbench extends Disposable implements IPartService { this.centerEditorLayout(true); } - const onRestored = (error?: Error): IWorkbenchStartedInfo => { + const onRestored = (error?: Error): void => { this.workbenchRestored = true; // Set lifecycle phase to `Restored` @@ -814,20 +921,64 @@ export class Workbench extends Disposable implements IPartService { }, 2500); if (error) { - errors.onUnexpectedError(error); + onUnexpectedError(error); } - return { + this.logStartupTelemetry({ customKeybindingsCount: this.keybindingService.customKeybindingsCount(), pinnedViewlets: this.activitybarPart.getPinnedViewletIds(), restoredViewlet: viewletIdToRestore, restoredEditorsCount: this.editorService.visibleEditors.length - }; + }); }; return Promise.all(restorePromises).then(() => onRestored(), error => onRestored(error)); } + private logStartupTelemetry(info: IWorkbenchStartedInfo): void { + const { filesToOpen, filesToCreate, filesToDiff } = this.configuration; + + /* __GDPR__ + "workspaceLoad" : { + "userAgent" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "windowSize.innerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "windowSize.innerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "windowSize.outerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "windowSize.outerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "emptyWorkbench": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workbench.filesToOpen": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workbench.filesToCreate": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workbench.filesToDiff": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "customKeybindingsCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "theme": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "language": { "classification": "SystemMetaData", "purpose": "BusinessInsight" }, + "pinnedViewlets": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "restoredViewlet": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "restoredEditors": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "pinnedViewlets": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "startupKind": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } + } + */ + this.telemetryService.publicLog('workspaceLoad', { + userAgent: navigator.userAgent, + windowSize: { innerHeight: window.innerHeight, innerWidth: window.innerWidth, outerHeight: window.outerHeight, outerWidth: window.outerWidth }, + emptyWorkbench: this.contextService.getWorkbenchState() === WorkbenchState.EMPTY, + 'workbench.filesToOpen': filesToOpen && filesToOpen.length || 0, + 'workbench.filesToCreate': filesToCreate && filesToCreate.length || 0, + 'workbench.filesToDiff': filesToDiff && filesToDiff.length || 0, + customKeybindingsCount: info.customKeybindingsCount, + theme: this.themeService.getColorTheme().id, + language, + pinnedViewlets: info.pinnedViewlets, + restoredViewlet: info.restoredViewlet, + restoredEditors: info.restoredEditorsCount, + startupKind: this.lifecycleService.startupKind + }); + + // Telemetry: startup metrics + mark('didStartWorkbench'); + } + private shouldRestoreLastOpenedViewlet(): boolean { if (!this.environmentService.isBuilt) { return true; // always restore sidebar when we are in development mode @@ -999,9 +1150,9 @@ export class Workbench extends Disposable implements IPartService { // Adjust CSS if (hidden) { - DOM.addClass(this.workbench, 'nostatusbar'); + addClass(this.workbench, 'nostatusbar'); } else { - DOM.removeClass(this.workbench, 'nostatusbar'); + removeClass(this.workbench, 'nostatusbar'); } // Layout @@ -1028,6 +1179,7 @@ export class Workbench extends Disposable implements IPartService { private createWorkbenchLayout(): void { if (this.configurationService.getValue('workbench.useExperimentalGridLayout')) { + // Create view wrappers for all parts this.titlebarPartView = new View(this.titlebarPart); this.sidebarPartView = new View(this.sidebarPart); @@ -1039,7 +1191,6 @@ export class Workbench extends Disposable implements IPartService { this.workbenchGrid = new Grid(this.editorPartView, { proportionalLayout: false }); this.workbench.prepend(this.workbenchGrid.element); - this.layout(); } else { this.workbenchGrid = this.instantiationService.createInstance( WorkbenchLayout, @@ -1065,23 +1216,23 @@ export class Workbench extends Disposable implements IPartService { // Apply sidebar state as CSS class if (this.sideBarHidden) { - DOM.addClass(this.workbench, 'nosidebar'); + addClass(this.workbench, 'nosidebar'); } if (this.panelHidden) { - DOM.addClass(this.workbench, 'nopanel'); + addClass(this.workbench, 'nopanel'); } if (this.statusBarHidden) { - DOM.addClass(this.workbench, 'nostatusbar'); + addClass(this.workbench, 'nostatusbar'); } // Apply font aliasing this.setFontAliasing(this.fontAliasing); // Apply fullscreen state - if (browser.isFullscreen()) { - DOM.addClass(this.workbench, 'fullscreen'); + if (isFullscreen()) { + addClass(this.workbench, 'fullscreen'); } // Create Parts @@ -1143,7 +1294,7 @@ export class Workbench extends Disposable implements IPartService { private createPart(id: string, classes: string[], role: string): HTMLElement { const part = document.createElement('div'); - classes.forEach(clazz => DOM.addClass(part, clazz)); + classes.forEach(clazz => addClass(part, clazz)); part.id = id; part.setAttribute('role', role); @@ -1228,7 +1379,7 @@ export class Workbench extends Disposable implements IPartService { } const container = this.getContainer(part); - return DOM.isAncestor(activeElement, container); + return isAncestor(activeElement, container); } getContainer(part: Parts): HTMLElement | null { @@ -1255,7 +1406,7 @@ export class Workbench extends Disposable implements IPartService { case Parts.TITLEBAR_PART: if (!this.useCustomTitleBarStyle()) { return false; - } else if (!browser.isFullscreen()) { + } else if (!isFullscreen()) { return true; } else if (isMacintosh) { return false; @@ -1291,7 +1442,7 @@ export class Workbench extends Disposable implements IPartService { } if (isMacintosh || this.menubarVisibility === 'hidden') { - offset /= browser.getZoomFactor(); + offset /= getZoomFactor(); } } @@ -1322,7 +1473,7 @@ export class Workbench extends Disposable implements IPartService { if (this.zenMode.active) { const config = this.configurationService.getValue('zenMode'); - toggleFullScreen = !browser.isFullscreen() && config.fullScreen; + toggleFullScreen = !isFullscreen() && config.fullScreen; this.zenMode.transitionedToFullScreen = restoring ? config.fullScreen : toggleFullScreen; this.zenMode.transitionedToCenteredEditorLayout = !this.isEditorLayoutCentered() && config.centerLayout; this.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART); @@ -1373,7 +1524,7 @@ export class Workbench extends Disposable implements IPartService { this.editorGroupService.activeGroup.focus(); - toggleFullScreen = this.zenMode.transitionedToFullScreen && browser.isFullscreen(); + toggleFullScreen = this.zenMode.transitionedToFullScreen && isFullscreen(); } this.inZenMode.set(this.zenMode.active); @@ -1493,9 +1644,9 @@ export class Workbench extends Disposable implements IPartService { if (this.workbenchStarted && !this.workbenchShutdown) { if (this.workbenchGrid instanceof Grid) { - const dimensions = DOM.getClientArea(this.container); - DOM.position(this.workbench, 0, 0, 0, 0, 'relative'); - DOM.size(this.workbench, dimensions.width, dimensions.height); + const dimensions = getClientArea(this.container); + position(this.workbench, 0, 0, 0, 0, 'relative'); + size(this.workbench, dimensions.width, dimensions.height); // Layout the grid this.workbenchGrid.layout(dimensions.width, dimensions.height); @@ -1592,9 +1743,9 @@ export class Workbench extends Disposable implements IPartService { // Adjust CSS if (hidden) { - DOM.addClass(this.workbench, 'nosidebar'); + addClass(this.workbench, 'nosidebar'); } else { - DOM.removeClass(this.workbench, 'nosidebar'); + removeClass(this.workbench, 'nosidebar'); } // If sidebar becomes hidden, also hide the current active Viewlet if any @@ -1645,9 +1796,9 @@ export class Workbench extends Disposable implements IPartService { // Adjust CSS if (hidden) { - DOM.addClass(this.workbench, 'nopanel'); + addClass(this.workbench, 'nopanel'); } else { - DOM.removeClass(this.workbench, 'nopanel'); + removeClass(this.workbench, 'nopanel'); } // If panel part becomes hidden, also hide the current active panel if any @@ -1723,10 +1874,10 @@ export class Workbench extends Disposable implements IPartService { this.sideBarPosition = position; // Adjust CSS - DOM.removeClass(this.activitybarPart.getContainer(), oldPositionValue); - DOM.removeClass(this.sidebarPart.getContainer(), oldPositionValue); - DOM.addClass(this.activitybarPart.getContainer(), newPositionValue); - DOM.addClass(this.sidebarPart.getContainer(), newPositionValue); + removeClass(this.activitybarPart.getContainer(), oldPositionValue); + removeClass(this.sidebarPart.getContainer(), oldPositionValue); + addClass(this.activitybarPart.getContainer(), newPositionValue); + addClass(this.sidebarPart.getContainer(), newPositionValue); // Update Styles this.activitybarPart.updateStyles(); @@ -1759,7 +1910,7 @@ export class Workbench extends Disposable implements IPartService { // Layout if (!skipLayout) { if (this.workbenchGrid instanceof Grid) { - const dimensions = DOM.getClientArea(this.container); + const dimensions = getClientArea(this.container); this.workbenchGrid.layout(dimensions.width, dimensions.height); } else { this.workbenchGrid.layout(); @@ -1791,8 +1942,8 @@ export class Workbench extends Disposable implements IPartService { this.storageService.store(Workbench.panelPositionStorageKey, PositionToString(this.panelPosition).toLowerCase(), StorageScope.WORKSPACE); // Adjust CSS - DOM.removeClass(this.panelPart.getContainer(), oldPositionValue); - DOM.addClass(this.panelPart.getContainer(), newPositionValue); + removeClass(this.panelPart.getContainer(), oldPositionValue); + addClass(this.panelPart.getContainer(), newPositionValue); // Update Styles this.panelPart.updateStyles(); From b0206446e8fb8c447e31d127b705c22e7b4a3d0c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Feb 2019 10:08:32 +0100 Subject: [PATCH 175/207] adopt webpack'ed version of references view #64532 --- build/builtInExtensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index 9c463209c2f..2c97ed17625 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -31,7 +31,7 @@ }, { "name": "ms-vscode.references-view", - "version": "0.0.25", + "version": "0.0.26", "repo": "https://github.com/Microsoft/vscode-reference-view", "metadata": { "id": "dc489f46-520d-4556-ae85-1f9eab3c412d", From fb7b8dd2d9b422d5070aea793bab7828384f5e0d Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 12 Feb 2019 10:13:07 +0100 Subject: [PATCH 176/207] #68408 Show theme actions in the viewlet --- .../electron-browser/extensionEditor.ts | 250 +++++++++--------- .../electron-browser/extensionsActions.ts | 86 +++--- .../electron-browser/extensionsViews.ts | 36 +-- .../themes/common/workbenchThemeService.ts | 5 +- .../electron-browser/workbenchThemeService.ts | 11 +- 5 files changed, 208 insertions(+), 180 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts index fcf2068e3ac..c40a5cd3aeb 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts @@ -52,6 +52,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { getDefaultValue } from 'vs/platform/configuration/common/configurationRegistry'; import { isUndefined } from 'vs/base/common/types'; +import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; function renderBody(body: string): string { const styleSheetPath = require.toUrl('./media/markdown.css').replace('file://', 'vscode-core-resource://'); @@ -199,7 +200,9 @@ export class ExtensionEditor extends BaseEditor { @IPartService private readonly partService: IPartService, @IExtensionTipsService private readonly extensionTipsService: IExtensionTipsService, @IStorageService storageService: IStorageService, - @IExtensionService private readonly extensionService: IExtensionService + @IExtensionService private readonly extensionService: IExtensionService, + @IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService + ) { super(ExtensionEditor.ID, telemetryService, themeService, storageService); this.disposables = []; @@ -278,138 +281,139 @@ export class ExtensionEditor extends BaseEditor { this.content = append(body, $('.content')); } - setInput(input: ExtensionsInput, options: EditorOptions, token: CancellationToken): Promise { - return this.extensionService.getExtensions() - .then(runningExtensions => { - this.activeElement = null; - this.editorLoadComplete = false; - const extension = input.extension; + async setInput(input: ExtensionsInput, options: EditorOptions, token: CancellationToken): Promise { + const runningExtensions = await this.extensionService.getExtensions(); + const colorThemes = await this.workbenchThemeService.getColorThemes(); + const fileIconThemes = await this.workbenchThemeService.getFileIconThemes(); - this.transientDisposables = dispose(this.transientDisposables); + this.activeElement = null; + this.editorLoadComplete = false; + const extension = input.extension; - this.extensionReadme = new Cache(() => createCancelablePromise(token => extension.getReadme(token))); - this.extensionChangelog = new Cache(() => createCancelablePromise(token => extension.getChangelog(token))); - this.extensionManifest = new Cache(() => createCancelablePromise(token => extension.getManifest(token))); - this.extensionDependencies = new Cache(() => createCancelablePromise(token => this.extensionsWorkbenchService.loadDependencies(extension, token))); + this.transientDisposables = dispose(this.transientDisposables); - const remoteBadge = this.instantiationService.createInstance(RemoteBadgeWidget, this.iconContainer); - const onError = Event.once(domEvent(this.icon, 'error')); - onError(() => this.icon.src = extension.iconUrlFallback, null, this.transientDisposables); - this.icon.src = extension.iconUrl; + this.extensionReadme = new Cache(() => createCancelablePromise(token => extension.getReadme(token))); + this.extensionChangelog = new Cache(() => createCancelablePromise(token => extension.getChangelog(token))); + this.extensionManifest = new Cache(() => createCancelablePromise(token => extension.getManifest(token))); + this.extensionDependencies = new Cache(() => createCancelablePromise(token => this.extensionsWorkbenchService.loadDependencies(extension, token))); - this.name.textContent = extension.displayName; - this.identifier.textContent = extension.identifier.id; - this.preview.style.display = extension.preview ? 'inherit' : 'none'; - this.builtin.style.display = extension.type === ExtensionType.System ? 'inherit' : 'none'; + const remoteBadge = this.instantiationService.createInstance(RemoteBadgeWidget, this.iconContainer); + const onError = Event.once(domEvent(this.icon, 'error')); + onError(() => this.icon.src = extension.iconUrlFallback, null, this.transientDisposables); + this.icon.src = extension.iconUrl; - this.publisher.textContent = extension.publisherDisplayName; - this.description.textContent = extension.description; + this.name.textContent = extension.displayName; + this.identifier.textContent = extension.identifier.id; + this.preview.style.display = extension.preview ? 'inherit' : 'none'; + this.builtin.style.display = extension.type === ExtensionType.System ? 'inherit' : 'none'; - const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason(); - let recommendationsData = {}; - if (extRecommendations[extension.identifier.id.toLowerCase()]) { - recommendationsData = { recommendationReason: extRecommendations[extension.identifier.id.toLowerCase()].reasonId }; - } + this.publisher.textContent = extension.publisherDisplayName; + this.description.textContent = extension.description; - /* __GDPR__ - "extensionGallery:openExtension" : { - "recommendationReason": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "${include}": [ - "${GalleryExtensionTelemetryData}" - ] - } - */ - this.telemetryService.publicLog('extensionGallery:openExtension', assign(extension.telemetryData, recommendationsData)); + const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason(); + let recommendationsData = {}; + if (extRecommendations[extension.identifier.id.toLowerCase()]) { + recommendationsData = { recommendationReason: extRecommendations[extension.identifier.id.toLowerCase()].reasonId }; + } - toggleClass(this.name, 'clickable', !!extension.url); - toggleClass(this.publisher, 'clickable', !!extension.url); - toggleClass(this.rating, 'clickable', !!extension.url); - if (extension.url) { - this.name.onclick = finalHandler(() => window.open(extension.url)); - this.rating.onclick = finalHandler(() => window.open(`${extension.url}#review-details`)); - this.publisher.onclick = finalHandler(() => { - this.viewletService.openViewlet(VIEWLET_ID, true) - .then(viewlet => viewlet as IExtensionsViewlet) - .then(viewlet => viewlet.search(`publisher:"${extension.publisherDisplayName}"`)); - }); + /* __GDPR__ + "extensionGallery:openExtension" : { + "recommendationReason": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "${include}": [ + "${GalleryExtensionTelemetryData}" + ] + } + */ + this.telemetryService.publicLog('extensionGallery:openExtension', assign(extension.telemetryData, recommendationsData)); - if (extension.licenseUrl) { - this.license.onclick = finalHandler(() => window.open(extension.licenseUrl)); - this.license.style.display = 'initial'; - } else { - this.license.onclick = null; - this.license.style.display = 'none'; - } - } else { - this.name.onclick = null; - this.rating.onclick = null; - this.publisher.onclick = null; - this.license.onclick = null; - this.license.style.display = 'none'; - } - - if (extension.repository) { - this.repository.onclick = finalHandler(() => window.open(extension.repository)); - this.repository.style.display = 'initial'; - } - else { - this.repository.onclick = null; - this.repository.style.display = 'none'; - } - - const widgets = [ - remoteBadge, - this.instantiationService.createInstance(InstallCountWidget, this.installCount, false), - this.instantiationService.createInstance(RatingsWidget, this.rating, false) - ]; - const reloadAction = this.instantiationService.createInstance(ReloadAction); - const actions = [ - reloadAction, - this.instantiationService.createInstance(StatusLabelAction), - this.instantiationService.createInstance(UpdateAction), - this.instantiationService.createInstance(SetColorThemeAction), - this.instantiationService.createInstance(SetFileIconThemeAction), - this.instantiationService.createInstance(EnableDropDownAction), - this.instantiationService.createInstance(DisableDropDownAction, runningExtensions), - this.instantiationService.createInstance(CombinedInstallAction), - this.instantiationService.createInstance(MaliciousStatusLabelAction, true), - ]; - const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets]); - extensionContainers.extension = extension; - - this.extensionActionBar.clear(); - this.extensionActionBar.push(actions, { icon: true, label: true }); - this.transientDisposables.push(...[...actions, ...widgets, extensionContainers]); - - this.setSubText(extension, reloadAction); - this.content.innerHTML = ''; // Clear content before setting navbar actions. - - this.navbar.clear(); - this.navbar.onChange(this.onNavbarChange.bind(this, extension), this, this.transientDisposables); - - if (extension.hasReadme()) { - this.navbar.push(NavbarSection.Readme, localize('details', "Details"), localize('detailstooltip', "Extension details, rendered from the extension's 'README.md' file")); - } - this.extensionManifest.get() - .promise - .then(manifest => { - if (extension.extensionPack.length) { - this.navbar.push(NavbarSection.ExtensionPack, localize('extensionPack', "Extension Pack"), localize('extensionsPack', "Set of extensions that can be installed together")); - } - if (manifest && manifest.contributes) { - this.navbar.push(NavbarSection.Contributions, localize('contributions', "Contributions"), localize('contributionstooltip', "Lists contributions to VS Code by this extension")); - } - if (extension.hasChangelog()) { - this.navbar.push(NavbarSection.Changelog, localize('changelog', "Changelog"), localize('changelogtooltip', "Extension update history, rendered from the extension's 'CHANGELOG.md' file")); - } - if (extension.dependencies.length) { - this.navbar.push(NavbarSection.Dependencies, localize('dependencies', "Dependencies"), localize('dependenciestooltip', "Lists extensions this extension depends on")); - } - this.editorLoadComplete = true; - }); - - return super.setInput(input, options, token); + toggleClass(this.name, 'clickable', !!extension.url); + toggleClass(this.publisher, 'clickable', !!extension.url); + toggleClass(this.rating, 'clickable', !!extension.url); + if (extension.url) { + this.name.onclick = finalHandler(() => window.open(extension.url)); + this.rating.onclick = finalHandler(() => window.open(`${extension.url}#review-details`)); + this.publisher.onclick = finalHandler(() => { + this.viewletService.openViewlet(VIEWLET_ID, true) + .then(viewlet => viewlet as IExtensionsViewlet) + .then(viewlet => viewlet.search(`publisher:"${extension.publisherDisplayName}"`)); }); + + if (extension.licenseUrl) { + this.license.onclick = finalHandler(() => window.open(extension.licenseUrl)); + this.license.style.display = 'initial'; + } else { + this.license.onclick = null; + this.license.style.display = 'none'; + } + } else { + this.name.onclick = null; + this.rating.onclick = null; + this.publisher.onclick = null; + this.license.onclick = null; + this.license.style.display = 'none'; + } + + if (extension.repository) { + this.repository.onclick = finalHandler(() => window.open(extension.repository)); + this.repository.style.display = 'initial'; + } + else { + this.repository.onclick = null; + this.repository.style.display = 'none'; + } + + const widgets = [ + remoteBadge, + this.instantiationService.createInstance(InstallCountWidget, this.installCount, false), + this.instantiationService.createInstance(RatingsWidget, this.rating, false) + ]; + const reloadAction = this.instantiationService.createInstance(ReloadAction); + const actions = [ + reloadAction, + this.instantiationService.createInstance(StatusLabelAction), + this.instantiationService.createInstance(UpdateAction), + this.instantiationService.createInstance(SetColorThemeAction, colorThemes), + this.instantiationService.createInstance(SetFileIconThemeAction, fileIconThemes), + this.instantiationService.createInstance(EnableDropDownAction), + this.instantiationService.createInstance(DisableDropDownAction, runningExtensions), + this.instantiationService.createInstance(CombinedInstallAction), + this.instantiationService.createInstance(MaliciousStatusLabelAction, true), + ]; + const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets]); + extensionContainers.extension = extension; + + this.extensionActionBar.clear(); + this.extensionActionBar.push(actions, { icon: true, label: true }); + this.transientDisposables.push(...[...actions, ...widgets, extensionContainers]); + + this.setSubText(extension, reloadAction); + this.content.innerHTML = ''; // Clear content before setting navbar actions. + + this.navbar.clear(); + this.navbar.onChange(this.onNavbarChange.bind(this, extension), this, this.transientDisposables); + + if (extension.hasReadme()) { + this.navbar.push(NavbarSection.Readme, localize('details', "Details"), localize('detailstooltip', "Extension details, rendered from the extension's 'README.md' file")); + } + this.extensionManifest.get() + .promise + .then(manifest => { + if (extension.extensionPack.length) { + this.navbar.push(NavbarSection.ExtensionPack, localize('extensionPack', "Extension Pack"), localize('extensionsPack', "Set of extensions that can be installed together")); + } + if (manifest && manifest.contributes) { + this.navbar.push(NavbarSection.Contributions, localize('contributions', "Contributions"), localize('contributionstooltip', "Lists contributions to VS Code by this extension")); + } + if (extension.hasChangelog()) { + this.navbar.push(NavbarSection.Changelog, localize('changelog', "Changelog"), localize('changelogtooltip', "Extension update history, rendered from the extension's 'CHANGELOG.md' file")); + } + if (extension.dependencies.length) { + this.navbar.push(NavbarSection.Dependencies, localize('dependencies', "Dependencies"), localize('dependenciestooltip', "Lists extensions this extension depends on")); + } + this.editorLoadComplete = true; + }); + + return super.setInput(input, options, token); } private setSubText(extension: IExtension, reloadAction: ReloadAction): void { diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts index 5d2b234fa75..8fb5a492923 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts @@ -55,7 +55,7 @@ import { clipboard } from 'electron'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { coalesce } from 'vs/base/common/arrays'; -import { IWorkbenchThemeService, COLOR_THEME_SETTING, ICON_THEME_SETTING } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { IWorkbenchThemeService, COLOR_THEME_SETTING, ICON_THEME_SETTING, IFileIconTheme, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; function toExtensionDescription(local: ILocalExtension): IExtensionDescription { return { @@ -185,15 +185,15 @@ export class InstallAction extends ExtensionAction { if (extension.local) { const runningExtension = await this.getRunningExtension(extension.local); if (runningExtension) { - const colorThemes = await this.workbenchThemeService.getColorThemes(runningExtension.identifier); - const fileIconThemes = await this.workbenchThemeService.getFileIconThemes(runningExtension.identifier); - if (colorThemes.length) { - const action = this.instantiationService.createInstance(SetColorThemeAction); + const colorThemes = await this.workbenchThemeService.getColorThemes(); + const fileIconThemes = await this.workbenchThemeService.getFileIconThemes(); + if (SetColorThemeAction.getColorThemes(colorThemes, this.extension).length) { + const action = this.instantiationService.createInstance(SetColorThemeAction, colorThemes); action.extension = extension; return action.run(true); } - if (fileIconThemes.length) { - const action = this.instantiationService.createInstance(SetFileIconThemeAction); + if (SetFileIconThemeAction.getFileIconThemes(fileIconThemes, this.extension).length) { + const action = this.instantiationService.createInstance(SetFileIconThemeAction, fileIconThemes); action.extension = extension; return action.run(true); } @@ -548,7 +548,8 @@ export class ManageExtensionAction extends ExtensionDropDownAction { constructor( @IInstantiationService instantiationService: IInstantiationService, - @IExtensionService private readonly extensionService: IExtensionService + @IExtensionService private readonly extensionService: IExtensionService, + @IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService ) { super(ManageExtensionAction.ID, '', '', true, true, instantiationService); @@ -558,8 +559,22 @@ export class ManageExtensionAction extends ExtensionDropDownAction { this.update(); } - getActionGroups(runningExtensions: IExtensionDescription[]): IAction[][] { + getActionGroups(runningExtensions: IExtensionDescription[], colorThemes: IColorTheme[], fileIconThemes: IFileIconTheme[]): IAction[][] { const groups: ExtensionAction[][] = []; + if (this.extension) { + const extensionColorThemes = SetColorThemeAction.getColorThemes(colorThemes, this.extension); + const extensionFileIconThemes = SetFileIconThemeAction.getFileIconThemes(fileIconThemes, this.extension); + if (extensionColorThemes.length || extensionFileIconThemes.length) { + const themesGroup: ExtensionAction[] = []; + if (extensionColorThemes.length) { + themesGroup.push(this.instantiationService.createInstance(SetColorThemeAction, colorThemes)); + } + if (extensionFileIconThemes.length) { + themesGroup.push(this.instantiationService.createInstance(SetFileIconThemeAction, fileIconThemes)); + } + groups.push(themesGroup); + } + } groups.push([ this.instantiationService.createInstance(EnableGloballyAction), this.instantiationService.createInstance(EnableForWorkspaceAction) @@ -577,8 +592,11 @@ export class ManageExtensionAction extends ExtensionDropDownAction { return groups; } - run(): Promise { - return this.extensionService.getExtensions().then(runtimeExtensions => super.run({ actionGroups: this.getActionGroups(runtimeExtensions), disposeActionsOnHide: true })); + async run(): Promise { + const runtimeExtensions = await this.extensionService.getExtensions(); + const colorThemes = await this.workbenchThemeService.getColorThemes(); + const fileIconThemes = await this.workbenchThemeService.getFileIconThemes(); + return super.run({ actionGroups: this.getActionGroups(runtimeExtensions, colorThemes, fileIconThemes), disposeActionsOnHide: true }); } update(): void { @@ -1107,12 +1125,17 @@ export class ReloadAction extends ExtensionAction { export class SetColorThemeAction extends ExtensionAction { + static getColorThemes(colorThemes: IColorTheme[], extension: IExtension): IColorTheme[] { + return colorThemes.filter(c => ExtensionIdentifier.equals(c.extensionData.extensionId, extension.identifier.id)); + } + private static readonly EnabledClass = 'extension-action theme'; private static readonly DisabledClass = `${SetColorThemeAction.EnabledClass} disabled`; private disposables: IDisposable[] = []; constructor( + private readonly colorThemes: IColorTheme[], @IExtensionService extensionService: IExtensionService, @IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService, @IQuickInputService private readonly quickInputService: IQuickInputService, @@ -1123,34 +1146,33 @@ export class SetColorThemeAction extends ExtensionAction { this.update(); } - async update(): Promise { + update(): void { this.enabled = false; if (this.extension) { const isInstalled = this.extension.state === ExtensionState.Installed; if (isInstalled) { - const colorThemes = await this.workbenchThemeService.getColorThemes(new ExtensionIdentifier(this.extension.identifier.id)); - this.enabled = colorThemes.length > 0; + const extensionThemes = SetColorThemeAction.getColorThemes(this.colorThemes, this.extension); + this.enabled = extensionThemes.length > 0; } } this.class = this.enabled ? SetColorThemeAction.EnabledClass : SetColorThemeAction.DisabledClass; } async run(showCurrentTheme: boolean): Promise { - await this.update(); + this.update(); if (!this.enabled) { return; } - let colorThemes = await this.workbenchThemeService.getColorThemes(new ExtensionIdentifier(this.extension.identifier.id)); - const allThemes = await this.workbenchThemeService.getColorThemes(); - const currentTheme = allThemes.filter(t => t.settingsId === this.configurationService.getValue(COLOR_THEME_SETTING))[0]; - showCurrentTheme = showCurrentTheme || colorThemes.some(t => t.id === currentTheme.id); + let extensionThemes = SetColorThemeAction.getColorThemes(this.colorThemes, this.extension); + const currentTheme = this.colorThemes.filter(t => t.settingsId === this.configurationService.getValue(COLOR_THEME_SETTING))[0]; + showCurrentTheme = showCurrentTheme || extensionThemes.some(t => t.id === currentTheme.id); if (showCurrentTheme) { - colorThemes = colorThemes.filter(t => t.id !== currentTheme.id); + extensionThemes = extensionThemes.filter(t => t.id !== currentTheme.id); } const delayer = new Delayer(100); const picks: (IQuickPickItem | IQuickPickSeparator)[] = []; - picks.push(...colorThemes.map(theme => ({ label: theme.label, id: theme.id }))); + picks.push(...extensionThemes.map(theme => ({ label: theme.label, id: theme.id }))); if (showCurrentTheme) { picks.push({ type: 'separator', label: localize('current', "Current") }); picks.push({ label: currentTheme.label, id: currentTheme.id }); @@ -1179,7 +1201,12 @@ export class SetFileIconThemeAction extends ExtensionAction { private disposables: IDisposable[] = []; + static getFileIconThemes(fileIconThemes: IFileIconTheme[], extension: IExtension): IFileIconTheme[] { + return fileIconThemes.filter(c => c.extensionData && ExtensionIdentifier.equals(c.extensionData.extensionId, extension.identifier.id)); + } + constructor( + private readonly fileIconThemes: IFileIconTheme[], @IExtensionService extensionService: IExtensionService, @IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService, @IQuickInputService private readonly quickInputService: IQuickInputService, @@ -1190,13 +1217,13 @@ export class SetFileIconThemeAction extends ExtensionAction { this.update(); } - async update(): Promise { + update(): void { this.enabled = false; if (this.extension) { const isInstalled = this.extension.state === ExtensionState.Installed; if (isInstalled) { - const fileIconThemes = await this.workbenchThemeService.getFileIconThemes(new ExtensionIdentifier(this.extension.identifier.id)); - this.enabled = fileIconThemes.length > 0; + const extensionThemes = SetFileIconThemeAction.getFileIconThemes(this.fileIconThemes, this.extension); + this.enabled = extensionThemes.length > 0; } } this.class = this.enabled ? SetFileIconThemeAction.EnabledClass : SetFileIconThemeAction.DisabledClass; @@ -1207,17 +1234,16 @@ export class SetFileIconThemeAction extends ExtensionAction { if (!this.enabled) { return; } - let fileIconThemes = await this.workbenchThemeService.getFileIconThemes(new ExtensionIdentifier(this.extension.identifier.id)); - const allThemes = await this.workbenchThemeService.getFileIconThemes(); - const currentTheme = allThemes.filter(t => t.settingsId === this.configurationService.getValue(ICON_THEME_SETTING))[0] || this.workbenchThemeService.getFileIconTheme(); - showCurrentTheme = showCurrentTheme || fileIconThemes.some(t => t.id === currentTheme.id); + let extensionThemes = SetFileIconThemeAction.getFileIconThemes(this.fileIconThemes, this.extension); + const currentTheme = this.fileIconThemes.filter(t => t.settingsId === this.configurationService.getValue(ICON_THEME_SETTING))[0] || this.workbenchThemeService.getFileIconTheme(); + showCurrentTheme = showCurrentTheme || extensionThemes.some(t => t.id === currentTheme.id); if (showCurrentTheme) { - fileIconThemes = fileIconThemes.filter(t => t.id !== currentTheme.id); + extensionThemes = extensionThemes.filter(t => t.id !== currentTheme.id); } const delayer = new Delayer(100); const picks: (IQuickPickItem | IQuickPickSeparator)[] = []; - picks.push(...fileIconThemes.map(theme => ({ label: theme.label, id: theme.id }))); + picks.push(...extensionThemes.map(theme => ({ label: theme.label, id: theme.id }))); if (showCurrentTheme && currentTheme.label) { picks.push({ type: 'separator', label: localize('current', "Current") }); picks.push({ label: currentTheme.label, id: currentTheme.id }); diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsViews.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsViews.ts index 849f8161da7..ee0347e5fbe 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsViews.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsViews.ts @@ -43,6 +43,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { getKeywordsForExtension } from 'vs/workbench/contrib/extensions/electron-browser/extensionsUtils'; import { IAction } from 'vs/base/common/actions'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; +import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; class ExtensionsViewState extends Disposable implements IExtensionsViewState { @@ -84,7 +85,8 @@ export class ExtensionsListView extends ViewletPanel { @ITelemetryService private readonly telemetryService: ITelemetryService, @IConfigurationService configurationService: IConfigurationService, @IWorkspaceContextService protected contextService: IWorkspaceContextService, - @IExperimentService private readonly experimentService: IExperimentService + @IExperimentService private readonly experimentService: IExperimentService, + @IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService ) { super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService); } @@ -175,24 +177,24 @@ export class ExtensionsListView extends ViewletPanel { return Promise.resolve(emptyModel); } - private onContextMenu(e: IListContextMenuEvent): void { + private async onContextMenu(e: IListContextMenuEvent): Promise { if (e.element) { - this.extensionService.getExtensions() - .then(runningExtensions => { - const manageExtensionAction = this.instantiationService.createInstance(ManageExtensionAction); - manageExtensionAction.extension = e.element; - const groups = manageExtensionAction.getActionGroups(runningExtensions); - let actions: IAction[] = []; - for (const menuActions of groups) { - actions = [...actions, ...menuActions, new Separator()]; - } - if (manageExtensionAction.enabled) { - this.contextMenuService.showContextMenu({ - getAnchor: () => e.anchor, - getActions: () => actions.slice(0, actions.length - 1) - }); - } + const runningExtensions = await this.extensionService.getExtensions(); + const colorThemes = await this.workbenchThemeService.getColorThemes(); + const fileIconThemes = await this.workbenchThemeService.getFileIconThemes(); + const manageExtensionAction = this.instantiationService.createInstance(ManageExtensionAction); + manageExtensionAction.extension = e.element; + const groups = manageExtensionAction.getActionGroups(runningExtensions, colorThemes, fileIconThemes); + let actions: IAction[] = []; + for (const menuActions of groups) { + actions = [...actions, ...menuActions, new Separator()]; + } + if (manageExtensionAction.enabled) { + this.contextMenuService.showContextMenu({ + getAnchor: () => e.anchor, + getActions: () => actions.slice(0, actions.length - 1) }); + } } } diff --git a/src/vs/workbench/services/themes/common/workbenchThemeService.ts b/src/vs/workbench/services/themes/common/workbenchThemeService.ts index 4da012b7901..533d44586f5 100644 --- a/src/vs/workbench/services/themes/common/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/common/workbenchThemeService.ts @@ -8,7 +8,6 @@ import { Event } from 'vs/base/common/event'; import { Color } from 'vs/base/common/color'; import { ITheme, IThemeService, IIconTheme } from 'vs/platform/theme/common/themeService'; import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; -import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; export const IWorkbenchThemeService = createDecorator('themeService'); @@ -55,13 +54,13 @@ export interface IWorkbenchThemeService extends IThemeService { _serviceBrand: any; setColorTheme(themeId: string | undefined, settingsTarget: ConfigurationTarget | undefined): Promise; getColorTheme(): IColorTheme; - getColorThemes(extensionId?: ExtensionIdentifier): Promise; + getColorThemes(): Promise; onDidColorThemeChange: Event; restoreColorTheme(); setFileIconTheme(iconThemeId: string | undefined, settingsTarget: ConfigurationTarget | undefined): Promise; getFileIconTheme(): IFileIconTheme; - getFileIconThemes(extensionId?: ExtensionIdentifier): Promise; + getFileIconThemes(): Promise; onDidFileIconThemeChange: Event; } diff --git a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts index 099a3ca61be..8413a65817a 100644 --- a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts @@ -31,7 +31,6 @@ import * as resources from 'vs/base/common/resources'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { textmateColorsSchemaId, registerColorThemeSchemas, textmateColorSettingsSchemaId } from 'vs/workbench/services/themes/common/colorThemeSchema'; import { workbenchColorsSchemaId } from 'vs/platform/theme/common/colorRegistry'; -import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; // implementation @@ -320,9 +319,8 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { return this.currentColorTheme; } - public async getColorThemes(extensionId?: ExtensionIdentifier): Promise { - const colorThemes = await this.colorThemeStore.getColorThemes(); - return extensionId ? colorThemes.filter(c => ExtensionIdentifier.equals(new ExtensionIdentifier(c.extensionData.extensionId), extensionId)) : colorThemes; + public getColorThemes(): Promise { + return this.colorThemeStore.getColorThemes(); } public getTheme(): ITheme { @@ -460,9 +458,8 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } } - public async getFileIconThemes(extensionId?: ExtensionIdentifier): Promise { - const filIconThemes = await this.iconThemeStore.getFileIconThemes(); - return extensionId ? filIconThemes.filter(c => c.extensionData && ExtensionIdentifier.equals(new ExtensionIdentifier(c.extensionData.extensionId), extensionId)) : filIconThemes; + public getFileIconThemes(): Promise { + return this.iconThemeStore.getFileIconThemes(); } public getFileIconTheme() { From 9199ab8cef229c14e6b5ad5ba01fca2433c40dc9 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 12 Feb 2019 10:22:32 +0100 Subject: [PATCH 177/207] Commands with a keybinding context and a command context should respect both Fixes #68370 --- src/vs/workbench/common/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/common/actions.ts b/src/vs/workbench/common/actions.ts index f805576e516..995818a3920 100644 --- a/src/vs/workbench/common/actions.ts +++ b/src/vs/workbench/common/actions.ts @@ -44,7 +44,7 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR KeybindingsRegistry.registerKeybindingRule({ id: descriptor.id, weight: weight, - when: descriptor.keybindingContext, + when: ContextKeyExpr.and(descriptor.keybindingContext, when), primary: keybindings ? keybindings.primary : 0, secondary: keybindings && keybindings.secondary, win: keybindings && keybindings.win, From 63a682f31e57e1b957fa667435d0c3cc7f066a54 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 12 Feb 2019 10:47:57 +0100 Subject: [PATCH 178/207] Fix default task echo property Fixes #68411 --- src/vs/workbench/contrib/tasks/common/tasks.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/tasks/common/tasks.ts b/src/vs/workbench/contrib/tasks/common/tasks.ts index 46612113bb6..64284fe4728 100644 --- a/src/vs/workbench/contrib/tasks/common/tasks.ts +++ b/src/vs/workbench/contrib/tasks/common/tasks.ts @@ -223,7 +223,7 @@ export interface PresentationOptions { export namespace PresentationOptions { export const defaults: PresentationOptions = { - echo: false, reveal: RevealKind.Always, focus: false, panel: PanelKind.Shared, showReuseMessage: true, clear: false + echo: true, reveal: RevealKind.Always, focus: false, panel: PanelKind.Shared, showReuseMessage: true, clear: false }; } From a066fd1eab4234cdd52da54f5518243f790c16c9 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Feb 2019 10:42:00 +0100 Subject: [PATCH 179/207] don't double create gc signals, #68290 --- .../workbench/api/electron-browser/mainThreadHeapService.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/api/electron-browser/mainThreadHeapService.ts b/src/vs/workbench/api/electron-browser/mainThreadHeapService.ts index d7af8caf14a..fa6fc7eabf8 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadHeapService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadHeapService.ts @@ -51,6 +51,10 @@ export class HeapService implements IHeapService { return; } + if (this._activeIds.has(obj.$ident)) { + return; + } + if (this._ctor) { // track and leave this._activeIds.add(obj.$ident); From af247887dafed61a9aa07010f87cde2c462bd78c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Feb 2019 10:58:34 +0100 Subject: [PATCH 180/207] only resolve lenses that aren't resolved yet, #68290 --- src/vs/editor/contrib/codelens/codelensController.ts | 7 ++++--- src/vs/editor/contrib/codelens/codelensWidget.ts | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/codelens/codelensController.ts b/src/vs/editor/contrib/codelens/codelensController.ts index 5cda01790a3..924c840ea3f 100644 --- a/src/vs/editor/contrib/codelens/codelensController.ts +++ b/src/vs/editor/contrib/codelens/codelensController.ts @@ -309,13 +309,14 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { const resolvedSymbols = new Array(request.length); const promises = request.map((request, i) => { - if (typeof request.provider.resolveCodeLens === 'function') { + if (!request.symbol.command && typeof request.provider.resolveCodeLens === 'function') { return Promise.resolve(request.provider.resolveCodeLens(model, request.symbol, token)).then(symbol => { resolvedSymbols[i] = symbol; }); + } else { + resolvedSymbols[i] = request.symbol; + return Promise.resolve(undefined); } - resolvedSymbols[i] = request.symbol; - return Promise.resolve(undefined); }); return Promise.all(promises).then(() => { diff --git a/src/vs/editor/contrib/codelens/codelensWidget.ts b/src/vs/editor/contrib/codelens/codelensWidget.ts index 9fcc411fe63..726ade625b0 100644 --- a/src/vs/editor/contrib/codelens/codelensWidget.ts +++ b/src/vs/editor/contrib/codelens/codelensWidget.ts @@ -290,6 +290,13 @@ export class CodeLens { updateCommands(symbols: Array): void { this._contentWidget.withCommands(symbols); + for (let i = 0; i < this._data.length; i++) { + const resolved = symbols[i]; + if (resolved) { + const { symbol } = this._data[i]; + symbol.command = resolved.command || symbol.command; + } + } } updateHeight(): void { From c7813f6da3d5a0c85b297dee8ee361a4f6e1f7b5 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 12 Feb 2019 11:00:05 +0100 Subject: [PATCH 181/207] Allow spaces in gulp.cmd path Fixes #68413 --- extensions/gulp/src/main.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/gulp/src/main.ts b/extensions/gulp/src/main.ts index 1b89a4bdb1a..ffe7bd7d9a2 100644 --- a/extensions/gulp/src/main.ts +++ b/extensions/gulp/src/main.ts @@ -120,7 +120,7 @@ class FolderDetector { let gulpCommand: string; let platform = process.platform; if (platform === 'win32' && await exists(path.join(rootPath!, 'node_modules', '.bin', 'gulp.cmd'))) { - const globalGulp = path.join(process.env.APPDATA ? process.env.APPDATA : '', 'npm', 'gulp.cmd'); + const globalGulp = path.join(process.env.APPDATA ? process.env.APPDATA : '', 'npm - Copy', 'gulp.cmd'); if (await exists(globalGulp)) { gulpCommand = globalGulp; } else { @@ -132,7 +132,7 @@ class FolderDetector { gulpCommand = 'gulp'; } - let commandLine = `${gulpCommand} --tasks-simple --no-color`; + let commandLine = `\"${gulpCommand}\" --tasks-simple --no-color`; try { let { stdout, stderr } = await exec(commandLine, { cwd: rootPath }); if (stderr && stderr.length > 0) { From eca12e44fafa0d67b2e28f1b9659ab41e8e80743 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 12 Feb 2019 11:00:48 +0100 Subject: [PATCH 182/207] Fix incorrect gulp path --- extensions/gulp/src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/gulp/src/main.ts b/extensions/gulp/src/main.ts index ffe7bd7d9a2..9ec3b6265ec 100644 --- a/extensions/gulp/src/main.ts +++ b/extensions/gulp/src/main.ts @@ -120,7 +120,7 @@ class FolderDetector { let gulpCommand: string; let platform = process.platform; if (platform === 'win32' && await exists(path.join(rootPath!, 'node_modules', '.bin', 'gulp.cmd'))) { - const globalGulp = path.join(process.env.APPDATA ? process.env.APPDATA : '', 'npm - Copy', 'gulp.cmd'); + const globalGulp = path.join(process.env.APPDATA ? process.env.APPDATA : '', 'npm', 'gulp.cmd'); if (await exists(globalGulp)) { gulpCommand = globalGulp; } else { From 0445a47725dc11f30d6a232518ac827f26fe65d7 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 12 Feb 2019 11:14:03 +0100 Subject: [PATCH 183/207] tasks.json default should use tasks version 2.0.0 Fixes #68429 --- .../electron-browser/task.contribution.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts index 1260acdd106..25ea7c74e91 100644 --- a/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts @@ -2640,17 +2640,18 @@ let schema: IJSONSchema = { description: 'Task definition file', type: 'object', default: { - version: '0.1.0', - command: 'myCommand', - isShellCommand: false, - args: [], - showOutput: 'always', + version: '2.0.0', tasks: [ { - taskName: 'build', - showOutput: 'silent', - isBuildCommand: true, - problemMatcher: ['$tsc', '$lessCompile'] + label: 'My Task', + command: 'echo hello', + type: 'shell', + args: [], + problemMatcher: ['$tsc'], + presentation: { + reveal: 'always' + }, + group: 'build' } ] } From 5d31610c6e92bcd1a22e4e96d577cb1ee23eebef Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Feb 2019 11:19:14 +0100 Subject: [PATCH 184/207] fix #68498 --- src/vs/base/common/performance.js | 60 ++++++++++++++++++------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/src/vs/base/common/performance.js b/src/vs/base/common/performance.js index c7825a0e310..2bc77108620 100644 --- a/src/vs/base/common/performance.js +++ b/src/vs/base/common/performance.js @@ -5,39 +5,26 @@ 'use strict'; -/*global define*/ +//@ts-check -// This module can be loaded in an amd and commonjs-context. -// Because we want both instances to use the same perf-data -// we store them globally -// stores data as: 'name','timestamp' +function _factory(sharedObj) { -if (typeof define !== "function" && typeof module === "object" && typeof module.exports === "object") { - // this is commonjs, fake amd - global.define = function (_dep, callback) { - module.exports = callback(); - global.define = undefined; - }; -} - -define([], function () { - - global._performanceEntries = global._performanceEntries || []; + sharedObj._performanceEntries = sharedObj._performanceEntries || []; const _dataLen = 2; const _timeStamp = typeof console.timeStamp === 'function' ? console.timeStamp.bind(console) : () => { }; function importEntries(entries) { - global._performanceEntries.splice(0, 0, ...entries); + sharedObj._performanceEntries.splice(0, 0, ...entries); } function exportEntries() { - return global._performanceEntries.slice(0); + return sharedObj._performanceEntries.slice(0); } function getEntries() { const result = []; - const entries = global._performanceEntries; + const entries = sharedObj._performanceEntries; for (let i = 0; i < entries.length; i += _dataLen) { result.push({ name: entries[i], @@ -48,7 +35,7 @@ define([], function () { } function getEntry(name) { - const entries = global._performanceEntries; + const entries = sharedObj._performanceEntries; for (let i = 0; i < entries.length; i += _dataLen) { if (entries[i] === name) { return { @@ -60,7 +47,7 @@ define([], function () { } function getDuration(from, to) { - const entries = global._performanceEntries; + const entries = sharedObj._performanceEntries; let target = to; let endIndex = 0; for (let i = entries.length - _dataLen; i >= 0; i -= _dataLen) { @@ -79,11 +66,11 @@ define([], function () { } function mark(name) { - global._performanceEntries.push(name, Date.now()); + sharedObj._performanceEntries.push(name, Date.now()); _timeStamp(name); } - var exports = { + const exports = { mark: mark, getEntries: getEntries, getEntry: getEntry, @@ -93,4 +80,29 @@ define([], function () { }; return exports; -}); +} + +// This module can be loaded in an amd and commonjs-context. +// Because we want both instances to use the same perf-data +// we store them globally + +let sharedObj; +if (typeof global === 'object') { + // nodejs + sharedObj = global; +} else if (typeof self === 'object') { + // browser + sharedObj = self; +} else { + sharedObj = {}; +} + +if (typeof define === 'function') { + // amd + define([], function () { return _factory(sharedObj); }); +} else if (typeof module === "object" && typeof module.exports === "object") { + // commonjs + module.exports = _factory(sharedObj); +} else { + // invalid context... +} From 4cfbdcda771107d4d65441ea2c971911cb718294 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 12 Feb 2019 11:25:23 +0100 Subject: [PATCH 185/207] Revert "Fix incorrect gulp path" This reverts commit eca12e44fafa0d67b2e28f1b9659ab41e8e80743. --- extensions/gulp/src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/gulp/src/main.ts b/extensions/gulp/src/main.ts index 9ec3b6265ec..ffe7bd7d9a2 100644 --- a/extensions/gulp/src/main.ts +++ b/extensions/gulp/src/main.ts @@ -120,7 +120,7 @@ class FolderDetector { let gulpCommand: string; let platform = process.platform; if (platform === 'win32' && await exists(path.join(rootPath!, 'node_modules', '.bin', 'gulp.cmd'))) { - const globalGulp = path.join(process.env.APPDATA ? process.env.APPDATA : '', 'npm', 'gulp.cmd'); + const globalGulp = path.join(process.env.APPDATA ? process.env.APPDATA : '', 'npm - Copy', 'gulp.cmd'); if (await exists(globalGulp)) { gulpCommand = globalGulp; } else { From 357efea93b0ff0529f02ebe8ee0728043700038b Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Feb 2019 11:26:47 +0100 Subject: [PATCH 186/207] debt - move services out of shell into workbench (#68510) --- .../windows/electron-browser/windowService.ts | 13 +- src/vs/workbench/electron-browser/main.ts | 5 - src/vs/workbench/electron-browser/shell.ts | 216 +------------- .../workbench/electron-browser/workbench.ts | 280 +++++++++++++++--- .../electron-browser/broadcastService.ts | 13 +- .../services/part/common/partService.ts | 3 +- 6 files changed, 271 insertions(+), 259 deletions(-) diff --git a/src/vs/platform/windows/electron-browser/windowService.ts b/src/vs/platform/windows/electron-browser/windowService.ts index 179df0df102..1a1cffb8839 100644 --- a/src/vs/platform/windows/electron-browser/windowService.ts +++ b/src/vs/platform/windows/electron-browser/windowService.ts @@ -18,20 +18,23 @@ export class WindowService extends Disposable implements IWindowService { _serviceBrand: any; + private windowId: number; + private _hasFocus: boolean; get hasFocus(): boolean { return this._hasFocus; } constructor( - private windowId: number, private configuration: IWindowConfiguration, @IWindowsService private readonly windowsService: IWindowsService ) { super(); - const onThisWindowFocus = Event.map(Event.filter(windowsService.onWindowFocus, id => id === windowId), _ => true); - const onThisWindowBlur = Event.map(Event.filter(windowsService.onWindowBlur, id => id === windowId), _ => false); - const onThisWindowMaximize = Event.map(Event.filter(windowsService.onWindowMaximize, id => id === windowId), _ => true); - const onThisWindowUnmaximize = Event.map(Event.filter(windowsService.onWindowUnmaximize, id => id === windowId), _ => false); + this.windowId = configuration.windowId; + + const onThisWindowFocus = Event.map(Event.filter(windowsService.onWindowFocus, id => id === this.windowId), _ => true); + const onThisWindowBlur = Event.map(Event.filter(windowsService.onWindowBlur, id => id === this.windowId), _ => false); + const onThisWindowMaximize = Event.map(Event.filter(windowsService.onWindowMaximize, id => id === this.windowId), _ => true); + const onThisWindowUnmaximize = Event.map(Event.filter(windowsService.onWindowUnmaximize, id => id === this.windowId), _ => false); this.onDidChangeFocus = Event.any(onThisWindowFocus, onThisWindowBlur); this.onDidChangeMaximize = Event.any(onThisWindowMaximize, onThisWindowUnmaximize); diff --git a/src/vs/workbench/electron-browser/main.ts b/src/vs/workbench/electron-browser/main.ts index 86622a111a7..6c1c066a5d5 100644 --- a/src/vs/workbench/electron-browser/main.ts +++ b/src/vs/workbench/electron-browser/main.ts @@ -138,11 +138,6 @@ function openWorkbench(configuration: IWindowConfiguration): Promise { storageService }, mainServices, mainProcessClient, configuration); - // Gracefully Shutdown Storage - shell.onWillShutdown(event => { - event.join(storageService.close()); - }); - // Open Shell shell.open(); diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 3f825444640..54f1f63e6b0 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -4,91 +4,21 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable } from 'vs/base/common/lifecycle'; -import product from 'vs/platform/node/product'; -import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import pkg from 'vs/platform/node/package'; -import { Workbench } from 'vs/workbench/electron-browser/workbench'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { NullTelemetryService, configurationTelemetry, combinedAppender, LogAppender } from 'vs/platform/telemetry/common/telemetryUtils'; -import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc'; -import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; -import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry'; -import { ElectronWindow } from 'vs/workbench/electron-browser/window'; -import { resolveWorkbenchCommonProperties } from 'vs/platform/telemetry/node/workbenchCommonProperties'; -import { IWindowsService, IWindowService, IWindowConfiguration } from 'vs/platform/windows/common/windows'; -import { WindowService } from 'vs/platform/windows/electron-browser/windowService'; -import { IRequestService } from 'vs/platform/request/node/request'; -import { RequestService } from 'vs/platform/request/electron-browser/requestService'; +import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { SearchService } from 'vs/workbench/services/search/node/searchService'; -import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService'; -import { MarkerService } from 'vs/platform/markers/common/markerService'; -import { IModelService } from 'vs/editor/common/services/modelService'; -import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; -import { CodeEditorService } from 'vs/workbench/services/editor/browser/codeEditorService'; -import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { IntegrityServiceImpl } from 'vs/workbench/services/integrity/node/integrityServiceImpl'; -import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity'; -import { EditorWorkerServiceImpl } from 'vs/editor/common/services/editorWorkerServiceImpl'; -import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; -import { ExtensionService } from 'vs/workbench/services/extensions/electron-browser/extensionService'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { InstantiationService } from 'vs/platform/instantiation/node/instantiationService'; -import { ILifecycleService, WillShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle'; -import { IMarkerService } from 'vs/platform/markers/common/markers'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { ISearchService, ISearchHistoryService } from 'vs/workbench/services/search/common/search'; -import { ICommandService } from 'vs/platform/commands/common/commands'; -import { CommandService } from 'vs/workbench/services/commands/common/commandService'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { WorkbenchModeServiceImpl } from 'vs/workbench/services/mode/common/workbenchModeService'; -import { IModeService } from 'vs/editor/common/services/modeService'; -import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { getDelayedChannel, IPCClient } from 'vs/base/parts/ipc/node/ipc'; -import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net'; -import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/node/extensionManagementIpc'; -import { IExtensionManagementService, IExtensionEnablementService, IExtensionManagementServerService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { ExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService'; -import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; -import { WorkbenchThemeService } from 'vs/workbench/services/themes/electron-browser/workbenchThemeService'; -import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; -import { TextResourceConfigurationService } from 'vs/editor/common/services/resourceConfigurationImpl'; -import { TextMateService } from 'vs/workbench/services/textMate/electron-browser/TMSyntax'; -import { ITextMateService } from 'vs/workbench/services/textMate/electron-browser/textMateService'; -import { IBroadcastService, BroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService'; -import { HashService } from 'vs/workbench/services/hash/node/hashService'; -import { IHashService } from 'vs/workbench/services/hash/common/hashService'; import { ILogService } from 'vs/platform/log/common/log'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { Event, Emitter } from 'vs/base/common/event'; -import { LocalizationsChannelClient } from 'vs/platform/localizations/node/localizationsIpc'; -import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; -import { INotificationService } from 'vs/platform/notification/common/notification'; -import { NotificationService } from 'vs/workbench/services/notification/common/notificationService'; -import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { DialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService'; -import { DialogChannel } from 'vs/platform/dialogs/node/dialogIpc'; -import { IRemoteAgentService } from 'vs/workbench/services/remote/node/remoteAgentService'; -import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; -import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { OpenerService } from 'vs/editor/browser/services/openerService'; -import { SearchHistoryService } from 'vs/workbench/services/search/common/searchHistoryService'; -import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/node/extensionManagementServerService'; -import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; -import { LogLevelSetterChannel } from 'vs/platform/log/node/logIpc'; -import { ILabelService } from 'vs/platform/label/common/label'; -import { IDownloadService } from 'vs/platform/download/common/download'; -import { DownloadService } from 'vs/platform/download/node/downloadService'; -import { DownloadServiceChannel } from 'vs/platform/download/node/downloadIpc'; -import { TextResourcePropertiesService } from 'vs/workbench/services/textfile/electron-browser/textResourcePropertiesService'; -import { MultiExtensionManagementService } from 'vs/workbench/services/extensionManagement/node/multiExtensionManagement'; -import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-browser/remoteAuthorityResolverService'; -import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService'; -import { MarkerDecorationsService } from 'vs/editor/common/services/markerDecorationsServiceImpl'; -import { LabelService } from 'vs/workbench/services/label/common/labelService'; + +// import@node +import { InstantiationService } from 'vs/platform/instantiation/node/instantiationService'; +import { IPCClient } from 'vs/base/parts/ipc/node/ipc'; + +// import@electron-browser +import { Workbench } from 'vs/workbench/electron-browser/workbench'; +import { ElectronWindow } from 'vs/workbench/electron-browser/window'; /** * Services that we require for the Shell @@ -106,20 +36,11 @@ export interface ICoreServices { * With the Shell being the top level element in the page, it is also responsible for driving the layouting. */ export class Shell extends Disposable { - - private readonly _onWillShutdown = this._register(new Emitter()); - get onWillShutdown(): Event { return this._onWillShutdown.event; } - private storageService: IStorageService; private environmentService: IEnvironmentService; private logService: ILogService; private configurationService: IConfigurationService; private contextService: IWorkspaceContextService; - private telemetryService: ITelemetryService; - private broadcastService: IBroadcastService; - private themeService: WorkbenchThemeService; - private lifecycleService: LifecycleService; - private notificationService: INotificationService; private container: HTMLElement; private mainProcessClient: IPCClient; @@ -153,7 +74,8 @@ export class Shell extends Disposable { open(): void { // Instantiation service with services - const [instantiationService, serviceCollection] = this.initServiceCollection(); + const serviceCollection = this.initServiceCollection(); + const instantiationService = new InstantiationService(serviceCollection, true); // Workbench const workbench = this._register(instantiationService.createInstance( @@ -161,7 +83,6 @@ export class Shell extends Disposable { this.container, this.configuration, serviceCollection, - this.lifecycleService, this.mainProcessClient )); workbench.startup(); @@ -170,12 +91,11 @@ export class Shell extends Disposable { workbench.getInstantiationService().createInstance(ElectronWindow); } - private initServiceCollection(): [IInstantiationService, ServiceCollection] { + private initServiceCollection(): ServiceCollection { const serviceCollection = new ServiceCollection(); serviceCollection.set(IWorkspaceContextService, this.contextService); serviceCollection.set(IConfigurationService, this.configurationService); serviceCollection.set(IEnvironmentService, this.environmentService); - serviceCollection.set(ILabelService, new SyncDescriptor(LabelService, undefined, true)); serviceCollection.set(ILogService, this._register(this.logService)); serviceCollection.set(IStorageService, this.storageService); @@ -183,116 +103,6 @@ export class Shell extends Disposable { serviceCollection.set(serviceIdentifier, serviceInstance); }); - const instantiationService: IInstantiationService = new InstantiationService(serviceCollection, true); - - this.notificationService = new NotificationService(); - serviceCollection.set(INotificationService, this.notificationService); - - this.broadcastService = instantiationService.createInstance(BroadcastService, this.configuration.windowId); - serviceCollection.set(IBroadcastService, this.broadcastService); - - serviceCollection.set(IWindowService, new SyncDescriptor(WindowService, [this.configuration.windowId, this.configuration])); - - const sharedProcess = (serviceCollection.get(IWindowsService)).whenSharedProcessReady() - .then(() => connectNet(this.environmentService.sharedIPCHandle, `window:${this.configuration.windowId}`)) - .then(client => { - client.registerChannel('dialog', instantiationService.createInstance(DialogChannel)); - - return client; - }); - - // Hash - serviceCollection.set(IHashService, new SyncDescriptor(HashService, undefined, true)); - - // Telemetry - if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) { - const channel = getDelayedChannel(sharedProcess.then(c => c.getChannel('telemetryAppender'))); - const config: ITelemetryServiceConfig = { - appender: combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService)), - commonProperties: resolveWorkbenchCommonProperties(this.storageService, product.commit, pkg.version, this.configuration.machineId, this.environmentService.installSourcePath), - piiPaths: [this.environmentService.appRoot, this.environmentService.extensionsPath] - }; - - this.telemetryService = this._register(instantiationService.createInstance(TelemetryService, config)); - this._register(new ErrorTelemetry(this.telemetryService)); - } else { - this.telemetryService = NullTelemetryService; - } - - serviceCollection.set(ITelemetryService, this.telemetryService); - this._register(configurationTelemetry(this.telemetryService, this.configurationService)); - - serviceCollection.set(IDialogService, instantiationService.createInstance(DialogService)); - - const lifecycleService = instantiationService.createInstance(LifecycleService); - this._register(lifecycleService.onWillShutdown(event => this._onWillShutdown.fire(event))); - this._register(lifecycleService.onShutdown(() => this.dispose())); - serviceCollection.set(ILifecycleService, lifecycleService); - this.lifecycleService = lifecycleService; - - serviceCollection.set(IRequestService, new SyncDescriptor(RequestService, undefined, true)); - serviceCollection.set(IDownloadService, new SyncDescriptor(DownloadService, undefined, true)); - serviceCollection.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService, undefined, true)); - - const remoteAuthorityResolverService = new RemoteAuthorityResolverService(); - serviceCollection.set(IRemoteAuthorityResolverService, remoteAuthorityResolverService); - - const remoteAgentService = new RemoteAgentService(this.configuration, this.notificationService, this.environmentService, remoteAuthorityResolverService); - serviceCollection.set(IRemoteAgentService, remoteAgentService); - - const remoteAgentConnection = remoteAgentService.getConnection(); - if (remoteAgentConnection) { - remoteAgentConnection.registerChannel('dialog', instantiationService.createInstance(DialogChannel)); - remoteAgentConnection.registerChannel('download', new DownloadServiceChannel()); - remoteAgentConnection.registerChannel('loglevel', new LogLevelSetterChannel(this.logService)); - } - - const extensionManagementChannel = getDelayedChannel(sharedProcess.then(c => c.getChannel('extensions'))); - const extensionManagementChannelClient = new ExtensionManagementChannelClient(extensionManagementChannel); - serviceCollection.set(IExtensionManagementServerService, new SyncDescriptor(ExtensionManagementServerService, [extensionManagementChannelClient])); - serviceCollection.set(IExtensionManagementService, new SyncDescriptor(MultiExtensionManagementService)); - - const extensionEnablementService = this._register(instantiationService.createInstance(ExtensionEnablementService)); - serviceCollection.set(IExtensionEnablementService, extensionEnablementService); - - serviceCollection.set(IExtensionService, instantiationService.createInstance(ExtensionService)); - - this.themeService = instantiationService.createInstance(WorkbenchThemeService, document.body); - serviceCollection.set(IWorkbenchThemeService, this.themeService); - - serviceCollection.set(ICommandService, new SyncDescriptor(CommandService, undefined, true)); - - serviceCollection.set(IMarkerService, new SyncDescriptor(MarkerService, undefined, true)); - - serviceCollection.set(IModeService, new SyncDescriptor(WorkbenchModeServiceImpl)); - - serviceCollection.set(ITextResourceConfigurationService, new SyncDescriptor(TextResourceConfigurationService)); - - serviceCollection.set(ITextResourcePropertiesService, new SyncDescriptor(TextResourcePropertiesService)); - - serviceCollection.set(IModelService, new SyncDescriptor(ModelServiceImpl, undefined, true)); - - serviceCollection.set(IMarkerDecorationsService, new SyncDescriptor(MarkerDecorationsService)); - - serviceCollection.set(IEditorWorkerService, new SyncDescriptor(EditorWorkerServiceImpl)); - - serviceCollection.set(IUntitledEditorService, new SyncDescriptor(UntitledEditorService, undefined, true)); - - serviceCollection.set(ITextMateService, new SyncDescriptor(TextMateService)); - - serviceCollection.set(ISearchService, new SyncDescriptor(SearchService)); - - serviceCollection.set(ISearchHistoryService, new SyncDescriptor(SearchHistoryService)); - - serviceCollection.set(ICodeEditorService, new SyncDescriptor(CodeEditorService)); - - serviceCollection.set(IOpenerService, new SyncDescriptor(OpenerService, undefined, true)); - - serviceCollection.set(IIntegrityService, new SyncDescriptor(IntegrityServiceImpl)); - - const localizationsChannel = getDelayedChannel(sharedProcess.then(c => c.getChannel('localizations'))); - serviceCollection.set(ILocalizationsService, new SyncDescriptor(LocalizationsChannelClient, [localizationsChannel])); - - return [instantiationService, serviceCollection]; + return serviceCollection; } } diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index e11d491f04c..506839cf21d 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -13,14 +13,12 @@ import { RunOnceScheduler, runWhenIdle } from 'vs/base/common/async'; import { getZoomLevel, onDidChangeFullscreen, isFullscreen, getZoomFactor } from 'vs/base/browser/browser'; import { mark } from 'vs/base/common/performance'; import { onUnexpectedError, setUnexpectedErrorHandler } from 'vs/base/common/errors'; -import { BackupFileService, InMemoryBackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { Registry } from 'vs/platform/registry/common/platform'; import { isWindows, isLinux, isMacintosh, language } from 'vs/base/common/platform'; import { IResourceInput } from 'vs/platform/editor/common/editor'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IEditorInputFactoryRegistry, Extensions as EditorExtensions, TextCompareEditorVisibleContext, TEXT_DIFF_EDITOR_ID, EditorsVisibleContext, InEditorZenModeContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, IUntitledResourceInput, IResourceDiffInput, SplitEditorsVertically, TextCompareEditorActiveContext, ActiveEditorContext } from 'vs/workbench/common/editor'; -import { HistoryService } from 'vs/workbench/services/history/electron-browser/history'; import { ActivitybarPart } from 'vs/workbench/browser/parts/activitybar/activitybarPart'; import { SidebarPart } from 'vs/workbench/browser/parts/sidebar/sidebarPart'; import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart'; @@ -36,28 +34,21 @@ import { getServices } from 'vs/platform/instantiation/common/extensions'; import { Position, Parts, IPartService, IDimension, PositionToString, ILayoutOptions } from 'vs/workbench/services/part/common/partService'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IStorageService, StorageScope, IWillSaveStateEvent, WillSaveStateReason } from 'vs/platform/storage/common/storage'; -import { ContextMenuService as NativeContextMenuService } from 'vs/workbench/services/contextview/electron-browser/contextmenuService'; import { ContextMenuService as HTMLContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; -import { WorkbenchKeybindingService } from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { WorkspaceService, DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationService'; import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; -import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService'; import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingEditingService, KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing'; import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IActivityService } from 'vs/workbench/services/activity/common/activity'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { RemoteFileService } from 'vs/workbench/services/files/electron-browser/remoteFileService'; import { IFileService } from 'vs/platform/files/common/files'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; -import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/electron-browser/configurationResolverService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { ITitleService } from 'vs/workbench/services/title/common/titleService'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; @@ -68,20 +59,16 @@ import { ProgressService2 } from 'vs/workbench/services/progress/browser/progres import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { LifecyclePhase, StartupKind } from 'vs/platform/lifecycle/common/lifecycle'; -import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService'; -import { IWindowService, IWindowConfiguration, IPath, MenuBarVisibility, getTitleBarStyle } from 'vs/platform/windows/common/windows'; +import { LifecyclePhase, StartupKind, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { IWindowService, IWindowConfiguration, IPath, MenuBarVisibility, getTitleBarStyle, IWindowsService } from 'vs/platform/windows/common/windows'; import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { IMenuService, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { MenuService } from 'vs/platform/actions/common/menuService'; import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; -import { ShowPreviousWindowTab, MoveWindowTabToNewWindow, MergeAllWindowTabs, ShowNextWindowTab, ToggleWindowTabsBar, NewWindowTab, OpenRecentAction, ReloadWindowAction, ReloadWindowWithExtensionsDisabledAction } from 'vs/workbench/electron-browser/actions/windowActions'; -import { ToggleDevToolsAction } from 'vs/workbench/electron-browser/actions/developerActions'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; -import { WorkspaceEditingService } from 'vs/workbench/services/workspace/node/workspaceEditingService'; import { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService'; import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations'; import { ActivityService } from 'vs/workbench/services/activity/browser/activityService'; @@ -97,20 +84,14 @@ import { NotificationsAlerts } from 'vs/workbench/browser/parts/notifications/no import { NotificationsStatus } from 'vs/workbench/browser/parts/notifications/notificationsStatus'; import { registerNotificationCommands } from 'vs/workbench/browser/parts/notifications/notificationsCommands'; import { NotificationsToasts } from 'vs/workbench/browser/parts/notifications/notificationsToasts'; -import { IPCClient } from 'vs/base/parts/ipc/node/ipc'; -import { registerWindowDriver } from 'vs/platform/driver/electron-browser/driver'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { PreferencesService } from 'vs/workbench/services/preferences/browser/preferencesService'; import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupsService, GroupDirection, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService'; import { EditorService } from 'vs/workbench/services/editor/browser/editorService'; -import { IExtensionUrlHandler, ExtensionUrlHandler } from 'vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler'; import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService'; -import { WorkbenchThemeService } from 'vs/workbench/services/themes/electron-browser/workbenchThemeService'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; -import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { RemoteFileDialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService'; -import { LogStorageAction } from 'vs/platform/storage/node/storageService'; +import { IFileDialogService, IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { Sizing, Direction, Grid, View } from 'vs/base/browser/ui/grid/grid'; import { IEditor } from 'vs/editor/common/editorCommon'; import { WorkbenchLayout } from 'vs/workbench/browser/layout'; @@ -120,6 +101,91 @@ import { restoreFontInfo, readFontInfo, saveFontInfo } from 'vs/editor/browser/c import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { ILogService } from 'vs/platform/log/common/log'; import { toErrorMessage } from 'vs/base/common/errorMessage'; +import { ILabelService } from 'vs/platform/label/common/label'; +import { LabelService } from 'vs/workbench/services/label/common/labelService'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; +import { ITelemetryServiceConfig, TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; +import { combinedAppender, LogAppender, NullTelemetryService, configurationTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; +import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry'; +import { IDownloadService } from 'vs/platform/download/common/download'; +import { IExtensionGalleryService, IExtensionManagementServerService, IExtensionManagementService, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { ExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { CommandService } from 'vs/workbench/services/commands/common/commandService'; +import { IMarkerService } from 'vs/platform/markers/common/markers'; +import { MarkerService } from 'vs/platform/markers/common/markerService'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { WorkbenchModeServiceImpl } from 'vs/workbench/services/mode/common/workbenchModeService'; +import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; +import { TextResourceConfigurationService } from 'vs/editor/common/services/resourceConfigurationImpl'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; +import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService'; +import { MarkerDecorationsService } from 'vs/editor/common/services/markerDecorationsServiceImpl'; +import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; +import { EditorWorkerServiceImpl } from 'vs/editor/common/services/editorWorkerServiceImpl'; +import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; +import { ISearchService, ISearchHistoryService } from 'vs/workbench/services/search/common/search'; +import { SearchHistoryService } from 'vs/workbench/services/search/common/searchHistoryService'; +import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; +import { CodeEditorService } from 'vs/workbench/services/editor/browser/codeEditorService'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { OpenerService } from 'vs/editor/browser/services/openerService'; +import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity'; +import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; + +// import@node +import product from 'vs/platform/node/product'; +import pkg from 'vs/platform/node/package'; +import { BackupFileService, InMemoryBackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; +import { WorkspaceService, DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationService'; +import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService'; +import { WorkspaceEditingService } from 'vs/workbench/services/workspace/node/workspaceEditingService'; +import { IPCClient, getDelayedChannel } from 'vs/base/parts/ipc/node/ipc'; +import { LogStorageAction, StorageService } from 'vs/platform/storage/node/storageService'; +import { HashService } from 'vs/workbench/services/hash/node/hashService'; +import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net'; +import { DialogChannel } from 'vs/platform/dialogs/node/dialogIpc'; +import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc'; +import { resolveWorkbenchCommonProperties } from 'vs/platform/telemetry/node/workbenchCommonProperties'; +import { IRequestService } from 'vs/platform/request/node/request'; +import { RequestService } from 'vs/platform/request/node/requestService'; +import { DownloadService } from 'vs/platform/download/node/downloadService'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/node/remoteAgentService'; +import { DownloadServiceChannel } from 'vs/platform/download/node/downloadIpc'; +import { LogLevelSetterChannel } from 'vs/platform/log/node/logIpc'; +import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/node/extensionManagementIpc'; +import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/node/extensionManagementServerService'; +import { MultiExtensionManagementService } from 'vs/workbench/services/extensionManagement/node/multiExtensionManagement'; +import { SearchService } from 'vs/workbench/services/search/node/searchService'; +import { IntegrityServiceImpl } from 'vs/workbench/services/integrity/node/integrityServiceImpl'; +import { LocalizationsChannelClient } from 'vs/platform/localizations/node/localizationsIpc'; + +// import@electron-browser +import { HistoryService } from 'vs/workbench/services/history/electron-browser/history'; +import { ContextMenuService as NativeContextMenuService } from 'vs/workbench/services/contextview/electron-browser/contextmenuService'; +import { WorkbenchKeybindingService } from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; +import { RemoteFileService } from 'vs/workbench/services/files/electron-browser/remoteFileService'; +import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/electron-browser/configurationResolverService'; +import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService'; +import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService'; +import { ToggleDevToolsAction } from 'vs/workbench/electron-browser/actions/developerActions'; +import { registerWindowDriver } from 'vs/platform/driver/electron-browser/driver'; +import { IExtensionUrlHandler, ExtensionUrlHandler } from 'vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler'; +import { WorkbenchThemeService } from 'vs/workbench/services/themes/electron-browser/workbenchThemeService'; +import { RemoteFileDialogService, DialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService'; +import { ShowPreviousWindowTab, MoveWindowTabToNewWindow, MergeAllWindowTabs, ShowNextWindowTab, ToggleWindowTabsBar, NewWindowTab, OpenRecentAction, ReloadWindowAction, ReloadWindowWithExtensionsDisabledAction } from 'vs/workbench/electron-browser/actions/windowActions'; +import { IBroadcastService, BroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService'; +import { WindowService } from 'vs/platform/windows/electron-browser/windowService'; +import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-browser/remoteAuthorityResolverService'; +import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; +import { ExtensionService } from 'vs/workbench/services/extensions/electron-browser/extensionService'; +import { TextResourcePropertiesService } from 'vs/workbench/services/textfile/electron-browser/textResourcePropertiesService'; +import { ITextMateService } from 'vs/workbench/services/textMate/electron-browser/textMateService'; +import { TextMateService } from 'vs/workbench/services/textMate/electron-browser/TMSyntax'; interface WorkbenchParams { configuration: IWindowConfiguration; @@ -211,6 +277,11 @@ export class Workbench extends Disposable implements IPartService { private contextKeyService: IContextKeyService; private keybindingService: IKeybindingService; private backupFileService: IBackupFileService; + private notificationService: NotificationService; + private themeService: WorkbenchThemeService; + private telemetryService: ITelemetryService; + private windowService: IWindowService; + private lifecycleService: LifecycleService; private fileService: IFileService; private quickInput: QuickInputService; @@ -262,18 +333,14 @@ export class Workbench extends Disposable implements IPartService { private container: HTMLElement, private configuration: IWindowConfiguration, serviceCollection: ServiceCollection, - private lifecycleService: LifecycleService, private mainProcessClient: IPCClient, @IInstantiationService private readonly instantiationService: IInstantiationService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @IStorageService private readonly storageService: IStorageService, + @IStorageService private readonly storageService: StorageService, @IConfigurationService private readonly configurationService: WorkspaceService, - @IWorkbenchThemeService private readonly themeService: WorkbenchThemeService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @IWindowService private readonly windowService: IWindowService, - @INotificationService private readonly notificationService: NotificationService, - @ITelemetryService private readonly telemetryService: ITelemetryService, - @ILogService private readonly logService: ILogService + @ILogService private readonly logService: ILogService, + @IWindowsService private readonly windowsService: IWindowsService ) { super(); @@ -339,9 +406,6 @@ export class Workbench extends Disposable implements IPartService { private doStartup(): Promise { this.workbenchStarted = true; - // Set lifecycle phase to `Ready` - this.lifecycleService.phase = LifecyclePhase.Ready; - // ARIA setARIAContainer(document.body); @@ -430,12 +494,156 @@ export class Workbench extends Disposable implements IPartService { private initServices(): void { const { serviceCollection } = this.workbenchParams; - // Services we contribute + // Parts serviceCollection.set(IPartService, this); + // Labels + serviceCollection.set(ILabelService, new SyncDescriptor(LabelService, undefined, true)); + // Clipboard serviceCollection.set(IClipboardService, new SyncDescriptor(ClipboardService)); + // Broadcast + serviceCollection.set(IBroadcastService, new SyncDescriptor(BroadcastService, [this.configuration.windowId])); + + // Notifications + this.notificationService = new NotificationService(); + serviceCollection.set(INotificationService, this.notificationService); + + // Window + this.windowService = this.instantiationService.createInstance(WindowService, this.configuration); + serviceCollection.set(IWindowService, this.windowService); + + // Shared Process + const sharedProcess = this.windowsService.whenSharedProcessReady() + .then(() => connectNet(this.environmentService.sharedIPCHandle, `window:${this.configuration.windowId}`)) + .then(client => { + client.registerChannel('dialog', this.instantiationService.createInstance(DialogChannel)); + + return client; + }); + + // Telemetry + if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) { + const channel = getDelayedChannel(sharedProcess.then(c => c.getChannel('telemetryAppender'))); + const config: ITelemetryServiceConfig = { + appender: combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService)), + commonProperties: resolveWorkbenchCommonProperties(this.storageService, product.commit, pkg.version, this.configuration.machineId, this.environmentService.installSourcePath), + piiPaths: [this.environmentService.appRoot, this.environmentService.extensionsPath] + }; + + this.telemetryService = this._register(this.instantiationService.createInstance(TelemetryService, config)); + this._register(new ErrorTelemetry(this.telemetryService)); + } else { + this.telemetryService = NullTelemetryService; + } + + serviceCollection.set(ITelemetryService, this.telemetryService); + this._register(configurationTelemetry(this.telemetryService, this.configurationService)); + + // Dialogs + serviceCollection.set(IDialogService, this.instantiationService.createInstance(DialogService)); + + // Lifecycle + this.lifecycleService = this.instantiationService.createInstance(LifecycleService); + this.lifecycleService.phase = LifecyclePhase.Ready; // Set lifecycle phase to `Ready` + + serviceCollection.set(ILifecycleService, this.lifecycleService); + + this._register(this.lifecycleService.onWillShutdown(event => event.join(this.storageService.close()))); + this._register(this.lifecycleService.onShutdown(() => this.dispose())); + + // Request Service + serviceCollection.set(IRequestService, new SyncDescriptor(RequestService, undefined, true)); + + // Download Service + serviceCollection.set(IDownloadService, new SyncDescriptor(DownloadService, undefined, true)); + + // Extension Gallery + serviceCollection.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService, undefined, true)); + + // Remote Resolver + const remoteAuthorityResolverService = new RemoteAuthorityResolverService(); + serviceCollection.set(IRemoteAuthorityResolverService, remoteAuthorityResolverService); + + // Remote Agent + const remoteAgentService = new RemoteAgentService(this.configuration, this.notificationService, this.environmentService, remoteAuthorityResolverService); + serviceCollection.set(IRemoteAgentService, remoteAgentService); + + const remoteAgentConnection = remoteAgentService.getConnection(); + if (remoteAgentConnection) { + remoteAgentConnection.registerChannel('dialog', this.instantiationService.createInstance(DialogChannel)); + remoteAgentConnection.registerChannel('download', new DownloadServiceChannel()); + remoteAgentConnection.registerChannel('loglevel', new LogLevelSetterChannel(this.logService)); + } + + // Extensions Management + const extensionManagementChannel = getDelayedChannel(sharedProcess.then(c => c.getChannel('extensions'))); + const extensionManagementChannelClient = new ExtensionManagementChannelClient(extensionManagementChannel); + serviceCollection.set(IExtensionManagementServerService, new SyncDescriptor(ExtensionManagementServerService, [extensionManagementChannelClient])); + serviceCollection.set(IExtensionManagementService, new SyncDescriptor(MultiExtensionManagementService)); + + // Extension Enablement + const extensionEnablementService = this._register(this.instantiationService.createInstance(ExtensionEnablementService)); + serviceCollection.set(IExtensionEnablementService, extensionEnablementService); + + // Extensions + serviceCollection.set(IExtensionService, this.instantiationService.createInstance(ExtensionService)); + + // Theming + this.themeService = this.instantiationService.createInstance(WorkbenchThemeService, document.body); + serviceCollection.set(IWorkbenchThemeService, this.themeService); + + // Commands + serviceCollection.set(ICommandService, new SyncDescriptor(CommandService, undefined, true)); + + // Markers + serviceCollection.set(IMarkerService, new SyncDescriptor(MarkerService, undefined, true)); + + // Editor Mode + serviceCollection.set(IModeService, new SyncDescriptor(WorkbenchModeServiceImpl)); + + // Text Resource Config + serviceCollection.set(ITextResourceConfigurationService, new SyncDescriptor(TextResourceConfigurationService)); + + // Text Resource Properties + serviceCollection.set(ITextResourcePropertiesService, new SyncDescriptor(TextResourcePropertiesService)); + + // Editor Models + serviceCollection.set(IModelService, new SyncDescriptor(ModelServiceImpl, undefined, true)); + + // Marker Decorations + serviceCollection.set(IMarkerDecorationsService, new SyncDescriptor(MarkerDecorationsService)); + + // Editor Worker + serviceCollection.set(IEditorWorkerService, new SyncDescriptor(EditorWorkerServiceImpl)); + + // Untitled Editors + serviceCollection.set(IUntitledEditorService, new SyncDescriptor(UntitledEditorService, undefined, true)); + + // Text Mate + serviceCollection.set(ITextMateService, new SyncDescriptor(TextMateService)); + + // Search + serviceCollection.set(ISearchService, new SyncDescriptor(SearchService)); + serviceCollection.set(ISearchHistoryService, new SyncDescriptor(SearchHistoryService)); + + // Code Editor + serviceCollection.set(ICodeEditorService, new SyncDescriptor(CodeEditorService)); + + // Opener + serviceCollection.set(IOpenerService, new SyncDescriptor(OpenerService, undefined, true)); + + // Integrity + serviceCollection.set(IIntegrityService, new SyncDescriptor(IntegrityServiceImpl)); + + // Localization + const localizationsChannel = getDelayedChannel(sharedProcess.then(c => c.getChannel('localizations'))); + serviceCollection.set(ILocalizationsService, new SyncDescriptor(LocalizationsChannelClient, [localizationsChannel])); + + // Hash + serviceCollection.set(IHashService, new SyncDescriptor(HashService, undefined, true)); + // Status bar this.statusbarPart = this.instantiationService.createInstance(StatusbarPart, Identifiers.STATUSBAR_PART); serviceCollection.set(IStatusbarService, this.statusbarPart); @@ -1639,7 +1847,7 @@ export class Workbench extends Disposable implements IPartService { } } - layout(options?: ILayoutOptions): void { + private layout(options?: ILayoutOptions): void { this.contextViewService.layout(); if (this.workbenchStarted && !this.workbenchShutdown) { @@ -1772,7 +1980,6 @@ export class Workbench extends Disposable implements IPartService { } } - // Remember in settings const defaultHidden = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY; if (hidden !== defaultHidden) { @@ -1815,7 +2022,6 @@ export class Workbench extends Disposable implements IPartService { } } - // Remember in settings if (!hidden) { this.storageService.store(Workbench.panelHiddenStorageKey, 'false', StorageScope.WORKSPACE); @@ -1960,4 +2166,6 @@ export class Workbench extends Disposable implements IPartService { this.workbenchGrid.layout(); } } + + //#endregion } diff --git a/src/vs/workbench/services/broadcast/electron-browser/broadcastService.ts b/src/vs/workbench/services/broadcast/electron-browser/broadcastService.ts index 27d8cfb4e5a..d78d3e3b56e 100644 --- a/src/vs/workbench/services/broadcast/electron-browser/broadcastService.ts +++ b/src/vs/workbench/services/broadcast/electron-browser/broadcastService.ts @@ -19,15 +19,16 @@ export interface IBroadcast { export interface IBroadcastService { _serviceBrand: any; - broadcast(b: IBroadcast): void; - onBroadcast: Event; + + broadcast(b: IBroadcast): void; } export class BroadcastService implements IBroadcastService { - public _serviceBrand: any; + _serviceBrand: any; private readonly _onBroadcast: Emitter; + get onBroadcast(): Event { return this._onBroadcast.event; } constructor( private windowId: number, @@ -46,11 +47,7 @@ export class BroadcastService implements IBroadcastService { }); } - public get onBroadcast(): Event { - return this._onBroadcast.event; - } - - public broadcast(b: IBroadcast): void { + broadcast(b: IBroadcast): void { this.logService.trace(`Sending broadcast to main from window ${this.windowId}: `, b); ipc.send('vscode:broadcast', this.windowId, { diff --git a/src/vs/workbench/services/part/common/partService.ts b/src/vs/workbench/services/part/common/partService.ts index ad8908763f7..c779417568b 100644 --- a/src/vs/workbench/services/part/common/partService.ts +++ b/src/vs/workbench/services/part/common/partService.ts @@ -13,8 +13,7 @@ export const enum Parts { PANEL_PART, EDITOR_PART, STATUSBAR_PART, - TITLEBAR_PART, - MENUBAR_PART + TITLEBAR_PART } export const enum Position { From 5643c089348266dc24d7c6cef6268206259f973d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Feb 2019 11:53:08 +0100 Subject: [PATCH 187/207] paths - use isAbsolute() --- src/vs/workbench/contrib/debug/common/debugSource.ts | 2 +- src/vs/workbench/contrib/debug/common/debugUtils.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/debug/common/debugSource.ts b/src/vs/workbench/contrib/debug/common/debugSource.ts index 0cfc1e8b6b3..41ced00cc31 100644 --- a/src/vs/workbench/contrib/debug/common/debugSource.ts +++ b/src/vs/workbench/contrib/debug/common/debugSource.ts @@ -52,7 +52,7 @@ export class Source { this.uri = uri.parse(path); } else { // assume a filesystem path - if (paths.isAbsolute_posix(path) || paths.isAbsolute_win32(path)) { + if (paths.isAbsolute(path)) { this.uri = uri.file(path); } else { // path is relative: since VS Code cannot deal with this by itself diff --git a/src/vs/workbench/contrib/debug/common/debugUtils.ts b/src/vs/workbench/contrib/debug/common/debugUtils.ts index 7bd7849ceb1..0804f0433c3 100644 --- a/src/vs/workbench/contrib/debug/common/debugUtils.ts +++ b/src/vs/workbench/contrib/debug/common/debugUtils.ts @@ -6,7 +6,7 @@ import { equalsIgnoreCase } from 'vs/base/common/strings'; import { IConfig, IDebuggerContribution } from 'vs/workbench/contrib/debug/common/debug'; import { URI as uri } from 'vs/base/common/uri'; -import { isAbsolute_posix, isAbsolute_win32 } from 'vs/base/common/paths'; +import { isAbsolute } from 'vs/base/common/paths'; import { deepClone } from 'vs/base/common/objects'; const _formatPIIRegexp = /{([^}]+)}/g; @@ -90,7 +90,7 @@ function stringToUri(path: string): string { return uri.parse(path); } else { // assume path - if (isAbsolute_posix(path) || isAbsolute_win32(path)) { + if (isAbsolute(path)) { return uri.file(path); } else { // leave relative path as is From 40c17e4e79dc7c96c7c0c22dfdb786cb864b582d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Feb 2019 12:03:25 +0100 Subject: [PATCH 188/207] debt - use paths.sep in more places --- src/vs/code/electron-main/app.ts | 9 +++++---- .../contrib/files/electron-browser/files.contribution.ts | 6 +++--- .../contrib/webview/electron-browser/webviewProtocols.ts | 5 ++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 02729fd6138..cd25faa7584 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -63,8 +63,9 @@ import { hasArgs } from 'vs/platform/environment/node/argv'; import { RunOnceScheduler } from 'vs/base/common/async'; import { registerContextMenuListener } from 'vs/base/parts/contextmenu/electron-main/contextmenu'; import { storeBackgroundColor } from 'vs/code/electron-main/theme'; -import { nativeSep, join } from 'vs/base/common/paths'; +import { join } from 'vs/base/common/paths'; import { homedir } from 'os'; +import { sep } from 'path'; import { localize } from 'vs/nls'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from 'vs/platform/remote/node/remoteAgentFileSystemChannel'; @@ -154,7 +155,7 @@ export class CodeApplication extends Disposable { const srcUri = URI.parse(source).fsPath.toLowerCase(); const rootUri = URI.file(this.environmentService.appRoot).fsPath.toLowerCase(); - return startsWith(srcUri, rootUri + nativeSep); + return startsWith(srcUri, rootUri + sep); }; // Ensure defaults @@ -685,7 +686,7 @@ export class CodeApplication extends Disposable { this._disposeRunner = new RunOnceScheduler(() => this.dispose(), 5000); } - public dispose(): void { + dispose(): void { this._disposeRunner.dispose(); connectionPool.delete(this._authority); this._client.then((connection) => { @@ -693,7 +694,7 @@ export class CodeApplication extends Disposable { }); } - public getClient(): Promise> { + getClient(): Promise> { this._disposeRunner.schedule(); return this._client; } diff --git a/src/vs/workbench/contrib/files/electron-browser/files.contribution.ts b/src/vs/workbench/contrib/files/electron-browser/files.contribution.ts index be0be8bf599..46c71acd168 100644 --- a/src/vs/workbench/contrib/files/electron-browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/electron-browser/files.contribution.ts @@ -6,6 +6,7 @@ import { URI } from 'vs/base/common/uri'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ShowViewletAction } from 'vs/workbench/browser/viewlet'; import * as nls from 'vs/nls'; +import { sep } from 'path'; import { SyncActionDescriptor, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; @@ -33,7 +34,6 @@ import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ILabelService } from 'vs/platform/label/common/label'; -import { nativeSep } from 'vs/base/common/paths'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExplorerService } from 'vs/workbench/contrib/files/electron-browser/explorerService'; @@ -61,10 +61,10 @@ class FileUriLabelContribution implements IWorkbenchContribution { scheme: 'file', formatting: { label: '${authority}${path}', - separator: nativeSep, + separator: sep, tildify: !platform.isWindows, normalizeDriveLetter: platform.isWindows, - authorityPrefix: nativeSep + nativeSep, + authorityPrefix: sep + sep, workspaceSuffix: '' } }); diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewProtocols.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewProtocols.ts index 9cfa61a57ce..e2210e8916b 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewProtocols.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewProtocols.ts @@ -2,9 +2,8 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { extname } from 'path'; +import { extname, sep } from 'path'; import { getMediaMime, MIME_UNKNOWN } from 'vs/base/common/mime'; -import { nativeSep } from 'vs/base/common/paths'; import { startsWith } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; @@ -52,7 +51,7 @@ export function registerFileProtocol( const requestPath = URI.parse(request.url).path; const normalizedPath = URI.file(requestPath); for (const root of getRoots()) { - if (startsWith(normalizedPath.fsPath, root.fsPath + nativeSep)) { + if (startsWith(normalizedPath.fsPath, root.fsPath + sep)) { resolveContent(fileService, normalizedPath, getMimeType(normalizedPath), callback); return; } From 9fdca2d5c8a753a8a106c31b81b58b006e11cef5 Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Tue, 12 Feb 2019 12:27:28 +0100 Subject: [PATCH 189/207] node path implementation * node path impl * update export * fix strict null checks --- src/vs/base/common/paths.node.ts | 1662 ++++++++++++++++++++ src/vs/base/test/common/paths.node.test.ts | 630 ++++++++ 2 files changed, 2292 insertions(+) create mode 100644 src/vs/base/common/paths.node.ts create mode 100644 src/vs/base/test/common/paths.node.test.ts diff --git a/src/vs/base/common/paths.node.ts b/src/vs/base/common/paths.node.ts new file mode 100644 index 00000000000..29aa5f8572f --- /dev/null +++ b/src/vs/base/common/paths.node.ts @@ -0,0 +1,1662 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { isWindows } from 'vs/base/common/platform'; + +const CHAR_UPPERCASE_A = 65;/* A */ +const CHAR_LOWERCASE_A = 97; /* a */ +const CHAR_UPPERCASE_Z = 90; /* Z */ +const CHAR_LOWERCASE_Z = 122; /* z */ +const CHAR_DOT = 46; /* . */ +const CHAR_FORWARD_SLASH = 47; /* / */ +const CHAR_BACKWARD_SLASH = 92; /* \ */ +const CHAR_COLON = 58; /* : */ +const CHAR_QUESTION_MARK = 63; /* ? */ + +interface IProcess { + cwd(): string; + platform: string; + env: object; +} + +declare let process: IProcess; +if (typeof process === 'undefined') { + // Logic to set up process + process = { + cwd() { return '/'; }, + env: {}, + get platform() { return isWindows ? 'win32' : 'posix'; } + }; +} + +class ErrorInvalidArgType extends Error { + code: 'ERR_INVALID_ARG_TYPE'; + constructor(name: string, expected: string, actual: string) { + // determiner: 'must be' or 'must not be' + let determiner; + if (typeof expected === 'string' && expected.indexOf('not ') === 0) { + determiner = 'must not be'; + expected = expected.replace(/^not /, ''); + } else { + determiner = 'must be'; + } + + let msg; + const type = name.indexOf('.') !== -1 ? 'property' : 'argument'; + msg = `The "${name}" ${type} ${determiner} of type ${expected}`; + + msg += `. Received type ${typeof actual}`; + super(msg); + } +} + +function validateString(value: string, name) { + if (typeof value !== 'string') { + throw new ErrorInvalidArgType(name, 'string', value); + } +} + +function isPathSeparator(code) { + return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; +} + +function isPosixPathSeparator(code) { + return code === CHAR_FORWARD_SLASH; +} + +function isWindowsDeviceRoot(code) { + return code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z || + code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z; +} + +// Resolves . and .. elements in a path with directory names +function normalizeString(path, allowAboveRoot, separator, isPathSeparator) { + let res = ''; + let lastSegmentLength = 0; + let lastSlash = -1; + let dots = 0; + let code; + for (let i = 0; i <= path.length; ++i) { + if (i < path.length) { + code = path.charCodeAt(i); + } + else if (isPathSeparator(code)) { + break; + } + else { + code = CHAR_FORWARD_SLASH; + } + + if (isPathSeparator(code)) { + if (lastSlash === i - 1 || dots === 1) { + // NOOP + } else if (lastSlash !== i - 1 && dots === 2) { + if (res.length < 2 || lastSegmentLength !== 2 || + res.charCodeAt(res.length - 1) !== CHAR_DOT || + res.charCodeAt(res.length - 2) !== CHAR_DOT) { + if (res.length > 2) { + const lastSlashIndex = res.lastIndexOf(separator); + if (lastSlashIndex === -1) { + res = ''; + lastSegmentLength = 0; + } else { + res = res.slice(0, lastSlashIndex); + lastSegmentLength = res.length - 1 - res.lastIndexOf(separator); + } + lastSlash = i; + dots = 0; + continue; + } else if (res.length === 2 || res.length === 1) { + res = ''; + lastSegmentLength = 0; + lastSlash = i; + dots = 0; + continue; + } + } + if (allowAboveRoot) { + if (res.length > 0) { + res += `${separator}..`; + } + else { + res = '..'; + } + lastSegmentLength = 2; + } + } else { + if (res.length > 0) { + res += separator + path.slice(lastSlash + 1, i); + } + else { + res = path.slice(lastSlash + 1, i); + } + lastSegmentLength = i - lastSlash - 1; + } + lastSlash = i; + dots = 0; + } else if (code === CHAR_DOT && dots !== -1) { + ++dots; + } else { + dots = -1; + } + } + return res; +} + +function _format(sep, pathObject) { + const dir = pathObject.dir || pathObject.root; + const base = pathObject.base || + ((pathObject.name || '') + (pathObject.ext || '')); + if (!dir) { + return base; + } + if (dir === pathObject.root) { + return dir + base; + } + return dir + sep + base; +} + +interface IPath { + normalize(path: string): string; + isAbsolute(path: string): boolean; + join(...paths: any[]): string; + resolve(...pathSegments: any[]): string; + relative(from: string, to: string): string; + dirname(path: string): string; + basename(path: string, ext?: string): string; + extname(path: string): string; + format(pathObject): string; + parse(path: string): object; + toNamespacedPath(path: string): string; + sep: string; + delimiter: string; + win32: IPath | null; + posix: IPath | null; +} + +interface IExportedPath extends IPath { + win32: IPath; + posix: IPath; +} + +const win32: IPath = { + // path.resolve([from ...], to) + resolve(...pathSegments: any[]): string { + let resolvedDevice = ''; + let resolvedTail = ''; + let resolvedAbsolute = false; + + for (let i = pathSegments.length - 1; i >= -1; i--) { + let path; + if (i >= 0) { + path = pathSegments[i]; + } else if (!resolvedDevice) { + path = process.cwd(); + } else { + // Windows has the concept of drive-specific current working + // directories. If we've resolved a drive letter but not yet an + // absolute path, get cwd for that drive, or the process cwd if + // the drive cwd is not available. We're sure the device is not + // a UNC path at this points, because UNC paths are always absolute. + path = process.env['=' + resolvedDevice] || process.cwd(); + + // Verify that a cwd was found and that it actually points + // to our drive. If not, default to the drive's root. + if (path === undefined || + path.slice(0, 3).toLowerCase() !== + resolvedDevice.toLowerCase() + '\\') { + path = resolvedDevice + '\\'; + } + } + + validateString(path, 'path'); + + // Skip empty entries + if (path.length === 0) { + continue; + } + + let len = path.length; + let rootEnd = 0; + let device = ''; + let isAbsolute = false; + const code = path.charCodeAt(0); + + // Try to match a root + if (len > 1) { + if (isPathSeparator(code)) { + // Possible UNC root + + // If we started with a separator, we know we at least have an + // absolute path of some kind (UNC or otherwise) + isAbsolute = true; + + if (isPathSeparator(path.charCodeAt(1))) { + // Matched double path separator at beginning + let j = 2; + let last = j; + // Match 1 or more non-path separators + for (; j < len; ++j) { + if (isPathSeparator(path.charCodeAt(j))) { + break; + } + } + if (j < len && j !== last) { + const firstPart = path.slice(last, j); + // Matched! + last = j; + // Match 1 or more path separators + for (; j < len; ++j) { + if (!isPathSeparator(path.charCodeAt(j))) { + break; + } + } + if (j < len && j !== last) { + // Matched! + last = j; + // Match 1 or more non-path separators + for (; j < len; ++j) { + if (isPathSeparator(path.charCodeAt(j))) { + break; + } + } + if (j === len) { + // We matched a UNC root only + + device = '\\\\' + firstPart + '\\' + path.slice(last); + rootEnd = j; + } else if (j !== last) { + // We matched a UNC root with leftovers + + device = '\\\\' + firstPart + '\\' + path.slice(last, j); + rootEnd = j; + } + } + } + } else { + rootEnd = 1; + } + } else if (isWindowsDeviceRoot(code)) { + // Possible device root + + if (path.charCodeAt(1) === CHAR_COLON) { + device = path.slice(0, 2); + rootEnd = 2; + if (len > 2) { + if (isPathSeparator(path.charCodeAt(2))) { + // Treat separator following drive name as an absolute path + // indicator + isAbsolute = true; + rootEnd = 3; + } + } + } + } + } else if (isPathSeparator(code)) { + // `path` contains just a path separator + rootEnd = 1; + isAbsolute = true; + } + + if (device.length > 0 && + resolvedDevice.length > 0 && + device.toLowerCase() !== resolvedDevice.toLowerCase()) { + // This path points to another device so it is not applicable + continue; + } + + if (resolvedDevice.length === 0 && device.length > 0) { + resolvedDevice = device; + } + if (!resolvedAbsolute) { + resolvedTail = path.slice(rootEnd) + '\\' + resolvedTail; + resolvedAbsolute = isAbsolute; + } + + if (resolvedDevice.length > 0 && resolvedAbsolute) { + break; + } + } + + // At this point the path should be resolved to a full absolute path, + // but handle relative paths to be safe (might happen when process.cwd() + // fails) + + // Normalize the tail path + resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\\', + isPathSeparator); + + return (resolvedDevice + (resolvedAbsolute ? '\\' : '') + resolvedTail) || + '.'; + }, + + normalize(path: string): string { + validateString(path, 'path'); + const len = path.length; + if (len === 0) { + return '.'; + } + let rootEnd = 0; + let device; + let isAbsolute = false; + const code = path.charCodeAt(0); + + // Try to match a root + if (len > 1) { + if (isPathSeparator(code)) { + // Possible UNC root + + // If we started with a separator, we know we at least have an absolute + // path of some kind (UNC or otherwise) + isAbsolute = true; + + if (isPathSeparator(path.charCodeAt(1))) { + // Matched double path separator at beginning + let j = 2; + let last = j; + // Match 1 or more non-path separators + for (; j < len; ++j) { + if (isPathSeparator(path.charCodeAt(j))) { + break; + } + } + if (j < len && j !== last) { + const firstPart = path.slice(last, j); + // Matched! + last = j; + // Match 1 or more path separators + for (; j < len; ++j) { + if (!isPathSeparator(path.charCodeAt(j))) { + break; + } + } + if (j < len && j !== last) { + // Matched! + last = j; + // Match 1 or more non-path separators + for (; j < len; ++j) { + if (isPathSeparator(path.charCodeAt(j))) { + break; + } + } + if (j === len) { + // We matched a UNC root only + // Return the normalized version of the UNC root since there + // is nothing left to process + + return '\\\\' + firstPart + '\\' + path.slice(last) + '\\'; + } else if (j !== last) { + // We matched a UNC root with leftovers + + device = '\\\\' + firstPart + '\\' + path.slice(last, j); + rootEnd = j; + } + } + } + } else { + rootEnd = 1; + } + } else if (isWindowsDeviceRoot(code)) { + // Possible device root + + if (path.charCodeAt(1) === CHAR_COLON) { + device = path.slice(0, 2); + rootEnd = 2; + if (len > 2) { + if (isPathSeparator(path.charCodeAt(2))) { + // Treat separator following drive name as an absolute path + // indicator + isAbsolute = true; + rootEnd = 3; + } + } + } + } + } else if (isPathSeparator(code)) { + // `path` contains just a path separator, exit early to avoid unnecessary + // work + return '\\'; + } + + let tail; + if (rootEnd < len) { + tail = normalizeString(path.slice(rootEnd), !isAbsolute, '\\', + isPathSeparator); + } else { + tail = ''; + } + if (tail.length === 0 && !isAbsolute) { + tail = '.'; + } + if (tail.length > 0 && isPathSeparator(path.charCodeAt(len - 1))) { + tail += '\\'; + } + if (device === undefined) { + if (isAbsolute) { + if (tail.length > 0) { + return '\\' + tail; + } + else { + return '\\'; + } + } else if (tail.length > 0) { + return tail; + } else { + return ''; + } + } else if (isAbsolute) { + if (tail.length > 0) { + return device + '\\' + tail; + } + else { + return device + '\\'; + } + } else if (tail.length > 0) { + return device + tail; + } else { + return device; + } + }, + + isAbsolute(path: string): boolean { + validateString(path, 'path'); + const len = path.length; + if (len === 0) { + return false; + } + + const code = path.charCodeAt(0); + if (isPathSeparator(code)) { + return true; + } else if (isWindowsDeviceRoot(code)) { + // Possible device root + + if (len > 2 && path.charCodeAt(1) === CHAR_COLON) { + if (isPathSeparator(path.charCodeAt(2))) { + return true; + } + } + } + return false; + }, + + join(...paths: any[]): string { + if (paths.length === 0) { + return '.'; + } + + let joined; + let firstPart; + for (let i = 0; i < paths.length; ++i) { + let arg = paths[i]; + validateString(arg, 'path'); + if (arg.length > 0) { + if (joined === undefined) { + joined = firstPart = arg; + } + else { + joined += '\\' + arg; + } + } + } + + if (joined === undefined) { + return '.'; + } + + // Make sure that the joined path doesn't start with two slashes, because + // normalize() will mistake it for an UNC path then. + // + // This step is skipped when it is very clear that the user actually + // intended to point at an UNC path. This is assumed when the first + // non-empty string arguments starts with exactly two slashes followed by + // at least one more non-slash character. + // + // Note that for normalize() to treat a path as an UNC path it needs to + // have at least 2 components, so we don't filter for that here. + // This means that the user can use join to construct UNC paths from + // a server name and a share name; for example: + // path.join('//server', 'share') -> '\\\\server\\share\\') + let needsReplace = true; + let slashCount = 0; + if (isPathSeparator(firstPart.charCodeAt(0))) { + ++slashCount; + const firstLen = firstPart.length; + if (firstLen > 1) { + if (isPathSeparator(firstPart.charCodeAt(1))) { + ++slashCount; + if (firstLen > 2) { + if (isPathSeparator(firstPart.charCodeAt(2))) { + ++slashCount; + } + else { + // We matched a UNC path in the first part + needsReplace = false; + } + } + } + } + } + if (needsReplace) { + // Find any more consecutive slashes we need to replace + for (; slashCount < joined.length; ++slashCount) { + if (!isPathSeparator(joined.charCodeAt(slashCount))) { + break; + } + } + + // Replace the slashes if needed + if (slashCount >= 2) { + joined = '\\' + joined.slice(slashCount); + } + } + + return win32.normalize(joined); + }, + + + // It will solve the relative path from `from` to `to`, for instance: + // from = 'C:\\orandea\\test\\aaa' + // to = 'C:\\orandea\\impl\\bbb' + // The output of the function should be: '..\\..\\impl\\bbb' + relative(from: string, to: string): string { + validateString(from, 'from'); + validateString(to, 'to'); + + if (from === to) { + return ''; + } + + let fromOrig = win32.resolve(from); + let toOrig = win32.resolve(to); + + if (fromOrig === toOrig) { + return ''; + } + + from = fromOrig.toLowerCase(); + to = toOrig.toLowerCase(); + + if (from === to) { + return ''; + } + + // Trim any leading backslashes + let fromStart = 0; + for (; fromStart < from.length; ++fromStart) { + if (from.charCodeAt(fromStart) !== CHAR_BACKWARD_SLASH) { + break; + } + } + // Trim trailing backslashes (applicable to UNC paths only) + let fromEnd = from.length; + for (; fromEnd - 1 > fromStart; --fromEnd) { + if (from.charCodeAt(fromEnd - 1) !== CHAR_BACKWARD_SLASH) { + break; + } + } + let fromLen = (fromEnd - fromStart); + + // Trim any leading backslashes + let toStart = 0; + for (; toStart < to.length; ++toStart) { + if (to.charCodeAt(toStart) !== CHAR_BACKWARD_SLASH) { + break; + } + } + // Trim trailing backslashes (applicable to UNC paths only) + let toEnd = to.length; + for (; toEnd - 1 > toStart; --toEnd) { + if (to.charCodeAt(toEnd - 1) !== CHAR_BACKWARD_SLASH) { + break; + } + } + let toLen = (toEnd - toStart); + + // Compare paths to find the longest common path from root + let length = (fromLen < toLen ? fromLen : toLen); + let lastCommonSep = -1; + let i = 0; + for (; i <= length; ++i) { + if (i === length) { + if (toLen > length) { + if (to.charCodeAt(toStart + i) === CHAR_BACKWARD_SLASH) { + // We get here if `from` is the exact base path for `to`. + // For example: from='C:\\foo\\bar'; to='C:\\foo\\bar\\baz' + return toOrig.slice(toStart + i + 1); + } else if (i === 2) { + // We get here if `from` is the device root. + // For example: from='C:\\'; to='C:\\foo' + return toOrig.slice(toStart + i); + } + } + if (fromLen > length) { + if (from.charCodeAt(fromStart + i) === CHAR_BACKWARD_SLASH) { + // We get here if `to` is the exact base path for `from`. + // For example: from='C:\\foo\\bar'; to='C:\\foo' + lastCommonSep = i; + } else if (i === 2) { + // We get here if `to` is the device root. + // For example: from='C:\\foo\\bar'; to='C:\\' + lastCommonSep = 3; + } + } + break; + } + let fromCode = from.charCodeAt(fromStart + i); + let toCode = to.charCodeAt(toStart + i); + if (fromCode !== toCode) { + break; + } + else if (fromCode === CHAR_BACKWARD_SLASH) { + lastCommonSep = i; + } + } + + // We found a mismatch before the first common path separator was seen, so + // return the original `to`. + if (i !== length && lastCommonSep === -1) { + return toOrig; + } + + let out = ''; + if (lastCommonSep === -1) { + lastCommonSep = 0; + } + // Generate the relative path based on the path difference between `to` and + // `from` + for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { + if (i === fromEnd || from.charCodeAt(i) === CHAR_BACKWARD_SLASH) { + if (out.length === 0) { + out += '..'; + } + else { + out += '\\..'; + } + } + } + + // Lastly, append the rest of the destination (`to`) path that comes after + // the common path parts + if (out.length > 0) { + return out + toOrig.slice(toStart + lastCommonSep, toEnd); + } + else { + toStart += lastCommonSep; + if (toOrig.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) { + ++toStart; + } + return toOrig.slice(toStart, toEnd); + } + }, + + toNamespacedPath(path: string): string { + // Note: this will *probably* throw somewhere. + if (typeof path !== 'string') { + return path; + } + + if (path.length === 0) { + return ''; + } + + const resolvedPath = win32.resolve(path); + + if (resolvedPath.length >= 3) { + if (resolvedPath.charCodeAt(0) === CHAR_BACKWARD_SLASH) { + // Possible UNC root + + if (resolvedPath.charCodeAt(1) === CHAR_BACKWARD_SLASH) { + const code = resolvedPath.charCodeAt(2); + if (code !== CHAR_QUESTION_MARK && code !== CHAR_DOT) { + // Matched non-long UNC root, convert the path to a long UNC path + return '\\\\?\\UNC\\' + resolvedPath.slice(2); + } + } + } else if (isWindowsDeviceRoot(resolvedPath.charCodeAt(0))) { + // Possible device root + + if (resolvedPath.charCodeAt(1) === CHAR_COLON && + resolvedPath.charCodeAt(2) === CHAR_BACKWARD_SLASH) { + // Matched device root, convert the path to a long UNC path + return '\\\\?\\' + resolvedPath; + } + } + } + + return path; + }, + + dirname(path: string): string { + validateString(path, 'path'); + const len = path.length; + if (len === 0) { + return '.'; + } + let rootEnd = -1; + let end = -1; + let matchedSlash = true; + let offset = 0; + const code = path.charCodeAt(0); + + // Try to match a root + if (len > 1) { + if (isPathSeparator(code)) { + // Possible UNC root + + rootEnd = offset = 1; + + if (isPathSeparator(path.charCodeAt(1))) { + // Matched double path separator at beginning + let j = 2; + let last = j; + // Match 1 or more non-path separators + for (; j < len; ++j) { + if (isPathSeparator(path.charCodeAt(j))) { + break; + } + } + if (j < len && j !== last) { + // Matched! + last = j; + // Match 1 or more path separators + for (; j < len; ++j) { + if (!isPathSeparator(path.charCodeAt(j))) { + break; + } + } + if (j < len && j !== last) { + // Matched! + last = j; + // Match 1 or more non-path separators + for (; j < len; ++j) { + if (isPathSeparator(path.charCodeAt(j))) { + break; + } + } + if (j === len) { + // We matched a UNC root only + return path; + } + if (j !== last) { + // We matched a UNC root with leftovers + + // Offset by 1 to include the separator after the UNC root to + // treat it as a "normal root" on top of a (UNC) root + rootEnd = offset = j + 1; + } + } + } + } + } else if (isWindowsDeviceRoot(code)) { + // Possible device root + + if (path.charCodeAt(1) === CHAR_COLON) { + rootEnd = offset = 2; + if (len > 2) { + if (isPathSeparator(path.charCodeAt(2))) { + rootEnd = offset = 3; + } + } + } + } + } else if (isPathSeparator(code)) { + // `path` contains just a path separator, exit early to avoid + // unnecessary work + return path; + } + + for (let i = len - 1; i >= offset; --i) { + if (isPathSeparator(path.charCodeAt(i))) { + if (!matchedSlash) { + end = i; + break; + } + } else { + // We saw the first non-path separator + matchedSlash = false; + } + } + + if (end === -1) { + if (rootEnd === -1) { + return '.'; + } + else { + end = rootEnd; + } + } + return path.slice(0, end); + }, + + basename(path: string, ext?: string): string { + if (ext !== undefined) { + validateString(ext, 'ext'); + } + validateString(path, 'path'); + let start = 0; + let end = -1; + let matchedSlash = true; + let i; + + // Check for a drive letter prefix so as not to mistake the following + // path separator as an extra separator at the end of the path that can be + // disregarded + if (path.length >= 2) { + const drive = path.charCodeAt(0); + if (isWindowsDeviceRoot(drive)) { + if (path.charCodeAt(1) === CHAR_COLON) { + start = 2; + } + } + } + + if (ext !== undefined && ext.length > 0 && ext.length <= path.length) { + if (ext.length === path.length && ext === path) { + return ''; + } + let extIdx = ext.length - 1; + let firstNonSlashEnd = -1; + for (i = path.length - 1; i >= start; --i) { + const code = path.charCodeAt(i); + if (isPathSeparator(code)) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else { + if (firstNonSlashEnd === -1) { + // We saw the first non-path separator, remember this index in case + // we need it if the extension ends up not matching + matchedSlash = false; + firstNonSlashEnd = i + 1; + } + if (extIdx >= 0) { + // Try to match the explicit extension + if (code === ext.charCodeAt(extIdx)) { + if (--extIdx === -1) { + // We matched the extension, so mark this as the end of our path + // component + end = i; + } + } else { + // Extension does not match, so our result is the entire path + // component + extIdx = -1; + end = firstNonSlashEnd; + } + } + } + } + + if (start === end) { + end = firstNonSlashEnd; + } + else if (end === -1) { + end = path.length; + } + return path.slice(start, end); + } else { + for (i = path.length - 1; i >= start; --i) { + if (isPathSeparator(path.charCodeAt(i))) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // path component + matchedSlash = false; + end = i + 1; + } + } + + if (end === -1) { + return ''; + } + return path.slice(start, end); + } + }, + + extname(path: string): string { + validateString(path, 'path'); + let start = 0; + let startDot = -1; + let startPart = 0; + let end = -1; + let matchedSlash = true; + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + let preDotState = 0; + + // Check for a drive letter prefix so as not to mistake the following + // path separator as an extra separator at the end of the path that can be + // disregarded + + if (path.length >= 2 && + path.charCodeAt(1) === CHAR_COLON && + isWindowsDeviceRoot(path.charCodeAt(0))) { + start = startPart = 2; + } + + for (let i = path.length - 1; i >= start; --i) { + const code = path.charCodeAt(i); + if (isPathSeparator(code)) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (code === CHAR_DOT) { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) { + startDot = i; + } + else if (preDotState !== 1) { + preDotState = 1; + } + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } + + if (startDot === -1 || + end === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + (preDotState === 1 && + startDot === end - 1 && + startDot === startPart + 1)) { + return ''; + } + return path.slice(startDot, end); + }, + + format(pathObject): string { + if (pathObject === null || typeof pathObject !== 'object') { + throw new ErrorInvalidArgType('pathObject', 'Object', pathObject); + } + + return _format('\\', pathObject); + }, + + + parse(path) { + validateString(path, 'path'); + + let ret = { root: '', dir: '', base: '', ext: '', name: '' }; + if (path.length === 0) { + return ret; + } + + let len = path.length; + let rootEnd = 0; + let code = path.charCodeAt(0); + + // Try to match a root + if (len > 1) { + if (isPathSeparator(code)) { + // Possible UNC root + + rootEnd = 1; + if (isPathSeparator(path.charCodeAt(1))) { + // Matched double path separator at beginning + let j = 2; + let last = j; + // Match 1 or more non-path separators + for (; j < len; ++j) { + if (isPathSeparator(path.charCodeAt(j))) { + break; + } + } + if (j < len && j !== last) { + // Matched! + last = j; + // Match 1 or more path separators + for (; j < len; ++j) { + if (!isPathSeparator(path.charCodeAt(j))) { + break; + } + } + if (j < len && j !== last) { + // Matched! + last = j; + // Match 1 or more non-path separators + for (; j < len; ++j) { + if (isPathSeparator(path.charCodeAt(j))) { + break; + } + } + if (j === len) { + // We matched a UNC root only + + rootEnd = j; + } else if (j !== last) { + // We matched a UNC root with leftovers + + rootEnd = j + 1; + } + } + } + } + } else if (isWindowsDeviceRoot(code)) { + // Possible device root + + if (path.charCodeAt(1) === CHAR_COLON) { + rootEnd = 2; + if (len > 2) { + if (isPathSeparator(path.charCodeAt(2))) { + if (len === 3) { + // `path` contains just a drive root, exit early to avoid + // unnecessary work + ret.root = ret.dir = path; + return ret; + } + rootEnd = 3; + } + } else { + // `path` contains just a drive root, exit early to avoid + // unnecessary work + ret.root = ret.dir = path; + return ret; + } + } + } + } else if (isPathSeparator(code)) { + // `path` contains just a path separator, exit early to avoid + // unnecessary work + ret.root = ret.dir = path; + return ret; + } + + if (rootEnd > 0) { + ret.root = path.slice(0, rootEnd); + } + + let startDot = -1; + let startPart = rootEnd; + let end = -1; + let matchedSlash = true; + let i = path.length - 1; + + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + let preDotState = 0; + + // Get non-dir info + for (; i >= rootEnd; --i) { + code = path.charCodeAt(i); + if (isPathSeparator(code)) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (code === CHAR_DOT) { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) { + startDot = i; + } + else if (preDotState !== 1) { + preDotState = 1; + } + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } + + if (startDot === -1 || + end === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + (preDotState === 1 && + startDot === end - 1 && + startDot === startPart + 1)) { + if (end !== -1) { + ret.base = ret.name = path.slice(startPart, end); + } + } else { + ret.name = path.slice(startPart, startDot); + ret.base = path.slice(startPart, end); + ret.ext = path.slice(startDot, end); + } + + // If the directory is the root, use the entire root as the `dir` including + // the trailing slash if any (`C:\abc` -> `C:\`). Otherwise, strip out the + // trailing slash (`C:\abc\def` -> `C:\abc`). + if (startPart > 0 && startPart !== rootEnd) { + ret.dir = path.slice(0, startPart - 1); + } + else { + ret.dir = ret.root; + } + + return ret; + }, + + sep: '\\', + delimiter: ';', + win32: null, + posix: null +}; + +const posix: IPath = { + // path.resolve([from ...], to) + resolve(...pathSegments: any[]): string { + let resolvedPath = ''; + let resolvedAbsolute = false; + + for (let i = pathSegments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + let path; + if (i >= 0) { + path = pathSegments[i]; + } + else { + path = process.cwd(); + } + + validateString(path, 'path'); + + // Skip empty entries + if (path.length === 0) { + continue; + } + + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; + } + + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + + // Normalize the path + resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, '/', + isPosixPathSeparator); + + if (resolvedAbsolute) { + if (resolvedPath.length > 0) { + return '/' + resolvedPath; + } + else { + return '/'; + } + } else if (resolvedPath.length > 0) { + return resolvedPath; + } else { + return '.'; + } + }, + + normalize(path: string): string { + validateString(path, 'path'); + + if (path.length === 0) { + return '.'; + } + + const isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; + const trailingSeparator = + path.charCodeAt(path.length - 1) === CHAR_FORWARD_SLASH; + + // Normalize the path + path = normalizeString(path, !isAbsolute, '/', isPosixPathSeparator); + + if (path.length === 0 && !isAbsolute) { + path = '.'; + } + if (path.length > 0 && trailingSeparator) { + path += '/'; + } + + if (isAbsolute) { + return '/' + path; + } + return path; + }, + + isAbsolute(path: string): boolean { + validateString(path, 'path'); + return path.length > 0 && path.charCodeAt(0) === CHAR_FORWARD_SLASH; + }, + + join(...paths: any[]): string { + if (paths.length === 0) { + return '.'; + } + let joined; + for (let i = 0; i < paths.length; ++i) { + let arg = arguments[i]; + validateString(arg, 'path'); + if (arg.length > 0) { + if (joined === undefined) { + joined = arg; + } + else { + joined += '/' + arg; + } + } + } + if (joined === undefined) { + return '.'; + } + return posix.normalize(joined); + }, + + relative(from: string, to: string): string { + validateString(from, 'from'); + validateString(to, 'to'); + + if (from === to) { + return ''; + } + + from = posix.resolve(from); + to = posix.resolve(to); + + if (from === to) { + return ''; + } + + // Trim any leading backslashes + let fromStart = 1; + for (; fromStart < from.length; ++fromStart) { + if (from.charCodeAt(fromStart) !== CHAR_FORWARD_SLASH) { + break; + } + } + let fromEnd = from.length; + let fromLen = (fromEnd - fromStart); + + // Trim any leading backslashes + let toStart = 1; + for (; toStart < to.length; ++toStart) { + if (to.charCodeAt(toStart) !== CHAR_FORWARD_SLASH) { + break; + } + } + let toEnd = to.length; + let toLen = (toEnd - toStart); + + // Compare paths to find the longest common path from root + let length = (fromLen < toLen ? fromLen : toLen); + let lastCommonSep = -1; + let i = 0; + for (; i <= length; ++i) { + if (i === length) { + if (toLen > length) { + if (to.charCodeAt(toStart + i) === CHAR_FORWARD_SLASH) { + // We get here if `from` is the exact base path for `to`. + // For example: from='/foo/bar'; to='/foo/bar/baz' + return to.slice(toStart + i + 1); + } else if (i === 0) { + // We get here if `from` is the root + // For example: from='/'; to='/foo' + return to.slice(toStart + i); + } + } else if (fromLen > length) { + if (from.charCodeAt(fromStart + i) === CHAR_FORWARD_SLASH) { + // We get here if `to` is the exact base path for `from`. + // For example: from='/foo/bar/baz'; to='/foo/bar' + lastCommonSep = i; + } else if (i === 0) { + // We get here if `to` is the root. + // For example: from='/foo'; to='/' + lastCommonSep = 0; + } + } + break; + } + let fromCode = from.charCodeAt(fromStart + i); + let toCode = to.charCodeAt(toStart + i); + if (fromCode !== toCode) { + break; + } + else if (fromCode === CHAR_FORWARD_SLASH) { + lastCommonSep = i; + } + } + + let out = ''; + // Generate the relative path based on the path difference between `to` + // and `from` + for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { + if (i === fromEnd || from.charCodeAt(i) === CHAR_FORWARD_SLASH) { + if (out.length === 0) { + out += '..'; + } + else { + out += '/..'; + } + } + } + + // Lastly, append the rest of the destination (`to`) path that comes after + // the common path parts + if (out.length > 0) { + return out + to.slice(toStart + lastCommonSep); + } + else { + toStart += lastCommonSep; + if (to.charCodeAt(toStart) === CHAR_FORWARD_SLASH) { + ++toStart; + } + return to.slice(toStart); + } + }, + + toNamespacedPath(path: string): string { + // Non-op on posix systems + return path; + }, + + dirname(path: string): string { + validateString(path, 'path'); + if (path.length === 0) { + return '.'; + } + const hasRoot = path.charCodeAt(0) === CHAR_FORWARD_SLASH; + let end = -1; + let matchedSlash = true; + for (let i = path.length - 1; i >= 1; --i) { + if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) { + if (!matchedSlash) { + end = i; + break; + } + } else { + // We saw the first non-path separator + matchedSlash = false; + } + } + + if (end === -1) { + return hasRoot ? '/' : '.'; + } + if (hasRoot && end === 1) { + return '//'; + } + return path.slice(0, end); + }, + + basename(path: string, ext?: string): string { + if (ext !== undefined) { + validateString(ext, 'ext'); + } + validateString(path, 'path'); + + let start = 0; + let end = -1; + let matchedSlash = true; + let i; + + if (ext !== undefined && ext.length > 0 && ext.length <= path.length) { + if (ext.length === path.length && ext === path) { + return ''; + } + let extIdx = ext.length - 1; + let firstNonSlashEnd = -1; + for (i = path.length - 1; i >= 0; --i) { + const code = path.charCodeAt(i); + if (code === CHAR_FORWARD_SLASH) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else { + if (firstNonSlashEnd === -1) { + // We saw the first non-path separator, remember this index in case + // we need it if the extension ends up not matching + matchedSlash = false; + firstNonSlashEnd = i + 1; + } + if (extIdx >= 0) { + // Try to match the explicit extension + if (code === ext.charCodeAt(extIdx)) { + if (--extIdx === -1) { + // We matched the extension, so mark this as the end of our path + // component + end = i; + } + } else { + // Extension does not match, so our result is the entire path + // component + extIdx = -1; + end = firstNonSlashEnd; + } + } + } + } + + if (start === end) { + end = firstNonSlashEnd; + } + else if (end === -1) { + end = path.length; + } + return path.slice(start, end); + } else { + for (i = path.length - 1; i >= 0; --i) { + if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // path component + matchedSlash = false; + end = i + 1; + } + } + + if (end === -1) { + return ''; + } + return path.slice(start, end); + } + }, + + extname(path: string): string { + validateString(path, 'path'); + let startDot = -1; + let startPart = 0; + let end = -1; + let matchedSlash = true; + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + let preDotState = 0; + for (let i = path.length - 1; i >= 0; --i) { + const code = path.charCodeAt(i); + if (code === CHAR_FORWARD_SLASH) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (code === CHAR_DOT) { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) { + startDot = i; + } + else if (preDotState !== 1) { + preDotState = 1; + } + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } + + if (startDot === -1 || + end === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + (preDotState === 1 && + startDot === end - 1 && + startDot === startPart + 1)) { + return ''; + } + return path.slice(startDot, end); + }, + + format(pathObject): string { + if (pathObject === null || typeof pathObject !== 'object') { + throw new ErrorInvalidArgType('pathObject', 'Object', pathObject); + } + + return _format('/', pathObject); + }, + + parse(path: string): object { + validateString(path, 'path'); + + let ret = { root: '', dir: '', base: '', ext: '', name: '' }; + if (path.length === 0) { + return ret; + } + let isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; + let start; + if (isAbsolute) { + ret.root = '/'; + start = 1; + } else { + start = 0; + } + let startDot = -1; + let startPart = 0; + let end = -1; + let matchedSlash = true; + let i = path.length - 1; + + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + let preDotState = 0; + + // Get non-dir info + for (; i >= start; --i) { + const code = path.charCodeAt(i); + if (code === CHAR_FORWARD_SLASH) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (code === CHAR_DOT) { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) { + startDot = i; + } + else if (preDotState !== 1) { + preDotState = 1; + } + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } + + if (startDot === -1 || + end === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + (preDotState === 1 && + startDot === end - 1 && + startDot === startPart + 1)) { + if (end !== -1) { + if (startPart === 0 && isAbsolute) { + ret.base = ret.name = path.slice(1, end); + } + else { + ret.base = ret.name = path.slice(startPart, end); + } + } + } else { + if (startPart === 0 && isAbsolute) { + ret.name = path.slice(1, startDot); + ret.base = path.slice(1, end); + } else { + ret.name = path.slice(startPart, startDot); + ret.base = path.slice(startPart, end); + } + ret.ext = path.slice(startDot, end); + } + + if (startPart > 0) { + ret.dir = path.slice(0, startPart - 1); + } + else if (isAbsolute) { + ret.dir = '/'; + } + + return ret; + }, + + sep: '/', + delimiter: ':', + win32: null, + posix: null +}; + +posix.win32 = win32.win32 = win32; +posix.posix = win32.posix = posix; + +const impl = (process.platform === 'win32' ? win32 : posix) as IExportedPath; +export = impl; diff --git a/src/vs/base/test/common/paths.node.test.ts b/src/vs/base/test/common/paths.node.test.ts new file mode 100644 index 00000000000..6f60d3b67ec --- /dev/null +++ b/src/vs/base/test/common/paths.node.test.ts @@ -0,0 +1,630 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import * as assert from 'assert'; +import * as path from 'vs/base/common/paths.node'; +import { isWindows } from 'vs/base/common/platform'; + +suite('Paths (Node Implementation)', () => { + test('join', () => { + const failures = [] as string[]; + const backslashRE = /\\/g; + + const joinTests: any = [ + [[path.posix.join, path.win32.join], + // arguments result + [[['.', 'x/b', '..', '/b/c.js'], 'x/b/c.js'], + [[], '.'], + [['/.', 'x/b', '..', '/b/c.js'], '/x/b/c.js'], + [['/foo', '../../../bar'], '/bar'], + [['foo', '../../../bar'], '../../bar'], + [['foo/', '../../../bar'], '../../bar'], + [['foo/x', '../../../bar'], '../bar'], + [['foo/x', './bar'], 'foo/x/bar'], + [['foo/x/', './bar'], 'foo/x/bar'], + [['foo/x/', '.', 'bar'], 'foo/x/bar'], + [['./'], './'], + [['.', './'], './'], + [['.', '.', '.'], '.'], + [['.', './', '.'], '.'], + [['.', '/./', '.'], '.'], + [['.', '/////./', '.'], '.'], + [['.'], '.'], + [['', '.'], '.'], + [['', 'foo'], 'foo'], + [['foo', '/bar'], 'foo/bar'], + [['', '/foo'], '/foo'], + [['', '', '/foo'], '/foo'], + [['', '', 'foo'], 'foo'], + [['foo', ''], 'foo'], + [['foo/', ''], 'foo/'], + [['foo', '', '/bar'], 'foo/bar'], + [['./', '..', '/foo'], '../foo'], + [['./', '..', '..', '/foo'], '../../foo'], + [['.', '..', '..', '/foo'], '../../foo'], + [['', '..', '..', '/foo'], '../../foo'], + [['/'], '/'], + [['/', '.'], '/'], + [['/', '..'], '/'], + [['/', '..', '..'], '/'], + [[''], '.'], + [['', ''], '.'], + [[' /foo'], ' /foo'], + [[' ', 'foo'], ' /foo'], + [[' ', '.'], ' '], + [[' ', '/'], ' /'], + [[' ', ''], ' '], + [['/', 'foo'], '/foo'], + [['/', '/foo'], '/foo'], + [['/', '//foo'], '/foo'], + [['/', '', '/foo'], '/foo'], + [['', '/', 'foo'], '/foo'], + [['', '/', '/foo'], '/foo'] + ] + ] + ]; + + // Windows-specific join tests + joinTests.push([ + path.win32.join, + joinTests[0][1].slice(0).concat( + [// arguments result + // UNC path expected + [['//foo/bar'], '\\\\foo\\bar\\'], + [['\\/foo/bar'], '\\\\foo\\bar\\'], + [['\\\\foo/bar'], '\\\\foo\\bar\\'], + // UNC path expected - server and share separate + [['//foo', 'bar'], '\\\\foo\\bar\\'], + [['//foo/', 'bar'], '\\\\foo\\bar\\'], + [['//foo', '/bar'], '\\\\foo\\bar\\'], + // UNC path expected - questionable + [['//foo', '', 'bar'], '\\\\foo\\bar\\'], + [['//foo/', '', 'bar'], '\\\\foo\\bar\\'], + [['//foo/', '', '/bar'], '\\\\foo\\bar\\'], + // UNC path expected - even more questionable + [['', '//foo', 'bar'], '\\\\foo\\bar\\'], + [['', '//foo/', 'bar'], '\\\\foo\\bar\\'], + [['', '//foo/', '/bar'], '\\\\foo\\bar\\'], + // No UNC path expected (no double slash in first component) + [['\\', 'foo/bar'], '\\foo\\bar'], + [['\\', '/foo/bar'], '\\foo\\bar'], + [['', '/', '/foo/bar'], '\\foo\\bar'], + // No UNC path expected (no non-slashes in first component - + // questionable) + [['//', 'foo/bar'], '\\foo\\bar'], + [['//', '/foo/bar'], '\\foo\\bar'], + [['\\\\', '/', '/foo/bar'], '\\foo\\bar'], + [['//'], '\\'], + // No UNC path expected (share name missing - questionable). + [['//foo'], '\\foo'], + [['//foo/'], '\\foo\\'], + [['//foo', '/'], '\\foo\\'], + [['//foo', '', '/'], '\\foo\\'], + // No UNC path expected (too many leading slashes - questionable) + [['///foo/bar'], '\\foo\\bar'], + [['////foo', 'bar'], '\\foo\\bar'], + [['\\\\\\/foo/bar'], '\\foo\\bar'], + // Drive-relative vs drive-absolute paths. This merely describes the + // status quo, rather than being obviously right + [['c:'], 'c:.'], + [['c:.'], 'c:.'], + [['c:', ''], 'c:.'], + [['', 'c:'], 'c:.'], + [['c:.', '/'], 'c:.\\'], + [['c:.', 'file'], 'c:file'], + [['c:', '/'], 'c:\\'], + [['c:', 'file'], 'c:\\file'] + ] + ) + ]); + joinTests.forEach((test) => { + if (!Array.isArray(test[0])) { + test[0] = [test[0]]; + } + test[0].forEach((join) => { + test[1].forEach((test) => { + const actual = join.apply(null, test[0]); + const expected = test[1]; + // For non-Windows specific tests with the Windows join(), we need to try + // replacing the slashes since the non-Windows specific tests' `expected` + // use forward slashes + let actualAlt; + let os; + if (join === path.win32.join) { + actualAlt = actual.replace(backslashRE, '/'); + os = 'win32'; + } else { + os = 'posix'; + } + const message = + `path.${os}.join(${test[0].map(JSON.stringify).join(',')})\n expect=${ + JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`; + if (actual !== expected && actualAlt !== expected) { + failures.push(`\n${message}`); + } + }); + }); + }); + assert.strictEqual(failures.length, 0, failures.join('')); + }); + + test('dirname', () => { + assert.strictEqual(path.dirname(path.normalize(__filename)).substr(-11), + isWindows ? 'test\\common' : 'test/common'); + + assert.strictEqual(path.posix.dirname('/a/b/'), '/a'); + assert.strictEqual(path.posix.dirname('/a/b'), '/a'); + assert.strictEqual(path.posix.dirname('/a'), '/'); + assert.strictEqual(path.posix.dirname(''), '.'); + assert.strictEqual(path.posix.dirname('/'), '/'); + assert.strictEqual(path.posix.dirname('////'), '/'); + assert.strictEqual(path.posix.dirname('//a'), '//'); + assert.strictEqual(path.posix.dirname('foo'), '.'); + + assert.strictEqual(path.win32.dirname('c:\\'), 'c:\\'); + assert.strictEqual(path.win32.dirname('c:\\foo'), 'c:\\'); + assert.strictEqual(path.win32.dirname('c:\\foo\\'), 'c:\\'); + assert.strictEqual(path.win32.dirname('c:\\foo\\bar'), 'c:\\foo'); + assert.strictEqual(path.win32.dirname('c:\\foo\\bar\\'), 'c:\\foo'); + assert.strictEqual(path.win32.dirname('c:\\foo\\bar\\baz'), 'c:\\foo\\bar'); + assert.strictEqual(path.win32.dirname('\\'), '\\'); + assert.strictEqual(path.win32.dirname('\\foo'), '\\'); + assert.strictEqual(path.win32.dirname('\\foo\\'), '\\'); + assert.strictEqual(path.win32.dirname('\\foo\\bar'), '\\foo'); + assert.strictEqual(path.win32.dirname('\\foo\\bar\\'), '\\foo'); + assert.strictEqual(path.win32.dirname('\\foo\\bar\\baz'), '\\foo\\bar'); + assert.strictEqual(path.win32.dirname('c:'), 'c:'); + assert.strictEqual(path.win32.dirname('c:foo'), 'c:'); + assert.strictEqual(path.win32.dirname('c:foo\\'), 'c:'); + assert.strictEqual(path.win32.dirname('c:foo\\bar'), 'c:foo'); + assert.strictEqual(path.win32.dirname('c:foo\\bar\\'), 'c:foo'); + assert.strictEqual(path.win32.dirname('c:foo\\bar\\baz'), 'c:foo\\bar'); + assert.strictEqual(path.win32.dirname('file:stream'), '.'); + assert.strictEqual(path.win32.dirname('dir\\file:stream'), 'dir'); + assert.strictEqual(path.win32.dirname('\\\\unc\\share'), + '\\\\unc\\share'); + assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo'), + '\\\\unc\\share\\'); + assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo\\'), + '\\\\unc\\share\\'); + assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo\\bar'), + '\\\\unc\\share\\foo'); + assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo\\bar\\'), + '\\\\unc\\share\\foo'); + assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo\\bar\\baz'), + '\\\\unc\\share\\foo\\bar'); + assert.strictEqual(path.win32.dirname('/a/b/'), '/a'); + assert.strictEqual(path.win32.dirname('/a/b'), '/a'); + assert.strictEqual(path.win32.dirname('/a'), '/'); + assert.strictEqual(path.win32.dirname(''), '.'); + assert.strictEqual(path.win32.dirname('/'), '/'); + assert.strictEqual(path.win32.dirname('////'), '/'); + assert.strictEqual(path.win32.dirname('foo'), '.'); + }); + + test('extname', () => { + const failures = [] as string[]; + const slashRE = /\//g; + + [ + [__filename, '.js'], + ['', ''], + ['/path/to/file', ''], + ['/path/to/file.ext', '.ext'], + ['/path.to/file.ext', '.ext'], + ['/path.to/file', ''], + ['/path.to/.file', ''], + ['/path.to/.file.ext', '.ext'], + ['/path/to/f.ext', '.ext'], + ['/path/to/..ext', '.ext'], + ['/path/to/..', ''], + ['file', ''], + ['file.ext', '.ext'], + ['.file', ''], + ['.file.ext', '.ext'], + ['/file', ''], + ['/file.ext', '.ext'], + ['/.file', ''], + ['/.file.ext', '.ext'], + ['.path/file.ext', '.ext'], + ['file.ext.ext', '.ext'], + ['file.', '.'], + ['.', ''], + ['./', ''], + ['.file.ext', '.ext'], + ['.file', ''], + ['.file.', '.'], + ['.file..', '.'], + ['..', ''], + ['../', ''], + ['..file.ext', '.ext'], + ['..file', '.file'], + ['..file.', '.'], + ['..file..', '.'], + ['...', '.'], + ['...ext', '.ext'], + ['....', '.'], + ['file.ext/', '.ext'], + ['file.ext//', '.ext'], + ['file/', ''], + ['file//', ''], + ['file./', '.'], + ['file.//', '.'], + ].forEach((test) => { + const expected = test[1]; + [path.posix.extname, path.win32.extname].forEach((extname) => { + let input = test[0]; + let os; + if (extname === path.win32.extname) { + input = input.replace(slashRE, '\\'); + os = 'win32'; + } else { + os = 'posix'; + } + const actual = extname(input); + const message = `path.${os}.extname(${JSON.stringify(input)})\n expect=${ + JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`; + if (actual !== expected) { + failures.push(`\n${message}`); + } + }); + { + const input = `C:${test[0].replace(slashRE, '\\')}`; + const actual = path.win32.extname(input); + const message = `path.win32.extname(${JSON.stringify(input)})\n expect=${ + JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`; + if (actual !== expected) { + failures.push(`\n${message}`); + } + } + }); + assert.strictEqual(failures.length, 0, failures.join('')); + + // On Windows, backslash is a path separator. + assert.strictEqual(path.win32.extname('.\\'), ''); + assert.strictEqual(path.win32.extname('..\\'), ''); + assert.strictEqual(path.win32.extname('file.ext\\'), '.ext'); + assert.strictEqual(path.win32.extname('file.ext\\\\'), '.ext'); + assert.strictEqual(path.win32.extname('file\\'), ''); + assert.strictEqual(path.win32.extname('file\\\\'), ''); + assert.strictEqual(path.win32.extname('file.\\'), '.'); + assert.strictEqual(path.win32.extname('file.\\\\'), '.'); + + // On *nix, backslash is a valid name component like any other character. + assert.strictEqual(path.posix.extname('.\\'), ''); + assert.strictEqual(path.posix.extname('..\\'), '.\\'); + assert.strictEqual(path.posix.extname('file.ext\\'), '.ext\\'); + assert.strictEqual(path.posix.extname('file.ext\\\\'), '.ext\\\\'); + assert.strictEqual(path.posix.extname('file\\'), ''); + assert.strictEqual(path.posix.extname('file\\\\'), ''); + assert.strictEqual(path.posix.extname('file.\\'), '.\\'); + assert.strictEqual(path.posix.extname('file.\\\\'), '.\\\\'); + }); + + test('resolve', () => { + const failures = [] as string[]; + const slashRE = /\//g; + const backslashRE = /\\/g; + + const resolveTests = [ + [path.win32.resolve, + // arguments result + [[['c:/blah\\blah', 'd:/games', 'c:../a'], 'c:\\blah\\a'], + [['c:/ignore', 'd:\\a/b\\c/d', '\\e.exe'], 'd:\\e.exe'], + [['c:/ignore', 'c:/some/file'], 'c:\\some\\file'], + [['d:/ignore', 'd:some/dir//'], 'd:\\ignore\\some\\dir'], + [['.'], process.cwd()], + [['//server/share', '..', 'relative\\'], '\\\\server\\share\\relative'], + [['c:/', '//'], 'c:\\'], + [['c:/', '//dir'], 'c:\\dir'], + [['c:/', '//server/share'], '\\\\server\\share\\'], + [['c:/', '//server//share'], '\\\\server\\share\\'], + [['c:/', '///some//dir'], 'c:\\some\\dir'], + [['C:\\foo\\tmp.3\\', '..\\tmp.3\\cycles\\root.js'], + 'C:\\foo\\tmp.3\\cycles\\root.js'] + ] + ], + [path.posix.resolve, + // arguments result + [[['/var/lib', '../', 'file/'], '/var/file'], + [['/var/lib', '/../', 'file/'], '/file'], + [['a/b/c/', '../../..'], process.cwd()], + [['.'], process.cwd()], + [['/some/dir', '.', '/absolute/'], '/absolute'], + [['/foo/tmp.3/', '../tmp.3/cycles/root.js'], '/foo/tmp.3/cycles/root.js'] + ] + ] + ]; + resolveTests.forEach((test) => { + const resolve = test[0]; + //@ts-ignore + test[1].forEach((test) => { + //@ts-ignore + const actual = resolve.apply(null, test[0]); + let actualAlt; + const os = resolve === path.win32.resolve ? 'win32' : 'posix'; + if (resolve === path.win32.resolve && !isWindows) { + actualAlt = actual.replace(backslashRE, '/'); + } + else if (resolve !== path.win32.resolve && isWindows) { + actualAlt = actual.replace(slashRE, '\\'); + } + + const expected = test[1]; + const message = + `path.${os}.resolve(${test[0].map(JSON.stringify).join(',')})\n expect=${ + JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`; + if (actual !== expected && actualAlt !== expected) { + failures.push(`\n${message}`); + } + }); + }); + assert.strictEqual(failures.length, 0, failures.join('')); + + // if (isWindows) { + // // Test resolving the current Windows drive letter from a spawned process. + // // See https://github.com/nodejs/node/issues/7215 + // const currentDriveLetter = path.parse(process.cwd()).root.substring(0, 2); + // const resolveFixture = fixtures.path('path-resolve.js'); + // const spawnResult = child.spawnSync( + // process.argv[0], [resolveFixture, currentDriveLetter]); + // const resolvedPath = spawnResult.stdout.toString().trim(); + // assert.strictEqual(resolvedPath.toLowerCase(), process.cwd().toLowerCase()); + // } + }); + + test('basename', () => { + assert.strictEqual(path.basename(__filename), 'paths.node.test.js'); + assert.strictEqual(path.basename(__filename, '.js'), 'paths.node.test'); + assert.strictEqual(path.basename('.js', '.js'), ''); + assert.strictEqual(path.basename(''), ''); + assert.strictEqual(path.basename('/dir/basename.ext'), 'basename.ext'); + assert.strictEqual(path.basename('/basename.ext'), 'basename.ext'); + assert.strictEqual(path.basename('basename.ext'), 'basename.ext'); + assert.strictEqual(path.basename('basename.ext/'), 'basename.ext'); + assert.strictEqual(path.basename('basename.ext//'), 'basename.ext'); + assert.strictEqual(path.basename('aaa/bbb', '/bbb'), 'bbb'); + assert.strictEqual(path.basename('aaa/bbb', 'a/bbb'), 'bbb'); + assert.strictEqual(path.basename('aaa/bbb', 'bbb'), 'bbb'); + assert.strictEqual(path.basename('aaa/bbb//', 'bbb'), 'bbb'); + assert.strictEqual(path.basename('aaa/bbb', 'bb'), 'b'); + assert.strictEqual(path.basename('aaa/bbb', 'b'), 'bb'); + assert.strictEqual(path.basename('/aaa/bbb', '/bbb'), 'bbb'); + assert.strictEqual(path.basename('/aaa/bbb', 'a/bbb'), 'bbb'); + assert.strictEqual(path.basename('/aaa/bbb', 'bbb'), 'bbb'); + assert.strictEqual(path.basename('/aaa/bbb//', 'bbb'), 'bbb'); + assert.strictEqual(path.basename('/aaa/bbb', 'bb'), 'b'); + assert.strictEqual(path.basename('/aaa/bbb', 'b'), 'bb'); + assert.strictEqual(path.basename('/aaa/bbb'), 'bbb'); + assert.strictEqual(path.basename('/aaa/'), 'aaa'); + assert.strictEqual(path.basename('/aaa/b'), 'b'); + assert.strictEqual(path.basename('/a/b'), 'b'); + assert.strictEqual(path.basename('//a'), 'a'); + assert.strictEqual(path.basename('a', 'a'), ''); + + // On Windows a backslash acts as a path separator. + assert.strictEqual(path.win32.basename('\\dir\\basename.ext'), 'basename.ext'); + assert.strictEqual(path.win32.basename('\\basename.ext'), 'basename.ext'); + assert.strictEqual(path.win32.basename('basename.ext'), 'basename.ext'); + assert.strictEqual(path.win32.basename('basename.ext\\'), 'basename.ext'); + assert.strictEqual(path.win32.basename('basename.ext\\\\'), 'basename.ext'); + assert.strictEqual(path.win32.basename('foo'), 'foo'); + assert.strictEqual(path.win32.basename('aaa\\bbb', '\\bbb'), 'bbb'); + assert.strictEqual(path.win32.basename('aaa\\bbb', 'a\\bbb'), 'bbb'); + assert.strictEqual(path.win32.basename('aaa\\bbb', 'bbb'), 'bbb'); + assert.strictEqual(path.win32.basename('aaa\\bbb\\\\\\\\', 'bbb'), 'bbb'); + assert.strictEqual(path.win32.basename('aaa\\bbb', 'bb'), 'b'); + assert.strictEqual(path.win32.basename('aaa\\bbb', 'b'), 'bb'); + assert.strictEqual(path.win32.basename('C:'), ''); + assert.strictEqual(path.win32.basename('C:.'), '.'); + assert.strictEqual(path.win32.basename('C:\\'), ''); + assert.strictEqual(path.win32.basename('C:\\dir\\base.ext'), 'base.ext'); + assert.strictEqual(path.win32.basename('C:\\basename.ext'), 'basename.ext'); + assert.strictEqual(path.win32.basename('C:basename.ext'), 'basename.ext'); + assert.strictEqual(path.win32.basename('C:basename.ext\\'), 'basename.ext'); + assert.strictEqual(path.win32.basename('C:basename.ext\\\\'), 'basename.ext'); + assert.strictEqual(path.win32.basename('C:foo'), 'foo'); + assert.strictEqual(path.win32.basename('file:stream'), 'file:stream'); + assert.strictEqual(path.win32.basename('a', 'a'), ''); + + // On unix a backslash is just treated as any other character. + assert.strictEqual(path.posix.basename('\\dir\\basename.ext'), + '\\dir\\basename.ext'); + assert.strictEqual(path.posix.basename('\\basename.ext'), '\\basename.ext'); + assert.strictEqual(path.posix.basename('basename.ext'), 'basename.ext'); + assert.strictEqual(path.posix.basename('basename.ext\\'), 'basename.ext\\'); + assert.strictEqual(path.posix.basename('basename.ext\\\\'), 'basename.ext\\\\'); + assert.strictEqual(path.posix.basename('foo'), 'foo'); + + // POSIX filenames may include control characters + // c.f. http://www.dwheeler.com/essays/fixing-unix-linux-filenames.html + const controlCharFilename = `Icon${String.fromCharCode(13)}`; + assert.strictEqual(path.posix.basename(`/a/b/${controlCharFilename}`), + controlCharFilename); + }); + + test('relative', () => { + const failures = [] as string[]; + + const relativeTests = [ + [path.win32.relative, + // arguments result + [['c:/blah\\blah', 'd:/games', 'd:\\games'], + ['c:/aaaa/bbbb', 'c:/aaaa', '..'], + ['c:/aaaa/bbbb', 'c:/cccc', '..\\..\\cccc'], + ['c:/aaaa/bbbb', 'c:/aaaa/bbbb', ''], + ['c:/aaaa/bbbb', 'c:/aaaa/cccc', '..\\cccc'], + ['c:/aaaa/', 'c:/aaaa/cccc', 'cccc'], + ['c:/', 'c:\\aaaa\\bbbb', 'aaaa\\bbbb'], + ['c:/aaaa/bbbb', 'd:\\', 'd:\\'], + ['c:/AaAa/bbbb', 'c:/aaaa/bbbb', ''], + ['c:/aaaaa/', 'c:/aaaa/cccc', '..\\aaaa\\cccc'], + ['C:\\foo\\bar\\baz\\quux', 'C:\\', '..\\..\\..\\..'], + ['C:\\foo\\test', 'C:\\foo\\test\\bar\\package.json', 'bar\\package.json'], + ['C:\\foo\\bar\\baz-quux', 'C:\\foo\\bar\\baz', '..\\baz'], + ['C:\\foo\\bar\\baz', 'C:\\foo\\bar\\baz-quux', '..\\baz-quux'], + ['\\\\foo\\bar', '\\\\foo\\bar\\baz', 'baz'], + ['\\\\foo\\bar\\baz', '\\\\foo\\bar', '..'], + ['\\\\foo\\bar\\baz-quux', '\\\\foo\\bar\\baz', '..\\baz'], + ['\\\\foo\\bar\\baz', '\\\\foo\\bar\\baz-quux', '..\\baz-quux'], + ['C:\\baz-quux', 'C:\\baz', '..\\baz'], + ['C:\\baz', 'C:\\baz-quux', '..\\baz-quux'], + ['\\\\foo\\baz-quux', '\\\\foo\\baz', '..\\baz'], + ['\\\\foo\\baz', '\\\\foo\\baz-quux', '..\\baz-quux'], + ['C:\\baz', '\\\\foo\\bar\\baz', '\\\\foo\\bar\\baz'], + ['\\\\foo\\bar\\baz', 'C:\\baz', 'C:\\baz'] + ] + ], + [path.posix.relative, + // arguments result + [['/var/lib', '/var', '..'], + ['/var/lib', '/bin', '../../bin'], + ['/var/lib', '/var/lib', ''], + ['/var/lib', '/var/apache', '../apache'], + ['/var/', '/var/lib', 'lib'], + ['/', '/var/lib', 'var/lib'], + ['/foo/test', '/foo/test/bar/package.json', 'bar/package.json'], + ['/Users/a/web/b/test/mails', '/Users/a/web/b', '../..'], + ['/foo/bar/baz-quux', '/foo/bar/baz', '../baz'], + ['/foo/bar/baz', '/foo/bar/baz-quux', '../baz-quux'], + ['/baz-quux', '/baz', '../baz'], + ['/baz', '/baz-quux', '../baz-quux'] + ] + ] + ]; + relativeTests.forEach((test) => { + const relative = test[0]; + //@ts-ignore + test[1].forEach((test) => { + //@ts-ignore + const actual = relative(test[0], test[1]); + const expected = test[2]; + const os = relative === path.win32.relative ? 'win32' : 'posix'; + const message = `path.${os}.relative(${ + test.slice(0, 2).map(JSON.stringify).join(',')})\n expect=${ + JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`; + if (actual !== expected) { + failures.push(`\n${message}`); + } + }); + }); + assert.strictEqual(failures.length, 0, failures.join('')); + }); + + test('normalize', () => { + assert.strictEqual(path.win32.normalize('./fixtures///b/../b/c.js'), + 'fixtures\\b\\c.js'); + assert.strictEqual(path.win32.normalize('/foo/../../../bar'), '\\bar'); + assert.strictEqual(path.win32.normalize('a//b//../b'), 'a\\b'); + assert.strictEqual(path.win32.normalize('a//b//./c'), 'a\\b\\c'); + assert.strictEqual(path.win32.normalize('a//b//.'), 'a\\b'); + assert.strictEqual(path.win32.normalize('//server/share/dir/file.ext'), + '\\\\server\\share\\dir\\file.ext'); + assert.strictEqual(path.win32.normalize('/a/b/c/../../../x/y/z'), '\\x\\y\\z'); + assert.strictEqual(path.win32.normalize('C:'), 'C:.'); + assert.strictEqual(path.win32.normalize('C:..\\abc'), 'C:..\\abc'); + assert.strictEqual(path.win32.normalize('C:..\\..\\abc\\..\\def'), + 'C:..\\..\\def'); + assert.strictEqual(path.win32.normalize('C:\\.'), 'C:\\'); + assert.strictEqual(path.win32.normalize('file:stream'), 'file:stream'); + assert.strictEqual(path.win32.normalize('bar\\foo..\\..\\'), 'bar\\'); + assert.strictEqual(path.win32.normalize('bar\\foo..\\..'), 'bar'); + assert.strictEqual(path.win32.normalize('bar\\foo..\\..\\baz'), 'bar\\baz'); + assert.strictEqual(path.win32.normalize('bar\\foo..\\'), 'bar\\foo..\\'); + assert.strictEqual(path.win32.normalize('bar\\foo..'), 'bar\\foo..'); + assert.strictEqual(path.win32.normalize('..\\foo..\\..\\..\\bar'), + '..\\..\\bar'); + assert.strictEqual(path.win32.normalize('..\\...\\..\\.\\...\\..\\..\\bar'), + '..\\..\\bar'); + assert.strictEqual(path.win32.normalize('../../../foo/../../../bar'), + '..\\..\\..\\..\\..\\bar'); + assert.strictEqual(path.win32.normalize('../../../foo/../../../bar/../../'), + '..\\..\\..\\..\\..\\..\\'); + assert.strictEqual( + path.win32.normalize('../foobar/barfoo/foo/../../../bar/../../'), + '..\\..\\' + ); + assert.strictEqual( + path.win32.normalize('../.../../foobar/../../../bar/../../baz'), + '..\\..\\..\\..\\baz' + ); + assert.strictEqual(path.win32.normalize('foo/bar\\baz'), 'foo\\bar\\baz'); + + assert.strictEqual(path.posix.normalize('./fixtures///b/../b/c.js'), + 'fixtures/b/c.js'); + assert.strictEqual(path.posix.normalize('/foo/../../../bar'), '/bar'); + assert.strictEqual(path.posix.normalize('a//b//../b'), 'a/b'); + assert.strictEqual(path.posix.normalize('a//b//./c'), 'a/b/c'); + assert.strictEqual(path.posix.normalize('a//b//.'), 'a/b'); + assert.strictEqual(path.posix.normalize('/a/b/c/../../../x/y/z'), '/x/y/z'); + assert.strictEqual(path.posix.normalize('///..//./foo/.//bar'), '/foo/bar'); + assert.strictEqual(path.posix.normalize('bar/foo../../'), 'bar/'); + assert.strictEqual(path.posix.normalize('bar/foo../..'), 'bar'); + assert.strictEqual(path.posix.normalize('bar/foo../../baz'), 'bar/baz'); + assert.strictEqual(path.posix.normalize('bar/foo../'), 'bar/foo../'); + assert.strictEqual(path.posix.normalize('bar/foo..'), 'bar/foo..'); + assert.strictEqual(path.posix.normalize('../foo../../../bar'), '../../bar'); + assert.strictEqual(path.posix.normalize('../.../.././.../../../bar'), + '../../bar'); + assert.strictEqual(path.posix.normalize('../../../foo/../../../bar'), + '../../../../../bar'); + assert.strictEqual(path.posix.normalize('../../../foo/../../../bar/../../'), + '../../../../../../'); + assert.strictEqual( + path.posix.normalize('../foobar/barfoo/foo/../../../bar/../../'), + '../../' + ); + assert.strictEqual( + path.posix.normalize('../.../../foobar/../../../bar/../../baz'), + '../../../../baz' + ); + assert.strictEqual(path.posix.normalize('foo/bar\\baz'), 'foo/bar\\baz'); + }); + + test('isAbsolute', () => { + assert.strictEqual(path.win32.isAbsolute('/'), true); + assert.strictEqual(path.win32.isAbsolute('//'), true); + assert.strictEqual(path.win32.isAbsolute('//server'), true); + assert.strictEqual(path.win32.isAbsolute('//server/file'), true); + assert.strictEqual(path.win32.isAbsolute('\\\\server\\file'), true); + assert.strictEqual(path.win32.isAbsolute('\\\\server'), true); + assert.strictEqual(path.win32.isAbsolute('\\\\'), true); + assert.strictEqual(path.win32.isAbsolute('c'), false); + assert.strictEqual(path.win32.isAbsolute('c:'), false); + assert.strictEqual(path.win32.isAbsolute('c:\\'), true); + assert.strictEqual(path.win32.isAbsolute('c:/'), true); + assert.strictEqual(path.win32.isAbsolute('c://'), true); + assert.strictEqual(path.win32.isAbsolute('C:/Users/'), true); + assert.strictEqual(path.win32.isAbsolute('C:\\Users\\'), true); + assert.strictEqual(path.win32.isAbsolute('C:cwd/another'), false); + assert.strictEqual(path.win32.isAbsolute('C:cwd\\another'), false); + assert.strictEqual(path.win32.isAbsolute('directory/directory'), false); + assert.strictEqual(path.win32.isAbsolute('directory\\directory'), false); + + assert.strictEqual(path.posix.isAbsolute('/home/foo'), true); + assert.strictEqual(path.posix.isAbsolute('/home/foo/..'), true); + assert.strictEqual(path.posix.isAbsolute('bar/'), false); + assert.strictEqual(path.posix.isAbsolute('./baz'), false); + }); + + test('path', () => { + // path.sep tests + // windows + assert.strictEqual(path.win32.sep, '\\'); + // posix + assert.strictEqual(path.posix.sep, '/'); + + // path.delimiter tests + // windows + assert.strictEqual(path.win32.delimiter, ';'); + // posix + assert.strictEqual(path.posix.delimiter, ':'); + + if (isWindows) { + assert.strictEqual(path, path.win32); + } else { + assert.strictEqual(path, path.posix); + } + }); +}); From 0c96de6d5dea1add28cc8e99e0e9442ec7988628 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Tue, 12 Feb 2019 12:27:42 +0100 Subject: [PATCH 190/207] Avoid allocation --- src/vs/workbench/common/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/common/actions.ts b/src/vs/workbench/common/actions.ts index 995818a3920..fa82000a8cb 100644 --- a/src/vs/workbench/common/actions.ts +++ b/src/vs/workbench/common/actions.ts @@ -44,7 +44,7 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR KeybindingsRegistry.registerKeybindingRule({ id: descriptor.id, weight: weight, - when: ContextKeyExpr.and(descriptor.keybindingContext, when), + when: (descriptor.keybindingContext || when ? ContextKeyExpr.and(descriptor.keybindingContext, when) : null), primary: keybindings ? keybindings.primary : 0, secondary: keybindings && keybindings.secondary, win: keybindings && keybindings.win, From 234ad6d2905f25f0541deeb6536e14c05b9a9040 Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Tue, 12 Feb 2019 12:32:09 +0100 Subject: [PATCH 191/207] adding nodejs copyright --- src/vs/base/common/paths.node.ts | 21 +++++++++++++++++++++ src/vs/base/test/common/paths.node.test.ts | 22 ++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/vs/base/common/paths.node.ts b/src/vs/base/common/paths.node.ts index 29aa5f8572f..5034fd51da0 100644 --- a/src/vs/base/common/paths.node.ts +++ b/src/vs/base/common/paths.node.ts @@ -3,6 +3,27 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + 'use strict'; import { isWindows } from 'vs/base/common/platform'; diff --git a/src/vs/base/test/common/paths.node.test.ts b/src/vs/base/test/common/paths.node.test.ts index 6f60d3b67ec..993bfef7bba 100644 --- a/src/vs/base/test/common/paths.node.test.ts +++ b/src/vs/base/test/common/paths.node.test.ts @@ -2,6 +2,28 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ + +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + import * as assert from 'assert'; import * as path from 'vs/base/common/paths.node'; import { isWindows } from 'vs/base/common/platform'; From 73028765b08b7c3ced204a7b91ccc389bd5d7206 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Tue, 12 Feb 2019 12:41:51 +0100 Subject: [PATCH 192/207] add availableFileSystems --- src/vs/platform/dialogs/common/dialogs.ts | 12 ++- .../browser/actions/workspaceActions.ts | 8 +- .../browser/actions/workspaceCommands.ts | 8 +- .../dialogs/electron-browser/dialogService.ts | 79 ++++++++++--------- 4 files changed, 59 insertions(+), 48 deletions(-) diff --git a/src/vs/platform/dialogs/common/dialogs.ts b/src/vs/platform/dialogs/common/dialogs.ts index 4c9156aa99a..aa8193ec548 100644 --- a/src/vs/platform/dialogs/common/dialogs.ts +++ b/src/vs/platform/dialogs/common/dialogs.ts @@ -43,7 +43,6 @@ export interface IPickAndOpenOptions { forceNewWindow?: boolean; defaultUri?: URI; telemetryExtraData?: ITelemetryData; - allowLocalPaths?: boolean; } export interface ISaveDialogOptions { @@ -67,6 +66,12 @@ export interface ISaveDialogOptions { * A human-readable string for the ok button */ saveLabel?: string; + + /** + * Specifies a list of schemas for the file systems the user can save to. If not specified, uses the schema of the defaultURI or, if also not specified, + * the schema of the current window. + */ + availableFileSystems?: string[]; } export interface IOpenDialogOptions { @@ -107,9 +112,10 @@ export interface IOpenDialogOptions { filters?: FileFilter[]; /** - * Wheter the user can pick local files or folders as well (only applies to remote dialogs) + * Specifies a list of schemas for the file systems the user can load from. If not specified, uses the schema of the defaultURI or, if also not available, + * the schema of the current window. */ - allowLocalPaths?: boolean; + availableFileSystems?: string[]; } diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index 5464ca6a1ec..4520821cde9 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -32,7 +32,7 @@ export class OpenFileAction extends Action { } run(event?: any, data?: ITelemetryData): Promise { - return this.dialogService.pickFileAndOpen({ forceNewWindow: false, telemetryExtraData: data, allowLocalPaths: true }); + return this.dialogService.pickFileAndOpen({ forceNewWindow: false, telemetryExtraData: data }); } } @@ -50,7 +50,7 @@ export class OpenFolderAction extends Action { } run(event?: any, data?: ITelemetryData): Promise { - return this.dialogService.pickFolderAndOpen({ forceNewWindow: false, telemetryExtraData: data, allowLocalPaths: true }); + return this.dialogService.pickFolderAndOpen({ forceNewWindow: false, telemetryExtraData: data }); } } @@ -68,7 +68,7 @@ export class OpenFileFolderAction extends Action { } run(event?: any, data?: ITelemetryData): Promise { - return this.dialogService.pickFileFolderAndOpen({ forceNewWindow: false, telemetryExtraData: data, allowLocalPaths: true }); + return this.dialogService.pickFileFolderAndOpen({ forceNewWindow: false, telemetryExtraData: data }); } } @@ -179,7 +179,7 @@ export class OpenWorkspaceAction extends Action { } run(event?: any, data?: ITelemetryData): Promise { - return this.dialogService.pickWorkspaceAndOpen({ telemetryExtraData: data, allowLocalPaths: true }); + return this.dialogService.pickWorkspaceAndOpen({ telemetryExtraData: data }); } } diff --git a/src/vs/workbench/browser/actions/workspaceCommands.ts b/src/vs/workbench/browser/actions/workspaceCommands.ts index e87473ea7ba..b124ab902bc 100644 --- a/src/vs/workbench/browser/actions/workspaceCommands.ts +++ b/src/vs/workbench/browser/actions/workspaceCommands.ts @@ -29,7 +29,7 @@ export const PICK_WORKSPACE_FOLDER_COMMAND_ID = '_workbench.pickWorkspaceFolder' CommandsRegistry.registerCommand({ id: 'workbench.action.files.openFileFolderInNewWindow', - handler: (accessor: ServicesAccessor) => accessor.get(IFileDialogService).pickFileFolderAndOpen({ forceNewWindow: true, allowLocalPaths: true }) + handler: (accessor: ServicesAccessor) => accessor.get(IFileDialogService).pickFileFolderAndOpen({ forceNewWindow: true }) }); CommandsRegistry.registerCommand({ @@ -39,17 +39,17 @@ CommandsRegistry.registerCommand({ CommandsRegistry.registerCommand({ id: 'workbench.action.files.openFolderInNewWindow', - handler: (accessor: ServicesAccessor) => accessor.get(IFileDialogService).pickFolderAndOpen({ forceNewWindow: true, allowLocalPaths: true }) + handler: (accessor: ServicesAccessor) => accessor.get(IFileDialogService).pickFolderAndOpen({ forceNewWindow: true }) }); CommandsRegistry.registerCommand({ id: 'workbench.action.files.openFileInNewWindow', - handler: (accessor: ServicesAccessor) => accessor.get(IFileDialogService).pickFileAndOpen({ forceNewWindow: true, allowLocalPaths: true }) + handler: (accessor: ServicesAccessor) => accessor.get(IFileDialogService).pickFileAndOpen({ forceNewWindow: true }) }); CommandsRegistry.registerCommand({ id: 'workbench.action.openWorkspaceInNewWindow', - handler: (accessor: ServicesAccessor) => accessor.get(IFileDialogService).pickWorkspaceAndOpen({ forceNewWindow: true, allowLocalPaths: true }) + handler: (accessor: ServicesAccessor) => accessor.get(IFileDialogService).pickWorkspaceAndOpen({ forceNewWindow: true }) }); CommandsRegistry.registerCommand({ diff --git a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts index 18c97ecaaa2..769835433d6 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts @@ -17,7 +17,6 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; import * as resources from 'vs/base/common/resources'; -import { IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { RemoteFileDialog } from 'vs/workbench/services/dialogs/electron-browser/remoteFileDialog'; import { WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces'; @@ -165,8 +164,7 @@ export class FileDialogService implements IFileDialogService { @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IHistoryService private readonly historyService: IHistoryService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @IInstantiationService private readonly instantiationService: IInstantiationService, - @IFileService private readonly fileService: IFileService + @IInstantiationService private readonly instantiationService: IInstantiationService ) { } defaultFilePath(schemeFilter = this.getSchemeFilterForWindow()): URI | undefined { @@ -209,10 +207,6 @@ export class FileDialogService implements IFileDialogService { return this.defaultFolderPath(schemeFilter); } - private getSchemeFilterForWindow() { - return !this.windowService.getConfiguration().remoteAuthority ? Schemas.file : REMOTE_HOST_SCHEME; - } - private toNativeOpenDialogOptions(options: IPickAndOpenOptions): INativeOpenDialogOptions { return { forceNewWindow: options.forceNewWindow, @@ -224,57 +218,66 @@ export class FileDialogService implements IFileDialogService { } pickFileFolderAndOpen(options: IPickAndOpenOptions): Promise { - let defaultUri = options.defaultUri; - if (!defaultUri) { - defaultUri = options.defaultUri = this.defaultFilePath(); + const schema = this.getFileSystemSchema(options); + + if (!options.defaultUri) { + options.defaultUri = this.defaultFilePath(schema); } - if (this.useRemoteDialogs(defaultUri)) { + if (schema !== Schemas.file) { const title = nls.localize('openFileOrFolder.title', 'Open File Or Folder'); - return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: true, canSelectMany: false, defaultUri, title, allowLocalPaths: options.allowLocalPaths }, options.forceNewWindow, true); + const availableFileSystems = [schema, Schemas.file]; // always allow file as well + return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: true, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }, options.forceNewWindow, true); } return this.windowService.pickFileFolderAndOpen(this.toNativeOpenDialogOptions(options)); } pickFileAndOpen(options: IPickAndOpenOptions): Promise { - let defaultUri = options.defaultUri; - if (!defaultUri) { - defaultUri = options.defaultUri = this.defaultFilePath(); + const schema = this.getFileSystemSchema(options); + + if (!options.defaultUri) { + options.defaultUri = this.defaultFilePath(schema); } - if (this.useRemoteDialogs(defaultUri)) { + if (schema !== Schemas.file) { const title = nls.localize('openFile.title', 'Open File'); - return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri, title, allowLocalPaths: options.allowLocalPaths }, options.forceNewWindow, true); + const availableFileSystems = [schema, Schemas.file]; // always allow file as well + return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }, options.forceNewWindow, true); } return this.windowService.pickFileAndOpen(this.toNativeOpenDialogOptions(options)); } pickFolderAndOpen(options: IPickAndOpenOptions): Promise { - let defaultUri = options.defaultUri; - if (!defaultUri) { - defaultUri = options.defaultUri = this.defaultFolderPath(); + const schema = this.getFileSystemSchema(options); + + if (!options.defaultUri) { + options.defaultUri = this.defaultFolderPath(schema); } - if (this.useRemoteDialogs(defaultUri)) { + if (schema !== Schemas.file) { const title = nls.localize('openFolder.title', 'Open Folder'); - return this.pickRemoteResourceAndOpen({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, defaultUri, title, allowLocalPaths: options.allowLocalPaths }, options.forceNewWindow, false); + const availableFileSystems = [schema, Schemas.file]; // always allow file as well + return this.pickRemoteResourceAndOpen({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }, options.forceNewWindow, false); } return this.windowService.pickFolderAndOpen(this.toNativeOpenDialogOptions(options)); } pickWorkspaceAndOpen(options: IPickAndOpenOptions): Promise { - let defaultUri = options.defaultUri; - if (!defaultUri) { - defaultUri = options.defaultUri = this.defaultWorkspacePath(); + const schema = this.getFileSystemSchema(options); + + if (!options.defaultUri) { + options.defaultUri = this.defaultWorkspacePath(schema); } - if (this.useRemoteDialogs(defaultUri)) { + if (schema !== Schemas.file) { const title = nls.localize('openWorkspace.title', 'Open Workspace'); const filters: FileFilter[] = [{ name: nls.localize('filterName.workspace', 'Workspace'), extensions: [WORKSPACE_EXTENSION] }]; - return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri, title, filters, allowLocalPaths: options.allowLocalPaths }, options.forceNewWindow, false); + const availableFileSystems = [schema, Schemas.file]; // always allow file as well + return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, filters, availableFileSystems }, options.forceNewWindow, false); + } return this.windowService.pickWorkspaceAndOpen(this.toNativeOpenDialogOptions(options)); @@ -290,8 +293,8 @@ export class FileDialogService implements IFileDialogService { } showSaveDialog(options: ISaveDialogOptions): Promise { - const defaultUri = options.defaultUri; - if (this.useRemoteDialogs(defaultUri)) { + const schema = this.getFileSystemSchema(options); + if (schema !== Schemas.file) { return this.saveRemoteResource(options); } @@ -305,13 +308,15 @@ export class FileDialogService implements IFileDialogService { } showOpenDialog(options: IOpenDialogOptions): Promise { - const defaultUri = options.defaultUri; - if (this.useRemoteDialogs(defaultUri)) { + const schema = this.getFileSystemSchema(options); + if (schema !== Schemas.file) { return this.pickRemoteResource(options).then(urisToOpen => { return urisToOpen && urisToOpen.map(uto => uto.uri); }); } + const defaultUri = options.defaultUri; + const newOptions: OpenDialogOptions = { title: options.title, defaultPath: defaultUri && defaultUri.fsPath, @@ -356,12 +361,12 @@ export class FileDialogService implements IFileDialogService { return remoteFileDialog.showSaveDialog(options); } - private useRemoteDialogs(defaultUri: URI) { - if (defaultUri) { - return defaultUri.scheme !== Schemas.file && this.fileService.canHandleResource(defaultUri); - } else { - return !!this.windowService.getConfiguration().remoteAuthority; - } + private getSchemeFilterForWindow() { + return !this.windowService.getConfiguration().remoteAuthority ? Schemas.file : REMOTE_HOST_SCHEME; + } + + private getFileSystemSchema(options: { availableFileSystems?: string[], defaultUri?: URI }): string { + return options.availableFileSystems && options.availableFileSystems[0] || options.defaultUri && options.defaultUri.scheme || this.getSchemeFilterForWindow(); } } From 757b99c62d7595d425357b1cf2e014d8903611d3 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Feb 2019 12:56:28 +0100 Subject: [PATCH 193/207] debt - remove vs/base/paths#isAbsolute() --- src/vs/base/common/paths.ts | 33 ------------ src/vs/base/common/resources.ts | 3 +- src/vs/base/test/common/paths.node.test.ts | 49 +++++++++++++++++ src/vs/base/test/common/paths.test.ts | 53 ------------------- src/vs/platform/workspace/common/workspace.ts | 4 +- .../contrib/debug/browser/linkDetector.ts | 2 +- .../debug/browser/loadedScriptsView.ts | 6 +-- .../contrib/debug/common/debugSource.ts | 6 +-- .../contrib/debug/common/debugUtils.ts | 2 +- .../contrib/debug/node/debugAdapter.ts | 5 +- .../markers/electron-browser/markersPanel.ts | 3 +- .../contrib/search/browser/openFileHandler.ts | 10 ++-- .../contrib/search/common/queryBuilder.ts | 8 +-- .../terminal/node/terminalEnvironment.ts | 6 +-- .../services/search/node/ripgrepFileSearch.ts | 2 +- 15 files changed, 79 insertions(+), 113 deletions(-) diff --git a/src/vs/base/common/paths.ts b/src/vs/base/common/paths.ts index 33496d1d7d9..1c32e533143 100644 --- a/src/vs/base/common/paths.ts +++ b/src/vs/base/common/paths.ts @@ -381,39 +381,6 @@ export function isEqualOrParent(path: string, candidate: string, ignoreCase?: bo return path.indexOf(candidate) === 0; } -/** - * Adapted from Node's path.isAbsolute functions - */ -export function isAbsolute(path: string): boolean { - return isWindows ? - isAbsolute_win32(path) : - isAbsolute_posix(path); -} - -export function isAbsolute_win32(path: string): boolean { - if (!path) { - return false; - } - - const char0 = path.charCodeAt(0); - if (isPathSeparator(char0)) { - return true; - } else if (isWindowsDriveLetter(char0)) { - if (path.length > 2 && path.charCodeAt(1) === CharCode.Colon) { - const char2 = path.charCodeAt(2); - if (isPathSeparator(char2)) { - return true; - } - } - } - - return false; -} - -export function isAbsolute_posix(path: string): boolean { - return !!(path && path.charCodeAt(0) === CharCode.Slash); -} - export function isWindowsDriveLetter(char0: number): boolean { return char0 >= CharCode.A && char0 <= CharCode.Z || char0 >= CharCode.a && char0 <= CharCode.z; } diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts index c759010f214..3066303e68f 100644 --- a/src/vs/base/common/resources.ts +++ b/src/vs/base/common/resources.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as paths from 'vs/base/common/paths'; +import { isAbsolute } from 'vs/base/common/paths.node'; import { URI } from 'vs/base/common/uri'; import { equalsIgnoreCase } from 'vs/base/common/strings'; import { Schemas } from 'vs/base/common/network'; @@ -159,7 +160,7 @@ export function fsPath(uri: URI): string { * Returns true if the URI path is absolute. */ export function isAbsolutePath(resource: URI): boolean { - return paths.isAbsolute(resource.path); + return isAbsolute(resource.path); } export function distinctParents(items: T[], resourceAccessor: (item: T) => URI): T[] { diff --git a/src/vs/base/test/common/paths.node.test.ts b/src/vs/base/test/common/paths.node.test.ts index 993bfef7bba..08520ad015a 100644 --- a/src/vs/base/test/common/paths.node.test.ts +++ b/src/vs/base/test/common/paths.node.test.ts @@ -628,6 +628,55 @@ suite('Paths (Node Implementation)', () => { assert.strictEqual(path.posix.isAbsolute('/home/foo/..'), true); assert.strictEqual(path.posix.isAbsolute('bar/'), false); assert.strictEqual(path.posix.isAbsolute('./baz'), false); + + // Tests from us: + + // Absolute Paths + [ + 'C:/', + 'C:\\', + 'C:/foo', + 'C:\\foo', + 'z:/foo/bar.txt', + 'z:\\foo\\bar.txt', + + '\\\\localhost\\c$\\foo', + + '/', + '/foo' + ].forEach(absolutePath => { + assert.ok(path.win32.isAbsolute(absolutePath), absolutePath); + }); + + [ + '/', + '/foo', + '/foo/bar.txt' + ].forEach(absolutePath => { + assert.ok(path.posix.isAbsolute(absolutePath), absolutePath); + }); + + // Relative Paths + [ + '', + 'foo', + 'foo/bar', + './foo', + 'http://foo.com/bar' + ].forEach(nonAbsolutePath => { + assert.ok(!path.win32.isAbsolute(nonAbsolutePath), nonAbsolutePath); + }); + + [ + '', + 'foo', + 'foo/bar', + './foo', + 'http://foo.com/bar', + 'z:/foo/bar.txt', + ].forEach(nonAbsolutePath => { + assert.ok(!path.posix.isAbsolute(nonAbsolutePath), nonAbsolutePath); + }); }); test('path', () => { diff --git a/src/vs/base/test/common/paths.test.ts b/src/vs/base/test/common/paths.test.ts index 835e7e5d2ef..5e0c0110d22 100644 --- a/src/vs/base/test/common/paths.test.ts +++ b/src/vs/base/test/common/paths.test.ts @@ -185,57 +185,4 @@ suite('Paths', () => { assert.ok(!paths.isValidBasename('tes"t.txt')); } }); - - test('isAbsolute_win', () => { - // Absolute paths - [ - 'C:/', - 'C:\\', - 'C:/foo', - 'C:\\foo', - 'z:/foo/bar.txt', - 'z:\\foo\\bar.txt', - - '\\\\localhost\\c$\\foo', - - '/', - '/foo' - ].forEach(absolutePath => { - assert.ok(paths.isAbsolute_win32(absolutePath), absolutePath); - }); - - // Not absolute paths - [ - '', - 'foo', - 'foo/bar', - './foo', - 'http://foo.com/bar' - ].forEach(nonAbsolutePath => { - assert.ok(!paths.isAbsolute_win32(nonAbsolutePath), nonAbsolutePath); - }); - }); - - test('isAbsolute_posix', () => { - // Absolute paths - [ - '/', - '/foo', - '/foo/bar.txt' - ].forEach(absolutePath => { - assert.ok(paths.isAbsolute_posix(absolutePath), absolutePath); - }); - - // Not absolute paths - [ - '', - 'foo', - 'foo/bar', - './foo', - 'http://foo.com/bar', - 'z:/foo/bar.txt', - ].forEach(nonAbsolutePath => { - assert.ok(!paths.isAbsolute_posix(nonAbsolutePath), nonAbsolutePath); - }); - }); }); diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index e2488422d95..3be9353605b 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import * as paths from 'vs/base/common/paths'; +import { isAbsolute } from 'vs/base/common/paths.node'; import * as resources from 'vs/base/common/resources'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { TernarySearchTree } from 'vs/base/common/map'; @@ -257,7 +257,7 @@ function parseWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], rela function toUri(path: string, relativeTo: URI | undefined): URI | null { if (path) { - if (paths.isAbsolute(path)) { + if (isAbsolute(path)) { return URI.file(path); } if (relativeTo) { diff --git a/src/vs/workbench/contrib/debug/browser/linkDetector.ts b/src/vs/workbench/contrib/debug/browser/linkDetector.ts index 49bb7903aca..be4545e5d25 100644 --- a/src/vs/workbench/contrib/debug/browser/linkDetector.ts +++ b/src/vs/workbench/contrib/debug/browser/linkDetector.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import strings = require('vs/base/common/strings'); -import { isAbsolute } from 'vs/base/common/paths'; +import { isAbsolute } from 'vs/base/common/paths.node'; import { URI as uri } from 'vs/base/common/uri'; import { isMacintosh } from 'vs/base/common/platform'; import { IMouseEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; diff --git a/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts index 8a85289d1d4..a20df7bc802 100644 --- a/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts +++ b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import * as dom from 'vs/base/browser/dom'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; -import { normalize, isAbsolute, sep } from 'vs/base/common/paths'; +import { normalize, isAbsolute } from 'vs/base/common/paths.node'; import { IViewletPanelOptions, ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -317,7 +317,7 @@ class SessionTreeItem extends BaseTreeItem { folder = this.rootProvider ? this.rootProvider.getWorkspaceFolder(resource) : null; if (folder) { // strip off the root folder path - path = normalize(ltrim(resource.path.substr(folder.uri.path.length), sep), true); + path = normalize(ltrim(resource.path.substr(folder.uri.path.length), '/')); const hasMultipleRoots = this.rootProvider.getWorkspace().folders.length > 1; if (hasMultipleRoots) { path = '/' + path; @@ -327,7 +327,7 @@ class SessionTreeItem extends BaseTreeItem { } } else { // on unix try to tildify absolute paths - path = normalize(path, true); + path = normalize(path); if (!isWindows) { path = tildify(path, this._environmentService.userHome); } diff --git a/src/vs/workbench/contrib/debug/common/debugSource.ts b/src/vs/workbench/contrib/debug/common/debugSource.ts index 41ced00cc31..4426c79b4b0 100644 --- a/src/vs/workbench/contrib/debug/common/debugSource.ts +++ b/src/vs/workbench/contrib/debug/common/debugSource.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { URI as uri } from 'vs/base/common/uri'; -import * as paths from 'vs/base/common/paths'; +import { normalize, isAbsolute } from 'vs/base/common/paths.node'; import * as resources from 'vs/base/common/resources'; import { DEBUG_SCHEME } from 'vs/workbench/contrib/debug/common/debug'; import { IRange } from 'vs/editor/common/core/range'; @@ -52,7 +52,7 @@ export class Source { this.uri = uri.parse(path); } else { // assume a filesystem path - if (paths.isAbsolute(path)) { + if (isAbsolute(path)) { this.uri = uri.file(path); } else { // path is relative: since VS Code cannot deal with this by itself @@ -104,7 +104,7 @@ export class Source { switch (modelUri.scheme) { case Schemas.file: - path = paths.normalize(modelUri.fsPath, true); + path = normalize(modelUri.fsPath); break; case DEBUG_SCHEME: path = modelUri.path; diff --git a/src/vs/workbench/contrib/debug/common/debugUtils.ts b/src/vs/workbench/contrib/debug/common/debugUtils.ts index 0804f0433c3..c7a13be11a1 100644 --- a/src/vs/workbench/contrib/debug/common/debugUtils.ts +++ b/src/vs/workbench/contrib/debug/common/debugUtils.ts @@ -6,7 +6,7 @@ import { equalsIgnoreCase } from 'vs/base/common/strings'; import { IConfig, IDebuggerContribution } from 'vs/workbench/contrib/debug/common/debug'; import { URI as uri } from 'vs/base/common/uri'; -import { isAbsolute } from 'vs/base/common/paths'; +import { isAbsolute } from 'vs/base/common/paths.node'; import { deepClone } from 'vs/base/common/objects'; const _formatPIIRegexp = /{([^}]+)}/g; diff --git a/src/vs/workbench/contrib/debug/node/debugAdapter.ts b/src/vs/workbench/contrib/debug/node/debugAdapter.ts index 09939841def..dd051c8382b 100644 --- a/src/vs/workbench/contrib/debug/node/debugAdapter.ts +++ b/src/vs/workbench/contrib/debug/node/debugAdapter.ts @@ -8,6 +8,7 @@ import * as cp from 'child_process'; import * as stream from 'stream'; import * as nls from 'vs/nls'; import * as net from 'net'; +import * as path from 'path'; import * as paths from 'vs/base/common/paths'; import * as strings from 'vs/base/common/strings'; import * as objects from 'vs/base/common/objects'; @@ -316,7 +317,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { // verify executables if (this.adapterExecutable.command) { - if (paths.isAbsolute(this.adapterExecutable.command)) { + if (path.isAbsolute(this.adapterExecutable.command)) { if (!fs.existsSync(this.adapterExecutable.command)) { reject(new Error(nls.localize('debugAdapterBinNotFound', "Debug adapter executable '{0}' does not exist.", this.adapterExecutable.command))); } @@ -449,7 +450,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { result.runtimeArgs = contribution.runtimeArgs; } if (contribution.program) { - if (!paths.isAbsolute(contribution.program)) { + if (!path.isAbsolute(contribution.program)) { result.program = paths.join(extensionFolderPath, contribution.program); } else { result.program = contribution.program; diff --git a/src/vs/workbench/contrib/markers/electron-browser/markersPanel.ts b/src/vs/workbench/contrib/markers/electron-browser/markersPanel.ts index b3d35c26455..77c6c4e6592 100644 --- a/src/vs/workbench/contrib/markers/electron-browser/markersPanel.ts +++ b/src/vs/workbench/contrib/markers/electron-browser/markersPanel.ts @@ -32,7 +32,8 @@ import { FilterOptions } from 'vs/workbench/contrib/markers/electron-browser/mar import { IExpression, getEmptyExpression } from 'vs/base/common/glob'; import { mixin, deepClone } from 'vs/base/common/objects'; import { IWorkspaceFolder, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { isAbsolute, join } from 'vs/base/common/paths'; +import { join } from 'vs/base/common/paths'; +import { isAbsolute } from 'vs/base/common/paths.node'; import { FilterData, Filter, VirtualDelegate, ResourceMarkersRenderer, MarkerRenderer, RelatedInformationRenderer, TreeElement, MarkersTreeAccessibilityProvider, MarkersViewModel, ResourceDragAndDrop } from 'vs/workbench/contrib/markers/electron-browser/markersTreeViewer'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { Separator, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; diff --git a/src/vs/workbench/contrib/search/browser/openFileHandler.ts b/src/vs/workbench/contrib/search/browser/openFileHandler.ts index e03cc673b30..fd878bc3752 100644 --- a/src/vs/workbench/contrib/search/browser/openFileHandler.ts +++ b/src/vs/workbench/contrib/search/browser/openFileHandler.ts @@ -5,11 +5,11 @@ import * as errors from 'vs/base/common/errors'; import * as nls from 'vs/nls'; -import * as paths from 'vs/base/common/paths'; +import { isAbsolute } from 'vs/base/common/paths.node'; import * as objects from 'vs/base/common/objects'; import { defaultGenerator } from 'vs/base/common/idGenerator'; import { URI } from 'vs/base/common/uri'; -import * as resources from 'vs/base/common/resources'; +import { basename, dirname } from 'vs/base/common/resources'; import { IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { IModeService } from 'vs/editor/common/services/modeService'; import { getIconClasses } from 'vs/editor/common/services/getIconClasses'; @@ -174,8 +174,8 @@ export class OpenFileHandler extends QuickOpenHandler { if (!token.isCancellationRequested) { for (const fileMatch of complete.results) { - const label = paths.basename(fileMatch.resource.fsPath); - const description = this.labelService.getUriLabel(resources.dirname(fileMatch.resource)!, { relative: true }); + const label = basename(fileMatch.resource); + const description = this.labelService.getUriLabel(dirname(fileMatch.resource)!, { relative: true }); results.push(this.instantiationService.createInstance(FileEntry, fileMatch.resource, label, description, iconClass)); } @@ -186,7 +186,7 @@ export class OpenFileHandler extends QuickOpenHandler { } private getAbsolutePathResult(query: IPreparedQuery): Promise { - if (paths.isAbsolute(query.original)) { + if (isAbsolute(query.original)) { const resource = URI.file(query.original); return this.fileService.resolveFile(resource).then(stat => stat.isDirectory ? undefined : resource, error => undefined); diff --git a/src/vs/workbench/contrib/search/common/queryBuilder.ts b/src/vs/workbench/contrib/search/common/queryBuilder.ts index f5c6ec5222b..6424ae7a1c2 100644 --- a/src/vs/workbench/contrib/search/common/queryBuilder.ts +++ b/src/vs/workbench/contrib/search/common/queryBuilder.ts @@ -8,7 +8,7 @@ import * as collections from 'vs/base/common/collections'; import * as glob from 'vs/base/common/glob'; import { untildify } from 'vs/base/common/labels'; import { values } from 'vs/base/common/map'; -import * as paths from 'vs/base/common/paths'; +import * as path from 'vs/base/common/paths.node'; import { isEqual } from 'vs/base/common/resources'; import * as strings from 'vs/base/common/strings'; import { URI as uri } from 'vs/base/common/uri'; @@ -211,7 +211,7 @@ export class QueryBuilder { parseSearchPaths(pattern: string): ISearchPathsResult { const isSearchPath = (segment: string) => { // A segment is a search path if it is an absolute path or starts with ./, ../, .\, or ..\ - return paths.isAbsolute(segment) || /^\.\.?[\/\\]/.test(segment); + return path.isAbsolute(segment) || /^\.\.?[\/\\]/.test(segment); }; const segments = splitGlobPattern(pattern) @@ -301,11 +301,11 @@ export class QueryBuilder { * Takes a searchPath like `./a/foo` and expands it to absolute paths for all the workspaces it matches. */ private expandOneSearchPath(searchPath: string): IOneSearchPathPattern[] { - if (paths.isAbsolute(searchPath)) { + if (path.isAbsolute(searchPath)) { // Currently only local resources can be searched for with absolute search paths. // TODO convert this to a workspace folder + pattern, so excludes will be resolved properly for an absolute path inside a workspace folder return [{ - searchPath: uri.file(paths.normalize(searchPath)) + searchPath: uri.file(path.normalize(searchPath)) }]; } diff --git a/src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts index bd134149555..89daae934fd 100644 --- a/src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as os from 'os'; -import * as paths from 'vs/base/common/paths'; +import * as path from 'path'; import * as platform from 'vs/base/common/platform'; import pkg from 'vs/platform/node/package'; import { URI as Uri } from 'vs/base/common/uri'; @@ -111,10 +111,10 @@ export function getCwd(shell: IShellLaunchConfig, root?: Uri, customCwd?: string // TODO: Handle non-existent customCwd if (!shell.ignoreConfigurationCwd && customCwd) { - if (paths.isAbsolute(customCwd)) { + if (path.isAbsolute(customCwd)) { cwd = customCwd; } else if (root) { - cwd = paths.normalize(paths.join(root.fsPath, customCwd)); + cwd = path.join(root.fsPath, customCwd); } } diff --git a/src/vs/workbench/services/search/node/ripgrepFileSearch.ts b/src/vs/workbench/services/search/node/ripgrepFileSearch.ts index 2c65ff9822e..2942235dbe9 100644 --- a/src/vs/workbench/services/search/node/ripgrepFileSearch.ts +++ b/src/vs/workbench/services/search/node/ripgrepFileSearch.ts @@ -159,7 +159,7 @@ function globExprsToRgGlobs(patterns: glob.IExpression, folder?: string, exclude * Exported for testing */ export function getAbsoluteGlob(folder: string, key: string): string { - return paths.isAbsolute(key) ? + return path.isAbsolute(key) ? key : path.join(folder, key); } From 3d08a0590e8c69857fb56188db6b4677441f4298 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Feb 2019 13:02:32 +0100 Subject: [PATCH 194/207] debt - lift some things to browser namespace --- src/tsconfig.strictNullChecks.json | 3 +- src/vs/workbench/common/resources.ts | 109 ++++++++++++++++ .../files/electron-browser/explorerService.ts | 2 +- .../workbench/electron-browser/resources.ts | 117 ------------------ .../workbench/electron-browser/workbench.ts | 2 +- .../{electron-browser => browser}/history.ts | 2 +- 6 files changed, 113 insertions(+), 122 deletions(-) delete mode 100644 src/vs/workbench/electron-browser/resources.ts rename src/vs/workbench/services/history/{electron-browser => browser}/history.ts (99%) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 385730e03cc..9a93f3283f7 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -664,7 +664,6 @@ "./vs/workbench/contrib/themes/electron-browser/themes.contribution.ts", "./vs/workbench/contrib/url/electron-browser/url.contribution.ts", "./vs/workbench/contrib/webview/electron-browser/webviewProtocols.ts", - "./vs/workbench/electron-browser/resources.ts", "./vs/workbench/electron-browser/window.ts", "./vs/workbench/services/activity/common/activity.ts", "./vs/workbench/services/backup/common/backup.ts", @@ -709,7 +708,7 @@ "./vs/workbench/services/hash/common/hashService.ts", "./vs/workbench/services/hash/node/hashService.ts", "./vs/workbench/services/history/common/history.ts", - "./vs/workbench/services/history/electron-browser/history.ts", + "./vs/workbench/services/history/browser/history.ts", "./vs/workbench/services/integrity/common/integrity.ts", "./vs/workbench/services/integrity/node/integrityServiceImpl.ts", "./vs/workbench/services/keybinding/common/keybindingIO.ts", diff --git a/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts index c726f2ce067..000fb0e98d1 100644 --- a/src/vs/workbench/common/resources.ts +++ b/src/vs/workbench/common/resources.ts @@ -5,10 +5,16 @@ import { URI } from 'vs/base/common/uri'; import * as paths from 'vs/base/common/paths'; +import * as objects from 'vs/base/common/objects'; +import { Event, Emitter } from 'vs/base/common/event'; +import { relative } from 'vs/base/common/paths.node'; import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IFileService } from 'vs/platform/files/common/files'; import { Disposable } from 'vs/base/common/lifecycle'; +import { ParsedExpression, IExpression, parse } from 'vs/base/common/glob'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; export class ResourceContextKey extends Disposable implements IContextKey { @@ -95,3 +101,106 @@ export class ResourceContextKey extends Disposable implements IContextKey { && a.toString() === b.toString(); // for equal we use the normalized toString-form } } + +export class ResourceGlobMatcher extends Disposable { + + private static readonly NO_ROOT: string | null = null; + + private readonly _onExpressionChange: Emitter = this._register(new Emitter()); + get onExpressionChange(): Event { return this._onExpressionChange.event; } + + private mapRootToParsedExpression: Map; + private mapRootToExpressionConfig: Map; + + constructor( + private globFn: (root?: URI) => IExpression, + private shouldUpdate: (event: IConfigurationChangeEvent) => boolean, + @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, + @IConfigurationService private readonly configurationService: IConfigurationService + ) { + super(); + + this.mapRootToParsedExpression = new Map(); + this.mapRootToExpressionConfig = new Map(); + + this.updateExcludes(false); + + this.registerListeners(); + } + + private registerListeners(): void { + this._register(this.configurationService.onDidChangeConfiguration(e => { + if (this.shouldUpdate(e)) { + this.updateExcludes(true); + } + })); + + this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.updateExcludes(true))); + } + + private updateExcludes(fromEvent: boolean): void { + let changed = false; + + // Add excludes per workspaces that got added + this.contextService.getWorkspace().folders.forEach(folder => { + const rootExcludes = this.globFn(folder.uri); + if (!this.mapRootToExpressionConfig.has(folder.uri.toString()) || !objects.equals(this.mapRootToExpressionConfig.get(folder.uri.toString()), rootExcludes)) { + changed = true; + + this.mapRootToParsedExpression.set(folder.uri.toString(), parse(rootExcludes)); + this.mapRootToExpressionConfig.set(folder.uri.toString(), objects.deepClone(rootExcludes)); + } + }); + + // Remove excludes per workspace no longer present + this.mapRootToExpressionConfig.forEach((value, root) => { + if (root === ResourceGlobMatcher.NO_ROOT) { + return; // always keep this one + } + + if (root && !this.contextService.getWorkspaceFolder(URI.parse(root))) { + this.mapRootToParsedExpression.delete(root); + this.mapRootToExpressionConfig.delete(root); + + changed = true; + } + }); + + // Always set for resources outside root as well + const globalExcludes = this.globFn(); + if (!this.mapRootToExpressionConfig.has(ResourceGlobMatcher.NO_ROOT) || !objects.equals(this.mapRootToExpressionConfig.get(ResourceGlobMatcher.NO_ROOT), globalExcludes)) { + changed = true; + + this.mapRootToParsedExpression.set(ResourceGlobMatcher.NO_ROOT, parse(globalExcludes)); + this.mapRootToExpressionConfig.set(ResourceGlobMatcher.NO_ROOT, objects.deepClone(globalExcludes)); + } + + if (fromEvent && changed) { + this._onExpressionChange.fire(); + } + } + + matches(resource: URI): boolean { + const folder = this.contextService.getWorkspaceFolder(resource); + + let expressionForRoot: ParsedExpression; + if (folder && this.mapRootToParsedExpression.has(folder.uri.toString())) { + expressionForRoot = this.mapRootToParsedExpression.get(folder.uri.toString())!; + } else { + expressionForRoot = this.mapRootToParsedExpression.get(ResourceGlobMatcher.NO_ROOT)!; + } + + // If the resource if from a workspace, convert its absolute path to a relative + // path so that glob patterns have a higher probability to match. For example + // a glob pattern of "src/**" will not match on an absolute path "/folder/src/file.txt" + // but can match on "src/file.txt" + let resourcePathToMatch: string; + if (folder) { + resourcePathToMatch = paths.normalize(relative(folder.uri.fsPath, resource.fsPath)); + } else { + resourcePathToMatch = resource.fsPath; + } + + return !!expressionForRoot(resourcePathToMatch); + } +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/files/electron-browser/explorerService.ts b/src/vs/workbench/contrib/files/electron-browser/explorerService.ts index a4e4689adb7..921c42347b3 100644 --- a/src/vs/workbench/contrib/files/electron-browser/explorerService.ts +++ b/src/vs/workbench/contrib/files/electron-browser/explorerService.ts @@ -12,7 +12,7 @@ import { URI } from 'vs/base/common/uri'; import { FileOperationEvent, FileOperation, IFileStat, IFileService, FileChangesEvent, FILES_EXCLUDE_CONFIG, FileChangeType, IResolveFileOptions } from 'vs/platform/files/common/files'; import { dirname } from 'vs/base/common/resources'; import { memoize } from 'vs/base/common/decorators'; -import { ResourceGlobMatcher } from 'vs/workbench/electron-browser/resources'; +import { ResourceGlobMatcher } from 'vs/workbench/common/resources'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IExpression } from 'vs/base/common/glob'; diff --git a/src/vs/workbench/electron-browser/resources.ts b/src/vs/workbench/electron-browser/resources.ts deleted file mode 100644 index 74c2b6751e6..00000000000 --- a/src/vs/workbench/electron-browser/resources.ts +++ /dev/null @@ -1,117 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { URI } from 'vs/base/common/uri'; -import * as objects from 'vs/base/common/objects'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { Event, Emitter } from 'vs/base/common/event'; -import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; -import { ParsedExpression, IExpression, parse } from 'vs/base/common/glob'; -import { relative } from 'path'; -import { normalize } from 'vs/base/common/paths'; - -export class ResourceGlobMatcher extends Disposable { - - private static readonly NO_ROOT: string | null = null; - - private readonly _onExpressionChange: Emitter = this._register(new Emitter()); - get onExpressionChange(): Event { return this._onExpressionChange.event; } - - private mapRootToParsedExpression: Map; - private mapRootToExpressionConfig: Map; - - constructor( - private globFn: (root?: URI) => IExpression, - private shouldUpdate: (event: IConfigurationChangeEvent) => boolean, - @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @IConfigurationService private readonly configurationService: IConfigurationService - ) { - super(); - - this.mapRootToParsedExpression = new Map(); - this.mapRootToExpressionConfig = new Map(); - - this.updateExcludes(false); - - this.registerListeners(); - } - - private registerListeners(): void { - this._register(this.configurationService.onDidChangeConfiguration(e => { - if (this.shouldUpdate(e)) { - this.updateExcludes(true); - } - })); - - this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.updateExcludes(true))); - } - - private updateExcludes(fromEvent: boolean): void { - let changed = false; - - // Add excludes per workspaces that got added - this.contextService.getWorkspace().folders.forEach(folder => { - const rootExcludes = this.globFn(folder.uri); - if (!this.mapRootToExpressionConfig.has(folder.uri.toString()) || !objects.equals(this.mapRootToExpressionConfig.get(folder.uri.toString()), rootExcludes)) { - changed = true; - - this.mapRootToParsedExpression.set(folder.uri.toString(), parse(rootExcludes)); - this.mapRootToExpressionConfig.set(folder.uri.toString(), objects.deepClone(rootExcludes)); - } - }); - - // Remove excludes per workspace no longer present - this.mapRootToExpressionConfig.forEach((value, root) => { - if (root === ResourceGlobMatcher.NO_ROOT) { - return; // always keep this one - } - - if (root && !this.contextService.getWorkspaceFolder(URI.parse(root))) { - this.mapRootToParsedExpression.delete(root); - this.mapRootToExpressionConfig.delete(root); - - changed = true; - } - }); - - // Always set for resources outside root as well - const globalExcludes = this.globFn(); - if (!this.mapRootToExpressionConfig.has(ResourceGlobMatcher.NO_ROOT) || !objects.equals(this.mapRootToExpressionConfig.get(ResourceGlobMatcher.NO_ROOT), globalExcludes)) { - changed = true; - - this.mapRootToParsedExpression.set(ResourceGlobMatcher.NO_ROOT, parse(globalExcludes)); - this.mapRootToExpressionConfig.set(ResourceGlobMatcher.NO_ROOT, objects.deepClone(globalExcludes)); - } - - if (fromEvent && changed) { - this._onExpressionChange.fire(); - } - } - - matches(resource: URI): boolean { - const folder = this.contextService.getWorkspaceFolder(resource); - - let expressionForRoot: ParsedExpression; - if (folder && this.mapRootToParsedExpression.has(folder.uri.toString())) { - expressionForRoot = this.mapRootToParsedExpression.get(folder.uri.toString())!; - } else { - expressionForRoot = this.mapRootToParsedExpression.get(ResourceGlobMatcher.NO_ROOT)!; - } - - // If the resource if from a workspace, convert its absolute path to a relative - // path so that glob patterns have a higher probability to match. For example - // a glob pattern of "src/**" will not match on an absolute path "/folder/src/file.txt" - // but can match on "src/file.txt" - let resourcePathToMatch: string; - if (folder) { - resourcePathToMatch = normalize(relative(folder.uri.fsPath, resource.fsPath)); - } else { - resourcePathToMatch = resource.fsPath; - } - - return !!expressionForRoot(resourcePathToMatch); - } -} \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 506839cf21d..7700d71be14 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -135,6 +135,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { OpenerService } from 'vs/editor/browser/services/openerService'; import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity'; import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; +import { HistoryService } from 'vs/workbench/services/history/browser/history'; // import@node import product from 'vs/platform/node/product'; @@ -165,7 +166,6 @@ import { IntegrityServiceImpl } from 'vs/workbench/services/integrity/node/integ import { LocalizationsChannelClient } from 'vs/platform/localizations/node/localizationsIpc'; // import@electron-browser -import { HistoryService } from 'vs/workbench/services/history/electron-browser/history'; import { ContextMenuService as NativeContextMenuService } from 'vs/workbench/services/contextview/electron-browser/contextmenuService'; import { WorkbenchKeybindingService } from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; import { RemoteFileService } from 'vs/workbench/services/files/electron-browser/remoteFileService'; diff --git a/src/vs/workbench/services/history/electron-browser/history.ts b/src/vs/workbench/services/history/browser/history.ts similarity index 99% rename from src/vs/workbench/services/history/electron-browser/history.ts rename to src/vs/workbench/services/history/browser/history.ts index a870f1f404f..86687c9c0ad 100644 --- a/src/vs/workbench/services/history/electron-browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -25,7 +25,7 @@ import { getExcludes, ISearchConfiguration } from 'vs/workbench/services/search/ import { IExpression } from 'vs/base/common/glob'; import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ResourceGlobMatcher } from 'vs/workbench/electron-browser/resources'; +import { ResourceGlobMatcher } from 'vs/workbench/common/resources'; import { EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey'; From c25de7d09fddf553b644ce34103b9f1a36d2f86f Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Tue, 12 Feb 2019 15:13:43 +0100 Subject: [PATCH 195/207] Extract task code to its own file --- build/gulpfile.compile.js | 5 +- build/gulpfile.editor.js | 11 ++-- build/gulpfile.extensions.js | 13 ++--- build/gulpfile.vscode.js | 31 ++++++------ build/gulpfile.vscode.linux.js | 13 ++--- build/gulpfile.vscode.win32.js | 11 ++-- build/lib/task.js | 78 ++++++++++++++++++++++++++++ build/lib/task.ts | 92 ++++++++++++++++++++++++++++++++++ build/lib/util.js | 75 --------------------------- build/lib/util.ts | 88 -------------------------------- gulpfile.js | 9 ++-- 11 files changed, 220 insertions(+), 206 deletions(-) create mode 100644 build/lib/task.js create mode 100644 build/lib/task.ts diff --git a/build/gulpfile.compile.js b/build/gulpfile.compile.js index 521a13a440d..17517184653 100644 --- a/build/gulpfile.compile.js +++ b/build/gulpfile.compile.js @@ -6,15 +6,16 @@ 'use strict'; const util = require('./lib/util'); +const task = require('./lib/task'); const compilation = require('./lib/compilation'); const { compileExtensionsBuildTask } = require('./gulpfile.extensions'); // Full compile, including nls and inline sources in sourcemaps, for build -const compileClientBuildTask = util.task.series(util.rimraf('out-build'), compilation.compileTask('src', 'out-build', true)); +const compileClientBuildTask = task.series(util.rimraf('out-build'), compilation.compileTask('src', 'out-build', true)); compileClientBuildTask.displayName = 'compile-client-build'; // All Build -const compileBuildTask = util.task.parallel(compileClientBuildTask, compileExtensionsBuildTask); +const compileBuildTask = task.parallel(compileClientBuildTask, compileExtensionsBuildTask); compileBuildTask.displayName = 'compile-build'; exports.compileBuildTask = compileBuildTask; \ No newline at end of file diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index f1aa8e77ff1..b64482da294 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -6,6 +6,7 @@ const gulp = require('gulp'); const path = require('path'); const util = require('./lib/util'); +const task = require('./lib/task'); const common = require('./lib/optimize'); const es = require('event-stream'); const File = require('vinyl'); @@ -290,8 +291,8 @@ const finalEditorResourcesTask = function () { finalEditorResourcesTask.displayName = 'final-editor-resources'; gulp.task('editor-distro', - util.task.series( - util.task.parallel( + task.series( + task.parallel( util.rimraf('out-editor-src'), util.rimraf('out-editor-build'), util.rimraf('out-editor-esm'), @@ -300,13 +301,13 @@ gulp.task('editor-distro', util.rimraf('out-editor-min') ), extractEditorSrcTask, - util.task.parallel( - util.task.series( + task.parallel( + task.series( compileEditorAMDTask, optimizeEditorAMDTask, minifyEditorAMDTask ), - util.task.series( + task.series( createESMSourcesAndResourcesTask, compileEditorESMTask ) diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index 458d0c0e4db..94e8103d8e4 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -12,6 +12,7 @@ const tsb = require('gulp-tsb'); const es = require('event-stream'); const filter = require('gulp-filter'); const util = require('./lib/util'); +const task = require('./lib/task'); const watcher = require('./lib/watch'); const createReporter = require('./lib/reporter').createReporter; const glob = require('glob'); @@ -112,7 +113,7 @@ const tasks = compilations.map(function (tsconfigFile) { .pipe(gulp.dest(out)); }; compileTask_.displayName = `compile-extension-${name}`; - const compileTask = util.task.series(cleanTask, compileTask_); + const compileTask = task.series(cleanTask, compileTask_); const watchTask_ = () => { const pipeline = createPipeline(false); @@ -124,7 +125,7 @@ const tasks = compilations.map(function (tsconfigFile) { .pipe(gulp.dest(out)); }; watchTask_.displayName = `watch-extension-${name}`; - const watchTask = util.task.series(cleanTask, watchTask_); + const watchTask = task.series(cleanTask, watchTask_); const compileBuildTask_ = () => { const pipeline = createPipeline(true, true); @@ -135,7 +136,7 @@ const tasks = compilations.map(function (tsconfigFile) { .pipe(gulp.dest(out)); }; compileBuildTask_.displayName = `compile-build-extension-${name}`; - const compileBuildTask = util.task.series(cleanTask, compileBuildTask_); + const compileBuildTask = task.series(cleanTask, compileBuildTask_); // Tasks gulp.task('compile-extension:' + name, compileTask); @@ -148,16 +149,16 @@ const tasks = compilations.map(function (tsconfigFile) { }; }); -const compileExtensionsTask = util.task.parallel(...tasks.map(t => t.compileTask)); +const compileExtensionsTask = task.parallel(...tasks.map(t => t.compileTask)); compileExtensionsTask.displayName = 'compile-extensions'; gulp.task(compileExtensionsTask.displayName, compileExtensionsTask); exports.compileExtensionsTask = compileExtensionsTask; -const watchExtensionsTask = util.task.parallel(...tasks.map(t => t.watchTask)); +const watchExtensionsTask = task.parallel(...tasks.map(t => t.watchTask)); watchExtensionsTask.displayName = 'watch-extensions'; gulp.task(watchExtensionsTask.displayName, watchExtensionsTask); exports.watchExtensionsTask = watchExtensionsTask; -const compileExtensionsBuildTask = util.task.parallel(...tasks.map(t => t.compileBuildTask)); +const compileExtensionsBuildTask = task.parallel(...tasks.map(t => t.compileBuildTask)); compileExtensionsBuildTask.displayName = 'compile-extensions-build'; exports.compileExtensionsBuildTask = compileExtensionsBuildTask; diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index dbddf5215dd..af2d78273a2 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -20,6 +20,7 @@ const filter = require('gulp-filter'); const json = require('gulp-json-editor'); const _ = require('underscore'); const util = require('./lib/util'); +const task = require('./lib/task'); const ext = require('./lib/extensions'); const buildfile = require('../src/buildfile'); const common = require('./lib/optimize'); @@ -87,8 +88,8 @@ const BUNDLED_FILE_HEADER = [ ' *--------------------------------------------------------*/' ].join('\n'); -const optimizeVSCodeTask = util.task.series( - util.task.parallel( +const optimizeVSCodeTask = task.series( + task.parallel( util.rimraf('out-vscode'), compileBuildTask ), @@ -105,7 +106,7 @@ const optimizeVSCodeTask = util.task.series( optimizeVSCodeTask.displayName = 'optimize-vscode'; -const optimizeIndexJSTask = util.task.series( +const optimizeIndexJSTask = task.series( optimizeVSCodeTask, () => { const fullpath = path.join(process.cwd(), 'out-vscode/bootstrap-window.js'); @@ -117,8 +118,8 @@ const optimizeIndexJSTask = util.task.series( optimizeIndexJSTask.displayName = 'optimize-index-js'; const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`; -const minifyVSCodeTask = util.task.series( - util.task.parallel( +const minifyVSCodeTask = task.series( + task.parallel( util.rimraf('out-vscode-min'), optimizeIndexJSTask ), @@ -213,11 +214,11 @@ function getElectron(arch) { }; } -gulp.task('electron', util.task.series(util.rimraf('.build/electron'), getElectron(process.arch))); -gulp.task('electron-ia32', util.task.series(util.rimraf('.build/electron'), getElectron('ia32'))); -gulp.task('electron-x64', util.task.series(util.rimraf('.build/electron'), getElectron('x64'))); -gulp.task('electron-arm', util.task.series(util.rimraf('.build/electron'), getElectron('arm'))); -gulp.task('electron-arm64', util.task.series(util.rimraf('.build/electron'), getElectron('arm64'))); +gulp.task('electron', task.series(util.rimraf('.build/electron'), getElectron(process.arch))); +gulp.task('electron-ia32', task.series(util.rimraf('.build/electron'), getElectron('ia32'))); +gulp.task('electron-x64', task.series(util.rimraf('.build/electron'), getElectron('x64'))); +gulp.task('electron-arm', task.series(util.rimraf('.build/electron'), getElectron('arm'))); +gulp.task('electron-arm64', task.series(util.rimraf('.build/electron'), getElectron('arm64'))); /** @@ -457,8 +458,8 @@ BUILD_TARGETS.forEach(buildTarget => { const sourceFolderName = `out-vscode${dashed(minified)}`; const destinationFolderName = `VSCode${dashed(platform)}${dashed(arch)}`; - const vscodeTask = util.task.series( - util.task.parallel( + const vscodeTask = task.series( + task.parallel( minified ? minifyVSCodeTask : optimizeVSCodeTask, util.rimraf(path.join(buildRoot, destinationFolderName)) ), @@ -491,7 +492,7 @@ const apiName = process.env.TRANSIFEX_API_NAME; const apiToken = process.env.TRANSIFEX_API_TOKEN; gulp.task('vscode-translations-push', - util.task.series( + task.series( optimizeVSCodeTask, function () { const pathToMetadata = './out-vscode/nls.metadata.json'; @@ -509,7 +510,7 @@ gulp.task('vscode-translations-push', ); gulp.task('vscode-translations-export', - util.task.series( + task.series( optimizeVSCodeTask, function () { const pathToMetadata = './out-vscode/nls.metadata.json'; @@ -614,7 +615,7 @@ generateVSCodeConfigurationTask.displayName = 'generate-vscode-configuration'; const allConfigDetailsPath = path.join(os.tmpdir(), 'configuration.json'); gulp.task('upload-vscode-configuration', - util.task.series( + task.series( generateVSCodeConfigurationTask, () => { if (!shouldSetupSettingsSearch()) { diff --git a/build/gulpfile.vscode.linux.js b/build/gulpfile.vscode.linux.js index b3599cbe39d..4d1bdbd825f 100644 --- a/build/gulpfile.vscode.linux.js +++ b/build/gulpfile.vscode.linux.js @@ -12,6 +12,7 @@ const shell = require('gulp-shell'); const es = require('event-stream'); const vfs = require('vinyl-fs'); const util = require('./lib/util'); +const task = require('./lib/task'); const packageJson = require('../package.json'); const product = require('../product.json'); const rpmDependencies = require('../resources/linux/rpm/dependencies.json'); @@ -241,29 +242,29 @@ BUILD_TARGETS.forEach((buildTarget) => { { const debArch = getDebPackageArch(arch); - const prepareDebTask = util.task.series(util.rimraf(`.build/linux/deb/${debArch}`), prepareDebPackage(arch)); + const prepareDebTask = task.series(util.rimraf(`.build/linux/deb/${debArch}`), prepareDebPackage(arch)); prepareDebTask.displayName = `vscode-linux-${arch}-prepare-deb`; // gulp.task(prepareDebTask.displayName, prepareDebTask); - const buildDebTask = util.task.series(prepareDebTask, buildDebPackage(arch)); + const buildDebTask = task.series(prepareDebTask, buildDebPackage(arch)); buildDebTask.displayName = `vscode-linux-${arch}-build-deb`; gulp.task(buildDebTask.displayName, buildDebTask); } { const rpmArch = getRpmPackageArch(arch); - const prepareRpmTask = util.task.series(util.rimraf(`.build/linux/rpm/${rpmArch}`), prepareRpmPackage(arch)); + const prepareRpmTask = task.series(util.rimraf(`.build/linux/rpm/${rpmArch}`), prepareRpmPackage(arch)); prepareRpmTask.displayName = `vscode-linux-${arch}-prepare-rpm`; // gulp.task(prepareRpmTask.displayName, prepareRpmTask); - const buildRpmTask = util.task.series(prepareRpmTask, buildRpmPackage(arch)); + const buildRpmTask = task.series(prepareRpmTask, buildRpmPackage(arch)); buildRpmTask.displayName = `vscode-linux-${arch}-build-rpm`; gulp.task(buildRpmTask.displayName, buildRpmTask); } { - const prepareSnapTask = util.task.series(util.rimraf(`.build/linux/snap/${arch}`), prepareSnapPackage(arch)); + const prepareSnapTask = task.series(util.rimraf(`.build/linux/snap/${arch}`), prepareSnapPackage(arch)); prepareSnapTask.displayName = `vscode-linux-${arch}-prepare-snap`; gulp.task(prepareSnapTask.displayName, prepareSnapTask); - const buildSnapTask = util.task.series(prepareSnapTask, buildSnapPackage(arch)); + const buildSnapTask = task.series(prepareSnapTask, buildSnapPackage(arch)); buildSnapTask.displayName = `vscode-linux-${arch}-build-snap`; gulp.task(buildSnapTask.displayName, buildSnapTask); } diff --git a/build/gulpfile.vscode.win32.js b/build/gulpfile.vscode.win32.js index efea0701d3f..367065c4568 100644 --- a/build/gulpfile.vscode.win32.js +++ b/build/gulpfile.vscode.win32.js @@ -12,6 +12,7 @@ const assert = require('assert'); const cp = require('child_process'); const _7z = require('7zip')['7z']; const util = require('./lib/util'); +const task = require('./lib/task'); const pkg = require('../package.json'); const product = require('../product.json'); const vfs = require('vinyl-fs'); @@ -106,7 +107,7 @@ function buildWin32Setup(arch, target) { function defineWin32SetupTasks(arch, target) { const cleanTask = util.rimraf(setupDir(arch, target)); - gulp.task(`vscode-win32-${arch}-${target}-setup`, util.task.series(cleanTask, buildWin32Setup(arch, target))); + gulp.task(`vscode-win32-${arch}-${target}-setup`, task.series(cleanTask, buildWin32Setup(arch, target))); } defineWin32SetupTasks('ia32', 'system'); @@ -124,8 +125,8 @@ function archiveWin32Setup(arch) { }; } -gulp.task('vscode-win32-ia32-archive', util.task.series(util.rimraf(zipDir('ia32')), archiveWin32Setup('ia32'))); -gulp.task('vscode-win32-x64-archive', util.task.series(util.rimraf(zipDir('x64')), archiveWin32Setup('x64'))); +gulp.task('vscode-win32-ia32-archive', task.series(util.rimraf(zipDir('ia32')), archiveWin32Setup('ia32'))); +gulp.task('vscode-win32-x64-archive', task.series(util.rimraf(zipDir('x64')), archiveWin32Setup('x64'))); function copyInnoUpdater(arch) { return () => { @@ -141,5 +142,5 @@ function patchInnoUpdater(arch) { }; } -gulp.task('vscode-win32-ia32-inno-updater', util.task.series(copyInnoUpdater('ia32'), patchInnoUpdater('ia32'))); -gulp.task('vscode-win32-x64-inno-updater', util.task.series(copyInnoUpdater('x64'), patchInnoUpdater('x64'))); \ No newline at end of file +gulp.task('vscode-win32-ia32-inno-updater', task.series(copyInnoUpdater('ia32'), patchInnoUpdater('ia32'))); +gulp.task('vscode-win32-x64-inno-updater', task.series(copyInnoUpdater('x64'), patchInnoUpdater('x64'))); \ No newline at end of file diff --git a/build/lib/task.js b/build/lib/task.js new file mode 100644 index 00000000000..54abe4f020e --- /dev/null +++ b/build/lib/task.js @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; +Object.defineProperty(exports, "__esModule", { value: true }); +const fancyLog = require("fancy-log"); +const ansiColors = require("ansi-colors"); +function _isPromise(p) { + if (typeof p.then === 'function') { + return true; + } + return false; +} +function _renderTime(time) { + if (time < 1000) { + return `${time.toFixed(2)} ms`; + } + let seconds = time / 1000; + if (seconds < 60) { + return `${seconds.toFixed(1)} s`; + } + let minutes = Math.floor(seconds / 60); + seconds -= minutes * 60; + return `${minutes} m and ${seconds} s`; +} +async function _execute(task) { + const name = task.displayName || task.name || ``; + fancyLog('Starting', ansiColors.cyan(name), '...'); + const startTime = process.hrtime(); + await _doExecute(task); + const elapsedArr = process.hrtime(startTime); + const elapsedNanoseconds = (elapsedArr[0] * 1e9 + elapsedArr[1]); + fancyLog(`Finished`, ansiColors.cyan(name), 'after', ansiColors.green(_renderTime(elapsedNanoseconds / 1e6))); +} +async function _doExecute(task) { + // Always invoke as if it were a callback task + return new Promise((resolve, reject) => { + if (task.length === 1) { + // this is a calback task + task((err) => { + if (err) { + return reject(err); + } + resolve(); + }); + return; + } + const taskResult = task(); + if (typeof taskResult === 'undefined') { + // this is a sync task + resolve(); + return; + } + if (_isPromise(taskResult)) { + // this is a promise returning task + taskResult.then(resolve, reject); + return; + } + // this is a stream returning task + taskResult.on('end', _ => resolve()); + taskResult.on('error', err => reject(err)); + }); +} +function series(...tasks) { + return async () => { + for (let i = 0; i < tasks.length; i++) { + await _execute(tasks[i]); + } + }; +} +exports.series = series; +function parallel(...tasks) { + return async () => { + await Promise.all(tasks.map(t => _execute(t))); + }; +} +exports.parallel = parallel; diff --git a/build/lib/task.ts b/build/lib/task.ts new file mode 100644 index 00000000000..2fc7ae11251 --- /dev/null +++ b/build/lib/task.ts @@ -0,0 +1,92 @@ +/*--------------------------------------------------------------------------------------------- + * 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 fancyLog from 'fancy-log'; +import * as ansiColors from 'ansi-colors'; + +export type PromiseTask = () => Promise; +export type StreamTask = () => NodeJS.ReadWriteStream; +export type CallbackTask = (cb?: (err?: any) => void) => void; +export type Task = PromiseTask | StreamTask | CallbackTask; + +function _isPromise(p: Promise | NodeJS.ReadWriteStream): p is Promise { + if (typeof (p).then === 'function') { + return true; + } + return false; +} + +function _renderTime(time: number): string { + if (time < 1000) { + return `${time.toFixed(2)} ms`; + } + let seconds = time / 1000; + if (seconds < 60) { + return `${seconds.toFixed(1)} s`; + } + let minutes = Math.floor(seconds / 60); + seconds -= minutes * 60; + return `${minutes} m and ${seconds} s`; +} + +async function _execute(task: Task): Promise { + const name = (task).displayName || task.name || ``; + fancyLog('Starting', ansiColors.cyan(name), '...'); + const startTime = process.hrtime(); + await _doExecute(task); + const elapsedArr = process.hrtime(startTime); + const elapsedNanoseconds = (elapsedArr[0] * 1e9 + elapsedArr[1]); + fancyLog(`Finished`, ansiColors.cyan(name), 'after', ansiColors.green(_renderTime(elapsedNanoseconds / 1e6))); +} + +async function _doExecute(task: Task): Promise { + // Always invoke as if it were a callback task + return new Promise((resolve, reject) => { + if (task.length === 1) { + // this is a calback task + task((err) => { + if (err) { + return reject(err); + } + resolve(); + }); + return; + } + + const taskResult = task(); + + if (typeof taskResult === 'undefined') { + // this is a sync task + resolve(); + return; + } + + if (_isPromise(taskResult)) { + // this is a promise returning task + taskResult.then(resolve, reject); + return; + } + + // this is a stream returning task + taskResult.on('end', _ => resolve()); + taskResult.on('error', err => reject(err)); + }); +} + +export function series(...tasks: Task[]): PromiseTask { + return async () => { + for (let i = 0; i < tasks.length; i++) { + await _execute(tasks[i]); + } + }; +} + +export function parallel(...tasks: Task[]): PromiseTask { + return async () => { + await Promise.all(tasks.map(t => _execute(t))); + }; +} diff --git a/build/lib/util.js b/build/lib/util.js index 10d4493e78b..2ffa7123671 100644 --- a/build/lib/util.js +++ b/build/lib/util.js @@ -14,8 +14,6 @@ const fs = require("fs"); const _rimraf = require("rimraf"); const git = require("./git"); const VinylFile = require("vinyl"); -const fancyLog = require("fancy-log"); -const ansiColors = require("ansi-colors"); const NoCancellationToken = { isCancellationRequested: () => false }; function incremental(streamProvider, initial, supportsCancellation) { const input = es.through(); @@ -186,79 +184,6 @@ function rimraf(dir) { return retry; } exports.rimraf = rimraf; -var task; -(function (task_1) { - function _isPromise(p) { - if (typeof p.then === 'function') { - return true; - } - return false; - } - function _renderTime(time) { - if (time < 1000) { - return `${time.toFixed(2)} ms`; - } - let seconds = time / 1000; - if (seconds < 60) { - return `${seconds.toFixed(1)} s`; - } - let minutes = Math.floor(seconds / 60); - seconds -= minutes * 60; - return `${minutes} m and ${seconds} s`; - } - async function _execute(task) { - const name = task.displayName || task.name || ``; - fancyLog('Starting', ansiColors.cyan(name), '...'); - const startTime = process.hrtime(); - await _doExecute(task); - const elapsedArr = process.hrtime(startTime); - const elapsedNanoseconds = (elapsedArr[0] * 1e9 + elapsedArr[1]); - fancyLog(`Finished`, ansiColors.cyan(name), 'after', ansiColors.green(_renderTime(elapsedNanoseconds / 1e6))); - } - async function _doExecute(task) { - // Always invoke as if it were a callback task - return new Promise((resolve, reject) => { - if (task.length === 1) { - // this is a calback task - task((err) => { - if (err) { - return reject(err); - } - resolve(); - }); - return; - } - const taskResult = task(); - if (typeof taskResult === 'undefined') { - // this is a sync task - resolve(); - return; - } - if (_isPromise(taskResult)) { - // this is a promise returning task - taskResult.then(resolve, reject); - return; - } - // this is a stream returning task - taskResult.on('end', _ => resolve()); - taskResult.on('error', err => reject(err)); - }); - } - function series(...tasks) { - return async () => { - for (let i = 0; i < tasks.length; i++) { - await _execute(tasks[i]); - } - }; - } - task_1.series = series; - function parallel(...tasks) { - return async () => { - await Promise.all(tasks.map(t => _execute(t))); - }; - } - task_1.parallel = parallel; -})(task = exports.task || (exports.task = {})); function getVersion(root) { let version = process.env['BUILD_SOURCEVERSION']; if (!version || !/^[0-9a-f]{40}$/i.test(version)) { diff --git a/build/lib/util.ts b/build/lib/util.ts index 0df157feb54..e614410f488 100644 --- a/build/lib/util.ts +++ b/build/lib/util.ts @@ -17,8 +17,6 @@ import * as git from './git'; import * as VinylFile from 'vinyl'; import { ThroughStream } from 'through'; import * as sm from 'source-map'; -import * as fancyLog from 'fancy-log'; -import * as ansiColors from 'ansi-colors'; export interface ICancellationToken { isCancellationRequested(): boolean; @@ -239,92 +237,6 @@ export function rimraf(dir: string): (cb: any) => void { return retry; } -export type PromiseTask = () => Promise; -export type StreamTask = () => NodeJS.ReadWriteStream; -export type CallbackTask = (cb?: (err?: any) => void) => void; -export type Task = PromiseTask | StreamTask | CallbackTask; - -export namespace task { - - function _isPromise(p: Promise | NodeJS.ReadWriteStream): p is Promise { - if (typeof (p).then === 'function') { - return true; - } - return false; - } - - function _renderTime(time: number): string { - if (time < 1000) { - return `${time.toFixed(2)} ms`; - } - let seconds = time / 1000; - if (seconds < 60) { - return `${seconds.toFixed(1)} s`; - } - let minutes = Math.floor(seconds / 60); - seconds -= minutes * 60; - return `${minutes} m and ${seconds} s`; - } - - async function _execute(task: Task): Promise { - const name = (task).displayName || task.name || ``; - fancyLog('Starting', ansiColors.cyan(name), '...'); - const startTime = process.hrtime(); - await _doExecute(task); - const elapsedArr = process.hrtime(startTime); - const elapsedNanoseconds = (elapsedArr[0] * 1e9 + elapsedArr[1]); - fancyLog(`Finished`, ansiColors.cyan(name), 'after', ansiColors.green(_renderTime(elapsedNanoseconds / 1e6))); - } - - async function _doExecute(task: Task): Promise { - // Always invoke as if it were a callback task - return new Promise((resolve, reject) => { - if (task.length === 1) { - // this is a calback task - task((err) => { - if (err) { - return reject(err); - } - resolve(); - }); - return; - } - - const taskResult = task(); - - if (typeof taskResult === 'undefined') { - // this is a sync task - resolve(); - return; - } - - if (_isPromise(taskResult)) { - // this is a promise returning task - taskResult.then(resolve, reject); - return; - } - - // this is a stream returning task - taskResult.on('end', _ => resolve()); - taskResult.on('error', err => reject(err)); - }); - } - - export function series(...tasks: Task[]): PromiseTask { - return async () => { - for (let i = 0; i < tasks.length; i++) { - await _execute(tasks[i]); - } - }; - } - - export function parallel(...tasks: Task[]): PromiseTask { - return async () => { - await Promise.all(tasks.map(t => _execute(t))); - }; - } -} - export function getVersion(root: string): string | undefined { let version = process.env['BUILD_SOURCEVERSION']; diff --git a/gulpfile.js b/gulpfile.js index b41fa640399..2f43d0e73ed 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -10,26 +10,27 @@ require('events').EventEmitter.defaultMaxListeners = 100; const gulp = require('gulp'); const util = require('./build/lib/util'); +const task = require('./build/lib/task'); const path = require('path'); const compilation = require('./build/lib/compilation'); const { monacoTypecheckTask/* , monacoTypecheckWatchTask */ } = require('./build/gulpfile.editor'); const { compileExtensionsTask, watchExtensionsTask } = require('./build/gulpfile.extensions'); // Fast compile for development time -const compileClientTask = util.task.series(util.rimraf('out'), compilation.compileTask('src', 'out', false)); +const compileClientTask = task.series(util.rimraf('out'), compilation.compileTask('src', 'out', false)); compileClientTask.displayName = 'compile-client'; gulp.task(compileClientTask.displayName, compileClientTask); -const watchClientTask = util.task.series(util.rimraf('out'), compilation.watchTask('out', false)); +const watchClientTask = task.series(util.rimraf('out'), compilation.watchTask('out', false)); watchClientTask.displayName = 'watch-client'; gulp.task(watchClientTask.displayName, watchClientTask); // All -const compileTask = util.task.parallel(monacoTypecheckTask, compileClientTask, compileExtensionsTask); +const compileTask = task.parallel(monacoTypecheckTask, compileClientTask, compileExtensionsTask); compileTask.displayName = 'compile'; gulp.task(compileTask.displayName, compileTask); -gulp.task('watch', util.task.parallel(/* monacoTypecheckWatchTask, */ watchClientTask, watchExtensionsTask)); +gulp.task('watch', task.parallel(/* monacoTypecheckWatchTask, */ watchClientTask, watchExtensionsTask)); // Default gulp.task('default', compileTask); From f63494e93c5ba3b48e360d27ff0d6f264712a107 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Feb 2019 15:18:21 +0100 Subject: [PATCH 196/207] debt - clean up sep/nativeSep --- src/vs/base/common/comparers.ts | 6 +- src/vs/base/common/glob.ts | 5 +- src/vs/base/common/labels.ts | 29 ++++---- src/vs/base/common/mime.ts | 20 ++--- src/vs/base/common/paths.ts | 73 +++++++++---------- .../parts/quickopen/common/quickOpenScorer.ts | 8 +- .../test/common/quickOpenScorer.test.ts | 4 +- src/vs/platform/files/common/files.ts | 6 +- .../browser/parts/titlebar/titlebarPart.ts | 10 +-- .../debug/browser/loadedScriptsView.ts | 8 +- .../contrib/debug/common/debugModel.ts | 4 +- .../contrib/files/common/explorerModel.ts | 11 +-- .../node/watcher/win32/watcherService.ts | 7 +- .../services/label/test/label.test.ts | 4 +- 14 files changed, 95 insertions(+), 100 deletions(-) diff --git a/src/vs/base/common/comparers.ts b/src/vs/base/common/comparers.ts index 4a780995790..b5ac2014f83 100644 --- a/src/vs/base/common/comparers.ts +++ b/src/vs/base/common/comparers.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as strings from 'vs/base/common/strings'; -import * as paths from 'vs/base/common/paths'; +import { sep } from 'vs/base/common/paths.node'; import { IdleValue } from 'vs/base/common/async'; let intlFileNameCollator: IdleValue<{ collator: Intl.Collator, collatorIsNumeric: boolean }>; @@ -116,8 +116,8 @@ function comparePathComponents(one: string, other: string, caseSensitive = false } export function comparePaths(one: string, other: string, caseSensitive = false): number { - const oneParts = one.split(paths.nativeSep); - const otherParts = other.split(paths.nativeSep); + const oneParts = one.split(sep); + const otherParts = other.split(sep); const lastOne = oneParts.length - 1; const lastOther = otherParts.length - 1; diff --git a/src/vs/base/common/glob.ts b/src/vs/base/common/glob.ts index a26f954ef31..07bfdeb61c3 100644 --- a/src/vs/base/common/glob.ts +++ b/src/vs/base/common/glob.ts @@ -6,6 +6,7 @@ import * as arrays from 'vs/base/common/arrays'; import * as strings from 'vs/base/common/strings'; import * as paths from 'vs/base/common/paths'; +import { sep, posix } from 'vs/base/common/paths.node'; import { LRUCache } from 'vs/base/common/map'; import { CharCode } from 'vs/base/common/charCode'; import { isThenable } from 'vs/base/common/async'; @@ -396,8 +397,8 @@ function trivia3(pattern: string, options: IGlobOptions): ParsedStringPattern { // common patterns: **/something/else just need endsWith check, something/else just needs and equals check function trivia4and5(path: string, pattern: string, matchPathEnds: boolean): ParsedStringPattern { - const nativePath = paths.nativeSep !== paths.sep ? path.replace(ALL_FORWARD_SLASHES, paths.nativeSep) : path; - const nativePathEnd = paths.nativeSep + nativePath; + const nativePath = sep !== posix.sep ? path.replace(ALL_FORWARD_SLASHES, sep) : path; + const nativePathEnd = sep + nativePath; const parsedPattern: ParsedStringPattern = matchPathEnds ? function (path, basename) { return typeof path === 'string' && (path === nativePath || strings.endsWith(path, nativePathEnd)) ? pattern : null; } : function (path, basename) { diff --git a/src/vs/base/common/labels.ts b/src/vs/base/common/labels.ts index c9e2a9b1733..348aa895d8e 100644 --- a/src/vs/base/common/labels.ts +++ b/src/vs/base/common/labels.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { nativeSep, normalize, basename as pathsBasename, sep } from 'vs/base/common/paths'; +import { normalize, basename as pathsBasename } from 'vs/base/common/paths'; +import { sep, posix } from 'vs/base/common/paths.node'; import { endsWith, ltrim, startsWithIgnoreCase, rtrim, startsWith } from 'vs/base/common/strings'; import { Schemas } from 'vs/base/common/network'; import { isLinux, isWindows, isMacintosh } from 'vs/base/common/platform'; @@ -39,7 +40,7 @@ export function getPathLabel(resource: URI | string, userHomeProvider?: IUserHom if (isEqual(baseResource.uri, resource, !isLinux)) { pathLabel = ''; // no label if paths are identical } else { - pathLabel = normalize(ltrim(resource.path.substr(baseResource.uri.path.length), sep)!, true); + pathLabel = normalize(ltrim(resource.path.substr(baseResource.uri.path.length), posix.sep)!, true); } if (hasMultipleRoots) { @@ -112,7 +113,7 @@ export function tildify(path: string, userHome: string): string { // Keep a normalized user home path as cache to prevent accumulated string creation let normalizedUserHome = normalizedUserHomeCached.original === userHome ? normalizedUserHomeCached.normalized : undefined; if (!normalizedUserHome) { - normalizedUserHome = `${rtrim(userHome, sep)}${sep}`; + normalizedUserHome = `${rtrim(userHome, posix.sep)}${posix.sep}`; normalizedUserHomeCached = { original: userHome, normalized: normalizedUserHome }; } @@ -169,7 +170,7 @@ export function shorten(paths: string[]): string[] { let path = paths[pathIndex]; if (path === '') { - shortenedPaths[pathIndex] = `.${nativeSep}`; + shortenedPaths[pathIndex] = `.${sep}`; continue; } @@ -185,20 +186,20 @@ export function shorten(paths: string[]): string[] { if (path.indexOf(unc) === 0) { prefix = path.substr(0, path.indexOf(unc) + unc.length); path = path.substr(path.indexOf(unc) + unc.length); - } else if (path.indexOf(nativeSep) === 0) { - prefix = path.substr(0, path.indexOf(nativeSep) + nativeSep.length); - path = path.substr(path.indexOf(nativeSep) + nativeSep.length); + } else if (path.indexOf(sep) === 0) { + prefix = path.substr(0, path.indexOf(sep) + sep.length); + path = path.substr(path.indexOf(sep) + sep.length); } else if (path.indexOf(home) === 0) { prefix = path.substr(0, path.indexOf(home) + home.length); path = path.substr(path.indexOf(home) + home.length); } // pick the first shortest subpath found - const segments: string[] = path.split(nativeSep); + const segments: string[] = path.split(sep); for (let subpathLength = 1; match && subpathLength <= segments.length; subpathLength++) { for (let start = segments.length - subpathLength; match && start >= 0; start--) { match = false; - let subpath = segments.slice(start, start + subpathLength).join(nativeSep); + let subpath = segments.slice(start, start + subpathLength).join(sep); // that is unique to any other path for (let otherPathIndex = 0; !match && otherPathIndex < paths.length; otherPathIndex++) { @@ -209,7 +210,7 @@ export function shorten(paths: string[]): string[] { // Adding separator as prefix for subpath, such that 'endsWith(src, trgt)' considers subpath as directory name instead of plain string. // prefix is not added when either subpath is root directory or path[otherPathIndex] does not have multiple directories. - const subpathWithSep: string = (start > 0 && paths[otherPathIndex].indexOf(nativeSep) > -1) ? nativeSep + subpath : subpath; + const subpathWithSep: string = (start > 0 && paths[otherPathIndex].indexOf(sep) > -1) ? sep + subpath : subpath; const isOtherPathEnding: boolean = endsWith(paths[otherPathIndex], subpathWithSep); match = !isSubpathEnding || isOtherPathEnding; @@ -226,11 +227,11 @@ export function shorten(paths: string[]): string[] { // extend subpath to include disk drive prefix start = 0; subpathLength++; - subpath = segments[0] + nativeSep + subpath; + subpath = segments[0] + sep + subpath; } if (start > 0) { - result = segments[0] + nativeSep; + result = segments[0] + sep; } result = prefix + result; @@ -238,14 +239,14 @@ export function shorten(paths: string[]): string[] { // add ellipsis at the beginning if neeeded if (start > 0) { - result = result + ellipsis + nativeSep; + result = result + ellipsis + sep; } result = result + subpath; // add ellipsis at the end if needed if (start + subpathLength < segments.length) { - result = result + nativeSep + ellipsis; + result = result + sep + ellipsis; } shortenedPaths[pathIndex] = result; diff --git a/src/vs/base/common/mime.ts b/src/vs/base/common/mime.ts index dea84057f73..333357c8784 100644 --- a/src/vs/base/common/mime.ts +++ b/src/vs/base/common/mime.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as paths from 'vs/base/common/paths'; -import * as strings from 'vs/base/common/strings'; -import * as arrays from 'vs/base/common/arrays'; +import { basename, posix, extname } from 'vs/base/common/paths.node'; +import { endsWith, startsWithUTF8BOM, startsWith } from 'vs/base/common/strings'; +import { coalesce } from 'vs/base/common/arrays'; import { match } from 'vs/base/common/glob'; export const MIME_TEXT = 'text/plain'; @@ -85,7 +85,7 @@ function toTextMimeAssociationItem(association: ITextMimeAssociation): ITextMime filenameLowercase: association.filename ? association.filename.toLowerCase() : undefined, extensionLowercase: association.extension ? association.extension.toLowerCase() : undefined, filepatternLowercase: association.filepattern ? association.filepattern.toLowerCase() : undefined, - filepatternOnPath: association.filepattern ? association.filepattern.indexOf(paths.sep) >= 0 : false + filepatternOnPath: association.filepattern ? association.filepattern.indexOf(posix.sep) >= 0 : false }; } @@ -112,7 +112,7 @@ export function guessMimeTypes(path: string | null, firstLine?: string): string[ } path = path.toLowerCase(); - const filename = paths.basename(path); + const filename = basename(path); // 1.) User configured mappings have highest priority const configuredMime = guessMimeTypeByPath(path, filename, userRegisteredAssociations); @@ -166,7 +166,7 @@ function guessMimeTypeByPath(path: string, filename: string, associations: IText // Longest extension match if (association.extension) { if (!extensionMatch || association.extension.length > extensionMatch.extension!.length) { - if (strings.endsWith(filename, association.extensionLowercase!)) { + if (endsWith(filename, association.extensionLowercase!)) { extensionMatch = association; } } @@ -192,7 +192,7 @@ function guessMimeTypeByPath(path: string, filename: string, associations: IText } function guessMimeTypeByFirstline(firstLine: string): string | null { - if (strings.startsWithUTF8BOM(firstLine)) { + if (startsWithUTF8BOM(firstLine)) { firstLine = firstLine.substr(1); } @@ -234,8 +234,8 @@ export function suggestFilename(langId: string, prefix: string): string { const extensions = registeredAssociations .filter(assoc => !assoc.userConfigured && assoc.extension && assoc.id === langId) .map(assoc => assoc.extension); - const extensionsWithDotFirst = arrays.coalesce(extensions) - .filter(assoc => strings.startsWith(assoc, '.')); + const extensionsWithDotFirst = coalesce(extensions) + .filter(assoc => startsWith(assoc, '.')); if (extensionsWithDotFirst.length > 0) { return prefix + extensionsWithDotFirst[0]; @@ -299,6 +299,6 @@ const mapExtToMediaMimes: MapExtToMediaMimes = { }; export function getMediaMime(path: string): string | undefined { - const ext = paths.extname(path); + const ext = extname(path); return mapExtToMediaMimes[ext.toLowerCase()]; } diff --git a/src/vs/base/common/paths.ts b/src/vs/base/common/paths.ts index 1c32e533143..0f2e48da1d9 100644 --- a/src/vs/base/common/paths.ts +++ b/src/vs/base/common/paths.ts @@ -6,17 +6,7 @@ import { isWindows } from 'vs/base/common/platform'; import { startsWithIgnoreCase, equalsIgnoreCase } from 'vs/base/common/strings'; import { CharCode } from 'vs/base/common/charCode'; - -/** - * The forward slash path separator. - */ -export const sep = '/'; - -/** - * The native path separator depending on the OS. - */ -export const nativeSep = isWindows ? '\\' : '/'; - +import { sep, posix } from 'vs/base/common/paths.node'; function isPathSeparator(code: number) { return code === CharCode.Slash || code === CharCode.Backslash; @@ -29,7 +19,7 @@ function isPathSeparator(code: number) { * '.' is returned for empty paths or single segment relative paths (as done by NodeJS) * For paths consisting only of a root, the input path is returned */ -export function dirname(path: string, separator = nativeSep): string { +export function dirname(path: string, separator = sep): string { const len = path.length; if (len === 0) { return '.'; @@ -154,6 +144,34 @@ function streql(value: string, start: number, end: number, other: string): boole return start + other.length === end && value.indexOf(other, start) === start; } +export const join: (...parts: string[]) => string = function () { + // Not using a function with var-args because of how TS compiles + // them to JS - it would result in 2*n runtime cost instead + // of 1*n, where n is parts.length. + + let value = ''; + for (let i = 0; i < arguments.length; i++) { + let part = arguments[i]; + if (i > 0) { + // add the separater between two parts unless + // there already is one + let last = value.charCodeAt(value.length - 1); + if (!isPathSeparator(last)) { + let next = part.charCodeAt(0); + if (!isPathSeparator(next)) { + value += posix.sep; + } + } + } + value += part; + } + + return normalize(value); +}; + + +// #region extpath + /** * Computes the _root_ this path, like `getRoot('c:\files') === c:\`, * `getRoot('files:///files/path') === files:///`, @@ -227,33 +245,6 @@ export function getRoot(path: string, sep: string = '/'): string { return ''; } -export const join: (...parts: string[]) => string = function () { - // Not using a function with var-args because of how TS compiles - // them to JS - it would result in 2*n runtime cost instead - // of 1*n, where n is parts.length. - - let value = ''; - for (let i = 0; i < arguments.length; i++) { - let part = arguments[i]; - if (i > 0) { - // add the separater between two parts unless - // there already is one - let last = value.charCodeAt(value.length - 1); - if (!isPathSeparator(last)) { - let next = part.charCodeAt(0); - if (!isPathSeparator(next)) { - - value += sep; - } - } - } - value += part; - } - - return normalize(value); -}; - - /** * Check if the path follows this pattern: `\\hostname\sharename`. * @@ -343,7 +334,7 @@ export function isEqual(pathA: string, pathB: string, ignoreCase?: boolean): boo return equalsIgnoreCase(pathA, pathB); } -export function isEqualOrParent(path: string, candidate: string, ignoreCase?: boolean, separator = nativeSep): boolean { +export function isEqualOrParent(path: string, candidate: string, ignoreCase?: boolean, separator = sep): boolean { if (path === candidate) { return true; } @@ -384,3 +375,5 @@ export function isEqualOrParent(path: string, candidate: string, ignoreCase?: bo export function isWindowsDriveLetter(char0: number): boolean { return char0 >= CharCode.A && char0 <= CharCode.Z || char0 >= CharCode.a && char0 <= CharCode.z; } + +// #endregion \ No newline at end of file diff --git a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts index c1c1a82673e..66d53e1782d 100644 --- a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts +++ b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts @@ -5,7 +5,7 @@ import { compareAnything } from 'vs/base/common/comparers'; import { matchesPrefix, IMatch, matchesCamelCase, isUpper } from 'vs/base/common/filters'; -import { nativeSep } from 'vs/base/common/paths'; +import { sep } from 'vs/base/common/paths.node'; import { isWindows, isLinux } from 'vs/base/common/platform'; import { stripWildcards, equalsIgnoreCase } from 'vs/base/common/strings'; import { CharCode } from 'vs/base/common/charCode'; @@ -320,11 +320,11 @@ export function prepareQuery(original: string): IPreparedQuery { let value = stripWildcards(original).replace(/\s/g, ''); // get rid of all wildcards and whitespace if (isWindows) { - value = value.replace(/\//g, nativeSep); // Help Windows users to search for paths when using slash + value = value.replace(/\//g, sep); // Help Windows users to search for paths when using slash } const lowercase = value.toLowerCase(); - const containsPathSeparator = value.indexOf(nativeSep) >= 0; + const containsPathSeparator = value.indexOf(sep) >= 0; return { original, value, lowercase, containsPathSeparator }; } @@ -410,7 +410,7 @@ function doScoreItem(label: string, description: string | null, path: string | u if (description) { let descriptionPrefix = description; if (!!path) { - descriptionPrefix = `${description}${nativeSep}`; // assume this is a file path + descriptionPrefix = `${description}${sep}`; // assume this is a file path } const descriptionPrefixLength = descriptionPrefix.length; diff --git a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts index 1ecc9e83e42..92dc797004a 100644 --- a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts +++ b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import * as scorer from 'vs/base/parts/quickopen/common/quickOpenScorer'; import { URI } from 'vs/base/common/uri'; -import { basename, dirname, nativeSep } from 'vs/base/common/paths'; +import { basename, dirname, sep } from 'vs/base/common/paths.node'; import { isWindows } from 'vs/base/common/platform'; class ResourceAccessorClass implements scorer.IItemAccessor { @@ -815,6 +815,6 @@ suite('Quick Open Scorer', () => { assert.equal(scorer.prepareQuery('model Tester.ts').value, 'modelTester.ts'); assert.equal(scorer.prepareQuery('Model Tester.ts').lowercase, 'modeltester.ts'); assert.equal(scorer.prepareQuery('ModelTester.ts').containsPathSeparator, false); - assert.equal(scorer.prepareQuery('Model' + nativeSep + 'Tester.ts').containsPathSeparator, true); + assert.equal(scorer.prepareQuery('Model' + sep + 'Tester.ts').containsPathSeparator, true); }); }); \ No newline at end of file diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 9797cae2147..3d347c78fe0 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as paths from 'vs/base/common/paths'; +import { sep } from 'vs/base/common/paths.node'; import { URI } from 'vs/base/common/uri'; import * as glob from 'vs/base/common/glob'; import { isLinux } from 'vs/base/common/platform'; @@ -385,8 +385,8 @@ export function isParent(path: string, candidate: string, ignoreCase?: boolean): return false; } - if (candidate.charAt(candidate.length - 1) !== paths.nativeSep) { - candidate += paths.nativeSep; + if (candidate.charAt(candidate.length - 1) !== sep) { + candidate += sep; } if (ignoreCase) { diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 4b3eb7bdb87..b81bef70a48 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/titlebarpart'; -import * as paths from 'vs/base/common/paths'; +import { dirname, posix } from 'vs/base/common/paths.node'; import * as resources from 'vs/base/common/resources'; import { Part } from 'vs/workbench/browser/part'; import { ITitleService, ITitleProperties } from 'vs/workbench/services/title/common/titleService'; @@ -514,7 +514,7 @@ export class TitlebarPart extends Part implements ITitleService, ISerializableVi const actions: IAction[] = []; if (this.representedFileName) { - const segments = this.representedFileName.split(paths.sep); + const segments = this.representedFileName.split(posix.sep); for (let i = segments.length; i > 0; i--) { const isFile = (i === segments.length); @@ -523,16 +523,16 @@ export class TitlebarPart extends Part implements ITitleService, ISerializableVi pathOffset++; // for segments which are not the file name we want to open the folder } - const path = segments.slice(0, pathOffset).join(paths.sep); + const path = segments.slice(0, pathOffset).join(posix.sep); let label: string; if (!isFile) { - label = getBaseLabel(paths.dirname(path)); + label = getBaseLabel(dirname(path)); } else { label = getBaseLabel(path); } - actions.push(new ShowItemInFolderAction(path, label || paths.sep, this.windowsService)); + actions.push(new ShowItemInFolderAction(path, label || posix.sep, this.windowsService)); } } diff --git a/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts index a20df7bc802..17e710b3070 100644 --- a/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts +++ b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import * as dom from 'vs/base/browser/dom'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; -import { normalize, isAbsolute } from 'vs/base/common/paths.node'; +import { normalize, isAbsolute, posix } from 'vs/base/common/paths.node'; import { IViewletPanelOptions, ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -154,7 +154,7 @@ class BaseTreeItem { getLabel(separateRootFolder = true): string { const child = this.oneChild(); if (child) { - const sep = (this instanceof RootFolderTreeItem && separateRootFolder) ? ' • ' : '/'; + const sep = (this instanceof RootFolderTreeItem && separateRootFolder) ? ' • ' : posix.sep; return `${this._label}${sep}${child.getLabel()}`; } return this._label; @@ -317,10 +317,10 @@ class SessionTreeItem extends BaseTreeItem { folder = this.rootProvider ? this.rootProvider.getWorkspaceFolder(resource) : null; if (folder) { // strip off the root folder path - path = normalize(ltrim(resource.path.substr(folder.uri.path.length), '/')); + path = normalize(ltrim(resource.path.substr(folder.uri.path.length), posix.sep)); const hasMultipleRoots = this.rootProvider.getWorkspace().folders.length > 1; if (hasMultipleRoots) { - path = '/' + path; + path = posix.sep + path; } else { // don't show root folder folder = undefined; diff --git a/src/vs/workbench/contrib/debug/common/debugModel.ts b/src/vs/workbench/contrib/debug/common/debugModel.ts index 54afae5c265..8e0c0c9130e 100644 --- a/src/vs/workbench/contrib/debug/common/debugModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugModel.ts @@ -20,7 +20,7 @@ import { } from 'vs/workbench/contrib/debug/common/debug'; import { Source } from 'vs/workbench/contrib/debug/common/debugSource'; import { commonSuffixLength } from 'vs/base/common/strings'; -import { sep } from 'vs/base/common/paths'; +import { posix } from 'vs/base/common/paths.node'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; @@ -354,7 +354,7 @@ export class StackFrame implements IStackFrame { return this.source.name; } - const from = Math.max(0, this.source.uri.path.lastIndexOf(sep, this.source.uri.path.length - suffixLength - 1)); + const from = Math.max(0, this.source.uri.path.lastIndexOf(posix.sep, this.source.uri.path.length - suffixLength - 1)); return (from > 0 ? '...' : '') + this.source.uri.path.substr(from); } diff --git a/src/vs/workbench/contrib/files/common/explorerModel.ts b/src/vs/workbench/contrib/files/common/explorerModel.ts index 0bbd5075ca8..1520f1472cc 100644 --- a/src/vs/workbench/contrib/files/common/explorerModel.ts +++ b/src/vs/workbench/contrib/files/common/explorerModel.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import * as paths from 'vs/base/common/paths'; +import { isEqual } from 'vs/base/common/paths'; +import { posix } from 'vs/base/common/paths.node'; import * as resources from 'vs/base/common/resources'; import { ResourceMap } from 'vs/base/common/map'; import { isLinux } from 'vs/base/common/platform'; @@ -331,24 +332,24 @@ export class ExplorerItem { // For performance reasons try to do the comparison as fast as possible if (resource && this.resource.scheme === resource.scheme && equalsIgnoreCase(this.resource.authority, resource.authority) && (resources.hasToIgnoreCase(resource) ? startsWithIgnoreCase(resource.path, this.resource.path) : startsWith(resource.path, this.resource.path))) { - return this.findByPath(rtrim(resource.path, paths.sep), this.resource.path.length); + return this.findByPath(rtrim(resource.path, posix.sep), this.resource.path.length); } return null; //Unable to find } private findByPath(path: string, index: number): ExplorerItem | null { - if (paths.isEqual(rtrim(this.resource.path, paths.sep), path, !isLinux)) { + if (isEqual(rtrim(this.resource.path, posix.sep), path, !isLinux)) { return this; } if (this.isDirectory) { // Ignore separtor to more easily deduct the next name to search - while (index < path.length && path[index] === paths.sep) { + while (index < path.length && path[index] === posix.sep) { index++; } - let indexOfNextSep = path.indexOf(paths.sep, index); + let indexOfNextSep = path.indexOf(posix.sep, index); if (indexOfNextSep === -1) { // If there is no separator take the remainder of the path indexOfNextSep = path.length; diff --git a/src/vs/workbench/services/files/node/watcher/win32/watcherService.ts b/src/vs/workbench/services/files/node/watcher/win32/watcherService.ts index 688f5e23c7b..fa48cb9fd5f 100644 --- a/src/vs/workbench/services/files/node/watcher/win32/watcherService.ts +++ b/src/vs/workbench/services/files/node/watcher/win32/watcherService.ts @@ -7,9 +7,8 @@ import { IRawFileChange, toFileChangesEvent } from 'vs/workbench/services/files/ import { OutOfProcessWin32FolderWatcher } from 'vs/workbench/services/files/node/watcher/win32/csharpWatcherService'; import { FileChangesEvent } from 'vs/platform/files/common/files'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { normalize } from 'path'; +import { normalize, posix } from 'path'; import { rtrim, endsWith } from 'vs/base/common/strings'; -import { sep } from 'vs/base/common/paths'; import { Schemas } from 'vs/base/common/network'; export class FileWatcher { @@ -30,12 +29,12 @@ export class FileWatcher { } let basePath: string = normalize(this.contextService.getWorkspace().folders[0].uri.fsPath); - if (basePath && basePath.indexOf('\\\\') === 0 && endsWith(basePath, sep)) { + if (basePath && basePath.indexOf('\\\\') === 0 && endsWith(basePath, posix.sep)) { // for some weird reason, node adds a trailing slash to UNC paths // we never ever want trailing slashes as our base path unless // someone opens root ("/"). // See also https://github.com/nodejs/io.js/issues/1765 - basePath = rtrim(basePath, sep); + basePath = rtrim(basePath, posix.sep); } const watcher = new OutOfProcessWin32FolderWatcher( diff --git a/src/vs/workbench/services/label/test/label.test.ts b/src/vs/workbench/services/label/test/label.test.ts index 233d942bc6c..653740c4234 100644 --- a/src/vs/workbench/services/label/test/label.test.ts +++ b/src/vs/workbench/services/label/test/label.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { TestEnvironmentService, TestContextService, TestWindowService } from 'vs/workbench/test/workbenchTestServices'; import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; import { URI } from 'vs/base/common/uri'; -import { nativeSep } from 'vs/base/common/paths'; +import { sep } from 'vs/base/common/paths.node'; import { isWindows } from 'vs/base/common/platform'; import { LabelService } from 'vs/workbench/services/label/common/labelService'; @@ -24,7 +24,7 @@ suite('URI Label', () => { scheme: 'file', formatting: { label: '${path}', - separator: nativeSep, + separator: sep === '/' ? '/' : '\\', tildify: !isWindows, normalizeDriveLetter: isWindows } From de805f821a09c148263a0868c92c8bc4e7cc3f81 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Feb 2019 15:19:40 +0100 Subject: [PATCH 197/207] debt - fix process access --- src/vs/base/common/paths.node.ts | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/vs/base/common/paths.node.ts b/src/vs/base/common/paths.node.ts index 5034fd51da0..b770ec1a00c 100644 --- a/src/vs/base/common/paths.node.ts +++ b/src/vs/base/common/paths.node.ts @@ -24,8 +24,6 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -'use strict'; - import { isWindows } from 'vs/base/common/platform'; const CHAR_UPPERCASE_A = 65;/* A */ @@ -44,15 +42,11 @@ interface IProcess { env: object; } -declare let process: IProcess; -if (typeof process === 'undefined') { - // Logic to set up process - process = { - cwd() { return '/'; }, - env: {}, - get platform() { return isWindows ? 'win32' : 'posix'; } - }; -} +const safeProcess: IProcess = (typeof process === 'undefined') ? { + cwd() { return '/'; }, + env: {}, + get platform() { return isWindows ? 'win32' : 'posix'; } +} : process; class ErrorInvalidArgType extends Error { code: 'ERR_INVALID_ARG_TYPE'; @@ -216,14 +210,14 @@ const win32: IPath = { if (i >= 0) { path = pathSegments[i]; } else if (!resolvedDevice) { - path = process.cwd(); + path = safeProcess.cwd(); } else { // Windows has the concept of drive-specific current working // directories. If we've resolved a drive letter but not yet an // absolute path, get cwd for that drive, or the process cwd if // the drive cwd is not available. We're sure the device is not // a UNC path at this points, because UNC paths are always absolute. - path = process.env['=' + resolvedDevice] || process.cwd(); + path = safeProcess.env['=' + resolvedDevice] || safeProcess.cwd(); // Verify that a cwd was found and that it actually points // to our drive. If not, default to the drive's root. @@ -1205,7 +1199,7 @@ const posix: IPath = { path = pathSegments[i]; } else { - path = process.cwd(); + path = safeProcess.cwd(); } validateString(path, 'path'); @@ -1679,5 +1673,5 @@ const posix: IPath = { posix.win32 = win32.win32 = win32; posix.posix = win32.posix = posix; -const impl = (process.platform === 'win32' ? win32 : posix) as IExportedPath; +const impl = (safeProcess.platform === 'win32' ? win32 : posix) as IExportedPath; export = impl; From 18f629986f15adec0712f692737489c914d2b493 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Feb 2019 15:27:15 +0100 Subject: [PATCH 198/207] paths - avoid any[] --- src/vs/base/common/paths.node.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/base/common/paths.node.ts b/src/vs/base/common/paths.node.ts index b770ec1a00c..e0133238ffb 100644 --- a/src/vs/base/common/paths.node.ts +++ b/src/vs/base/common/paths.node.ts @@ -178,8 +178,8 @@ function _format(sep, pathObject) { interface IPath { normalize(path: string): string; isAbsolute(path: string): boolean; - join(...paths: any[]): string; - resolve(...pathSegments: any[]): string; + join(...paths: string[]): string; + resolve(...pathSegments: string[]): string; relative(from: string, to: string): string; dirname(path: string): string; basename(path: string, ext?: string): string; @@ -200,7 +200,7 @@ interface IExportedPath extends IPath { const win32: IPath = { // path.resolve([from ...], to) - resolve(...pathSegments: any[]): string { + resolve(...pathSegments: string[]): string { let resolvedDevice = ''; let resolvedTail = ''; let resolvedAbsolute = false; @@ -499,7 +499,7 @@ const win32: IPath = { return false; }, - join(...paths: any[]): string { + join(...paths: string[]): string { if (paths.length === 0) { return '.'; } @@ -1189,7 +1189,7 @@ const win32: IPath = { const posix: IPath = { // path.resolve([from ...], to) - resolve(...pathSegments: any[]): string { + resolve(...pathSegments: string[]): string { let resolvedPath = ''; let resolvedAbsolute = false; @@ -1266,7 +1266,7 @@ const posix: IPath = { return path.length > 0 && path.charCodeAt(0) === CHAR_FORWARD_SLASH; }, - join(...paths: any[]): string { + join(...paths: string[]): string { if (paths.length === 0) { return '.'; } From be2fcbf5bdb57d3ab2f706a40ce8eaab16e6afc0 Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Tue, 12 Feb 2019 15:31:52 +0100 Subject: [PATCH 199/207] use latest DAP with data breakpoints --- build/builtInExtensions.json | 2 +- package.json | 2 +- .../contrib/debug/common/debugProtocol.d.ts | 84 +++++++++++++++++-- yarn.lock | 8 +- 4 files changed, 85 insertions(+), 11 deletions(-) diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index 2c97ed17625..1465582fb1d 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -1,7 +1,7 @@ [ { "name": "ms-vscode.node-debug", - "version": "1.31.2", + "version": "1.32.1", "repo": "https://github.com/Microsoft/vscode-node-debug", "metadata": { "id": "b6ded8fb-a0a0-4c1c-acbd-ab2a3bc995a6", diff --git a/package.json b/package.json index ecfa099e064..d1569d3f72c 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "sudo-prompt": "8.2.0", "v8-inspect-profiler": "^0.0.20", "vscode-chokidar": "1.6.5", - "vscode-debugprotocol": "1.33.0", + "vscode-debugprotocol": "^1.34.0-pre.0", "vscode-nsfw": "1.1.1", "vscode-proxy-agent": "0.3.0", "vscode-ripgrep": "^1.2.5", diff --git a/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts b/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts index 34b2e1ed4b3..a6a1215b778 100644 --- a/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts +++ b/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts @@ -83,7 +83,7 @@ declare module DebugProtocol { body: { /** The reason for the event. For backward compatibility this string is shown in the UI if the 'description' attribute is missing (but it must not be translated). - Values: 'step', 'breakpoint', 'exception', 'pause', 'entry', 'goto', etc. + Values: 'step', 'breakpoint', 'exception', 'pause', 'entry', 'goto', 'function breakpoint', 'data breakpoint', etc. */ reason: string; /** The full reason for the event, e.g. 'Paused on exception'. This string is shown in the UI as is and must be translated. */ @@ -487,9 +487,9 @@ declare module DebugProtocol { } /** SetFunctionBreakpoints request; value of command field is 'setFunctionBreakpoints'. - Sets multiple function breakpoints and clears all previous function breakpoints. - To clear all function breakpoint, specify an empty array. - When a function breakpoint is hit, a 'stopped' event (event type 'function breakpoint') is generated. + Replaces all existing function breakpoints with new function breakpoints. + To clear all function breakpoints, specify an empty array. + When a function breakpoint is hit, a 'stopped' event (with reason 'function breakpoint') is generated. */ export interface SetFunctionBreakpointsRequest extends Request { // command: 'setFunctionBreakpoints'; @@ -532,6 +532,62 @@ declare module DebugProtocol { export interface SetExceptionBreakpointsResponse extends Response { } + /** DataBreakpointInfo request; value of command field is 'dataBreakpointInfo'. + Obtains information on a possible data breakpoint that could be set on an expression or variable. + */ + export interface DataBreakpointInfoRequest extends Request { + // command: 'dataBreakpointInfo'; + arguments: DataBreakpointInfoArguments; + } + + /** Arguments for 'dataBreakpointInfo' request. */ + export interface DataBreakpointInfoArguments { + /** Reference to the Variable container if the data breakpoint is requested for a child of the container. */ + variablesReference?: number; + /** The name of the Variable's child to obtain data breakpoint information for. If variableReference isn’t provided, this can be an expression. */ + name: string; + } + + /** Response to 'dataBreakpointInfo' request. */ + export interface DataBreakpointInfoResponse extends Response { + body: { + /** An identifier for the data on which a data breakpoint can be registered with the setDataBreakpoints request or null if no data breakpoint is available. */ + dataId: string | null; + /** UI string that describes on what data the breakpoint is set on or why a data breakpoint is not available. */ + description: string; + /** Optional attribute listing the available access types for a potential data breakpoint. A UI frontend could surface this information. */ + accessTypes?: DataBreakpointAccessType[]; + /** Optional attribute indicating that a potential data breakpoint could be persisted across sessions. */ + canPersist?: boolean; + }; + } + + /** SetDataBreakpoints request; value of command field is 'setDataBreakpoints'. + Replaces all existing data breakpoints with new data breakpoints. + To clear all data breakpoints, specify an empty array. + When a data breakpoint is hit, a 'stopped' event (with reason 'data breakpoint') is generated. + */ + export interface SetDataBreakpointsRequest extends Request { + // command: 'setDataBreakpoints'; + arguments: SetDataBreakpointsArguments; + } + + /** Arguments for 'setDataBreakpoints' request. */ + export interface SetDataBreakpointsArguments { + /** The contents of this array replaces all existing data breakpoints. An empty array clears all data breakpoints. */ + breakpoints: DataBreakpoint[]; + } + + /** Response to 'setDataBreakpoints' request. + Returned is information about each breakpoint created by this request. + */ + export interface SetDataBreakpointsResponse extends Response { + body: { + /** Information about the data breakpoints. The array elements correspond to the elements of the input argument 'breakpoints' array. */ + breakpoints: Breakpoint[]; + }; + } + /** Continue request; value of command field is 'continue'. The request starts the debuggee to run again. */ @@ -812,7 +868,7 @@ declare module DebugProtocol { export interface SetVariableArguments { /** The reference of the variable container. */ variablesReference: number; - /** The name of the variable. */ + /** The name of the variable in the container. */ name: string; /** The value of the variable. */ value: string; @@ -1200,6 +1256,8 @@ declare module DebugProtocol { supportsSetExpression?: boolean; /** The debug adapter supports the 'terminate' request. */ supportsTerminateRequest?: boolean; + /** The debug adapter supports data breakpoints. */ + supportsDataBreakpoints?: boolean; } /** An ExceptionBreakpointsFilter is shown in the UI as an option for configuring how exceptions are dealt with. */ @@ -1413,6 +1471,7 @@ declare module DebugProtocol { 'interface': Indicates that the object is an interface. 'mostDerivedClass': Indicates that the object is the most derived class. 'virtual': Indicates that the object is virtual, that means it is a synthetic object introduced by the adapter for rendering purposes, e.g. an index range for large arrays. + 'dataBreakpoint': Indicates that a data breakpoint is registered for the object. etc. */ kind?: string; @@ -1458,6 +1517,21 @@ declare module DebugProtocol { hitCondition?: string; } + /** This enumeration defines all possible access types for data breakpoints. */ + export type DataBreakpointAccessType = 'read' | 'write' | 'readWrite'; + + /** Properties of a data breakpoint passed to the setDataBreakpoints request. */ + export interface DataBreakpoint { + /** An id representing the data. This id is returned from the dataBreakpointInfo request. */ + dataId: string; + /** The access type of the data. */ + accessType?: DataBreakpointAccessType; + /** An optional expression for conditional breakpoints. */ + condition?: string; + /** An optional expression that controls how many hits of the breakpoint are ignored. The backend is expected to interpret the expression as needed. */ + hitCondition?: string; + } + /** Information about a Breakpoint created in setBreakpoints or setFunctionBreakpoints. */ export interface Breakpoint { /** An optional identifier for the breakpoint. It is needed if breakpoint events are used to update or remove breakpoints. */ diff --git a/yarn.lock b/yarn.lock index 35c689a7ae9..3fdec48c164 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9342,10 +9342,10 @@ vscode-chokidar@1.6.5: optionalDependencies: vscode-fsevents "0.3.10" -vscode-debugprotocol@1.33.0: - version "1.33.0" - resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.33.0.tgz#334d2e76ac965f33437a0298441facdcad377d99" - integrity sha512-d+l4lrEz6OP2kmGpweqe37x9H7icAMV8S4m8azTWGAIlNJxBP4rlSTnZa7NMLcbgqWkWG9lTGY7fJ+rSPaW7yg== +vscode-debugprotocol@^1.34.0-pre.0: + version "1.34.0-pre.0" + resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.34.0-pre.0.tgz#ba2110875f1127c9ce773351e1054b85fab67c00" + integrity sha512-JjrlTpUG7uFO5yctHQcx8zLbnyw30cUMVaKw0GEiski0lJ1w8A8zXP18MUqDJN7dMHqcB4r6PsuicUOgjLIFJA== vscode-fsevents@0.3.10: version "0.3.10" From 85eaaf4ad8318220b601be2b1234b74b4c608be4 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 12 Feb 2019 15:52:50 +0100 Subject: [PATCH 200/207] Fix #68315 --- src/vs/base/parts/tree/browser/treeDefaults.ts | 2 +- .../workbench/contrib/markers/electron-browser/markersPanel.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/base/parts/tree/browser/treeDefaults.ts b/src/vs/base/parts/tree/browser/treeDefaults.ts index 8d30a79e501..542eb083f5c 100644 --- a/src/vs/base/parts/tree/browser/treeDefaults.ts +++ b/src/vs/base/parts/tree/browser/treeDefaults.ts @@ -553,7 +553,7 @@ export class DefaultTreestyler implements _.ITreeStyler { export class CollapseAllAction extends Action { constructor(private viewer: _.ITree, enabled: boolean) { - super('vs.tree.collapse', nls.localize('collapse', "Collapse"), 'monaco-tree-action collapse-all', enabled); + super('vs.tree.collapse', nls.localize('collapse all', "Collapse All"), 'monaco-tree-action collapse-all', enabled); } public run(context?: any): Promise { diff --git a/src/vs/workbench/contrib/markers/electron-browser/markersPanel.ts b/src/vs/workbench/contrib/markers/electron-browser/markersPanel.ts index 77c6c4e6592..771ae04db82 100644 --- a/src/vs/workbench/contrib/markers/electron-browser/markersPanel.ts +++ b/src/vs/workbench/contrib/markers/electron-browser/markersPanel.ts @@ -402,7 +402,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { } private createActions(): void { - this.collapseAllAction = new Action('vs.tree.collapse', localize('collapse', "Collapse"), 'monaco-tree-action collapse-all', true, async () => { + this.collapseAllAction = new Action('vs.tree.collapse', localize('collapseAll', "Collapse All"), 'monaco-tree-action collapse-all', true, async () => { this.tree.collapseAll(); this.tree.setSelection([]); this.tree.setFocus([]); From 810a54ddef4a2ad9eb188c5b2ed9a62163bb9345 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 12 Feb 2019 15:57:58 +0100 Subject: [PATCH 201/207] Fix gulp global path for tasks and remove quotes in favor of community PR --- extensions/gulp/src/main.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/gulp/src/main.ts b/extensions/gulp/src/main.ts index ffe7bd7d9a2..1b89a4bdb1a 100644 --- a/extensions/gulp/src/main.ts +++ b/extensions/gulp/src/main.ts @@ -120,7 +120,7 @@ class FolderDetector { let gulpCommand: string; let platform = process.platform; if (platform === 'win32' && await exists(path.join(rootPath!, 'node_modules', '.bin', 'gulp.cmd'))) { - const globalGulp = path.join(process.env.APPDATA ? process.env.APPDATA : '', 'npm - Copy', 'gulp.cmd'); + const globalGulp = path.join(process.env.APPDATA ? process.env.APPDATA : '', 'npm', 'gulp.cmd'); if (await exists(globalGulp)) { gulpCommand = globalGulp; } else { @@ -132,7 +132,7 @@ class FolderDetector { gulpCommand = 'gulp'; } - let commandLine = `\"${gulpCommand}\" --tasks-simple --no-color`; + let commandLine = `${gulpCommand} --tasks-simple --no-color`; try { let { stdout, stderr } = await exec(commandLine, { cwd: rootPath }); if (stderr && stderr.length > 0) { From 6f11645ee2fa2c26c772a527cf1f532b8b33d7e3 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Feb 2019 16:09:01 +0100 Subject: [PATCH 202/207] paths - adopt node-path.dirname() --- src/vs/base/common/paths.ts | 36 ------------------- src/vs/base/common/resources.ts | 10 ++++-- src/vs/base/test/common/paths.node.test.ts | 32 ++++++++++++++++- src/vs/base/test/common/paths.test.ts | 30 ---------------- .../contrib/snippet/snippetVariables.ts | 2 +- .../workbench/api/node/extHostDebugService.ts | 2 +- .../execution.contribution.ts | 2 +- .../electron-browser/markersTreeViewer.ts | 8 ++--- .../contrib/output/browser/logViewer.ts | 4 +-- .../output/electron-browser/outputServices.ts | 3 +- .../search/browser/searchResultsView.ts | 2 +- .../snippets/browser/configureSnippets.ts | 3 +- .../workbench/electron-browser/workbench.ts | 2 +- .../configurationResolverService.ts | 2 +- .../{node => common}/variableResolver.ts | 5 ++- .../configurationResolverService.test.ts | 2 +- .../textfile/common/textFileService.ts | 10 +++--- 17 files changed, 62 insertions(+), 93 deletions(-) rename src/vs/workbench/services/configurationResolver/{electron-browser => browser}/configurationResolverService.ts (99%) rename src/vs/workbench/services/configurationResolver/{node => common}/variableResolver.ts (98%) diff --git a/src/vs/base/common/paths.ts b/src/vs/base/common/paths.ts index 0f2e48da1d9..16745874d5a 100644 --- a/src/vs/base/common/paths.ts +++ b/src/vs/base/common/paths.ts @@ -12,42 +12,6 @@ function isPathSeparator(code: number) { return code === CharCode.Slash || code === CharCode.Backslash; } -/** - * @param path the path to get the dirname from - * @param separator the separator to use - * @returns the directory name of a path. - * '.' is returned for empty paths or single segment relative paths (as done by NodeJS) - * For paths consisting only of a root, the input path is returned - */ -export function dirname(path: string, separator = sep): string { - const len = path.length; - if (len === 0) { - return '.'; - } else if (len === 1) { - return isPathSeparator(path.charCodeAt(0)) ? path : '.'; - } - const root = getRoot(path, separator); - let rootLength = root.length; - if (rootLength >= len) { - return path; // matched the root - } - if (rootLength === 0 && isPathSeparator(path.charCodeAt(0))) { - rootLength = 1; // absolute paths stay absolute paths. - } - - let i = len - 1; - if (i > rootLength) { - i--; // no need to look at the last character. If it's a trailing slash, we ignore it. - while (i > rootLength && !isPathSeparator(path.charCodeAt(i))) { - i--; - } - } - if (i === 0) { - return '.'; // it was a relative path with a single segment, no root. Nodejs returns '.' here. - } - return path.substr(0, i); -} - /** * @returns the base name of a path. */ diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts index 3066303e68f..2bc29f13a17 100644 --- a/src/vs/base/common/resources.ts +++ b/src/vs/base/common/resources.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as paths from 'vs/base/common/paths'; -import { isAbsolute } from 'vs/base/common/paths.node'; +import { isAbsolute, posix, dirname as pathDirname } from 'vs/base/common/paths.node'; import { URI } from 'vs/base/common/uri'; import { equalsIgnoreCase } from 'vs/base/common/strings'; import { Schemas } from 'vs/base/common/network'; @@ -67,6 +67,10 @@ export function basename(resource: URI): string { return paths.basename(resource.path); } +export function extname(resource: URI): string { + return paths.extname(resource.path); +} + /** * Return a URI representing the directory of a URI path. * @@ -78,9 +82,9 @@ export function dirname(resource: URI): URI | null { return resource; } if (resource.scheme === Schemas.file) { - return URI.file(paths.dirname(fsPath(resource))); + return URI.file(pathDirname(fsPath(resource))); } - let dirname = paths.dirname(resource.path, '/'); + let dirname = posix.dirname(resource.path); if (resource.authority && dirname.length && dirname.charCodeAt(0) !== CharCode.Slash) { return null; // If a URI contains an authority component, then the path component must either be empty or begin with a CharCode.Slash ("/") character } diff --git a/src/vs/base/test/common/paths.node.test.ts b/src/vs/base/test/common/paths.node.test.ts index 08520ad015a..94174920850 100644 --- a/src/vs/base/test/common/paths.node.test.ts +++ b/src/vs/base/test/common/paths.node.test.ts @@ -223,6 +223,36 @@ suite('Paths (Node Implementation)', () => { assert.strictEqual(path.win32.dirname('/'), '/'); assert.strictEqual(path.win32.dirname('////'), '/'); assert.strictEqual(path.win32.dirname('foo'), '.'); + + // Tests from VSCode + + function assertDirname(p: string, expected: string, win = false) { + const actual = win ? path.win32.dirname(p) : path.posix.dirname(p); + + if (actual !== expected) { + assert.fail(`${p}: expected: ${expected}, ours: ${actual}`); + } + } + + assertDirname('foo/bar', 'foo'); + assertDirname('foo\\bar', 'foo', true); + assertDirname('/foo/bar', '/foo'); + assertDirname('\\foo\\bar', '\\foo', true); + assertDirname('/foo', '/'); + assertDirname('\\foo', '\\', true); + assertDirname('/', '/'); + assertDirname('\\', '\\', true); + assertDirname('foo', '.'); + assertDirname('f', '.'); + assertDirname('f/', '.'); + assertDirname('/folder/', '/'); + assertDirname('c:\\some\\file.txt', 'c:\\some', true); + assertDirname('c:\\some', 'c:\\', true); + assertDirname('c:\\', 'c:\\', true); + assertDirname('c:', 'c:', true); + assertDirname('\\\\server\\share\\some\\path', '\\\\server\\share\\some', true); + assertDirname('\\\\server\\share\\some', '\\\\server\\share\\', true); + assertDirname('\\\\server\\share\\', '\\\\server\\share\\', true); }); test('extname', () => { @@ -629,7 +659,7 @@ suite('Paths (Node Implementation)', () => { assert.strictEqual(path.posix.isAbsolute('bar/'), false); assert.strictEqual(path.posix.isAbsolute('./baz'), false); - // Tests from us: + // Tests from VSCode: // Absolute Paths [ diff --git a/src/vs/base/test/common/paths.test.ts b/src/vs/base/test/common/paths.test.ts index 5e0c0110d22..fb43b36c767 100644 --- a/src/vs/base/test/common/paths.test.ts +++ b/src/vs/base/test/common/paths.test.ts @@ -8,36 +8,6 @@ import * as platform from 'vs/base/common/platform'; suite('Paths', () => { - function assertDirname(path: string, expected: string, win = false) { - const actual = paths.dirname(path, win ? '\\' : '/'); - - if (actual !== expected) { - assert.fail(`${path}: expected: ${expected}, ours: ${actual}`); - } - } - - test('dirname', () => { - assertDirname('foo/bar', 'foo'); - assertDirname('foo\\bar', 'foo', true); - assertDirname('/foo/bar', '/foo'); - assertDirname('\\foo\\bar', '\\foo', true); - assertDirname('/foo', '/'); - assertDirname('\\foo', '\\', true); - assertDirname('/', '/'); - assertDirname('\\', '\\', true); - assertDirname('foo', '.'); - assertDirname('f', '.'); - assertDirname('f/', '.'); - assertDirname('/folder/', '/'); - assertDirname('c:\\some\\file.txt', 'c:\\some', true); - assertDirname('c:\\some', 'c:\\', true); - assertDirname('c:\\', 'c:\\', true); - assertDirname('c:', 'c:', true); - assertDirname('\\\\server\\share\\some\\path', '\\\\server\\share\\some', true); - assertDirname('\\\\server\\share\\some', '\\\\server\\share\\', true); - assertDirname('\\\\server\\share\\', '\\\\server\\share\\', true); - }); - test('normalize', () => { assert.equal(paths.normalize(''), '.'); assert.equal(paths.normalize('.'), '.'); diff --git a/src/vs/editor/contrib/snippet/snippetVariables.ts b/src/vs/editor/contrib/snippet/snippetVariables.ts index 9545c299890..7b7b9546a3c 100644 --- a/src/vs/editor/contrib/snippet/snippetVariables.ts +++ b/src/vs/editor/contrib/snippet/snippetVariables.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { basename, dirname } from 'vs/base/common/paths'; +import { basename, dirname } from 'vs/base/common/paths.node'; import { ITextModel } from 'vs/editor/common/model'; import { Selection } from 'vs/editor/common/core/selection'; import { VariableResolver, Variable, Text } from 'vs/editor/contrib/snippet/snippetParser'; diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index 9cff4eb3b9c..75c0c7cb7b3 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -22,7 +22,7 @@ import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumen import { ITerminalSettings, IDebuggerContribution, IConfig, IDebugAdapter, IDebugAdapterServer, IDebugAdapterExecutable, IAdapterDescriptor } from 'vs/workbench/contrib/debug/common/debug'; import { getTerminalLauncher, hasChildProcesses, prepareCommand } from 'vs/workbench/contrib/debug/node/terminals'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/node/variableResolver'; +import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver'; import { ExtHostConfiguration, ExtHostConfigProvider } from './extHostConfiguration'; import { convertToVSCPaths, convertToDAPaths, isDebuggerMainContribution } from 'vs/workbench/contrib/debug/common/debugUtils'; import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService'; diff --git a/src/vs/workbench/contrib/execution/electron-browser/execution.contribution.ts b/src/vs/workbench/contrib/execution/electron-browser/execution.contribution.ts index f23572852da..5eca32359a2 100644 --- a/src/vs/workbench/contrib/execution/electron-browser/execution.contribution.ts +++ b/src/vs/workbench/contrib/execution/electron-browser/execution.contribution.ts @@ -8,7 +8,7 @@ import * as env from 'vs/base/common/platform'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import * as paths from 'vs/base/common/paths'; +import * as paths from 'vs/base/common/paths.node'; import { URI as uri } from 'vs/base/common/uri'; import { ITerminalService } from 'vs/workbench/contrib/execution/common/execution'; import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; diff --git a/src/vs/workbench/contrib/markers/electron-browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/electron-browser/markersTreeViewer.ts index 5dc45a8645f..9fb89f9d889 100644 --- a/src/vs/workbench/contrib/markers/electron-browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/electron-browser/markersTreeViewer.ts @@ -5,7 +5,7 @@ import * as dom from 'vs/base/browser/dom'; import * as network from 'vs/base/common/network'; -import * as paths from 'vs/base/common/paths'; +import * as paths from 'vs/base/common/paths.node'; import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; import { ResourceLabels, IResourceLabel } from 'vs/workbench/browser/labels'; import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; @@ -392,7 +392,7 @@ export class RelatedInformationRenderer implements ITreeRenderer { return false; } - const uriMatches = FilterOptions._filter(this.options.textFilter, paths.basename(resourceMarkers.resource.fsPath)); + const uriMatches = FilterOptions._filter(this.options.textFilter, basename(resourceMarkers.resource)); if (this.options.textFilter && uriMatches) { return { visibility: true, data: { type: FilterDataType.ResourceMarkers, uriMatches } }; @@ -476,7 +476,7 @@ export class Filter implements ITreeFilter { return true; } - const uriMatches = FilterOptions._filter(this.options.textFilter, paths.basename(relatedInformation.raw.resource.fsPath)); + const uriMatches = FilterOptions._filter(this.options.textFilter, basename(relatedInformation.raw.resource)); const messageMatches = FilterOptions._messageFilter(this.options.textFilter, paths.basename(relatedInformation.raw.message)); if (uriMatches || messageMatches) { diff --git a/src/vs/workbench/contrib/output/browser/logViewer.ts b/src/vs/workbench/contrib/output/browser/logViewer.ts index 6fb19a3e569..12bb9a1edea 100644 --- a/src/vs/workbench/contrib/output/browser/logViewer.ts +++ b/src/vs/workbench/contrib/output/browser/logViewer.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as paths from 'vs/base/common/paths'; +import { dirname, basename } from 'vs/base/common/paths.node'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IStorageService } from 'vs/platform/storage/common/storage'; @@ -30,7 +30,7 @@ export class LogViewerInput extends ResourceEditorInput { @ITextModelService textModelResolverService: ITextModelService, @IHashService hashService: IHashService ) { - super(paths.basename(outputChannelDescriptor.file.path), paths.dirname(outputChannelDescriptor.file.path), URI.from({ scheme: LOG_SCHEME, path: outputChannelDescriptor.id }), textModelResolverService, hashService); + super(basename(outputChannelDescriptor.file.path), dirname(outputChannelDescriptor.file.path), URI.from({ scheme: LOG_SCHEME, path: outputChannelDescriptor.id }), textModelResolverService, hashService); } public getTypeId(): string { diff --git a/src/vs/workbench/contrib/output/electron-browser/outputServices.ts b/src/vs/workbench/contrib/output/electron-browser/outputServices.ts index b18649d3cf1..13f4fca8889 100644 --- a/src/vs/workbench/contrib/output/electron-browser/outputServices.ts +++ b/src/vs/workbench/contrib/output/electron-browser/outputServices.ts @@ -5,6 +5,7 @@ import * as nls from 'vs/nls'; import * as paths from 'vs/base/common/paths'; +import { dirname } from 'vs/base/common/paths.node'; import * as strings from 'vs/base/common/strings'; import * as extfs from 'vs/base/node/extfs'; import { Event, Emitter } from 'vs/base/common/event'; @@ -189,7 +190,7 @@ class OutputChannelBackedByFile extends AbstractFileOutputChannel implements Out // Use one rotating file to check for main file reset this.appender = new OutputAppender(this.id, this.file.fsPath); this.rotatingFilePath = `${outputChannelDescriptor.id}.1.log`; - this._register(watchOutputDirectory(paths.dirname(this.file.fsPath), logService, (eventType, file) => this.onFileChangedInOutputDirector(eventType, file))); + this._register(watchOutputDirectory(dirname(this.file.fsPath), logService, (eventType, file) => this.onFileChangedInOutputDirector(eventType, file))); this.resettingDelayer = new ThrottledDelayer(50); } diff --git a/src/vs/workbench/contrib/search/browser/searchResultsView.ts b/src/vs/workbench/contrib/search/browser/searchResultsView.ts index aa275dc8c4d..db9031d025e 100644 --- a/src/vs/workbench/contrib/search/browser/searchResultsView.ts +++ b/src/vs/workbench/contrib/search/browser/searchResultsView.ts @@ -11,7 +11,7 @@ import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; import { ITreeNode, ITreeRenderer, ITreeDragAndDrop, ITreeDragOverReaction } from 'vs/base/browser/ui/tree/tree'; import { IAction } from 'vs/base/common/actions'; import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; -import * as paths from 'vs/base/common/paths'; +import * as paths from 'vs/base/common/paths.node'; import * as resources from 'vs/base/common/resources'; import * as nls from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; diff --git a/src/vs/workbench/contrib/snippets/browser/configureSnippets.ts b/src/vs/workbench/contrib/snippets/browser/configureSnippets.ts index 45322bd3c09..b5eab1644bd 100644 --- a/src/vs/workbench/contrib/snippets/browser/configureSnippets.ts +++ b/src/vs/workbench/contrib/snippets/browser/configureSnippets.ts @@ -8,7 +8,8 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IWindowService } from 'vs/platform/windows/common/windows'; -import { join, basename, dirname, extname } from 'vs/base/common/paths'; +import { join } from 'vs/base/common/paths'; +import { basename, dirname, extname } from 'vs/base/common/paths.node'; import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { timeout } from 'vs/base/common/async'; import { IOpenerService } from 'vs/platform/opener/common/opener'; diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 8771834095d..01cd5f2870c 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -136,6 +136,7 @@ import { OpenerService } from 'vs/editor/browser/services/openerService'; import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity'; import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; import { HistoryService } from 'vs/workbench/services/history/browser/history'; +import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; // import@node import product from 'vs/platform/node/product'; @@ -169,7 +170,6 @@ import { LocalizationsChannelClient } from 'vs/platform/localizations/node/local import { ContextMenuService as NativeContextMenuService } from 'vs/workbench/services/contextview/electron-browser/contextmenuService'; import { WorkbenchKeybindingService } from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; import { RemoteFileService } from 'vs/workbench/services/files/electron-browser/remoteFileService'; -import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/electron-browser/configurationResolverService'; import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService'; import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService'; import { ToggleDevToolsAction } from 'vs/workbench/electron-browser/actions/developerActions'; diff --git a/src/vs/workbench/services/configurationResolver/electron-browser/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts similarity index 99% rename from src/vs/workbench/services/configurationResolver/electron-browser/configurationResolverService.ts rename to src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts index cdc76396f9d..6a1337c5987 100644 --- a/src/vs/workbench/services/configurationResolver/electron-browser/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts @@ -16,7 +16,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { ICommandService } from 'vs/platform/commands/common/commands'; import { IWorkspaceFolder, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/node/variableResolver'; +import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { IQuickInputService, IInputOptions, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput'; diff --git a/src/vs/workbench/services/configurationResolver/node/variableResolver.ts b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts similarity index 98% rename from src/vs/workbench/services/configurationResolver/node/variableResolver.ts rename to src/vs/workbench/services/configurationResolver/common/variableResolver.ts index 7e86f0e4185..e4079c389b9 100644 --- a/src/vs/workbench/services/configurationResolver/node/variableResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts @@ -3,11 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as paths from 'vs/base/common/paths'; +import * as paths from 'vs/base/common/paths.node'; import * as types from 'vs/base/common/types'; import * as objects from 'vs/base/common/objects'; import { IStringDictionary } from 'vs/base/common/collections'; -import { relative } from 'path'; import { IProcessEnvironment, isWindows, isMacintosh, isLinux } from 'vs/base/common/platform'; import { normalizeDriveLetter } from 'vs/base/common/labels'; import { localize } from 'vs/nls'; @@ -237,7 +236,7 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe case 'relativeFile': if (folderUri) { - return resolvedValue = paths.normalize(relative(folderUri.fsPath, filePath)); + return resolvedValue = paths.posix.normalize(paths.relative(folderUri.fsPath, filePath)); } return resolvedValue = filePath; diff --git a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts index 9dd5e6f18ad..23106fa0871 100644 --- a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts @@ -9,7 +9,7 @@ import * as platform from 'vs/base/common/platform'; import { IConfigurationService, getConfigurationValue, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; -import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/electron-browser/configurationResolverService'; +import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { TestEnvironmentService, TestEditorService, TestContextService } from 'vs/workbench/test/workbenchTestServices'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index 146db7414b0..ee6f671ab48 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -31,7 +31,7 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c import { createTextBufferFactoryFromSnapshot, createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; import { IModelService } from 'vs/editor/common/services/modelService'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; -import { isEqualOrParent, isEqual, joinPath, dirname } from 'vs/base/common/resources'; +import { isEqualOrParent, isEqual, joinPath, dirname, extname, basename } from 'vs/base/common/resources'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { getConfirmMessage, IDialogService, IFileDialogService, ISaveDialogOptions, IConfirmation } from 'vs/platform/dialogs/common/dialogs'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -145,7 +145,7 @@ export class TextFileService extends Disposable implements ITextFileService { interface IFilter { name: string; extensions: string[]; } // Build the file filter by using our known languages - const ext: string = defaultUri ? paths.extname(defaultUri.path) : undefined; + const ext: string = defaultUri ? extname(defaultUri) : undefined; let matchingFilter: IFilter; const filters: IFilter[] = coalesce(this.modeService.getRegisteredLanguageNames().map(languageName => { const extensions = this.modeService.getExtensions(languageName); @@ -193,7 +193,7 @@ export class TextFileService extends Disposable implements ITextFileService { return Promise.resolve(ConfirmResult.DONT_SAVE); } - const message = resourcesToConfirm.length === 1 ? nls.localize('saveChangesMessage', "Do you want to save the changes you made to {0}?", paths.basename(resourcesToConfirm[0].fsPath)) + const message = resourcesToConfirm.length === 1 ? nls.localize('saveChangesMessage', "Do you want to save the changes you made to {0}?", basename(resourcesToConfirm[0])) : getConfirmMessage(nls.localize('saveChangesMessages', "Do you want to save the changes to the following {0} files?", resourcesToConfirm.length), resourcesToConfirm); const buttons: string[] = [ @@ -216,8 +216,8 @@ export class TextFileService extends Disposable implements ITextFileService { confirmOverwrite(resource: URI): Promise { const confirm: IConfirmation = { - message: nls.localize('confirmOverwrite', "'{0}' already exists. Do you want to replace it?", paths.basename(resource.fsPath)), - detail: nls.localize('irreversible', "A file or folder with the same name already exists in the folder {0}. Replacing it will overwrite its current contents.", paths.basename(paths.dirname(resource.fsPath))), + message: nls.localize('confirmOverwrite', "'{0}' already exists. Do you want to replace it?", basename(resource)), + detail: nls.localize('irreversible', "A file or folder with the same name already exists in the folder {0}. Replacing it will overwrite its current contents.", basename(dirname(resource))), primaryButton: nls.localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), type: 'warning' }; From 2772cde8ca3ba572baa9d671ff8d47663628b943 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Feb 2019 16:18:37 +0100 Subject: [PATCH 203/207] fix build --- src/vs/base/common/paths.node.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/base/common/paths.node.ts b/src/vs/base/common/paths.node.ts index e0133238ffb..32ddfeea171 100644 --- a/src/vs/base/common/paths.node.ts +++ b/src/vs/base/common/paths.node.ts @@ -42,6 +42,7 @@ interface IProcess { env: object; } +declare let process: IProcess; const safeProcess: IProcess = (typeof process === 'undefined') ? { cwd() { return '/'; }, env: {}, From 10ede292778d427501ef9d99a6a912582027c6d4 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Tue, 12 Feb 2019 16:29:42 +0100 Subject: [PATCH 204/207] MainThreadWorkspace: Initialize workspace immediatly --- src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts index 81924fb4f52..1ac6c84000b 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts @@ -44,7 +44,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { @ILabelService private readonly _labelService: ILabelService ) { this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostWorkspace); - this._contextService.getCompleteWorkspace().then(workspace => this._proxy.$initializeWorkspace(this.getWorkspaceData(workspace))); + this._proxy.$initializeWorkspace(this.getWorkspaceData(this._contextService.getWorkspace())); this._contextService.onDidChangeWorkspaceFolders(this._onDidChangeWorkspace, this, this._toDispose); this._contextService.onDidChangeWorkbenchState(this._onDidChangeWorkspace, this, this._toDispose); } From fd79885adefcc328d294130adfd70299b5368706 Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Tue, 12 Feb 2019 12:38:50 +0100 Subject: [PATCH 205/207] adding commit information --- src/vs/base/common/paths.node.ts | 2 ++ src/vs/base/test/common/paths.node.test.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/vs/base/common/paths.node.ts b/src/vs/base/common/paths.node.ts index 32ddfeea171..872c0dc939a 100644 --- a/src/vs/base/common/paths.node.ts +++ b/src/vs/base/common/paths.node.ts @@ -3,6 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +// extracted from nodejs commit 'https://github.com/nodejs/node/tree/43dd49c9782848c25e5b03448c8a0f923f13c158' + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/vs/base/test/common/paths.node.test.ts b/src/vs/base/test/common/paths.node.test.ts index 94174920850..4303ec1a0d3 100644 --- a/src/vs/base/test/common/paths.node.test.ts +++ b/src/vs/base/test/common/paths.node.test.ts @@ -3,6 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +// extracted from nodejs commit 'https://github.com/nodejs/node/tree/43dd49c9782848c25e5b03448c8a0f923f13c158' + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a From 8b4fd3733c7bcfd7dd3ee466f566ddedd709d4fe Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Tue, 12 Feb 2019 16:29:45 +0100 Subject: [PATCH 206/207] adding simple commented perf tests for new paths impl --- src/vs/base/test/common/paths.node.test.ts | 62 ++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/vs/base/test/common/paths.node.test.ts b/src/vs/base/test/common/paths.node.test.ts index 4303ec1a0d3..1f55c3e3846 100644 --- a/src/vs/base/test/common/paths.node.test.ts +++ b/src/vs/base/test/common/paths.node.test.ts @@ -730,4 +730,66 @@ suite('Paths (Node Implementation)', () => { assert.strictEqual(path, path.posix); } }); + + // test('perf', () => { + // const folderNames = [ + // 'abc', + // 'Users', + // 'reallylongfoldername', + // 's', + // 'reallyreallyreallylongfoldername', + // 'home' + // ]; + + // const basePaths = [ + // 'C:', + // '', + // ]; + + // const separators = [ + // '\\', + // '/' + // ]; + + // function randomInt(ciel: number): number { + // return Math.floor(Math.random() * ciel); + // } + + // let pathsToNormalize = []; + // let pathsToJoin = []; + // let i; + // for (i = 0; i < 1000000; i++) { + // const basePath = basePaths[randomInt(basePaths.length)]; + // let lengthOfPath = randomInt(10) + 2; + + // let pathToNormalize = basePath + separators[randomInt(separators.length)]; + // while (lengthOfPath-- > 0) { + // pathToNormalize = pathToNormalize + folderNames[randomInt(folderNames.length)] + separators[randomInt(separators.length)]; + // } + + // pathsToNormalize.push(pathToNormalize); + + // let pathToJoin = ''; + // lengthOfPath = randomInt(10) + 2; + // while (lengthOfPath-- > 0) { + // pathToJoin = pathToJoin + folderNames[randomInt(folderNames.length)] + separators[randomInt(separators.length)]; + // } + + // pathsToJoin.push(pathToJoin + '.ts'); + // } + + // let newTime = 0; + + // let j; + // for(j = 0; j < pathsToJoin.length; j++) { + // const path1 = pathsToNormalize[j]; + // const path2 = pathsToNormalize[j]; + + // const newStart = performance.now(); + // path.join(path1, path2); + // newTime += performance.now() - newStart; + // } + + // assert.ok(false, `Time: ${newTime}ms.`); + // }); }); From cb7261fc9cb6d60d4139e83a17f31770418ae070 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 12 Feb 2019 16:42:16 +0100 Subject: [PATCH 207/207] paths - adopt extname() --- src/vs/base/common/glob.ts | 10 +++---- src/vs/base/common/paths.ts | 9 ------ src/vs/base/common/resources.ts | 16 +++++------ src/vs/base/test/common/paths.node.test.ts | 28 +++++++++++++++++++ src/vs/base/test/common/paths.test.ts | 24 ---------------- src/vs/base/test/node/glob.test.ts | 5 +++- .../telemetry/common/telemetryUtils.ts | 4 +-- .../platform/workspaces/common/workspaces.ts | 2 +- .../browser/parts/editor/editorStatus.ts | 16 +++++------ src/vs/workbench/common/resources.ts | 5 ++-- .../electron-browser/extensionTipsService.ts | 3 +- .../contrib/snippets/browser/snippetsFile.ts | 2 +- .../snippets/browser/snippetsService.ts | 6 ++-- .../configuration/node/configuration.ts | 4 +-- .../textfile/common/textFileEditorModel.ts | 6 ++-- .../themes/electron-browser/colorThemeData.ts | 2 +- 16 files changed, 71 insertions(+), 71 deletions(-) diff --git a/src/vs/base/common/glob.ts b/src/vs/base/common/glob.ts index 07bfdeb61c3..4de80fd9917 100644 --- a/src/vs/base/common/glob.ts +++ b/src/vs/base/common/glob.ts @@ -5,8 +5,8 @@ import * as arrays from 'vs/base/common/arrays'; import * as strings from 'vs/base/common/strings'; -import * as paths from 'vs/base/common/paths'; -import { sep, posix } from 'vs/base/common/paths.node'; +import * as extpath from 'vs/base/common/paths'; +import * as paths from 'vs/base/common/paths.node'; import { LRUCache } from 'vs/base/common/map'; import { CharCode } from 'vs/base/common/charCode'; import { isThenable } from 'vs/base/common/async'; @@ -332,7 +332,7 @@ function wrapRelativePattern(parsedPattern: ParsedStringPattern, arg2: string | } return function (path, basename) { - if (!paths.isEqualOrParent(path, arg2.base)) { + if (!extpath.isEqualOrParent(path, arg2.base)) { return null; } @@ -397,8 +397,8 @@ function trivia3(pattern: string, options: IGlobOptions): ParsedStringPattern { // common patterns: **/something/else just need endsWith check, something/else just needs and equals check function trivia4and5(path: string, pattern: string, matchPathEnds: boolean): ParsedStringPattern { - const nativePath = sep !== posix.sep ? path.replace(ALL_FORWARD_SLASHES, sep) : path; - const nativePathEnd = sep + nativePath; + const nativePath = paths.sep !== paths.posix.sep ? path.replace(ALL_FORWARD_SLASHES, paths.sep) : path; + const nativePathEnd = paths.sep + nativePath; const parsedPattern: ParsedStringPattern = matchPathEnds ? function (path, basename) { return typeof path === 'string' && (path === nativePath || strings.endsWith(path, nativePathEnd)) ? pattern : null; } : function (path, basename) { diff --git a/src/vs/base/common/paths.ts b/src/vs/base/common/paths.ts index 16745874d5a..aa4ccf94e7e 100644 --- a/src/vs/base/common/paths.ts +++ b/src/vs/base/common/paths.ts @@ -26,15 +26,6 @@ export function basename(path: string): string { } } -/** - * @returns `.far` from `boo.far` or the empty string. - */ -export function extname(path: string): string { - path = basename(path); - const idx = ~path.lastIndexOf('.'); - return idx ? path.substring(~idx) : ''; -} - const _posixBadPath = /(\/\.\.?\/)|(\/\.\.?)$|^(\.\.?\/)|(\/\/+)|(\\)/; const _winBadPath = /(\\\.\.?\\)|(\\\.\.?)$|^(\.\.?\\)|(\\\\+)|(\/)/; diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts index 2bc29f13a17..645071964ed 100644 --- a/src/vs/base/common/resources.ts +++ b/src/vs/base/common/resources.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as paths from 'vs/base/common/paths'; -import { isAbsolute, posix, dirname as pathDirname } from 'vs/base/common/paths.node'; +import * as extpath from 'vs/base/common/paths'; +import * as paths from 'vs/base/common/paths.node'; import { URI } from 'vs/base/common/uri'; import { equalsIgnoreCase } from 'vs/base/common/strings'; import { Schemas } from 'vs/base/common/network'; @@ -33,10 +33,10 @@ export function basenameOrAuthority(resource: URI): string { export function isEqualOrParent(base: URI, parentCandidate: URI, ignoreCase = hasToIgnoreCase(base)): boolean { if (base.scheme === parentCandidate.scheme) { if (base.scheme === Schemas.file) { - return paths.isEqualOrParent(fsPath(base), fsPath(parentCandidate), ignoreCase); + return extpath.isEqualOrParent(fsPath(base), fsPath(parentCandidate), ignoreCase); } if (isEqualAuthority(base.authority, parentCandidate.authority, ignoreCase)) { - return paths.isEqualOrParent(base.path, parentCandidate.path, ignoreCase, '/'); + return extpath.isEqualOrParent(base.path, parentCandidate.path, ignoreCase, '/'); } } return false; @@ -82,9 +82,9 @@ export function dirname(resource: URI): URI | null { return resource; } if (resource.scheme === Schemas.file) { - return URI.file(pathDirname(fsPath(resource))); + return URI.file(paths.dirname(fsPath(resource))); } - let dirname = posix.dirname(resource.path); + let dirname = paths.posix.dirname(resource.path); if (resource.authority && dirname.length && dirname.charCodeAt(0) !== CharCode.Slash) { return null; // If a URI contains an authority component, then the path component must either be empty or begin with a CharCode.Slash ("/") character } @@ -146,7 +146,7 @@ export function fsPath(uri: URI): string { } else if ( isWindows && uriPath.charCodeAt(0) === CharCode.Slash - && paths.isWindowsDriveLetter(uriPath.charCodeAt(1)) + && extpath.isWindowsDriveLetter(uriPath.charCodeAt(1)) && uriPath.charCodeAt(2) === CharCode.Colon ) { value = uriPath.substr(1); @@ -164,7 +164,7 @@ export function fsPath(uri: URI): string { * Returns true if the URI path is absolute. */ export function isAbsolutePath(resource: URI): boolean { - return isAbsolute(resource.path); + return paths.isAbsolute(resource.path); } export function distinctParents(items: T[], resourceAccessor: (item: T) => URI): T[] { diff --git a/src/vs/base/test/common/paths.node.test.ts b/src/vs/base/test/common/paths.node.test.ts index 1f55c3e3846..c4b9a2d2194 100644 --- a/src/vs/base/test/common/paths.node.test.ts +++ b/src/vs/base/test/common/paths.node.test.ts @@ -354,6 +354,13 @@ suite('Paths (Node Implementation)', () => { assert.strictEqual(path.posix.extname('file\\\\'), ''); assert.strictEqual(path.posix.extname('file.\\'), '.\\'); assert.strictEqual(path.posix.extname('file.\\\\'), '.\\\\'); + + // Tests from VSCode + assert.equal(path.extname('far.boo'), '.boo'); + assert.equal(path.extname('far.b'), '.b'); + assert.equal(path.extname('far.'), '.'); + assert.equal(path.extname('far.boo/boo.far'), '.far'); + assert.equal(path.extname('far.boo/boo'), ''); }); test('resolve', () => { @@ -496,6 +503,27 @@ suite('Paths (Node Implementation)', () => { const controlCharFilename = `Icon${String.fromCharCode(13)}`; assert.strictEqual(path.posix.basename(`/a/b/${controlCharFilename}`), controlCharFilename); + + // Tests from VSCode + assert.equal(path.basename('foo/bar'), 'bar'); + assert.equal(path.posix.basename('foo\\bar'), 'foo\\bar'); + assert.equal(path.win32.basename('foo\\bar'), 'bar'); + assert.equal(path.basename('/foo/bar'), 'bar'); + assert.equal(path.posix.basename('\\foo\\bar'), '\\foo\\bar'); + assert.equal(path.win32.basename('\\foo\\bar'), 'bar'); + assert.equal(path.basename('./bar'), 'bar'); + assert.equal(path.posix.basename('.\\bar'), '.\\bar'); + assert.equal(path.win32.basename('.\\bar'), 'bar'); + assert.equal(path.basename('/bar'), 'bar'); + assert.equal(path.posix.basename('\\bar'), '\\bar'); + assert.equal(path.win32.basename('\\bar'), 'bar'); + assert.equal(path.basename('bar/'), 'bar'); + assert.equal(path.posix.basename('bar\\'), 'bar\\'); + assert.equal(path.win32.basename('bar\\'), 'bar'); + assert.equal(path.basename('bar'), 'bar'); + assert.equal(path.basename('////////'), ''); + assert.equal(path.posix.basename('\\\\\\\\'), '\\\\\\\\'); + assert.equal(path.win32.basename('\\\\\\\\'), ''); }); test('relative', () => { diff --git a/src/vs/base/test/common/paths.test.ts b/src/vs/base/test/common/paths.test.ts index fb43b36c767..18d903b70f0 100644 --- a/src/vs/base/test/common/paths.test.ts +++ b/src/vs/base/test/common/paths.test.ts @@ -71,22 +71,6 @@ suite('Paths', () => { }); - test('basename', () => { - assert.equal(paths.basename('foo/bar'), 'bar'); - assert.equal(paths.basename('foo\\bar'), 'bar'); - assert.equal(paths.basename('/foo/bar'), 'bar'); - assert.equal(paths.basename('\\foo\\bar'), 'bar'); - assert.equal(paths.basename('./bar'), 'bar'); - assert.equal(paths.basename('.\\bar'), 'bar'); - assert.equal(paths.basename('/bar'), 'bar'); - assert.equal(paths.basename('\\bar'), 'bar'); - assert.equal(paths.basename('bar/'), 'bar'); - assert.equal(paths.basename('bar\\'), 'bar'); - assert.equal(paths.basename('bar'), 'bar'); - assert.equal(paths.basename('////////'), ''); - assert.equal(paths.basename('\\\\\\\\'), ''); - }); - test('join', () => { assert.equal(paths.join('.', 'bar'), 'bar'); assert.equal(paths.join('../../foo/bar', '../../foo'), '../../foo'); @@ -114,14 +98,6 @@ suite('Paths', () => { assert.equal(paths.join('http://localhost/test', 'test'), 'http://localhost/test/test'); }); - test('extname', () => { - assert.equal(paths.extname('far.boo'), '.boo'); - assert.equal(paths.extname('far.b'), '.b'); - assert.equal(paths.extname('far.'), '.'); - assert.equal(paths.extname('far.boo/boo.far'), '.far'); - assert.equal(paths.extname('far.boo/boo'), ''); - }); - test('isUNC', () => { if (platform.isWindows) { assert.ok(!paths.isUNC('foo')); diff --git a/src/vs/base/test/node/glob.test.ts b/src/vs/base/test/node/glob.test.ts index ee10d64b839..8bfc51a35d8 100644 --- a/src/vs/base/test/node/glob.test.ts +++ b/src/vs/base/test/node/glob.test.ts @@ -722,7 +722,10 @@ suite('Glob', () => { assert.strictEqual(glob.match(expr, 'bar', hasSibling), '**/bar'); assert.strictEqual(glob.match(expr, 'foo', hasSibling), null); assert.strictEqual(glob.match(expr, 'foo/bar', hasSibling), '**/bar'); - assert.strictEqual(glob.match(expr, 'foo\\bar', hasSibling), '**/bar'); + if (isWindows) { + // backslash is a valid file name character on posix + assert.strictEqual(glob.match(expr, 'foo\\bar', hasSibling), '**/bar'); + } assert.strictEqual(glob.match(expr, 'foo/foo', hasSibling), null); assert.strictEqual(glob.match(expr, 'foo.js', hasSibling), '**/*.js'); assert.strictEqual(glob.match(expr, 'bar.js', hasSibling), null); diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index b0dcafe6568..3c7b1c6f3a8 100644 --- a/src/vs/platform/telemetry/common/telemetryUtils.ts +++ b/src/vs/platform/telemetry/common/telemetryUtils.ts @@ -5,7 +5,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { guessMimeTypes } from 'vs/base/common/mime'; -import * as paths from 'vs/base/common/paths'; +import { extname } from 'vs/base/common/paths.node'; import { URI } from 'vs/base/common/uri'; import { IConfigurationService, ConfigurationTarget, ConfigurationTargetToString } from 'vs/platform/configuration/common/configuration'; import { IKeybindingService, KeybindingSource } from 'vs/platform/keybinding/common/keybinding'; @@ -79,7 +79,7 @@ export interface URIDescriptor { export function telemetryURIDescriptor(uri: URI, hashPath: (path: string) => string): URIDescriptor { const fsPath = uri && uri.fsPath; - return fsPath ? { mimeType: guessMimeTypes(fsPath).join(', '), scheme: uri.scheme, ext: paths.extname(fsPath), path: hashPath(fsPath) } : {}; + return fsPath ? { mimeType: guessMimeTypes(fsPath).join(', '), scheme: uri.scheme, ext: extname(fsPath), path: hashPath(fsPath) } : {}; } /** diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index 2a6df51c8ff..5e7dde055de 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -8,7 +8,7 @@ import { localize } from 'vs/nls'; import { Event } from 'vs/base/common/event'; import { IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { URI, UriComponents } from 'vs/base/common/uri'; -import { extname } from 'vs/base/common/paths'; +import { extname } from 'vs/base/common/paths.node'; export const IWorkspacesMainService = createDecorator('workspacesMainService'); export const IWorkspacesService = createDecorator('workspacesService'); diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index 510422eb7cc..1a6dc34f037 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -7,7 +7,7 @@ import 'vs/css!./media/editorstatus'; import * as nls from 'vs/nls'; import { $, append, runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; import * as strings from 'vs/base/common/strings'; -import * as paths from 'vs/base/common/paths'; +import { extname, basename } from 'vs/base/common/resources'; import * as types from 'vs/base/common/types'; import { URI as uri } from 'vs/base/common/uri'; import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; @@ -911,7 +911,7 @@ export class ChangeModeAction extends Action { let configureModeSettings: IQuickPickItem; let galleryAction: Action; if (hasLanguageSupport) { - const ext = paths.extname(resource.fsPath) || paths.basename(resource.fsPath); + const ext = extname(resource) || basename(resource); galleryAction = this.instantiationService.createInstance(ShowLanguageExtensionsAction, ext); if (galleryAction.enabled) { @@ -992,9 +992,9 @@ export class ChangeModeAction extends Action { } private configureFileAssociation(resource: uri): void { - const extension = paths.extname(resource.fsPath); - const basename = paths.basename(resource.fsPath); - const currentAssociation = this.modeService.getModeIdByFilepathOrFirstLine(basename); + const extension = extname(resource); + const base = basename(resource); + const currentAssociation = this.modeService.getModeIdByFilepathOrFirstLine(base); const languages = this.modeService.getRegisteredLanguageNames(); const picks: IQuickPickItem[] = languages.sort().map((lang, index) => { @@ -1008,15 +1008,15 @@ export class ChangeModeAction extends Action { }); setTimeout(() => { - this.quickInputService.pick(picks, { placeHolder: nls.localize('pickLanguageToConfigure', "Select Language Mode to Associate with '{0}'", extension || basename) }).then(language => { + this.quickInputService.pick(picks, { placeHolder: nls.localize('pickLanguageToConfigure', "Select Language Mode to Associate with '{0}'", extension || base) }).then(language => { if (language) { const fileAssociationsConfig = this.configurationService.inspect(FILES_ASSOCIATIONS_CONFIG); let associationKey: string; - if (extension && basename[0] !== '.') { + if (extension && base[0] !== '.') { associationKey = `*${extension}`; // only use "*.ext" if the file path is in the form of . } else { - associationKey = basename; // otherwise use the basename (e.g. .gitignore, Dockerfile) + associationKey = base; // otherwise use the basename (e.g. .gitignore, Dockerfile) } // If the association is already being made in the workspace, make sure to target workspace settings diff --git a/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts index 000fb0e98d1..b0bf0945a38 100644 --- a/src/vs/workbench/common/resources.ts +++ b/src/vs/workbench/common/resources.ts @@ -8,6 +8,7 @@ import * as paths from 'vs/base/common/paths'; import * as objects from 'vs/base/common/objects'; import { Event, Emitter } from 'vs/base/common/event'; import { relative } from 'vs/base/common/paths.node'; +import { basename, extname } from 'vs/base/common/resources'; import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IFileService } from 'vs/platform/files/common/files'; @@ -64,9 +65,9 @@ export class ResourceContextKey extends Disposable implements IContextKey { if (!ResourceContextKey._uriEquals(this._resourceKey.get(), value)) { this._resourceKey.set(value); this._schemeKey.set(value && value.scheme); - this._filenameKey.set(value && paths.basename(value.fsPath)); + this._filenameKey.set(value && basename(value)); this._langIdKey.set(value ? this._modeService.getModeIdByFilepathOrFirstLine(value.fsPath) : null); - this._extensionKey.set(value && paths.extname(value.fsPath)); + this._extensionKey.set(value && extname(value)); this._hasResource.set(!!value); this._isFileSystemResource.set(value && this._fileService.canHandleResource(value)); } diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts index 32adbff953d..b1cd590be70 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts @@ -45,6 +45,7 @@ import { IExperimentService, ExperimentActionType, ExperimentState } from 'vs/wo import { CancellationToken } from 'vs/base/common/cancellation'; import { getKeywordsForExtension } from 'vs/workbench/contrib/extensions/electron-browser/extensionsUtils'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; +import { extname } from 'vs/base/common/resources'; const milliSecondsInADay = 1000 * 60 * 60 * 24; const choiceNever = localize('neverShowAgain', "Don't Show Again"); @@ -586,7 +587,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe return; } - let fileExtension = paths.extname(uri.path); + let fileExtension = extname(uri); if (fileExtension) { if (processedFileExtensions.indexOf(fileExtension) > -1) { return; diff --git a/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts b/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts index 3631253adcf..8983c7b36f8 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts @@ -7,7 +7,7 @@ import { parse as jsonParse } from 'vs/base/common/json'; import { forEach } from 'vs/base/common/collections'; import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import { localize } from 'vs/nls'; -import { basename, extname } from 'vs/base/common/paths'; +import { extname, basename } from 'vs/base/common/paths.node'; import { SnippetParser, Variable, Placeholder, Text } from 'vs/editor/contrib/snippet/snippetParser'; import { KnownSnippetVariableNames } from 'vs/editor/contrib/snippet/snippetVariables'; import { isFalsyOrWhitespace } from 'vs/base/common/strings'; diff --git a/src/vs/workbench/contrib/snippets/browser/snippetsService.ts b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts index 033852eaa4a..2013509f4d5 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippetsService.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { basename, extname, join } from 'vs/base/common/paths'; +import { join } from 'vs/base/common/paths'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { combinedDisposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { values } from 'vs/base/common/map'; @@ -321,10 +321,10 @@ class SnippetsService implements ISnippetsService { } private _addSnippetFile(uri: URI, source: SnippetSource): IDisposable { - const ext = extname(uri.path); + const ext = resources.extname(uri); const key = uri.toString(); if (source === SnippetSource.User && ext === '.json') { - const langName = basename(uri.path).replace(/\.json/, ''); + const langName = resources.basename(uri).replace(/\.json/, ''); this._files.set(key, new SnippetFile(source, uri, [langName], undefined, this._fileService)); } else if (ext === '.code-snippets') { this._files.set(key, new SnippetFile(source, uri, undefined, undefined, this._fileService)); diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configuration.ts index e219d2882bc..a6d2ccb5cd3 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configuration.ts @@ -23,7 +23,7 @@ import * as extfs from 'vs/base/node/extfs'; import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService'; import { WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import { relative } from 'path'; +import { relative, extname } from 'path'; import { equals } from 'vs/base/common/objects'; import { Schemas } from 'vs/base/common/network'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -497,7 +497,7 @@ export class FileServiceBasedFolderConfiguration extends AbstractFolderConfigura for (let i = 0, len = events.length; i < len; i++) { const resource = events[i].resource; const basename = resources.basename(resource); - const isJson = paths.extname(basename) === '.json'; + const isJson = extname(basename) === '.json'; const isDeletedSettingsFolder = (events[i].type === FileChangeType.DELETED && basename === this.configFolderRelativePath); if (!isJson && !isDeletedSettingsFolder) { diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index c127e2646f9..96d724c7fae 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -29,7 +29,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { isLinux } from 'vs/base/common/platform'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; -import { isEqual, isEqualOrParent } from 'vs/base/common/resources'; +import { isEqual, isEqualOrParent, extname } from 'vs/base/common/resources'; import { onUnexpectedError } from 'vs/base/common/errors'; /** @@ -769,7 +769,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } private getTypeIfSettings(): string { - if (path.extname(this.resource.fsPath) !== '.json') { + if (extname(this.resource) !== '.json') { return ''; } @@ -808,7 +808,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } private getTelemetryData(reason: number): Object { - const ext = path.extname(this.resource.fsPath); + const ext = extname(this.resource); const fileName = path.basename(this.resource.fsPath); const telemetryData = { mimeType: guessMimeTypes(this.resource.fsPath).join(', '), diff --git a/src/vs/workbench/services/themes/electron-browser/colorThemeData.ts b/src/vs/workbench/services/themes/electron-browser/colorThemeData.ts index 3ff37d4ac5a..b0f8f48be13 100644 --- a/src/vs/workbench/services/themes/electron-browser/colorThemeData.ts +++ b/src/vs/workbench/services/themes/electron-browser/colorThemeData.ts @@ -283,7 +283,7 @@ function toCSSSelector(str: string) { } function _loadColorTheme(fileService: IFileService, themeLocation: URI, resultRules: ITokenColorizationRule[], resultColors: IColorMap): Promise { - if (Paths.extname(themeLocation.path) === '.json') { + if (resources.extname(themeLocation) === '.json') { return fileService.resolveContent(themeLocation, { encoding: 'utf8' }).then(content => { let errors: Json.ParseError[] = []; let contentValue = Json.parse(content.value.toString(), errors);