diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index 94e02b37a29..8216a7805f0 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -9,6 +9,7 @@ import * as types from 'vs/base/common/types'; import * as objects from 'vs/base/common/objects'; import URI from 'vs/base/common/uri'; import { StrictResourceMap } from 'vs/base/common/map'; +import { Workspace } from 'vs/platform/workspace/common/workspace'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import Event from 'vs/base/common/event'; @@ -199,16 +200,15 @@ export interface IConfigurationData { defaults: IConfiguraionModel; user: IConfiguraionModel; folders: { [folder: string]: IConfiguraionModel }; - workspaceUri: string; } export class Configuration { - private _global: ConfigurationModel; - private _workspace: ConfigurationModel; - protected _foldersConsolidated: StrictResourceMap>; + private _globalConfiguration: ConfigurationModel; + private _workspaceConfiguration: ConfigurationModel; + protected _foldersConsolidatedConfigurations: StrictResourceMap>; - constructor(protected _defaults: ConfigurationModel, protected _user: ConfigurationModel, protected folders: StrictResourceMap> = new StrictResourceMap>(), protected workspaceUri?: URI) { + constructor(protected _defaults: ConfigurationModel, protected _user: ConfigurationModel, protected folders: StrictResourceMap> = new StrictResourceMap>(), protected _workspace?: Workspace) { this.merge(); } @@ -221,23 +221,23 @@ export class Configuration { } get workspace(): ConfigurationModel { - return this._workspace; + return this._workspaceConfiguration; } protected merge(): void { - this._global = this._workspace = new ConfigurationModel().merge(this._defaults).merge(this._user); - this._foldersConsolidated = new StrictResourceMap>(); + this._globalConfiguration = this._workspaceConfiguration = new ConfigurationModel().merge(this._defaults).merge(this._user); + this._foldersConsolidatedConfigurations = new StrictResourceMap>(); for (const folder of this.folders.keys()) { this.mergeFolder(folder); } } protected mergeFolder(folder: URI) { - if (this.workspaceUri && this.workspaceUri.fsPath === folder.fsPath) { - this._workspace = new ConfigurationModel().merge(this._global).merge(this.folders.get(this.workspaceUri)); - this._foldersConsolidated.set(folder, this._workspace); + if (this._workspace && this.workspaceUri.fsPath === folder.fsPath) { + this._workspaceConfiguration = new ConfigurationModel().merge(this._globalConfiguration).merge(this.folders.get(this.workspaceUri)); + this._foldersConsolidatedConfigurations.set(folder, this._workspaceConfiguration); } else { - this._foldersConsolidated.set(folder, new ConfigurationModel().merge(this._workspace).merge(this.folders.get(folder))); + this._foldersConsolidatedConfigurations.set(folder, new ConfigurationModel().merge(this._workspaceConfiguration).merge(this.folders.get(folder))); } } @@ -251,8 +251,8 @@ export class Configuration { return { default: objects.clone(getConfigurationValue(overrideIdentifier ? this._defaults.override(overrideIdentifier).contents : this._defaults.contents, key)), user: objects.clone(getConfigurationValue(overrideIdentifier ? this._user.override(overrideIdentifier).contents : this._user.contents, key)), - workspace: objects.clone(this.workspaceUri ? getConfigurationValue(overrideIdentifier ? this.folders.get(this.workspaceUri).override(overrideIdentifier).contents : this.folders.get(this.workspaceUri).contents, key) : void 0), - value: objects.clone(getConfigurationValue(overrideIdentifier ? this._workspace.override(overrideIdentifier).contents : this._workspace.contents, key)) + workspace: objects.clone(this._workspace ? getConfigurationValue(overrideIdentifier ? this.folders.get(this.workspaceUri).override(overrideIdentifier).contents : this.folders.get(this.workspaceUri).contents, key) : void 0), + value: objects.clone(getConfigurationValue(overrideIdentifier ? this._workspaceConfiguration.override(overrideIdentifier).contents : this._workspaceConfiguration.contents, key)) }; } @@ -260,7 +260,7 @@ export class Configuration { return { default: this._defaults.keys, user: this._user.keys, - workspace: this.workspaceUri ? this.folders.get(this.workspaceUri).keys : [] + workspace: this._workspace ? this.folders.get(this.workspaceUri).keys : [] }; } @@ -296,8 +296,12 @@ export class Configuration { return result; } + protected get workspaceUri(): URI { + return this.workspace ? this._workspace.roots[0] : null; + } + private getConfigurationModel(overrides: IConfigurationOverrides): ConfigurationModel { - let configurationModel = overrides.resource ? this._foldersConsolidated.get(overrides.resource) || this._workspace : this._workspace; + let configurationModel = overrides.resource ? this._foldersConsolidatedConfigurations.get(overrides.resource) || this._workspaceConfiguration : this._workspaceConfiguration; return overrides.language ? configurationModel.override(overrides.language) : configurationModel; } @@ -315,20 +319,18 @@ export class Configuration { const { contents, overrides } = this.folders.get(folder); result[folder.toString()] = { contents, overrides }; return result; - }, Object.create({})), - workspaceUri: this.workspaceUri ? this.workspaceUri.toString() : void 0 + }, Object.create({})) }; } - public static parse(data: IConfigurationData): Configuration { + public static parse(data: IConfigurationData, workspace: Workspace): Configuration { const defaults = Configuration.parseConfigurationModel(data.defaults); const user = Configuration.parseConfigurationModel(data.user); const folders: StrictResourceMap> = Object.keys(data.folders).reduce((result, key) => { result.set(URI.parse(key), Configuration.parseConfigurationModel(data.folders[key])); return result; }, new StrictResourceMap>()); - const workspaceUri = data.workspaceUri ? URI.parse(data.workspaceUri) : void 0; - return new Configuration(defaults, user, folders, workspaceUri); + return new Configuration(defaults, user, folders, workspace); } private static parseConfigurationModel(model: IConfiguraionModel): ConfigurationModel { diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 4b1429aa294..7c4e72c853d 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -83,7 +83,8 @@ export function createApiFactory( const extHostEditors = col.define(ExtHostContext.ExtHostEditors).set(new ExtHostEditors(threadService, extHostDocumentsAndEditors)); const extHostCommands = col.define(ExtHostContext.ExtHostCommands).set(new ExtHostCommands(threadService, extHostHeapService)); const extHostTreeViews = col.define(ExtHostContext.ExtHostTreeViews).set(new ExtHostTreeViews(threadService, extHostCommands)); - const extHostConfiguration = col.define(ExtHostContext.ExtHostConfiguration).set(new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration), initData.configuration)); + const extHostWorkspace = col.define(ExtHostContext.ExtHostWorkspace).set(new ExtHostWorkspace(threadService, initData.workspace)); + const extHostConfiguration = col.define(ExtHostContext.ExtHostConfiguration).set(new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration), initData.configuration, extHostWorkspace)); const extHostDiagnostics = col.define(ExtHostContext.ExtHostDiagnostics).set(new ExtHostDiagnostics(threadService)); const languageFeatures = col.define(ExtHostContext.ExtHostLanguageFeatures).set(new ExtHostLanguageFeatures(threadService, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics)); const extHostFileSystemEvent = col.define(ExtHostContext.ExtHostFileSystemEventService).set(new ExtHostFileSystemEventService()); @@ -91,7 +92,6 @@ export function createApiFactory( const extHostTerminalService = col.define(ExtHostContext.ExtHostTerminalService).set(new ExtHostTerminalService(threadService)); const extHostSCM = col.define(ExtHostContext.ExtHostSCM).set(new ExtHostSCM(threadService, extHostCommands)); const extHostTask = col.define(ExtHostContext.ExtHostTask).set(new ExtHostTask(threadService)); - const extHostWorkspace = col.define(ExtHostContext.ExtHostWorkspace).set(new ExtHostWorkspace(threadService, initData.workspace)); col.define(ExtHostContext.ExtHostExtensionService).set(extensionService); col.finish(false, threadService); diff --git a/src/vs/workbench/api/node/extHostConfiguration.ts b/src/vs/workbench/api/node/extHostConfiguration.ts index 5ee24322929..da84ebf96ba 100644 --- a/src/vs/workbench/api/node/extHostConfiguration.ts +++ b/src/vs/workbench/api/node/extHostConfiguration.ts @@ -7,6 +7,7 @@ import { mixin } from 'vs/base/common/objects'; import Event, { Emitter } from 'vs/base/common/event'; import { WorkspaceConfiguration } from 'vscode'; +import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostConfigurationShape, MainThreadConfigurationShape } from './extHost.protocol'; import { IConfigurationData, Configuration } from 'vs/platform/configuration/common/configuration'; import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; @@ -29,7 +30,7 @@ export class ExtHostConfiguration extends ExtHostConfigurationShape { private _data: IConfigurationData; private _configuration: Configuration; - constructor(proxy: MainThreadConfigurationShape, data: IConfigurationData) { + constructor(proxy: MainThreadConfigurationShape, data: IConfigurationData, private extWorkspace: ExtHostWorkspace) { super(); this._proxy = proxy; this._data = data; @@ -47,7 +48,7 @@ export class ExtHostConfiguration extends ExtHostConfigurationShape { private get configuration(): Configuration { if (!this._configuration) { - this._configuration = Configuration.parse(this._data); + this._configuration = Configuration.parse(this._data, this.extWorkspace.workspace); } return this._configuration; } diff --git a/src/vs/workbench/api/node/extHostWorkspace.ts b/src/vs/workbench/api/node/extHostWorkspace.ts index e222fb03816..8cb2947fe41 100644 --- a/src/vs/workbench/api/node/extHostWorkspace.ts +++ b/src/vs/workbench/api/node/extHostWorkspace.ts @@ -9,6 +9,7 @@ import Event, { Emitter } from 'vs/base/common/event'; import { normalize } from 'vs/base/common/paths'; import { isFalsyOrEmpty } from 'vs/base/common/arrays'; import { relative } from 'path'; +import { Workspace } from 'vs/platform/workspace/common/workspace'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { IResourceEdit } from 'vs/editor/common/services/bulkEdit'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -22,18 +23,22 @@ export class ExtHostWorkspace extends ExtHostWorkspaceShape { private readonly _onDidChangeWorkspace = new Emitter(); private readonly _proxy: MainThreadWorkspaceShape; - private _workspace: IWorkspaceData; + private _workspace: Workspace; readonly onDidChangeWorkspace: Event = this._onDidChangeWorkspace.event; - constructor(threadService: IThreadService, workspace: IWorkspaceData) { + constructor(threadService: IThreadService, data: IWorkspaceData) { super(); this._proxy = threadService.get(MainContext.MainThreadWorkspace); - this._workspace = workspace; + this._workspace = data ? new Workspace(data.id, data.name, data.roots) : null; } // --- workspace --- + get workspace(): Workspace { + return this._workspace; + } + getPath(): string { // this is legacy from the days before having // multi-root and we keep it only alive if there @@ -69,8 +74,8 @@ export class ExtHostWorkspace extends ExtHostWorkspaceShape { return normalize(path); } - $acceptWorkspaceData(workspace: IWorkspaceData): void { - this._workspace = workspace; + $acceptWorkspaceData(data: IWorkspaceData): void { + this._workspace = data ? new Workspace(data.id, data.name, data.roots) : null; this._onDidChangeWorkspace.fire(this); } diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configuration.ts index cd6fa13bedc..28a61bbc46c 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configuration.ts @@ -69,7 +69,11 @@ export class WorkspaceConfigurationService extends Disposable implements IWorksp constructor(private environmentService: IEnvironmentService, private readonly legacyWorkspace?: LegacyWorkspace, private workspaceSettingsRootFolder: string = WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME) { super(); - this.workspace = legacyWorkspace ? new Workspace(createHash('md5').update(legacyWorkspace.resource.fsPath).update(legacyWorkspace.ctime ? String(legacyWorkspace.ctime) : '').digest('hex'), basename(legacyWorkspace.resource.fsPath), [legacyWorkspace.resource]) : null; + this.workspace = legacyWorkspace ? new Workspace( + createHash('md5').update(legacyWorkspace.resource.fsPath).update(legacyWorkspace.ctime ? String(legacyWorkspace.ctime) : '').digest('hex'), + basename(legacyWorkspace.resource.fsPath), + [legacyWorkspace.resource] + ) : null; this._register(this.onDidUpdateConfiguration(e => this.resolveAdditionalFolders(true))); this.baseConfigurationService = this._register(new GlobalConfigurationService(environmentService)); @@ -233,7 +237,7 @@ export class WorkspaceConfigurationService extends Disposable implements IWorksp private initCaches(): void { this.cachedFolderConfigs = new StrictResourceMap>(); - this._configuration = new Configuration(this.baseConfigurationService.configuration(), new StrictResourceMap>(), this.workspaceUri); + this._configuration = new Configuration(this.baseConfigurationService.configuration(), new StrictResourceMap>(), this.workspace); this.initCachesForFolders(this.workspace ? this.workspace.roots : []); } @@ -467,12 +471,12 @@ function resolveStat(resource: URI): TPromise { class Configuration extends BaseConfiguration { - constructor(private _baseConfiguration: Configuration, protected folders: StrictResourceMap>, workspaceUri: URI) { - super(_baseConfiguration.defaults, _baseConfiguration.user, folders, workspaceUri); + constructor(private _baseConfiguration: Configuration, protected folders: StrictResourceMap>, workspace: Workspace) { + super(_baseConfiguration.defaults, _baseConfiguration.user, folders, workspace); } updateBaseConfiguration(baseConfiguration: Configuration): boolean { - const current = new Configuration(this._baseConfiguration, this.folders, this.workspaceUri); + const current = new Configuration(this._baseConfiguration, this.folders, this._workspace); this._defaults = baseConfiguration.defaults; this._user = baseConfiguration.user; @@ -489,13 +493,13 @@ class Configuration extends BaseConfiguration { } deleteFolderConfiguration(folder: URI): boolean { - if (this.workspaceUri && this.workspaceUri.fsPath === folder.fsPath) { + if (this.workspace && this.workspaceUri.fsPath === folder.fsPath) { // Do not remove workspace configuration return false; } this.folders.delete(folder); - return this._foldersConsolidated.delete(folder); + return this._foldersConsolidatedConfigurations.delete(folder); } getFolderConfigurationModel(folder: URI): FolderConfigurationModel { @@ -511,11 +515,11 @@ class Configuration extends BaseConfiguration { return false; } - if (this._foldersConsolidated.size !== other._foldersConsolidated.size) { + if (this._foldersConsolidatedConfigurations.size !== other._foldersConsolidatedConfigurations.size) { return false; } - for (const resource of this._foldersConsolidated.keys()) { + for (const resource of this._foldersConsolidatedConfigurations.keys()) { if (!objects.equals(this.getValue(null, { resource }), other.getValue(null, { resource }))) { return false; } 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 acdf7e0de9f..a07b32c76b4 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts @@ -6,11 +6,13 @@ 'use strict'; import * as assert from 'assert'; +import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration'; import { MainThreadConfigurationShape } from 'vs/workbench/api/node/extHost.protocol'; import { TPromise } from 'vs/base/common/winjs.base'; import { ConfigurationTarget, ConfigurationEditingErrorCode, IConfigurationEditingError } from 'vs/workbench/services/configuration/common/configurationEditing'; import { ConfigurationModel } from 'vs/platform/configuration/common/configuration'; +import { TestThreadService } from './testThreadService'; suite('ExtHostConfiguration', function () { @@ -29,9 +31,8 @@ suite('ExtHostConfiguration', function () { return new ExtHostConfiguration(shape, { defaults: new ConfigurationModel(contents), user: new ConfigurationModel(contents), - folders: Object.create(null), - workspaceUri: void 0 - }); + folders: Object.create(null) + }, new ExtHostWorkspace(new TestThreadService(), null)); } test('getConfiguration fails regression test 1.7.1 -> 1.8 #15552', function () {