diff --git a/src/vs/platform/configuration/common/model.ts b/src/vs/platform/configuration/common/model.ts index 319d6f65bc8..a981336a59d 100644 --- a/src/vs/platform/configuration/common/model.ts +++ b/src/vs/platform/configuration/common/model.ts @@ -10,18 +10,22 @@ import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/co export function getDefaultValues(): any { const valueTreeRoot: any = Object.create(null); const properties = Registry.as(Extensions.Configuration).getConfigurationProperties(); + for (let key in properties) { let value = properties[key].default; addToValueTree(valueTreeRoot, key, value); } + return valueTreeRoot; } export function toValuesTree(properties: { [qualifiedKey: string]: any }): any { const root = Object.create(null); + for (let key in properties) { addToValueTree(root, key, properties[key]); } + return root; } @@ -51,5 +55,6 @@ function addToValueTree(settingsTreeRoot: any, key: string, value: any): void { export function getConfigurationKeys(): string[] { const properties = Registry.as(Extensions.Configuration).getConfigurationProperties(); + return Object.keys(properties); } \ No newline at end of file diff --git a/src/vs/platform/configuration/node/configurationService.ts b/src/vs/platform/configuration/node/configurationService.ts index 6ab74957ded..a6d45964518 100644 --- a/src/vs/platform/configuration/node/configurationService.ts +++ b/src/vs/platform/configuration/node/configurationService.ts @@ -50,7 +50,9 @@ export class ConfigurationService implements IConfigurationService, IDisposab private onConfigurationChange(source: ConfigurationSource): void { this.cache = void 0; // reset our caches + const cache = this.getCache(); + this._onDidUpdateConfiguration.fire({ config: this.getConfiguration(), source, @@ -74,6 +76,7 @@ export class ConfigurationService implements IConfigurationService, IDisposab public getConfiguration(section?: string): C { const cache = this.getCache(); + return section ? cache.consolidated[section] : cache.consolidated; } @@ -82,11 +85,13 @@ export class ConfigurationService implements IConfigurationService, IDisposab } public lookup(key: string): IConfigurationValue { + const cache = this.getCache(); + // make sure to clone the configuration so that the receiver does not tamper with the values return { - default: objects.clone(getConfigurationValue(getDefaultValues(), key)), - user: objects.clone(getConfigurationValue(toValuesTree(this.rawConfig.getConfig()), key)), - value: objects.clone(getConfigurationValue(this.getConfiguration(), key)) + default: objects.clone(getConfigurationValue(cache.defaults, key)), + user: objects.clone(getConfigurationValue(cache.user, key)), + value: objects.clone(getConfigurationValue(cache.consolidated, key)) }; } diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index f3f2d98ab63..43d81718bf8 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -29,7 +29,7 @@ import * as modes from 'vs/editor/common/modes'; import { IResourceEdit } from 'vs/editor/common/services/bulkEdit'; import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IWorkspaceConfiguration } from 'vs/workbench/services/configuration/common/configuration'; +import { IWorkspaceConfigurationValues } from 'vs/workbench/services/configuration/common/configuration'; import { IPickOpenEntry, IPickOptions } from 'vs/workbench/services/quickopen/common/quickOpenService'; import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; @@ -54,7 +54,7 @@ export interface IInitData { workspace: IWorkspace; }; extensions: IExtensionDescription[]; - configuration: IWorkspaceConfiguration; + configuration: IWorkspaceConfigurationValues; telemetryInfo: ITelemetryInfo; } @@ -236,7 +236,7 @@ export abstract class ExtHostCommandsShape { } export abstract class ExtHostConfigurationShape { - $acceptConfigurationChanged(entries: IWorkspaceConfiguration) { throw ni(); } + $acceptConfigurationChanged(values: IWorkspaceConfigurationValues) { throw ni(); } } export abstract class ExtHostDiagnosticsShape { diff --git a/src/vs/workbench/api/node/extHostConfiguration.ts b/src/vs/workbench/api/node/extHostConfiguration.ts index 8f7a6be3450..32d39cf84c5 100644 --- a/src/vs/workbench/api/node/extHostConfiguration.ts +++ b/src/vs/workbench/api/node/extHostConfiguration.ts @@ -9,7 +9,7 @@ import Event, { Emitter } from 'vs/base/common/event'; import { WorkspaceConfiguration } from 'vscode'; import { ExtHostConfigurationShape, MainThreadConfigurationShape } from './extHost.protocol'; import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; -import { IWorkspaceConfiguration } from 'vs/workbench/services/configuration/common/configuration'; +import { IWorkspaceConfigurationValues } from 'vs/workbench/services/configuration/common/configuration'; import { toValuesTree } from 'vs/platform/configuration/common/model'; function lookUp(tree: any, key: string) { @@ -24,11 +24,11 @@ function lookUp(tree: any, key: string) { } interface UsefulConfiguration { - data: IWorkspaceConfiguration; + data: IWorkspaceConfigurationValues; valueTree: any; } -function createUsefulConfiguration(data: IWorkspaceConfiguration): { data: IWorkspaceConfiguration, valueTree: any } { +function createUsefulConfiguration(data: IWorkspaceConfigurationValues): { data: IWorkspaceConfigurationValues, valueTree: any } { const valueMap: { [key: string]: any } = Object.create(null); for (let key in data) { if (Object.prototype.hasOwnProperty.call(data, key)) { @@ -48,7 +48,7 @@ export class ExtHostConfiguration extends ExtHostConfigurationShape { private _proxy: MainThreadConfigurationShape; private _configuration: UsefulConfiguration; - constructor(proxy: MainThreadConfigurationShape, data: IWorkspaceConfiguration) { + constructor(proxy: MainThreadConfigurationShape, data: IWorkspaceConfigurationValues) { super(); this._proxy = proxy; this._configuration = createUsefulConfiguration(data); @@ -58,7 +58,7 @@ export class ExtHostConfiguration extends ExtHostConfigurationShape { return this._onDidChangeConfiguration && this._onDidChangeConfiguration.event; } - public $acceptConfigurationChanged(data: IWorkspaceConfiguration) { + public $acceptConfigurationChanged(data: IWorkspaceConfigurationValues) { this._configuration = createUsefulConfiguration(data); this._onDidChangeConfiguration.fire(undefined); } diff --git a/src/vs/workbench/api/node/mainThreadConfiguration.ts b/src/vs/workbench/api/node/mainThreadConfiguration.ts index 486d4023598..c77a7b026f4 100644 --- a/src/vs/workbench/api/node/mainThreadConfiguration.ts +++ b/src/vs/workbench/api/node/mainThreadConfiguration.ts @@ -7,7 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; -import { IWorkspaceConfigurationService, getEntries } from 'vs/workbench/services/configuration/common/configuration'; +import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { MainThreadConfigurationShape, ExtHostContext } from './extHost.protocol'; @@ -26,8 +26,7 @@ export class MainThreadConfiguration extends MainThreadConfigurationShape { const proxy = threadService.get(ExtHostContext.ExtHostConfiguration); this._toDispose = configurationService.onDidUpdateConfiguration(() => { - const entries = getEntries(configurationService); - proxy.$acceptConfigurationChanged(entries); + proxy.$acceptConfigurationChanged(configurationService.values()); }); } diff --git a/src/vs/workbench/electron-browser/extensionHost.ts b/src/vs/workbench/electron-browser/extensionHost.ts index 73eb60ec53a..45cb2377562 100644 --- a/src/vs/workbench/electron-browser/extensionHost.ts +++ b/src/vs/workbench/electron-browser/extensionHost.ts @@ -30,7 +30,7 @@ import { WatchDog } from 'vs/base/common/watchDog'; import { createQueuedSender, IQueuedSender } from 'vs/base/node/processes'; import { IInitData } from 'vs/workbench/api/node/extHost.protocol'; import { MainProcessExtensionService } from 'vs/workbench/api/node/mainThreadExtensionService'; -import { IWorkspaceConfigurationService, getEntries } from 'vs/workbench/services/configuration/common/configuration'; +import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; export const EXTENSION_LOG_BROADCAST_CHANNEL = 'vscode:extensionLog'; export const EXTENSION_ATTACH_BROADCAST_CHANNEL = 'vscode:extensionAttach'; @@ -260,7 +260,7 @@ export class ExtensionHostProcessWorker { workspace: this.contextService.getWorkspace() }, extensions: extensionDescriptions, - configuration: getEntries(this.configurationService), + configuration: this.configurationService.values(), telemetryInfo }; this.extensionHostProcessQueuedSender.send(stringify(initData)); diff --git a/src/vs/workbench/services/configuration/common/configuration.ts b/src/vs/workbench/services/configuration/common/configuration.ts index 22d6bce007a..5a5f277bb74 100644 --- a/src/vs/workbench/services/configuration/common/configuration.ts +++ b/src/vs/workbench/services/configuration/common/configuration.ts @@ -12,6 +12,8 @@ export const WORKSPACE_CONFIG_DEFAULT_PATH = `${WORKSPACE_CONFIG_FOLDER_DEFAULT_ export const IWorkspaceConfigurationService = createDecorator('configurationService'); +export type IWorkspaceConfigurationValues = { [key: string]: IWorkspaceConfigurationValue } + export interface IWorkspaceConfigurationService extends IConfigurationService { /** @@ -28,6 +30,11 @@ export interface IWorkspaceConfigurationService extends IConfigurationService { * Override for the IConfigurationService#keys() method that adds information about workspace settings. */ keys(): IWorkspaceConfigurationKeys; + + /** + * Returns the defined values of configurations in the different scopes. + */ + values(): IWorkspaceConfigurationValues; } export interface IWorkspaceConfigurationValue extends IConfigurationValue { @@ -41,23 +48,4 @@ export interface IWorkspaceConfigurationKeys extends IConfigurationKeys { export const WORKSPACE_STANDALONE_CONFIGURATIONS = { 'tasks': `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/tasks.json`, 'launch': `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/launch.json` -}; - -export type IWorkspaceConfiguration = { [key: string]: IWorkspaceConfigurationValue } - -export function getEntries(configurationService: IWorkspaceConfigurationService): IWorkspaceConfiguration { - - const result: IWorkspaceConfiguration = Object.create(null); - const keyset = configurationService.keys(); - const keys = [...keyset.workspace, ...keyset.user, ...keyset.default].sort(); - let lastKey: string; - for (const key of keys) { - if (key !== lastKey) { - lastKey = key; - const config = configurationService.lookup(key); - result[key] = config; - } - } - - return result; -} +}; \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index e5ffa8328ad..8bbe0bb8c48 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -21,7 +21,7 @@ import errors = require('vs/base/common/errors'); import { IConfigFile, consolidate, newConfigFile } from 'vs/workbench/services/configuration/common/model'; import { IConfigurationServiceEvent, ConfigurationSource, getConfigurationValue } from 'vs/platform/configuration/common/configuration'; import { ConfigurationService as BaseConfigurationService } from 'vs/platform/configuration/node/configurationService'; -import { IWorkspaceConfigurationService, IWorkspaceConfigurationValue, CONFIG_DEFAULT_NAME, WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME, WORKSPACE_STANDALONE_CONFIGURATIONS, WORKSPACE_CONFIG_DEFAULT_PATH } from 'vs/workbench/services/configuration/common/configuration'; +import { IWorkspaceConfigurationValues, IWorkspaceConfigurationService, IWorkspaceConfigurationValue, CONFIG_DEFAULT_NAME, WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME, WORKSPACE_STANDALONE_CONFIGURATIONS, WORKSPACE_CONFIG_DEFAULT_PATH } from 'vs/workbench/services/configuration/common/configuration'; import { EventType as FileEventType, FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files'; import Event, { Emitter } from 'vs/base/common/event'; @@ -136,7 +136,7 @@ export class WorkspaceConfigurationService implements IWorkspaceConfigurationSer default: configurationValue.default, user: configurationValue.user, workspace: getConfigurationValue(this.cachedWorkspaceConfig, key), - value: getConfigurationValue(this.getConfiguration(), key) + value: getConfigurationValue(this.cachedConfig, key) }; } @@ -150,6 +150,22 @@ export class WorkspaceConfigurationService implements IWorkspaceConfigurationSer }; } + public values(): IWorkspaceConfigurationValues { + const result: IWorkspaceConfigurationValues = Object.create(null); + const keyset = this.keys(); + const keys = [...keyset.workspace, ...keyset.user, ...keyset.default].sort(); + + let lastKey: string; + for (const key of keys) { + if (key !== lastKey) { + lastKey = key; + result[key] = this.lookup(key); + } + } + + return result; + } + public reloadConfiguration(section?: string): TPromise { // Reset caches to ensure we are hitting the disk diff --git a/src/vs/workbench/services/configuration/test/node/configurationService.test.ts b/src/vs/workbench/services/configuration/test/node/configurationService.test.ts index d3ea1f4423e..dfa694fe0f3 100644 --- a/src/vs/workbench/services/configuration/test/node/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configurationService.test.ts @@ -361,4 +361,52 @@ suite('WorkspaceConfigurationService - Node', () => { }); }); }); + + test('values', (done: () => void) => { + const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); + configurationRegistry.registerConfiguration({ + 'id': '_test', + 'type': 'object', + 'properties': { + 'workspaceLookup.service.testSetting': { + 'type': 'string', + 'default': 'isSet' + } + } + }); + + createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { + return createService(workspaceDir, globalSettingsFile).then(service => { + let values = service.values(); + let value = values['workspaceLookup.service.testSetting']; + + assert.ok(value); + assert.equal(value.default, 'isSet'); + + fs.writeFileSync(globalSettingsFile, '{ "workspaceLookup.service.testSetting": true }'); + + return service.reloadConfiguration().then(() => { + values = service.values(); + value = values['workspaceLookup.service.testSetting']; + + assert.ok(value); + assert.equal(value.user, true); + + const settingsFile = path.join(workspaceDir, '.vscode', 'settings.json'); + fs.writeFileSync(settingsFile, '{ "workspaceLookup.service.testSetting": 55 }'); + + return service.reloadConfiguration().then(() => { + values = service.values(); + value = values['workspaceLookup.service.testSetting']; + + assert.ok(value); + assert.equal(value.user, true); + assert.equal(value.workspace, 55); + + done(); + }); + }); + }); + }); + }); }); \ No newline at end of file diff --git a/src/vs/workbench/test/node/api/extHostConfiguration.test.ts b/src/vs/workbench/test/node/api/extHostConfiguration.test.ts index 825611201c3..6eaf22734ae 100644 --- a/src/vs/workbench/test/node/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/node/api/extHostConfiguration.test.ts @@ -10,7 +10,7 @@ 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 { IWorkspaceConfiguration, IWorkspaceConfigurationValue } from 'vs/workbench/services/configuration/common/configuration'; +import { IWorkspaceConfigurationValues, IWorkspaceConfigurationValue } from 'vs/workbench/services/configuration/common/configuration'; suite('ExtHostConfiguration', function () { @@ -22,7 +22,7 @@ suite('ExtHostConfiguration', function () { } }; - function createExtHostConfiguration(data: IWorkspaceConfiguration = Object.create(null), shape?: MainThreadConfigurationShape) { + function createExtHostConfiguration(data: IWorkspaceConfigurationValues = Object.create(null), shape?: MainThreadConfigurationShape) { if (!shape) { shape = new class extends MainThreadConfigurationShape { }; }