提交 697c06f2 编写于 作者: J Johannes Rieken

use different data model to prep ExtHostConfiguration for #inspect knowledge

上级 2b5b2bcd
......@@ -9,6 +9,7 @@ import { TrieMap } from 'vs/base/common/map';
import { score } from 'vs/editor/common/modes/languageSelector';
import * as Platform from 'vs/base/common/platform';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { WorkspaceConfigurationNode } from 'vs/workbench/services/configuration/common/configuration';
import * as errors from 'vs/base/common/errors';
import product from 'vs/platform/product';
import pkg from 'vs/platform/package';
......@@ -42,7 +43,7 @@ import * as vscode from 'vscode';
import * as paths from 'vs/base/common/paths';
import { realpathSync } from 'fs';
import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { MainContext, ExtHostContext, InstanceCollection, IInitConfiguration } from './extHost.protocol';
import { MainContext, ExtHostContext, InstanceCollection } from './extHost.protocol';
import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration';
......@@ -63,7 +64,7 @@ function proposedApiFunction<T>(extension: IExtensionDescription, fn: T): T {
/**
* This method instantiates and returns the extension API surface
*/
export function createApiFactory(initDataConfiguration: IInitConfiguration, initTelemetryInfo: ITelemetryInfo, threadService: IThreadService, extensionService: ExtHostExtensionService, contextService: IWorkspaceContextService): IExtensionApiFactory {
export function createApiFactory(initDataConfiguration: WorkspaceConfigurationNode, initTelemetryInfo: ITelemetryInfo, threadService: IThreadService, extensionService: ExtHostExtensionService, contextService: IWorkspaceContextService): IExtensionApiFactory {
// Addressable instances
const col = new InstanceCollection();
......
......@@ -29,6 +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 { WorkspaceConfigurationNode } 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';
......@@ -43,10 +44,6 @@ export interface IEnvironment {
extensionTestsPath: string;
}
export interface IInitConfiguration {
_initConfigurationBrand: void;
}
export interface IInitData {
parentPid: number;
environment: IEnvironment;
......@@ -54,7 +51,7 @@ export interface IInitData {
workspace: IWorkspace;
};
extensions: IExtensionDescription[];
configuration: IInitConfiguration;
configuration: WorkspaceConfigurationNode;
telemetryInfo: ITelemetryInfo;
}
......@@ -232,7 +229,7 @@ export abstract class ExtHostCommandsShape {
}
export abstract class ExtHostConfigurationShape {
$acceptConfigurationChanged(config: any) { throw ni(); }
$acceptConfigurationChanged(config: WorkspaceConfigurationNode) { throw ni(); }
}
export abstract class ExtHostDiagnosticsShape {
......
......@@ -9,24 +9,25 @@ 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 { WorkspaceConfigurationNode, IWorkspaceConfigurationValue } from 'vs/workbench/services/configuration/common/configuration';
export class ExtHostConfiguration extends ExtHostConfigurationShape {
private _proxy: MainThreadConfigurationShape;
private _config: any;
private _config: WorkspaceConfigurationNode;
private _onDidChangeConfiguration = new Emitter<void>();
constructor(proxy: MainThreadConfigurationShape, configuration: any) {
constructor(proxy: MainThreadConfigurationShape, config: WorkspaceConfigurationNode) {
super();
this._proxy = proxy;
this._config = configuration;
this._config = config;
}
get onDidChangeConfiguration(): Event<void> {
return this._onDidChangeConfiguration && this._onDidChangeConfiguration.event;
}
public $acceptConfigurationChanged(config: any) {
public $acceptConfigurationChanged(config: WorkspaceConfigurationNode) {
this._config = config;
this._onDidChangeConfiguration.fire(undefined);
}
......@@ -39,14 +40,17 @@ export class ExtHostConfiguration extends ExtHostConfigurationShape {
const result: WorkspaceConfiguration = {
has(key: string): boolean {
return typeof ExtHostConfiguration._lookUp(key, config) !== 'undefined';
return typeof ExtHostConfiguration._lookUp(key, <WorkspaceConfigurationNode>config) !== 'undefined';
},
get<T>(key: string, defaultValue?: T): T {
let result = ExtHostConfiguration._lookUp(key, config);
get<T>(key: string, defaultValue?: T): any {
let result = ExtHostConfiguration._lookUp(key, <WorkspaceConfigurationNode>config);
if (typeof result === 'undefined') {
result = defaultValue;
return defaultValue;
} else if (isConfigurationValue(result)) {
return result.value;
} else {
return ExtHostConfiguration._values(result);
}
return result;
},
update: (key: string, value: any, global: boolean = false) => {
key = section ? `${section}.${key}` : key;
......@@ -59,23 +63,52 @@ export class ExtHostConfiguration extends ExtHostConfigurationShape {
}
};
if (typeof config === 'object') {
mixin(result, config, false);
if (!isConfigurationValue(config)) {
mixin(result, ExtHostConfiguration._values(config), false);
}
return Object.freeze(result);
}
private static _lookUp(section: string, config: any) {
private static _lookUp(section: string, config: WorkspaceConfigurationNode): WorkspaceConfigurationNode | IWorkspaceConfigurationValue<any> {
if (!section) {
return;
}
let parts = section.split('.');
let node = config;
while (node && parts.length) {
node = node[parts.shift()];
let child = node[parts.shift()];
if (isConfigurationValue(child)) {
return child;
} else {
node = child;
}
}
return node;
}
private static _values(node: WorkspaceConfigurationNode): any {
let target = Object.create(null);
for (let key in node) {
let child = node[key];
if (isConfigurationValue(child)) {
target[key] = child.value;
} else {
target[key] = ExtHostConfiguration._values(child);
}
}
return target;
}
}
function isConfigurationValue(thing: any): thing is IWorkspaceConfigurationValue<any> {
return typeof thing === 'object'
// must have 'value'
&& typeof (<IWorkspaceConfigurationValue<any>>thing).value !== 'undefined'
// and at least one source 'default', 'user', or 'workspace'
&& (typeof (<IWorkspaceConfigurationValue<any>>thing).default !== 'undefined'
|| typeof (<IWorkspaceConfigurationValue<any>>thing).user !== 'undefined'
|| typeof (<IWorkspaceConfigurationValue<any>>thing).workspace !== '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 } from 'vs/workbench/services/configuration/common/configuration';
import { IWorkspaceConfigurationService, getWorkspaceConfigurationTree } from 'vs/workbench/services/configuration/common/configuration';
import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
import { MainThreadConfigurationShape, ExtHostContext } from './extHost.protocol';
......@@ -24,7 +24,11 @@ export class MainThreadConfiguration extends MainThreadConfigurationShape {
super();
this._configurationEditingService = configurationEditingService;
const proxy = threadService.get(ExtHostContext.ExtHostConfiguration);
this._toDispose = configurationService.onDidUpdateConfiguration(event => proxy.$acceptConfigurationChanged(event.config));
this._toDispose = configurationService.onDidUpdateConfiguration(() => {
const tree = getWorkspaceConfigurationTree(configurationService);
proxy.$acceptConfigurationChanged(tree);
});
}
public dispose(): void {
......
......@@ -28,9 +28,9 @@ import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import Event, { Emitter } from 'vs/base/common/event';
import { WatchDog } from 'vs/base/common/watchDog';
import { createQueuedSender, IQueuedSender } from 'vs/base/node/processes';
import { IInitData, IInitConfiguration } from 'vs/workbench/api/node/extHost.protocol';
import { IInitData } from 'vs/workbench/api/node/extHost.protocol';
import { MainProcessExtensionService } from 'vs/workbench/api/node/mainThreadExtensionService';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import { IWorkspaceConfigurationService, getWorkspaceConfigurationTree } from 'vs/workbench/services/configuration/common/configuration';
export const EXTENSION_LOG_BROADCAST_CHANNEL = 'vscode:extensionLog';
export const EXTENSION_ATTACH_BROADCAST_CHANNEL = 'vscode:extensionAttach';
......@@ -258,7 +258,7 @@ export class ExtensionHostProcessWorker {
workspace: this.contextService.getWorkspace()
},
extensions: extensionDescriptions,
configuration: this.configurationService.getConfiguration<IInitConfiguration>(),
configuration: getWorkspaceConfigurationTree(this.configurationService),
telemetryInfo
};
this.extensionHostProcessQueuedSender.send(stringify(initData));
......
......@@ -42,4 +42,42 @@ export const WORKSPACE_STANDALONE_CONFIGURATIONS = {
'tasks': `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/tasks.json`,
'launch': `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/launch.json`,
'extensions': `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/extensions.json`
};
\ No newline at end of file
};
export interface WorkspaceConfigurationNode {
[part: string]: IWorkspaceConfigurationValue<any> | WorkspaceConfigurationNode;
}
export function getWorkspaceConfigurationTree(configurationService: IWorkspaceConfigurationService): WorkspaceConfigurationNode {
const result: WorkspaceConfigurationNode = 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);
insert(result, key, config);
}
}
return result;
}
function insert(root: WorkspaceConfigurationNode, key: string, value: any): void {
const parts = key.split('.');
let i = 0;
while (i < parts.length - 1) {
let child = root[parts[i]];
if (child) {
root = <any>child;
i += 1;
} else {
break;
}
}
while (i < parts.length - 1) {
root = root[parts[i]] = Object.create(null);
i += 1;
}
root[parts[parts.length - 1]] = value;
}
......@@ -10,6 +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 { WorkspaceConfigurationNode, IWorkspaceConfigurationValue } from 'vs/workbench/services/configuration/common/configuration';
suite('ExtHostConfiguration', function () {
......@@ -21,23 +22,32 @@ suite('ExtHostConfiguration', function () {
}
};
function createExtHostConfiguration(data: any = {}, shape?: MainThreadConfigurationShape) {
function createExtHostConfiguration(data: WorkspaceConfigurationNode = {}, shape?: MainThreadConfigurationShape) {
if (!shape) {
shape = new class extends MainThreadConfigurationShape { };
}
return new ExtHostConfiguration(shape, data);
}
function createConfigurationValue<T>(value: T): IWorkspaceConfigurationValue<T> {
return {
value,
default: value,
user: undefined,
workspace: undefined
};
}
test('has/get', function () {
const all = createExtHostConfiguration({
farboo: {
config0: true,
config0: createConfigurationValue(true),
nested: {
config1: 42,
config2: 'Das Pferd frisst kein Reis.'
config1: createConfigurationValue(42),
config2: createConfigurationValue('Das Pferd frisst kein Reis.'),
},
config4: ''
config4: createConfigurationValue('')
}
});
......@@ -49,18 +59,22 @@ suite('ExtHostConfiguration', function () {
assert.equal(config['config0'], true);
assert.equal(config['config4'], '');
assert.throws(() => config['config4'] = 'valuevalue');
assert.ok(config.has('nested.config1'));
assert.equal(config.get('nested.config1'), 42);
assert.ok(config.has('nested.config2'));
assert.equal(config.get('nested.config2'), 'Das Pferd frisst kein Reis.');
assert.ok(config.has('nested'));
assert.deepEqual(config.get('nested'), { config1: 42, config2: 'Das Pferd frisst kein Reis.' });
});
test('getConfiguration vs get', function () {
const all = createExtHostConfiguration({
farboo: {
config0: true,
config4: '38'
config0: createConfigurationValue(true),
config4: createConfigurationValue('38')
}
});
......@@ -76,7 +90,7 @@ suite('ExtHostConfiguration', function () {
test('name vs property', function () {
const all = createExtHostConfiguration({
farboo: {
get: 'get-prop'
get: createConfigurationValue('get-prop')
}
});
const config = all.getConfiguration('farboo');
......@@ -90,7 +104,7 @@ suite('ExtHostConfiguration', function () {
test('udate/section to key', function () {
const shape = new RecordingShape();
const allConfig = createExtHostConfiguration({ foo: { bar: 1, far: 2 } }, shape);
const allConfig = createExtHostConfiguration({ foo: { bar: createConfigurationValue(1), far: createConfigurationValue(2) } }, shape);
let config = allConfig.getConfiguration('foo');
config.update('bar', 42, true);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册