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

A
Alex Dima 已提交
6
import * as nls from 'vs/nls';
A
Alex Dima 已提交
7
import { Emitter, Event } from 'vs/base/common/event';
J
Johannes Rieken 已提交
8
import { Disposable } from 'vs/base/common/lifecycle';
A
Alex Dima 已提交
9
import * as objects from 'vs/base/common/objects';
A
Alex Dima 已提交
10
import * as arrays from 'vs/base/common/arrays';
11
import { IEditorOptions, editorOptionsRegistry, ValidatedEditorOptions, IEnvironmentalOptions, IComputedEditorOptions, ConfigurationChangedEvent, EDITOR_MODEL_DEFAULTS, EditorOption, FindComputedEditorOptionValueById } from 'vs/editor/common/config/editorOptions';
A
Alex Dima 已提交
12 13 14
import { EditorZoom } from 'vs/editor/common/config/editorZoom';
import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo';
import * as editorCommon from 'vs/editor/common/editorCommon';
15
import { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationRegistry, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';
A
Alex Dima 已提交
16
import { Registry } from 'vs/platform/registry/common/platform';
17
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
18
import { forEach } from 'vs/base/common/collections';
E
Erich Gamma 已提交
19

20 21 22 23 24 25 26
/**
 * Control what pressing Tab does.
 * If it is false, pressing Tab or Shift-Tab will be handled by the editor.
 * If it is true, pressing Tab or Shift-Tab will move the browser focus.
 * Defaults to false.
 */
export interface ITabFocus {
J
Johannes Rieken 已提交
27
	onDidChangeTabFocus: Event<boolean>;
28
	getTabFocusMode(): boolean;
J
Johannes Rieken 已提交
29
	setTabFocusMode(tabFocusMode: boolean): void;
30 31
}

A
Alex Dima 已提交
32
export const TabFocus: ITabFocus = new class implements ITabFocus {
33 34
	private _tabFocus: boolean = false;

35
	private readonly _onDidChangeTabFocus = new Emitter<boolean>();
36
	public readonly onDidChangeTabFocus: Event<boolean> = this._onDidChangeTabFocus.event;
37 38 39 40 41

	public getTabFocusMode(): boolean {
		return this._tabFocus;
	}

J
Johannes Rieken 已提交
42
	public setTabFocusMode(tabFocusMode: boolean): void {
43 44 45 46 47 48 49 50 51
		if (this._tabFocus === tabFocusMode) {
			return;
		}

		this._tabFocus = tabFocusMode;
		this._onDidChangeTabFocus.fire(this._tabFocus);
	}
};

A
Alex Dima 已提交
52 53 54 55
export interface IEnvConfiguration {
	extraEditorClassName: string;
	outerWidth: number;
	outerHeight: number;
56
	emptySelectionClipboard: boolean;
A
Alex Dima 已提交
57 58
	pixelRatio: number;
	zoomLevel: number;
59
	accessibilitySupport: AccessibilitySupport;
60 61
}

62 63
const hasOwnProperty = Object.hasOwnProperty;

A
Alex Dima 已提交
64
export class ComputedEditorOptions implements IComputedEditorOptions {
A
Alex Dima 已提交
65 66 67 68 69 70 71 72 73 74 75 76
	private readonly _values: any[] = [];
	public _read<T>(id: EditorOption): T {
		return this._values[id];
	}
	public get<T extends EditorOption>(id: T): FindComputedEditorOptionValueById<T> {
		return this._values[id];
	}
	public _write<T>(id: EditorOption, value: T): void {
		this._values[id] = value;
	}
}

77 78 79 80 81 82 83 84 85 86 87 88 89
class RawEditorOptions {
	private readonly _values: any[] = [];
	public _read<T>(id: EditorOption): T | undefined {
		return this._values[id];
	}
	public _write<T>(id: EditorOption, value: T | undefined): void {
		this._values[id] = value;
	}
}

class EditorConfiguration2 {
	public static readOptions(_options: IEditorOptions): RawEditorOptions {
		const options: { [key: string]: any; } = _options;
90 91
		const result = new RawEditorOptions();
		for (const editorOption of editorOptionsRegistry) {
A
Alex Dima 已提交
92
			const value = (editorOption.name === '_never_' ? undefined : options[editorOption.name]);
93
			result._write(editorOption.id, value);
94 95 96 97
		}
		return result;
	}

98 99 100
	public static validateOptions(options: RawEditorOptions): ValidatedEditorOptions {
		const result = new ValidatedEditorOptions();
		for (const editorOption of editorOptionsRegistry) {
101 102 103 104 105
			result._write(editorOption.id, editorOption.validate(options._read(editorOption.id)));
		}
		return result;
	}

106 107 108
	public static computeOptions(options: ValidatedEditorOptions, env: IEnvironmentalOptions): ComputedEditorOptions {
		const result = new ComputedEditorOptions();
		for (const editorOption of editorOptionsRegistry) {
A
Alex Dima 已提交
109
			result._write(editorOption.id, editorOption.compute(env, result, options._read(editorOption.id)));
110 111 112 113
		}
		return result;
	}

A
Alex Dima 已提交
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
	private static _deepEquals<T>(a: T, b: T): boolean {
		if (typeof a !== 'object' || typeof b !== 'object') {
			return (a === b);
		}
		if (Array.isArray(a) || Array.isArray(b)) {
			return (Array.isArray(a) && Array.isArray(b) ? arrays.equals(a, b) : false);
		}
		for (let key in a) {
			if (!EditorConfiguration2._deepEquals(a[key], b[key])) {
				return false;
			}
		}
		return true;
	}

129 130
	public static checkEquals(a: ComputedEditorOptions, b: ComputedEditorOptions): ConfigurationChangedEvent | null {
		const result: boolean[] = [];
131
		let somethingChanged = false;
132
		for (const editorOption of editorOptionsRegistry) {
A
Alex Dima 已提交
133
			const changed = !EditorConfiguration2._deepEquals(a._read(editorOption.id), b._read(editorOption.id));
134
			result[editorOption.id] = changed;
A
Alex Dima 已提交
135
			if (changed) {
136 137 138
				somethingChanged = true;
			}
		}
139
		return (somethingChanged ? new ConfigurationChangedEvent(result) : null);
140 141 142
	}
}

A
Alex Dima 已提交
143 144 145
/**
 * Compatibility with old options
 */
146
function migrateOptions(options: IEditorOptions): void {
A
Alex Dima 已提交
147
	const wordWrap = options.wordWrap;
A
Alex Dima 已提交
148 149 150 151 152 153
	if (<any>wordWrap === true) {
		options.wordWrap = 'on';
	} else if (<any>wordWrap === false) {
		options.wordWrap = 'off';
	}

A
Alex Dima 已提交
154
	const lineNumbers = options.lineNumbers;
A
Alex Dima 已提交
155 156 157 158 159
	if (<any>lineNumbers === true) {
		options.lineNumbers = 'on';
	} else if (<any>lineNumbers === false) {
		options.lineNumbers = 'off';
	}
A
Alex Dima 已提交
160

A
Alex Dima 已提交
161
	const autoClosingBrackets = options.autoClosingBrackets;
A
Alex Dima 已提交
162 163 164 165 166 167
	if (<any>autoClosingBrackets === false) {
		options.autoClosingBrackets = 'never';
		options.autoClosingQuotes = 'never';
		options.autoSurround = 'never';
	}

A
Alex Dima 已提交
168
	const cursorBlinking = options.cursorBlinking;
A
Alex Dima 已提交
169 170 171 172
	if (<any>cursorBlinking === 'visible') {
		options.cursorBlinking = 'solid';
	}

A
Alex Dima 已提交
173
	const renderWhitespace = options.renderWhitespace;
A
Alex Dima 已提交
174 175 176 177 178 179
	if (<any>renderWhitespace === true) {
		options.renderWhitespace = 'boundary';
	} else if (<any>renderWhitespace === false) {
		options.renderWhitespace = 'none';
	}

A
Alex Dima 已提交
180
	const renderLineHighlight = options.renderLineHighlight;
A
Alex Dima 已提交
181 182 183 184 185
	if (<any>renderLineHighlight === true) {
		options.renderLineHighlight = 'line';
	} else if (<any>renderLineHighlight === false) {
		options.renderLineHighlight = 'none';
	}
A
Alex Dima 已提交
186

A
Alex Dima 已提交
187
	const acceptSuggestionOnEnter = options.acceptSuggestionOnEnter;
A
Alex Dima 已提交
188 189 190 191 192
	if (<any>acceptSuggestionOnEnter === true) {
		options.acceptSuggestionOnEnter = 'on';
	} else if (<any>acceptSuggestionOnEnter === false) {
		options.acceptSuggestionOnEnter = 'off';
	}
A
Alex Dima 已提交
193 194 195 196 197 198 199 200

	const tabCompletion = options.tabCompletion;
	if (<any>tabCompletion === false) {
		options.tabCompletion = 'off';
	} else if (<any>tabCompletion === true) {
		options.tabCompletion = 'onlySnippets';
	}

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
	const suggest = options.suggest;
	if (suggest && typeof (<any>suggest).filteredTypes === 'object' && (<any>suggest).filteredTypes) {
		const mapping: Record<string, string> = {};
		mapping['method'] = 'showMethods';
		mapping['function'] = 'showFunctions';
		mapping['constructor'] = 'showConstructors';
		mapping['field'] = 'showFields';
		mapping['variable'] = 'showVariables';
		mapping['class'] = 'showClasses';
		mapping['struct'] = 'showStructs';
		mapping['interface'] = 'showInterfaces';
		mapping['module'] = 'showModules';
		mapping['property'] = 'showProperties';
		mapping['event'] = 'showEvents';
		mapping['operator'] = 'showOperators';
		mapping['unit'] = 'showUnits';
		mapping['value'] = 'showValues';
		mapping['constant'] = 'showConstants';
		mapping['enum'] = 'showEnums';
		mapping['enumMember'] = 'showEnumMembers';
		mapping['keyword'] = 'showKeywords';
		mapping['text'] = 'showWords';
		mapping['color'] = 'showColors';
		mapping['file'] = 'showFiles';
		mapping['reference'] = 'showReferences';
		mapping['folder'] = 'showFolders';
		mapping['typeParameter'] = 'showTypeParameters';
		mapping['snippet'] = 'showSnippets';
		forEach(mapping, entry => {
			const value = (<any>suggest).filteredTypes[entry.key];
			if (value === false) {
				(<any>suggest)[entry.value] = value;
			}
		});
		// delete (<any>suggest).filteredTypes;
	}

A
Alex Dima 已提交
238 239 240 241 242 243 244 245 246 247
	const hover = options.hover;
	if (<any>hover === true) {
		options.hover = {
			enabled: true
		};
	} else if (<any>hover === false) {
		options.hover = {
			enabled: false
		};
	}
248 249 250 251 252 253 254 255 256 257 258

	const parameterHints = options.parameterHints;
	if (<any>parameterHints === true) {
		options.parameterHints = {
			enabled: true
		};
	} else if (<any>parameterHints === false) {
		options.parameterHints = {
			enabled: false
		};
	}
A
Alex Dima 已提交
259 260
}

A
Alex Dima 已提交
261 262 263 264 265
function deepCloneAndMigrateOptions(_options: IEditorOptions): IEditorOptions {
	const options = objects.deepClone(_options);
	migrateOptions(options);
	return options;
}
E
Erich Gamma 已提交
266

A
Alex Dima 已提交
267
export abstract class CommonEditorConfiguration extends Disposable implements editorCommon.IConfiguration {
E
Erich Gamma 已提交
268

269 270
	private _onDidChange = this._register(new Emitter<ConfigurationChangedEvent>());
	public readonly onDidChange: Event<ConfigurationChangedEvent> = this._onDidChange.event;
A
Alex Dima 已提交
271

A
Alex Dima 已提交
272
	public readonly isSimpleWidget: boolean;
273
	public options!: ComputedEditorOptions;
274

A
Alex Dima 已提交
275 276
	private _isDominatedByLongLines: boolean;
	private _lineNumbersDigitCount: number;
A
Alex Dima 已提交
277

A
Alex Dima 已提交
278 279 280
	private _rawOptions: IEditorOptions;
	private _readOptions: RawEditorOptions;
	protected _validatedOptions: ValidatedEditorOptions;
281

A
Alex Dima 已提交
282 283 284
	constructor(isSimpleWidget: boolean, _options: IEditorOptions) {
		super();
		this.isSimpleWidget = isSimpleWidget;
285

E
Erich Gamma 已提交
286
		this._isDominatedByLongLines = false;
287
		this._lineNumbersDigitCount = 1;
A
Alex Dima 已提交
288

A
Alex Dima 已提交
289 290 291 292
		this._rawOptions = deepCloneAndMigrateOptions(_options);
		this._readOptions = EditorConfiguration2.readOptions(this._rawOptions);
		this._validatedOptions = EditorConfiguration2.validateOptions(this._readOptions);

293
		this._register(EditorZoom.onDidChangeZoomLevel(_ => this._recomputeOptions()));
294
		this._register(TabFocus.onDidChangeTabFocus(_ => this._recomputeOptions()));
E
Erich Gamma 已提交
295 296
	}

A
Alex Dima 已提交
297 298 299
	public observeReferenceElement(dimension?: editorCommon.IDimension): void {
	}

E
Erich Gamma 已提交
300 301 302 303 304
	public dispose(): void {
		super.dispose();
	}

	protected _recomputeOptions(): void {
305 306
		const oldOptions = this.options;
		const newOptions = this._computeInternalOptions();
307

A
Alex Dima 已提交
308 309 310 311
		if (!oldOptions) {
			this.options = newOptions;
		} else {
			const changeEvent = EditorConfiguration2.checkEquals(oldOptions, newOptions);
312

A
Alex Dima 已提交
313 314 315 316
			if (changeEvent === null) {
				// nothing changed!
				return;
			}
E
Erich Gamma 已提交
317

A
Alex Dima 已提交
318
			this.options = newOptions;
319
			this._onDidChange.fire(changeEvent);
320
		}
E
Erich Gamma 已提交
321
	}
322

323
	public getRawOptions(): IEditorOptions {
324
		return this._rawOptions;
E
Erich Gamma 已提交
325
	}
326

327
	private _computeInternalOptions(): ComputedEditorOptions {
A
Alex Dima 已提交
328
		const partialEnv = this._getEnvConfiguration();
A
Alex Dima 已提交
329
		const bareFontInfo = BareFontInfo.createFromValidatedSettings(this._validatedOptions, partialEnv.zoomLevel, this.isSimpleWidget);
330
		const env: IEnvironmentalOptions = {
A
Alex Dima 已提交
331 332
			outerWidth: partialEnv.outerWidth,
			outerHeight: partialEnv.outerHeight,
333
			fontInfo: this.readConfiguration(bareFontInfo),
334
			extraEditorClassName: partialEnv.extraEditorClassName,
335 336
			isDominatedByLongLines: this._isDominatedByLongLines,
			lineNumbersDigitCount: this._lineNumbersDigitCount,
337
			emptySelectionClipboard: partialEnv.emptySelectionClipboard,
A
Alex Dima 已提交
338
			pixelRatio: partialEnv.pixelRatio,
339 340
			tabFocusMode: TabFocus.getTabFocusMode(),
			accessibilitySupport: partialEnv.accessibilitySupport
A
Alex Dima 已提交
341
		};
A
Alex Dima 已提交
342
		return EditorConfiguration2.computeOptions(this._validatedOptions, env);
E
Erich Gamma 已提交
343 344
	}

345 346 347 348 349 350 351 352 353 354 355 356
	private static _primitiveArrayEquals(a: any[], b: any[]): boolean {
		if (a.length !== b.length) {
			return false;
		}
		for (let i = 0; i < a.length; i++) {
			if (a[i] !== b[i]) {
				return false;
			}
		}
		return true;
	}

M
Matt Bierner 已提交
357 358
	private static _subsetEquals(base: { [key: string]: any }, subset: { [key: string]: any }): boolean {
		for (const key in subset) {
359 360 361 362 363 364 365 366
			if (hasOwnProperty.call(subset, key)) {
				const subsetValue = subset[key];
				const baseValue = base[key];

				if (baseValue === subsetValue) {
					continue;
				}
				if (Array.isArray(baseValue) && Array.isArray(subsetValue)) {
367
					if (!this._primitiveArrayEquals(baseValue, subsetValue)) {
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
						return false;
					}
					continue;
				}
				if (typeof baseValue === 'object' && typeof subsetValue === 'object') {
					if (!this._subsetEquals(baseValue, subsetValue)) {
						return false;
					}
					continue;
				}

				return false;
			}
		}
		return true;
	}

A
Alex Dima 已提交
385 386
	public updateOptions(_newOptions: IEditorOptions): void {
		if (typeof _newOptions === 'undefined') {
387 388
			return;
		}
A
Alex Dima 已提交
389
		const newOptions = deepCloneAndMigrateOptions(_newOptions);
390 391 392
		if (CommonEditorConfiguration._subsetEquals(this._rawOptions, newOptions)) {
			return;
		}
393
		this._rawOptions = objects.mixin(this._rawOptions, newOptions || {});
A
Alex Dima 已提交
394 395
		this._readOptions = EditorConfiguration2.readOptions(this._rawOptions);
		this._validatedOptions = EditorConfiguration2.validateOptions(this._readOptions);
396

E
Erich Gamma 已提交
397 398 399
		this._recomputeOptions();
	}

J
Johannes Rieken 已提交
400
	public setIsDominatedByLongLines(isDominatedByLongLines: boolean): void {
E
Erich Gamma 已提交
401 402 403 404
		this._isDominatedByLongLines = isDominatedByLongLines;
		this._recomputeOptions();
	}

J
Johannes Rieken 已提交
405
	public setMaxLineNumber(maxLineNumber: number): void {
406
		let digitCount = CommonEditorConfiguration._digitCount(maxLineNumber);
407
		if (this._lineNumbersDigitCount === digitCount) {
A
Alex Dima 已提交
408 409
			return;
		}
410
		this._lineNumbersDigitCount = digitCount;
E
Erich Gamma 已提交
411 412 413
		this._recomputeOptions();
	}

414
	private static _digitCount(n: number): number {
A
Alex Dima 已提交
415
		let r = 0;
416 417 418 419 420 421
		while (n) {
			n = Math.floor(n / 10);
			r++;
		}
		return r ? r : 1;
	}
A
Alex Dima 已提交
422
	protected abstract _getEnvConfiguration(): IEnvConfiguration;
423

424
	protected abstract readConfiguration(styling: BareFontInfo): FontInfo;
425

E
Erich Gamma 已提交
426 427
}

428
const configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
429
const editorConfiguration: IConfigurationNode = {
430 431
	id: 'editor',
	order: 5,
432
	type: 'object',
433 434 435
	title: nls.localize('editorConfigurationTitle', "Editor"),
	overridable: true,
	scope: ConfigurationScope.RESOURCE,
436
	properties: {
J
Johannes Rieken 已提交
437
		'editor.tabSize': {
438 439 440 441
			type: 'number',
			default: EDITOR_MODEL_DEFAULTS.tabSize,
			minimum: 1,
			markdownDescription: nls.localize('tabSize', "The number of spaces a tab is equal to. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.")
E
Erich Gamma 已提交
442
		},
443 444 445
		// 'editor.indentSize': {
		// 	'anyOf': [
		// 		{
446 447
		// 			type: 'string',
		// 			enum: ['tabSize']
448 449
		// 		},
		// 		{
450 451
		// 			type: 'number',
		// 			minimum: 1
452 453
		// 		}
		// 	],
454 455
		// 	default: 'tabSize',
		// 	markdownDescription: nls.localize('indentSize', "The number of spaces used for indentation or 'tabSize' to use the value from `#editor.tabSize#`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.")
456
		// },
J
Johannes Rieken 已提交
457
		'editor.insertSpaces': {
458 459 460
			type: 'boolean',
			default: EDITOR_MODEL_DEFAULTS.insertSpaces,
			markdownDescription: nls.localize('insertSpaces', "Insert spaces when pressing `Tab`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.")
E
Erich Gamma 已提交
461
		},
J
Johannes Rieken 已提交
462
		'editor.detectIndentation': {
463 464 465
			type: 'boolean',
			default: EDITOR_MODEL_DEFAULTS.detectIndentation,
			markdownDescription: nls.localize('detectIndentation', "Controls whether `#editor.tabSize#` and `#editor.insertSpaces#` will be automatically detected when a file is opened based on the file contents.")
E
Erich Gamma 已提交
466
		},
467
		'editor.trimAutoWhitespace': {
468
			type: 'boolean',
469 470
			default: EDITOR_MODEL_DEFAULTS.trimAutoWhitespace,
			description: nls.localize('trimAutoWhitespace', "Remove trailing auto inserted whitespace.")
471
		},
472
		'editor.largeFileOptimizations': {
473
			type: 'boolean',
474 475
			default: EDITOR_MODEL_DEFAULTS.largeFileOptimizations,
			description: nls.localize('largeFileOptimizations', "Special handling for large files to disable certain memory intensive features.")
476
		},
477
		'editor.wordBasedSuggestions': {
478 479 480
			type: 'boolean',
			default: true,
			description: nls.localize('wordBasedSuggestions', "Controls whether completions should be computed based on words in the document.")
481
		},
J
Johannes Rieken 已提交
482
		'editor.stablePeek': {
483 484 485
			type: 'boolean',
			default: false,
			markdownDescription: nls.localize('stablePeek', "Keep peek editors open even when double clicking their content or when hitting `Escape`.")
486
		},
487
		'editor.maxTokenizationLineLength': {
488 489 490
			type: 'integer',
			default: 20_000,
			description: nls.localize('maxTokenizationLineLength', "Lines above this length will not be tokenized for performance reasons")
491
		},
492
		'editor.codeActionsOnSave': {
493 494
			type: 'object',
			properties: {
495
				'source.organizeImports': {
496 497
					type: 'boolean',
					description: nls.localize('codeActionsOnSave.organizeImports', "Controls whether organize imports action should be run on file save.")
498
				},
499
				'source.fixAll': {
500 501
					type: 'boolean',
					description: nls.localize('codeActionsOnSave.fixAll', "Controls whether auto fix action should be run on file save.")
502 503 504
				}
			},
			'additionalProperties': {
505
				type: 'boolean'
506
			},
507 508
			default: {},
			description: nls.localize('codeActionsOnSave', "Code action kinds to be run on save.")
509 510
		},
		'editor.codeActionsOnSaveTimeout': {
511 512 513
			type: 'number',
			default: 750,
			description: nls.localize('codeActionsOnSaveTimeout', "Timeout in milliseconds after which the code actions that are run on save are cancelled.")
514
		},
515
		'diffEditor.maxComputationTime': {
516 517
			type: 'number',
			default: 5000,
518
			description: nls.localize('maxComputationTime', "Timeout in milliseconds after which diff computation is cancelled. Use 0 for no timeout.")
519
		},
J
Johannes Rieken 已提交
520
		'diffEditor.renderSideBySide': {
521 522 523
			type: 'boolean',
			default: true,
			description: nls.localize('sideBySide', "Controls whether the diff editor shows the diff side by side or inline.")
E
Erich Gamma 已提交
524
		},
J
Johannes Rieken 已提交
525
		'diffEditor.ignoreTrimWhitespace': {
526 527 528
			type: 'boolean',
			default: true,
			description: nls.localize('ignoreTrimWhitespace', "Controls whether the diff editor shows changes in leading or trailing whitespace as diffs.")
529 530
		},
		'diffEditor.renderIndicators': {
531 532 533
			type: 'boolean',
			default: true,
			description: nls.localize('renderIndicators', "Controls whether the diff editor shows +/- indicators for added/removed changes.")
E
Erich Gamma 已提交
534 535
		}
	}
A
Alex Dima 已提交
536 537
};

538 539 540 541
function isConfigurationPropertySchema(x: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema; }): x is IConfigurationPropertySchema {
	return (typeof x.type !== 'undefined' || typeof x.anyOf !== 'undefined');
}

