提交 aac98278 编写于 作者: B Benjamin Pasero

ConfigurationService#lookup is responsible for 25% of startup time (fixes #15884)

上级 2c8ab1a5
......@@ -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<IConfigurationRegistry>(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<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
return Object.keys(properties);
}
\ No newline at end of file
......@@ -50,7 +50,9 @@ export class ConfigurationService<T> 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<T> implements IConfigurationService, IDisposab
public getConfiguration<C>(section?: string): C {
const cache = this.getCache();
return section ? cache.consolidated[section] : cache.consolidated;
}
......@@ -82,11 +85,13 @@ export class ConfigurationService<T> implements IConfigurationService, IDisposab
}
public lookup<C>(key: string): IConfigurationValue<C> {
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<C>(getDefaultValues(), key)),
user: objects.clone(getConfigurationValue<C>(toValuesTree(this.rawConfig.getConfig()), key)),
value: objects.clone(getConfigurationValue<C>(this.getConfiguration(), key))
default: objects.clone(getConfigurationValue<C>(cache.defaults, key)),
user: objects.clone(getConfigurationValue<C>(cache.user, key)),
value: objects.clone(getConfigurationValue<C>(cache.consolidated, key))
};
}
......
......@@ -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 {
......
......@@ -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);
}
......
......@@ -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());
});
}
......
......@@ -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));
......
......@@ -12,6 +12,8 @@ export const WORKSPACE_CONFIG_DEFAULT_PATH = `${WORKSPACE_CONFIG_FOLDER_DEFAULT_
export const IWorkspaceConfigurationService = createDecorator<IWorkspaceConfigurationService>('configurationService');
export type IWorkspaceConfigurationValues = { [key: string]: IWorkspaceConfigurationValue<any> }
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<T> extends IConfigurationValue<T> {
......@@ -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<any> }
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
......@@ -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<C>(this.cachedWorkspaceConfig, key),
value: getConfigurationValue<C>(this.getConfiguration(), key)
value: getConfigurationValue<C>(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<any> {
// Reset caches to ensure we are hitting the disk
......
......@@ -361,4 +361,52 @@ suite('WorkspaceConfigurationService - Node', () => {
});
});
});
test('values', (done: () => void) => {
const configurationRegistry = <IConfigurationRegistry>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
......@@ -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 { };
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册