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