extHostConfiguration.ts 7.3 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

S
Sandeep Somavarapu 已提交
7
import { mixin, clone } from 'vs/base/common/objects';
8
import URI from 'vs/base/common/uri';
9
import Event, { Emitter } from 'vs/base/common/event';
10
import * as vscode from 'vscode';
11
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
S
Sandeep Somavarapu 已提交
12
import { ExtHostConfigurationShape, MainThreadConfigurationShape, IWorkspaceConfigurationChangeEventData, IConfigurationInitData } from './extHost.protocol';
S
Sandeep Somavarapu 已提交
13
import { ConfigurationTarget as ExtHostConfigurationTarget } from './extHostTypes';
14
import { IConfigurationData, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
S
Sandeep Somavarapu 已提交
15
import { Configuration, ConfigurationChangeEvent, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
16 17
import { WorkspaceConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels';
import { StrictResourceMap } from 'vs/base/common/map';
S
Sandeep Somavarapu 已提交
18
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
19 20 21 22 23 24 25 26 27 28 29 30

function lookUp(tree: any, key: string) {
	if (key) {
		const parts = key.split('.');
		let node = tree;
		for (let i = 0; node && i < parts.length; i++) {
			node = node[parts[i]];
		}
		return node;
	}
}

S
Sandeep Somavarapu 已提交
31 32 33 34 35
type ConfigurationInspect<T> = {
	key: string;
	defaultValue?: T;
	globalValue?: T;
	workspaceValue?: T;
S
Sandeep Somavarapu 已提交
36
	workspaceFolderValue?: T;
S
Sandeep Somavarapu 已提交
37 38
};

39
export class ExtHostConfiguration implements ExtHostConfigurationShape {
E
Erich Gamma 已提交
40

S
Sandeep Somavarapu 已提交
41
	private readonly _onDidChangeConfiguration = new Emitter<vscode.ConfigurationChangeEvent>();
J
Johannes Rieken 已提交
42 43
	private readonly _proxy: MainThreadConfigurationShape;
	private readonly _extHostWorkspace: ExtHostWorkspace;
S
Sandeep Somavarapu 已提交
44
	private _configurationScopes: Map<string, ConfigurationScope>;
45
	private _configuration: Configuration;
E
Erich Gamma 已提交
46

S
Sandeep Somavarapu 已提交
47
	constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationInitData) {
J
Johannes Rieken 已提交
48
		this._proxy = proxy;
J
Johannes Rieken 已提交
49
		this._extHostWorkspace = extHostWorkspace;
S
Sandeep Somavarapu 已提交
50
		this._configuration = Configuration.parse(data);
S
Sandeep Somavarapu 已提交
51
		this._readConfigurationScopes(data.configurationScopes);
E
Erich Gamma 已提交
52 53
	}

S
Sandeep Somavarapu 已提交
54
	get onDidChangeConfiguration(): Event<vscode.ConfigurationChangeEvent> {
E
Erich Gamma 已提交
55 56 57
		return this._onDidChangeConfiguration && this._onDidChangeConfiguration.event;
	}

58
	$acceptConfigurationChanged(data: IConfigurationData, eventData: IWorkspaceConfigurationChangeEventData) {
S
Sandeep Somavarapu 已提交
59
		this._configuration = Configuration.parse(data);
S
Sandeep Somavarapu 已提交
60
		this._onDidChangeConfiguration.fire(this._toConfigurationChangeEvent(eventData));
E
Erich Gamma 已提交
61 62
	}

S
Sandeep Somavarapu 已提交
63
	getConfiguration(section?: string, resource?: URI, extensionId?: string): vscode.WorkspaceConfiguration {
S
Sandeep Somavarapu 已提交
64
		const config = clone(section
65
			? lookUp(this._configuration.getValue(null, { resource }, this._extHostWorkspace.workspace), section)
S
Sandeep Somavarapu 已提交
66
			: this._configuration.getValue(null, { resource }, this._extHostWorkspace.workspace));
E
Erich Gamma 已提交
67

S
Sandeep Somavarapu 已提交
68 69 70 71
		if (section) {
			this._validateConfigurationAccess(section, resource, extensionId);
		}

S
Sandeep Somavarapu 已提交
72 73
		function parseConfigurationTarget(arg: boolean | ExtHostConfigurationTarget): ConfigurationTarget {
			if (arg === void 0 || arg === null) {
S
Sandeep Somavarapu 已提交
74
				return null;
S
Sandeep Somavarapu 已提交
75 76 77 78 79 80 81 82
			}
			if (typeof arg === 'boolean') {
				return arg ? ConfigurationTarget.USER : ConfigurationTarget.WORKSPACE;
			}

			switch (arg) {
				case ExtHostConfigurationTarget.Global: return ConfigurationTarget.USER;
				case ExtHostConfigurationTarget.Workspace: return ConfigurationTarget.WORKSPACE;
83
				case ExtHostConfigurationTarget.WorkspaceFolder: return ConfigurationTarget.WORKSPACE_FOLDER;
S
Sandeep Somavarapu 已提交
84 85 86
			}
		}

87
		const result: vscode.WorkspaceConfiguration = {
88
			has(key: string): boolean {
89
				return typeof lookUp(config, key) !== 'undefined';
90
			},
S
Sandeep Somavarapu 已提交
91 92
			get: <T>(key: string, defaultValue?: T) => {
				this._validateConfigurationAccess(section ? `${section}.${key}` : key, resource, extensionId);
93
				let result = lookUp(config, key);
94
				if (typeof result === 'undefined') {
95
					result = defaultValue;
96
				}
97
				return result;
98
			},
S
Sandeep Somavarapu 已提交
99
			update: (key: string, value: any, arg: ExtHostConfigurationTarget | boolean) => {
100
				key = section ? `${section}.${key}` : key;
S
Sandeep Somavarapu 已提交
101
				const target = parseConfigurationTarget(arg);
102
				if (value !== void 0) {
S
Sandeep Somavarapu 已提交
103
					return this._proxy.$updateConfigurationOption(target, key, value, resource);
104
				} else {
S
Sandeep Somavarapu 已提交
105
					return this._proxy.$removeConfigurationOption(target, key, resource);
106
				}
107
			},
S
Sandeep Somavarapu 已提交
108
			inspect: <T>(key: string): ConfigurationInspect<T> => {
109
				key = section ? `${section}.${key}` : key;
110
				const config = clone(this._configuration.inspect<T>(key, { resource }, this._extHostWorkspace.workspace));
111
				if (config) {
S
Sandeep Somavarapu 已提交
112
					return {
113 114 115
						key,
						defaultValue: config.default,
						globalValue: config.user,
116
						workspaceValue: config.workspace,
117
						workspaceFolderValue: config.workspaceFolder
118 119
					};
				}
120
				return undefined;
E
Erich Gamma 已提交
121
			}
B
Benjamin Pasero 已提交
122
		};
123

124 125
		if (typeof config === 'object') {
			mixin(result, config, false);
126 127
		}

128
		return <vscode.WorkspaceConfiguration>Object.freeze(result);
129
	}
130

S
Sandeep Somavarapu 已提交
131 132 133 134
	private _validateConfigurationAccess(key: string, resource: URI, extensionId: string): void {
		const scope = this._configurationScopes.get(key);
		const extensionIdText = extensionId ? `[${extensionId}] ` : '';
		if (ConfigurationScope.RESOURCE === scope) {
135 136
			if (resource === void 0) {
				console.warn(`${extensionIdText}Accessing a resource scoped configuration without providing a resource is not expected. To get the effective value for '${key}', provide the URI of a resource or 'null' for any resource.`);
S
Sandeep Somavarapu 已提交
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
			}
			return;
		}
		if (ConfigurationScope.WINDOW === scope) {
			if (resource) {
				console.warn(`${extensionIdText}Accessing a window scoped configuration for a resource is not expected. To associate '${key}' to a resource, define its scope to 'resource' in configuration contributions in 'package.json'.`);
			}
			return;
		}
	}

	private _readConfigurationScopes(scopes: ConfigurationScope[]): void {
		this._configurationScopes = new Map<string, ConfigurationScope>();
		if (scopes.length) {
			const defaultKeys = this._configuration.keys(this._extHostWorkspace.workspace).default;
			if (defaultKeys.length === scopes.length) {
				for (let i = 0; i < defaultKeys.length; i++) {
					this._configurationScopes.set(defaultKeys[i], scopes[i]);
				}
			}
		}
	}

	private _toConfigurationChangeEvent(data: IWorkspaceConfigurationChangeEventData): vscode.ConfigurationChangeEvent {
161 162 163 164 165 166 167
		const changedConfiguration = new ConfigurationModel(data.changedConfiguration.contents, data.changedConfiguration.keys, data.changedConfiguration.overrides);
		const changedConfigurationByResource: StrictResourceMap<ConfigurationModel> = new StrictResourceMap<ConfigurationModel>();
		for (const key of Object.keys(data.changedConfigurationByResource)) {
			const resource = URI.parse(key);
			const model = data.changedConfigurationByResource[key];
			changedConfigurationByResource.set(resource, new ConfigurationModel(model.contents, model.keys, model.overrides));
		}
S
Sandeep Somavarapu 已提交
168 169 170 171
		const event = new WorkspaceConfigurationChangeEvent(new ConfigurationChangeEvent(changedConfiguration, changedConfigurationByResource), this._extHostWorkspace.workspace);
		return Object.freeze({
			affectsConfiguration: (section: string, resource?: URI) => event.affectsConfiguration(section, resource)
		});
172
	}
173
}