542 543
// Add properties from the Editor Option Registry
for (const editorOption of editorOptionsRegistry) {
544 545 546 547 548 549 550 551 552 553 554 555
	const schema = editorOption.schema;
	if (typeof schema !== 'undefined') {
		if (isConfigurationPropertySchema(schema)) {
			// This is a single schema contribution
			editorConfiguration.properties![`editor.${editorOption.name}`] = schema;
		} else {
			for (let key in schema) {
				if (hasOwnProperty.call(schema, key)) {
					editorConfiguration.properties![key] = schema[key];
				}
			}
		}
556 557 558
	}
}

A
Alex Dima 已提交
559
let cachedEditorConfigurationKeys: { [key: string]: boolean; } | null = null;
560 561
function getEditorConfigurationKeys(): { [key: string]: boolean; } {
	if (cachedEditorConfigurationKeys === null) {
A
Alex Dima 已提交
562 563 564
		cachedEditorConfigurationKeys = <{ [key: string]: boolean; }>Object.create(null);
		Object.keys(editorConfiguration.properties!).forEach((prop) => {
			cachedEditorConfigurationKeys![prop] = true;
565 566 567 568 569 570 571 572 573 574 575 576 577 578
		});
	}
	return cachedEditorConfigurationKeys;
}

export function isEditorConfigurationKey(key: string): boolean {
	const editorConfigurationKeys = getEditorConfigurationKeys();
	return (editorConfigurationKeys[`editor.${key}`] || false);
}
export function isDiffEditorConfigurationKey(key: string): boolean {
	const editorConfigurationKeys = getEditorConfigurationKeys();
	return (editorConfigurationKeys[`diffEditor.${key}`] || false);
}

579
configurationRegistry.registerConfiguration(editorConfiguration);