commonEditorConfig.ts 34.1 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';

A
Alex Dima 已提交
7
import * as nls from 'vs/nls';
J
Johannes Rieken 已提交
8 9
import Event, { Emitter } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
A
Alex Dima 已提交
10
import * as objects from 'vs/base/common/objects';
A
Alex Dima 已提交
11
import * as platform from 'vs/base/common/platform';
J
Johannes Rieken 已提交
12 13
import { Extensions, IConfigurationRegistry, IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry';
import { Registry } from 'vs/platform/platform';
14
import { DefaultConfig, DEFAULT_INDENTATION, DEFAULT_TRIM_AUTO_WHITESPACE } from 'vs/editor/common/config/defaultConfig';
A
Alex Dima 已提交
15
import * as editorCommon from 'vs/editor/common/editorCommon';
16
import { EditorLayoutProvider } from 'vs/editor/common/viewLayout/editorLayoutProvider';
J
Johannes Rieken 已提交
17
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
18
import { FontInfo, BareFontInfo } from 'vs/editor/common/config/fontInfo';
19
import { Constants } from 'vs/editor/common/core/uint';
A
Alex Dima 已提交
20
import { EditorZoom } from 'vs/editor/common/config/editorZoom';
E
Erich Gamma 已提交
21

22 23 24 25 26 27 28
/**
 * 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 已提交
29
	onDidChangeTabFocus: Event<boolean>;
30
	getTabFocusMode(): boolean;
J
Johannes Rieken 已提交
31
	setTabFocusMode(tabFocusMode: boolean): void;
32 33 34 35 36 37
}

export const TabFocus: ITabFocus = new class {
	private _tabFocus: boolean = false;

	private _onDidChangeTabFocus: Emitter<boolean> = new Emitter<boolean>();
J
Johannes Rieken 已提交
38
	public onDidChangeTabFocus: Event<boolean> = this._onDidChangeTabFocus.event;
39 40 41 42 43

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

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

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

54 55 56 57 58 59 60 61 62 63 64 65 66
/**
 * Experimental screen reader support toggle
 */
export class GlobalScreenReaderNVDA {

	private static _value = false;
	private static _onChange = new Emitter<boolean>();
	public static onChange: Event<boolean> = GlobalScreenReaderNVDA._onChange.event;

	public static getValue(): boolean {
		return this._value;
	}

J
Johannes Rieken 已提交
67
	public static setValue(value: boolean): void {
68 69 70 71 72 73 74 75
		if (this._value === value) {
			return;
		}
		this._value = value;
		this._onChange.fire(this._value);
	}
}

E
Erich Gamma 已提交
76 77
export class ConfigurationWithDefaults {

J
Johannes Rieken 已提交
78
	private _editor: editorCommon.IEditorOptions;
E
Erich Gamma 已提交
79

J
Johannes Rieken 已提交
80
	constructor(options: editorCommon.IEditorOptions) {
A
Alex Dima 已提交
81
		this._editor = <editorCommon.IEditorOptions>objects.clone(DefaultConfig.editor);
E
Erich Gamma 已提交
82 83 84 85

		this._mergeOptionsIn(options);
	}

A
Alex Dima 已提交
86
	public getEditorOptions(): editorCommon.IEditorOptions {
E
Erich Gamma 已提交
87 88 89
		return this._editor;
	}

J
Johannes Rieken 已提交
90
	private _mergeOptionsIn(newOptions: editorCommon.IEditorOptions): void {
A
Alex Dima 已提交
91
		this._editor = objects.mixin(this._editor, newOptions || {});
E
Erich Gamma 已提交
92 93
	}

J
Johannes Rieken 已提交
94
	public updateOptions(newOptions: editorCommon.IEditorOptions): void {
E
Erich Gamma 已提交
95 96 97 98 99 100 101 102 103 104 105
		// Apply new options
		this._mergeOptionsIn(newOptions);
	}
}

class InternalEditorOptionsHelper {

	constructor() {
	}

	public static createInternalEditorOptions(
106 107
		outerWidth: number,
		outerHeight: number,
J
Johannes Rieken 已提交
108
		opts: editorCommon.IEditorOptions,
109
		fontInfo: FontInfo,
J
Johannes Rieken 已提交
110 111
		editorClassName: string,
		isDominatedByLongLines: boolean,
112
		lineNumbersDigitCount: number,
113 114
		canUseTranslate3d: boolean,
		pixelRatio: number
115
	): editorCommon.InternalEditorOptions {
E
Erich Gamma 已提交
116

J
Johannes Rieken 已提交
117
		let stopRenderingLineAfter: number;
E
Erich Gamma 已提交
118 119 120 121 122 123
		if (typeof opts.stopRenderingLineAfter !== 'undefined') {
			stopRenderingLineAfter = toInteger(opts.stopRenderingLineAfter, -1);
		} else {
			stopRenderingLineAfter = 10000;
		}

124
		let scrollbar = this._sanitizeScrollbarOpts(opts.scrollbar, toFloat(opts.mouseWheelScrollSensitivity, 1));
125
		let minimap = this._sanitizeMinimapOpts(opts.minimap);
E
Erich Gamma 已提交
126 127 128

		let glyphMargin = toBoolean(opts.glyphMargin);
		let lineNumbersMinChars = toInteger(opts.lineNumbersMinChars, 1);
129 130 131 132 133 134 135 136

		let lineDecorationsWidth: number;
		if (typeof opts.lineDecorationsWidth === 'string' && /^\d+(\.\d+)?ch$/.test(opts.lineDecorationsWidth)) {
			let multiple = parseFloat(opts.lineDecorationsWidth.substr(0, opts.lineDecorationsWidth.length - 2));
			lineDecorationsWidth = multiple * fontInfo.typicalHalfwidthCharacterWidth;
		} else {
			lineDecorationsWidth = toInteger(opts.lineDecorationsWidth, 0);
		}
M
Martin Aeschlimann 已提交
137
		if (opts.folding) {
138
			lineDecorationsWidth += 16;
M
Martin Aeschlimann 已提交
139
		}
140

141
		let renderLineNumbers: boolean;
J
Johannes Rieken 已提交
142
		let renderCustomLineNumbers: (lineNumber: number) => string;
143
		let renderRelativeLineNumbers: boolean;
144 145 146 147 148 149 150 151
		{
			let lineNumbers = opts.lineNumbers;
			// Compatibility with old true or false values
			if (<any>lineNumbers === true) {
				lineNumbers = 'on';
			} else if (<any>lineNumbers === false) {
				lineNumbers = 'off';
			}
152

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
			if (typeof lineNumbers === 'function') {
				renderLineNumbers = true;
				renderCustomLineNumbers = lineNumbers;
				renderRelativeLineNumbers = false;
			} else if (lineNumbers === 'relative') {
				renderLineNumbers = true;
				renderCustomLineNumbers = null;
				renderRelativeLineNumbers = true;
			} else if (lineNumbers === 'on') {
				renderLineNumbers = true;
				renderCustomLineNumbers = null;
				renderRelativeLineNumbers = false;
			} else {
				renderLineNumbers = false;
				renderCustomLineNumbers = null;
				renderRelativeLineNumbers = false;
			}
170 171
		}

E
Erich Gamma 已提交
172 173 174 175
		let layoutInfo = EditorLayoutProvider.compute({
			outerWidth: outerWidth,
			outerHeight: outerHeight,
			showGlyphMargin: glyphMargin,
176
			lineHeight: fontInfo.lineHeight,
177
			showLineNumbers: renderLineNumbers,
E
Erich Gamma 已提交
178
			lineNumbersMinChars: lineNumbersMinChars,
179
			lineNumbersDigitCount: lineNumbersDigitCount,
E
Erich Gamma 已提交
180
			lineDecorationsWidth: lineDecorationsWidth,
A
Alex Dima 已提交
181
			typicalHalfwidthCharacterWidth: fontInfo.typicalHalfwidthCharacterWidth,
182
			maxDigitWidth: fontInfo.maxDigitWidth,
E
Erich Gamma 已提交
183 184 185
			verticalScrollbarWidth: scrollbar.verticalScrollbarSize,
			horizontalScrollbarHeight: scrollbar.horizontalScrollbarSize,
			scrollbarArrowSize: scrollbar.arrowSize,
A
Alex Dima 已提交
186
			verticalScrollbarHasArrows: scrollbar.verticalHasArrows,
187
			minimap: minimap.enabled,
188
			minimapRenderText: minimap.renderText,
189
			pixelRatio: pixelRatio
E
Erich Gamma 已提交
190 191
		});

192 193 194 195
		let bareWrappingInfo: { isViewportWrapping: boolean; wrappingColumn: number; } = null;
		{
			let wordWrap = opts.wordWrap;
			let wordWrapColumn = toInteger(opts.wordWrapColumn, 1);
E
Erich Gamma 已提交
196

197 198 199 200 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
			// Compatibility with old true or false values
			if (<any>wordWrap === true) {
				wordWrap = 'on';
			} else if (<any>wordWrap === false) {
				wordWrap = 'off';
			}

			if (isDominatedByLongLines) {
				// Force viewport width wrapping if model is dominated by long lines
				bareWrappingInfo = {
					isViewportWrapping: true,
					wrappingColumn: Math.max(1, layoutInfo.viewportColumn)
				};
			} else if (wordWrap === 'on') {
				bareWrappingInfo = {
					isViewportWrapping: true,
					wrappingColumn: Math.max(1, layoutInfo.viewportColumn)
				};
			} else if (wordWrap === 'clamped') {
				bareWrappingInfo = {
					isViewportWrapping: true,
					wrappingColumn: Math.min(Math.max(1, layoutInfo.viewportColumn), wordWrapColumn)
				};
			} else if (wordWrap === 'fixed') {
				bareWrappingInfo = {
					isViewportWrapping: false,
					wrappingColumn: wordWrapColumn
				};
			} else {
				bareWrappingInfo = {
					isViewportWrapping: false,
					wrappingColumn: -1
				};
			}
E
Erich Gamma 已提交
231
		}
232

233 234 235 236 237 238 239 240
		let wrappingInfo = new editorCommon.EditorWrappingInfo({
			isViewportWrapping: bareWrappingInfo.isViewportWrapping,
			wrappingColumn: bareWrappingInfo.wrappingColumn,
			wrappingIndent: wrappingIndentFromString(opts.wrappingIndent),
			wordWrapBreakBeforeCharacters: String(opts.wordWrapBreakBeforeCharacters),
			wordWrapBreakAfterCharacters: String(opts.wordWrapBreakAfterCharacters),
			wordWrapBreakObtrusiveCharacters: String(opts.wordWrapBreakObtrusiveCharacters),
		});
E
Erich Gamma 已提交
241

242 243
		let readOnly = toBoolean(opts.readOnly);

244
		let tabFocusMode = TabFocus.getTabFocusMode();
245 246 247 248
		if (readOnly) {
			tabFocusMode = true;
		}

249

250 251 252 253 254 255 256 257
		let renderWhitespace = opts.renderWhitespace;
		// Compatibility with old true or false values
		if (<any>renderWhitespace === true) {
			renderWhitespace = 'boundary';
		} else if (<any>renderWhitespace === false) {
			renderWhitespace = 'none';
		}

258 259 260 261 262 263 264 265
		let renderLineHighlight = opts.renderLineHighlight;
		// Compatibility with old true or false values
		if (<any>renderLineHighlight === true) {
			renderLineHighlight = 'line';
		} else if (<any>renderLineHighlight === false) {
			renderLineHighlight = 'none';
		}

266
		let viewInfo = new editorCommon.InternalEditorViewOptions({
267
			theme: opts.theme,
268
			canUseTranslate3d: canUseTranslate3d,
269
			disableMonospaceOptimizations: (toBoolean(opts.disableMonospaceOptimizations) || toBoolean(opts.fontLigatures)),
270 271 272
			experimentalScreenReader: toBoolean(opts.experimentalScreenReader),
			rulers: toSortedIntegerArray(opts.rulers),
			ariaLabel: String(opts.ariaLabel),
273 274 275
			renderLineNumbers: renderLineNumbers,
			renderCustomLineNumbers: renderCustomLineNumbers,
			renderRelativeLineNumbers: renderRelativeLineNumbers,
E
Erich Gamma 已提交
276 277 278 279 280
			selectOnLineNumbers: toBoolean(opts.selectOnLineNumbers),
			glyphMargin: glyphMargin,
			revealHorizontalRightPadding: toInteger(opts.revealHorizontalRightPadding, 0),
			roundedSelection: toBoolean(opts.roundedSelection),
			overviewRulerLanes: toInteger(opts.overviewRulerLanes, 0, 3),
281
			cursorBlinking: cursorBlinkingStyleFromString(opts.cursorBlinking),
282
			mouseWheelZoom: toBoolean(opts.mouseWheelZoom),
A
Alex Dima 已提交
283
			cursorStyle: cursorStyleFromString(opts.cursorStyle),
E
Erich Gamma 已提交
284 285
			hideCursorInOverviewRuler: toBoolean(opts.hideCursorInOverviewRuler),
			scrollBeyondLastLine: toBoolean(opts.scrollBeyondLastLine),
286 287
			editorClassName: editorClassName,
			stopRenderingLineAfter: stopRenderingLineAfter,
288
			renderWhitespace: renderWhitespace,
289
			renderControlCharacters: toBoolean(opts.renderControlCharacters),
290
			renderIndentGuides: toBoolean(opts.renderIndentGuides),
291
			renderLineHighlight: renderLineHighlight,
292
			scrollbar: scrollbar,
293
			minimap: minimap,
J
Joao Moreno 已提交
294
			fixedOverflowWidgets: toBoolean(opts.fixedOverflowWidgets)
295 296
		});

A
Alex Dima 已提交
297
		let contribInfo = new editorCommon.EditorContribOptions({
298
			selectionClipboard: toBoolean(opts.selectionClipboard),
E
Erich Gamma 已提交
299 300 301 302
			hover: toBoolean(opts.hover),
			contextmenu: toBoolean(opts.contextmenu),
			quickSuggestions: toBoolean(opts.quickSuggestions),
			quickSuggestionsDelay: toInteger(opts.quickSuggestionsDelay),
J
Joao Moreno 已提交
303
			parameterHints: toBoolean(opts.parameterHints),
E
Erich Gamma 已提交
304 305
			iconsInSuggestions: toBoolean(opts.iconsInSuggestions),
			formatOnType: toBoolean(opts.formatOnType),
306
			formatOnPaste: toBoolean(opts.formatOnPaste),
E
Erich Gamma 已提交
307
			suggestOnTriggerCharacters: toBoolean(opts.suggestOnTriggerCharacters),
308
			acceptSuggestionOnEnter: toBoolean(opts.acceptSuggestionOnEnter),
309
			acceptSuggestionOnCommitCharacter: toBoolean(opts.acceptSuggestionOnCommitCharacter),
310
			snippetSuggestions: opts.snippetSuggestions,
311
			emptySelectionClipboard: opts.emptySelectionClipboard,
312
			wordBasedSuggestions: opts.wordBasedSuggestions,
J
Joao Moreno 已提交
313 314
			suggestFontSize: opts.suggestFontSize,
			suggestLineHeight: opts.suggestLineHeight,
E
Erich Gamma 已提交
315
			selectionHighlight: toBoolean(opts.selectionHighlight),
316
			codeLens: opts.referenceInfos && opts.codeLens,
M
Martin Aeschlimann 已提交
317
			folding: toBoolean(opts.folding),
318
			matchBrackets: toBoolean(opts.matchBrackets),
A
Alex Dima 已提交
319 320
		});

321 322 323 324
		return new editorCommon.InternalEditorOptions({
			lineHeight: fontInfo.lineHeight, // todo -> duplicated in styling
			readOnly: readOnly,
			wordSeparators: String(opts.wordSeparators),
A
Alex Dima 已提交
325
			autoClosingBrackets: toBoolean(opts.autoClosingBrackets),
326
			useTabStops: toBoolean(opts.useTabStops),
327
			tabFocusMode: tabFocusMode,
328
			dragAndDrop: toBoolean(opts.dragAndDrop),
E
Erich Gamma 已提交
329
			layoutInfo: layoutInfo,
330
			fontInfo: fontInfo,
331
			viewInfo: viewInfo,
E
Erich Gamma 已提交
332
			wrappingInfo: wrappingInfo,
A
Alex Dima 已提交
333
			contribInfo: contribInfo,
334
		});
E
Erich Gamma 已提交
335 336
	}

J
Johannes Rieken 已提交
337
	private static _sanitizeScrollbarOpts(raw: editorCommon.IEditorScrollbarOptions, mouseWheelScrollSensitivity: number): editorCommon.InternalEditorScrollbarOptions {
A
Alex Dima 已提交
338

A
Alex Dima 已提交
339
		let visibilityFromString = (visibility: string) => {
A
Alex Dima 已提交
340 341 342 343 344 345 346 347 348 349
			switch (visibility) {
				case 'hidden':
					return ScrollbarVisibility.Hidden;
				case 'visible':
					return ScrollbarVisibility.Visible;
				default:
					return ScrollbarVisibility.Auto;
			}
		};

A
Alex Dima 已提交
350 351
		let horizontalScrollbarSize = toIntegerWithDefault(raw.horizontalScrollbarSize, 10);
		let verticalScrollbarSize = toIntegerWithDefault(raw.verticalScrollbarSize, 14);
A
Alex Dima 已提交
352 353 354
		return new editorCommon.InternalEditorScrollbarOptions({
			vertical: visibilityFromString(raw.vertical),
			horizontal: visibilityFromString(raw.horizontal),
E
Erich Gamma 已提交
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369

			arrowSize: toIntegerWithDefault(raw.arrowSize, 11),
			useShadows: toBooleanWithDefault(raw.useShadows, true),

			verticalHasArrows: toBooleanWithDefault(raw.verticalHasArrows, false),
			horizontalHasArrows: toBooleanWithDefault(raw.horizontalHasArrows, false),

			horizontalScrollbarSize: horizontalScrollbarSize,
			horizontalSliderSize: toIntegerWithDefault(raw.horizontalSliderSize, horizontalScrollbarSize),

			verticalScrollbarSize: verticalScrollbarSize,
			verticalSliderSize: toIntegerWithDefault(raw.verticalSliderSize, verticalScrollbarSize),

			handleMouseWheel: toBooleanWithDefault(raw.handleMouseWheel, true),
			mouseWheelScrollSensitivity: mouseWheelScrollSensitivity
A
Alex Dima 已提交
370
		});
E
Erich Gamma 已提交
371
	}
372 373 374

	private static _sanitizeMinimapOpts(raw: editorCommon.IEditorMinimapOptions): editorCommon.InternalEditorMinimapOptions {
		return new editorCommon.InternalEditorMinimapOptions({
375 376
			enabled: toBooleanWithDefault(raw.enabled, false),
			renderText: toBooleanWithDefault(raw.renderText, true),
377 378
		});
	}
E
Erich Gamma 已提交
379 380
}

J
Johannes Rieken 已提交
381
function toBoolean(value: any): boolean {
E
Erich Gamma 已提交
382 383 384
	return value === 'false' ? false : Boolean(value);
}

J
Johannes Rieken 已提交
385
function toBooleanWithDefault(value: any, defaultValue: boolean): boolean {
E
Erich Gamma 已提交
386 387 388 389 390 391 392
	if (typeof value === 'undefined') {
		return defaultValue;
	}
	return toBoolean(value);
}

function toFloat(source: any, defaultValue: number): number {
A
Alex Dima 已提交
393
	let r = parseFloat(source);
E
Erich Gamma 已提交
394 395 396 397 398 399
	if (isNaN(r)) {
		r = defaultValue;
	}
	return r;
}

400
function toInteger(source: any, minimum: number = Constants.MIN_SAFE_SMALL_INTEGER, maximum: number = Constants.MAX_SAFE_SMALL_INTEGER): number {
A
Alex Dima 已提交
401
	let r = parseInt(source, 10);
E
Erich Gamma 已提交
402 403 404
	if (isNaN(r)) {
		r = 0;
	}
405 406 407
	r = Math.max(minimum, r);
	r = Math.min(maximum, r);
	return r | 0;
E
Erich Gamma 已提交
408 409
}

J
Johannes Rieken 已提交
410
function toSortedIntegerArray(source: any): number[] {
411 412 413 414 415 416 417 418 419
	if (!Array.isArray(source)) {
		return [];
	}
	let arrSource = <any[]>source;
	let r = arrSource.map(el => toInteger(el));
	r.sort();
	return r;
}

J
Johannes Rieken 已提交
420
function wrappingIndentFromString(wrappingIndent: string): editorCommon.WrappingIndent {
A
Alex Dima 已提交
421 422 423 424 425 426 427 428 429
	if (wrappingIndent === 'indent') {
		return editorCommon.WrappingIndent.Indent;
	} else if (wrappingIndent === 'same') {
		return editorCommon.WrappingIndent.Same;
	} else {
		return editorCommon.WrappingIndent.None;
	}
}

J
Johannes Rieken 已提交
430
function cursorStyleFromString(cursorStyle: string): editorCommon.TextEditorCursorStyle {
A
Alex Dima 已提交
431 432 433 434 435 436
	if (cursorStyle === 'line') {
		return editorCommon.TextEditorCursorStyle.Line;
	} else if (cursorStyle === 'block') {
		return editorCommon.TextEditorCursorStyle.Block;
	} else if (cursorStyle === 'underline') {
		return editorCommon.TextEditorCursorStyle.Underline;
437 438 439 440
	} else if (cursorStyle === 'line-thin') {
		return editorCommon.TextEditorCursorStyle.LineThin;
	} else if (cursorStyle === 'block-outline') {
		return editorCommon.TextEditorCursorStyle.BlockOutline;
441 442
	} else if (cursorStyle === 'underline-thin') {
		return editorCommon.TextEditorCursorStyle.UnderlineThin;
A
Alex Dima 已提交
443 444 445 446
	}
	return editorCommon.TextEditorCursorStyle.Line;
}

447
function cursorBlinkingStyleFromString(cursorBlinkingStyle: string): editorCommon.TextEditorCursorBlinkingStyle {
448 449 450 451 452 453 454 455 456 457 458 459
	switch (cursorBlinkingStyle) {
		case 'blink':
			return editorCommon.TextEditorCursorBlinkingStyle.Blink;
		case 'smooth':
			return editorCommon.TextEditorCursorBlinkingStyle.Smooth;
		case 'phase':
			return editorCommon.TextEditorCursorBlinkingStyle.Phase;
		case 'expand':
			return editorCommon.TextEditorCursorBlinkingStyle.Expand;
		case 'visible': // maintain compatibility
		case 'solid':
			return editorCommon.TextEditorCursorBlinkingStyle.Solid;
460 461 462 463
	}
	return editorCommon.TextEditorCursorBlinkingStyle.Blink;
}

J
Johannes Rieken 已提交
464
function toIntegerWithDefault(source: any, defaultValue: number): number {
E
Erich Gamma 已提交
465 466 467 468 469 470
	if (typeof source === 'undefined') {
		return defaultValue;
	}
	return toInteger(source);
}

471 472
export interface IElementSizeObserver {
	startObserving(): void;
J
Johannes Rieken 已提交
473
	observe(dimension?: editorCommon.IDimension): void;
474 475 476 477 478
	dispose(): void;
	getWidth(): number;
	getHeight(): number;
}

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

J
Johannes Rieken 已提交
481 482
	public editor: editorCommon.InternalEditorOptions;
	public editorClone: editorCommon.InternalEditorOptions;
E
Erich Gamma 已提交
483

J
Johannes Rieken 已提交
484
	protected _configWithDefaults: ConfigurationWithDefaults;
485
	protected _elementSizeObserver: IElementSizeObserver;
J
Johannes Rieken 已提交
486
	private _isDominatedByLongLines: boolean;
487
	private _lineNumbersDigitCount: number;
E
Erich Gamma 已提交
488

A
Alex Dima 已提交
489 490
	private _onDidChange = this._register(new Emitter<editorCommon.IConfigurationChangedEvent>());
	public onDidChange: Event<editorCommon.IConfigurationChangedEvent> = this._onDidChange.event;
A
Alex Dima 已提交
491

J
Johannes Rieken 已提交
492
	constructor(options: editorCommon.IEditorOptions, elementSizeObserver: IElementSizeObserver = null) {
A
Alex Dima 已提交
493
		super();
E
Erich Gamma 已提交
494
		this._configWithDefaults = new ConfigurationWithDefaults(options);
495
		this._elementSizeObserver = elementSizeObserver;
E
Erich Gamma 已提交
496
		this._isDominatedByLongLines = false;
497
		this._lineNumbersDigitCount = 1;
E
Erich Gamma 已提交
498
		this.editor = this._computeInternalOptions();
499
		this.editorClone = this.editor.clone();
500
		this._register(EditorZoom.onDidChangeZoomLevel(_ => this._recomputeOptions()));
501
		this._register(TabFocus.onDidChangeTabFocus(_ => this._recomputeOptions()));
E
Erich Gamma 已提交
502 503 504 505 506 507 508
	}

	public dispose(): void {
		super.dispose();
	}

	protected _recomputeOptions(): void {
509 510
		this._setOptions(this._computeInternalOptions());
	}
511

J
Johannes Rieken 已提交
512
	private _setOptions(newOptions: editorCommon.InternalEditorOptions): void {
513 514
		if (this.editor && this.editor.equals(newOptions)) {
			return;
E
Erich Gamma 已提交
515 516
		}

517 518 519 520
		let changeEvent = this.editor.createChangeEvent(newOptions);
		this.editor = newOptions;
		this.editorClone = this.editor.clone();
		this._onDidChange.fire(changeEvent);
E
Erich Gamma 已提交
521 522
	}

A
Alex Dima 已提交
523
	public getRawOptions(): editorCommon.IEditorOptions {
E
Erich Gamma 已提交
524 525 526
		return this._configWithDefaults.getEditorOptions();
	}

527
	private _computeInternalOptions(): editorCommon.InternalEditorOptions {
E
Erich Gamma 已提交
528 529
		let opts = this._configWithDefaults.getEditorOptions();

530
		let editorClassName = this._getEditorClassName(opts.theme, toBoolean(opts.fontLigatures));
E
Erich Gamma 已提交
531

532 533 534 535 536 537
		let disableTranslate3d = toBoolean(opts.disableTranslate3d);
		let canUseTranslate3d = this._getCanUseTranslate3d();
		if (disableTranslate3d) {
			canUseTranslate3d = false;
		}

538 539
		let bareFontInfo = BareFontInfo.createFromRawSettings(opts);

540
		return InternalEditorOptionsHelper.createInternalEditorOptions(
E
Erich Gamma 已提交
541 542 543
			this.getOuterWidth(),
			this.getOuterHeight(),
			opts,
544
			this.readConfiguration(bareFontInfo),
545
			editorClassName,
E
Erich Gamma 已提交
546
			this._isDominatedByLongLines,
547
			this._lineNumbersDigitCount,
548 549
			canUseTranslate3d,
			this._getPixelRatio()
E
Erich Gamma 已提交
550 551 552
		);
	}

J
Johannes Rieken 已提交
553
	public updateOptions(newOptions: editorCommon.IEditorOptions): void {
E
Erich Gamma 已提交
554 555 556 557
		this._configWithDefaults.updateOptions(newOptions);
		this._recomputeOptions();
	}

J
Johannes Rieken 已提交
558
	public setIsDominatedByLongLines(isDominatedByLongLines: boolean): void {
E
Erich Gamma 已提交
559 560 561 562
		this._isDominatedByLongLines = isDominatedByLongLines;
		this._recomputeOptions();
	}

J
Johannes Rieken 已提交
563
	public setMaxLineNumber(maxLineNumber: number): void {
564 565
		let digitCount = CommonEditorConfiguration.digitCount(maxLineNumber);
		if (this._lineNumbersDigitCount === digitCount) {
A
Alex Dima 已提交
566 567
			return;
		}
568
		this._lineNumbersDigitCount = digitCount;
E
Erich Gamma 已提交
569 570 571
		this._recomputeOptions();
	}

572 573 574 575 576 577 578 579 580
	private static digitCount(n: number): number {
		var r = 0;
		while (n) {
			n = Math.floor(n / 10);
			r++;
		}
		return r ? r : 1;
	}

J
Johannes Rieken 已提交
581
	protected abstract _getEditorClassName(theme: string, fontLigatures: boolean): string;
E
Erich Gamma 已提交
582

583
	protected abstract getOuterWidth(): number;
E
Erich Gamma 已提交
584

585
	protected abstract getOuterHeight(): number;
E
Erich Gamma 已提交
586

587 588
	protected abstract _getCanUseTranslate3d(): boolean;

589 590
	protected abstract _getPixelRatio(): number;

591
	protected abstract readConfiguration(styling: BareFontInfo): FontInfo;
E
Erich Gamma 已提交
592 593
}

594 595
const configurationRegistry = <IConfigurationRegistry>Registry.as(Extensions.Configuration);
const editorConfiguration: IConfigurationNode = {
E
Erich Gamma 已提交
596 597 598
	'id': 'editor',
	'order': 5,
	'type': 'object',
599
	'title': nls.localize('editorConfigurationTitle', "Editor"),
600
	'overridable': true,
J
Johannes Rieken 已提交
601 602
	'properties': {
		'editor.fontFamily': {
E
Erich Gamma 已提交
603 604 605 606
			'type': 'string',
			'default': DefaultConfig.editor.fontFamily,
			'description': nls.localize('fontFamily', "Controls the font family.")
		},
J
Johannes Rieken 已提交
607
		'editor.fontWeight': {
608
			'type': 'string',
609
			'enum': ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'],
610 611 612
			'default': DefaultConfig.editor.fontWeight,
			'description': nls.localize('fontWeight', "Controls the font weight.")
		},
J
Johannes Rieken 已提交
613
		'editor.fontSize': {
E
Erich Gamma 已提交
614 615
			'type': 'number',
			'default': DefaultConfig.editor.fontSize,
616
			'description': nls.localize('fontSize', "Controls the font size in pixels.")
E
Erich Gamma 已提交
617
		},
J
Johannes Rieken 已提交
618
		'editor.lineHeight': {
E
Erich Gamma 已提交
619 620
			'type': 'number',
			'default': DefaultConfig.editor.lineHeight,
621
			'description': nls.localize('lineHeight', "Controls the line height. Use 0 to compute the lineHeight from the fontSize.")
E
Erich Gamma 已提交
622
		},
J
Johannes Rieken 已提交
623
		'editor.lineNumbers': {
624 625
			'type': 'string',
			'enum': ['off', 'on', 'relative'],
E
Erich Gamma 已提交
626
			'default': DefaultConfig.editor.lineNumbers,
627
			'description': nls.localize('lineNumbers', "Controls the display of line numbers. Possible values are 'on', 'off', and 'relative'. 'relative' shows the line count from the current cursor position.")
E
Erich Gamma 已提交
628
		},
J
Johannes Rieken 已提交
629
		'editor.rulers': {
630 631 632 633 634 635 636
			'type': 'array',
			'items': {
				'type': 'number'
			},
			'default': DefaultConfig.editor.rulers,
			'description': nls.localize('rulers', "Columns at which to show vertical rulers")
		},
J
Johannes Rieken 已提交
637
		'editor.wordSeparators': {
A
Alex Dima 已提交
638 639 640 641
			'type': 'string',
			'default': DefaultConfig.editor.wordSeparators,
			'description': nls.localize('wordSeparators', "Characters that will be used as word separators when doing word related navigations or operations")
		},
J
Johannes Rieken 已提交
642
		'editor.tabSize': {
643 644
			'type': 'number',
			'default': DEFAULT_INDENTATION.tabSize,
E
Erich Gamma 已提交
645
			'minimum': 1,
646
			'description': nls.localize('tabSize', "The number of spaces a tab is equal to. This setting is overriden based on the file contents when `editor.detectIndentation` is on."),
647
			'errorMessage': nls.localize('tabSize.errorMessage', "Expected 'number'. Note that the value \"auto\" has been replaced by the `editor.detectIndentation` setting.")
E
Erich Gamma 已提交
648
		},
J
Johannes Rieken 已提交
649
		'editor.insertSpaces': {
650 651
			'type': 'boolean',
			'default': DEFAULT_INDENTATION.insertSpaces,
652
			'description': nls.localize('insertSpaces', "Insert spaces when pressing Tab. This setting is overriden based on the file contents when `editor.detectIndentation` is on."),
653
			'errorMessage': nls.localize('insertSpaces.errorMessage', "Expected 'boolean'. Note that the value \"auto\" has been replaced by the `editor.detectIndentation` setting.")
E
Erich Gamma 已提交
654
		},
J
Johannes Rieken 已提交
655
		'editor.detectIndentation': {
656 657
			'type': 'boolean',
			'default': DEFAULT_INDENTATION.detectIndentation,
A
Alex Dima 已提交
658
			'description': nls.localize('detectIndentation', "When opening a file, `editor.tabSize` and `editor.insertSpaces` will be detected based on the file contents.")
659
		},
J
Johannes Rieken 已提交
660
		'editor.roundedSelection': {
E
Erich Gamma 已提交
661 662 663 664
			'type': 'boolean',
			'default': DefaultConfig.editor.roundedSelection,
			'description': nls.localize('roundedSelection', "Controls if selections have rounded corners")
		},
J
Johannes Rieken 已提交
665
		'editor.scrollBeyondLastLine': {
E
Erich Gamma 已提交
666 667 668 669
			'type': 'boolean',
			'default': DefaultConfig.editor.scrollBeyondLastLine,
			'description': nls.localize('scrollBeyondLastLine', "Controls if the editor will scroll beyond the last line")
		},
670 671 672 673 674
		'editor.minimap.enabled': {
			'type': 'boolean',
			'default': DefaultConfig.editor.minimap.enabled,
			'description': nls.localize('minimap.enabled', "Controls if the minimap is shown")
		},
675 676 677 678 679
		'editor.minimap.renderText': {
			'type': 'boolean',
			'default': DefaultConfig.editor.minimap.renderText,
			'description': nls.localize('minimap.renderText', "Render the actual text on a line (as opposed to color blocks)")
		},
J
Johannes Rieken 已提交
680
		'editor.wordWrap': {
681 682
			'type': 'string',
			'enum': ['off', 'on', 'fixed', 'clamped'],
683
			'default': DefaultConfig.editor.wordWrap,
684 685 686 687 688 689 690
			'description': nls.localize('wordWrap', "Controls how lines should wrap. Can be: 'off' (disable wrapping), 'on' (viewport wrapping), 'fixed' (wrap at `editor.wordWrapColumn`) or 'clamped' (wrap at minimum of viewport and `editor.wordWrapColumn`).")
		},
		'editor.wordWrapColumn': {
			'type': 'integer',
			'default': DefaultConfig.editor.wordWrapColumn,
			'minimum': 1,
			'description': nls.localize('wordWrapColumn', "Controls the wrapping column of the editor when `editor.wordWrap` is 'fixed' or 'clamped'.")
691
		},
J
Johannes Rieken 已提交
692
		'editor.wrappingIndent': {
E
Erich Gamma 已提交
693 694 695 696 697
			'type': 'string',
			'enum': ['none', 'same', 'indent'],
			'default': DefaultConfig.editor.wrappingIndent,
			'description': nls.localize('wrappingIndent', "Controls the indentation of wrapped lines. Can be one of 'none', 'same' or 'indent'.")
		},
J
Johannes Rieken 已提交
698
		'editor.mouseWheelScrollSensitivity': {
E
Erich Gamma 已提交
699 700 701 702
			'type': 'number',
			'default': DefaultConfig.editor.mouseWheelScrollSensitivity,
			'description': nls.localize('mouseWheelScrollSensitivity', "A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events")
		},
J
Johannes Rieken 已提交
703
		'editor.quickSuggestions': {
E
Erich Gamma 已提交
704 705 706 707
			'type': 'boolean',
			'default': DefaultConfig.editor.quickSuggestions,
			'description': nls.localize('quickSuggestions', "Controls if quick suggestions should show up or not while typing")
		},
J
Johannes Rieken 已提交
708
		'editor.quickSuggestionsDelay': {
E
Erich Gamma 已提交
709 710 711 712 713
			'type': 'integer',
			'default': DefaultConfig.editor.quickSuggestionsDelay,
			'minimum': 0,
			'description': nls.localize('quickSuggestionsDelay', "Controls the delay in ms after which quick suggestions will show up")
		},
J
Johannes Rieken 已提交
714
		'editor.parameterHints': {
J
Joao Moreno 已提交
715 716 717 718
			'type': 'boolean',
			'default': DefaultConfig.editor.parameterHints,
			'description': nls.localize('parameterHints', "Enables parameter hints")
		},
J
Johannes Rieken 已提交
719
		'editor.autoClosingBrackets': {
E
Erich Gamma 已提交
720 721 722 723
			'type': 'boolean',
			'default': DefaultConfig.editor.autoClosingBrackets,
			'description': nls.localize('autoClosingBrackets', "Controls if the editor should automatically close brackets after opening them")
		},
J
Johannes Rieken 已提交
724
		'editor.formatOnType': {
E
Erich Gamma 已提交
725 726 727 728
			'type': 'boolean',
			'default': DefaultConfig.editor.formatOnType,
			'description': nls.localize('formatOnType', "Controls if the editor should automatically format the line after typing")
		},
729 730 731
		'editor.formatOnPaste': {
			'type': 'boolean',
			'default': DefaultConfig.editor.formatOnPaste,
732
			'description': nls.localize('formatOnPaste', "Controls if the editor should automatically format the pasted content. A formatter must be available and the formatter should be able to format a range in a document.")
733
		},
J
Johannes Rieken 已提交
734
		'editor.suggestOnTriggerCharacters': {
E
Erich Gamma 已提交
735 736 737 738
			'type': 'boolean',
			'default': DefaultConfig.editor.suggestOnTriggerCharacters,
			'description': nls.localize('suggestOnTriggerCharacters', "Controls if suggestions should automatically show up when typing trigger characters")
		},
J
Johannes Rieken 已提交
739
		'editor.acceptSuggestionOnEnter': {
740 741
			'type': 'boolean',
			'default': DefaultConfig.editor.acceptSuggestionOnEnter,
742 743 744 745 746 747
			'description': nls.localize('acceptSuggestionOnEnter', "Controls if suggestions should be accepted on 'Enter' - in addition to 'Tab'. Helps to avoid ambiguity between inserting new lines or accepting suggestions.")
		},
		'editor.acceptSuggestionOnCommitCharacter': {
			'type': 'boolean',
			'default': DefaultConfig.editor.acceptSuggestionOnCommitCharacter,
			'description': nls.localize('acceptSuggestionOnCommitCharacter', "Controls if suggestions should be accepted on commit characters. For instance in JavaScript the semi-colon (';') can be a commit character that accepts a suggestion and types that character.")
748
		},
749
		'editor.snippetSuggestions': {
750
			'type': 'string',
751 752 753
			'enum': ['top', 'bottom', 'inline', 'none'],
			'default': DefaultConfig.editor.snippetSuggestions,
			'description': nls.localize('snippetSuggestions', "Controls whether snippets are shown with other suggestions and how they are sorted.")
754
		},
755 756 757 758 759
		'editor.emptySelectionClipboard': {
			'type': 'boolean',
			'default': DefaultConfig.editor.emptySelectionClipboard,
			'description': nls.localize('emptySelectionClipboard', "Controls whether copying without a selection copies the current line.")
		},
760 761 762 763 764
		'editor.wordBasedSuggestions': {
			'type': 'boolean',
			'default': DefaultConfig.editor.wordBasedSuggestions,
			'description': nls.localize('wordBasedSuggestions', "Enable word based suggestions.")
		},
J
Johannes Rieken 已提交
765
		'editor.suggestFontSize': {
J
Joao Moreno 已提交
766 767 768 769 770
			'type': 'integer',
			'default': 0,
			'minimum': 0,
			'description': nls.localize('suggestFontSize', "Font size for the suggest widget")
		},
J
Johannes Rieken 已提交
771
		'editor.suggestLineHeight': {
J
Joao Moreno 已提交
772 773 774 775 776
			'type': 'integer',
			'default': 0,
			'minimum': 0,
			'description': nls.localize('suggestLineHeight', "Line height for the suggest widget")
		},
J
Johannes Rieken 已提交
777
		'editor.selectionHighlight': {
E
Erich Gamma 已提交
778 779 780 781
			'type': 'boolean',
			'default': DefaultConfig.editor.selectionHighlight,
			'description': nls.localize('selectionHighlight', "Controls whether the editor should highlight similar matches to the selection")
		},
J
Johannes Rieken 已提交
782
		'editor.overviewRulerLanes': {
E
Erich Gamma 已提交
783 784 785 786
			'type': 'integer',
			'default': 3,
			'description': nls.localize('overviewRulerLanes', "Controls the number of decorations that can show up at the same position in the overview ruler")
		},
J
Johannes Rieken 已提交
787
		'editor.cursorBlinking': {
788
			'type': 'string',
789
			'enum': ['blink', 'smooth', 'phase', 'expand', 'solid'],
790
			'default': DefaultConfig.editor.cursorBlinking,
791
			'description': nls.localize('cursorBlinking', "Control the cursor animation style, possible values are 'blink', 'smooth', 'phase', 'expand' and 'solid'")
792
		},
793 794 795 796 797
		'editor.mouseWheelZoom': {
			'type': 'boolean',
			'default': DefaultConfig.editor.mouseWheelZoom,
			'description': nls.localize('mouseWheelZoom', "Zoom the font of the editor when using mouse wheel and holding Ctrl")
		},
J
Johannes Rieken 已提交
798
		'editor.cursorStyle': {
M
markrendle 已提交
799
			'type': 'string',
800
			'enum': ['block', 'block-outline', 'line', 'line-thin', 'underline', 'underline-thin'],
M
markrendle 已提交
801
			'default': DefaultConfig.editor.cursorStyle,
802
			'description': nls.localize('cursorStyle', "Controls the cursor style, accepted values are 'block', 'block-outline', 'line', 'line-thin', 'underline' and 'underline-thin'")
M
markrendle 已提交
803
		},
J
Johannes Rieken 已提交
804
		'editor.fontLigatures': {
805 806 807 808
			'type': 'boolean',
			'default': DefaultConfig.editor.fontLigatures,
			'description': nls.localize('fontLigatures', "Enables font ligatures")
		},
J
Johannes Rieken 已提交
809
		'editor.hideCursorInOverviewRuler': {
E
Erich Gamma 已提交
810 811 812 813 814
			'type': 'boolean',
			'default': DefaultConfig.editor.hideCursorInOverviewRuler,
			'description': nls.localize('hideCursorInOverviewRuler', "Controls if the cursor should be hidden in the overview ruler.")
		},
		'editor.renderWhitespace': {
815 816
			'type': 'string',
			'enum': ['none', 'boundary', 'all'],
E
Erich Gamma 已提交
817
			default: DefaultConfig.editor.renderWhitespace,
818
			description: nls.localize('renderWhitespace', "Controls how the editor should render whitespace characters, possibilities are 'none', 'boundary', and 'all'. The 'boundary' option does not render single spaces between words.")
E
Erich Gamma 已提交
819
		},
820 821 822 823 824
		'editor.renderControlCharacters': {
			'type': 'boolean',
			default: DefaultConfig.editor.renderControlCharacters,
			description: nls.localize('renderControlCharacters', "Controls whether the editor should render control characters")
		},
825 826 827 828 829
		'editor.renderIndentGuides': {
			'type': 'boolean',
			default: DefaultConfig.editor.renderIndentGuides,
			description: nls.localize('renderIndentGuides', "Controls whether the editor should render indent guides")
		},
830
		'editor.renderLineHighlight': {
831 832
			'type': 'string',
			'enum': ['none', 'gutter', 'line', 'all'],
833
			default: DefaultConfig.editor.renderLineHighlight,
834
			description: nls.localize('renderLineHighlight', "Controls how the editor should render the current line highlight, possibilities are 'none', 'gutter', 'line', and 'all'.")
835
		},
J
Johannes Rieken 已提交
836
		'editor.codeLens': {
E
Erich Gamma 已提交
837
			'type': 'boolean',
838 839
			'default': DefaultConfig.editor.codeLens,
			'description': nls.localize('codeLens', "Controls if the editor shows code lenses")
E
Erich Gamma 已提交
840
		},
J
Johannes Rieken 已提交
841
		'editor.folding': {
M
Martin Aeschlimann 已提交
842 843
			'type': 'boolean',
			'default': DefaultConfig.editor.folding,
844
			'description': nls.localize('folding', "Controls whether the editor has code folding enabled")
M
Martin Aeschlimann 已提交
845
		},
846
		'editor.matchBrackets': {
847
			'type': 'boolean',
848 849
			'default': DefaultConfig.editor.matchBrackets,
			'description': nls.localize('matchBrackets', "Highlight matching brackets when one of them is selected.")
850
		},
I
isidor 已提交
851 852 853 854 855
		'editor.glyphMargin': {
			'type': 'boolean',
			'default': DefaultConfig.editor.glyphMargin,
			'description': nls.localize('glyphMargin', "Controls whether the editor should render the vertical glyph margin. Glyph margin is mostly used for debugging.")
		},
J
Johannes Rieken 已提交
856
		'editor.useTabStops': {
857 858 859 860
			'type': 'boolean',
			'default': DefaultConfig.editor.useTabStops,
			'description': nls.localize('useTabStops', "Inserting and deleting whitespace follows tab stops")
		},
J
Johannes Rieken 已提交
861
		'editor.trimAutoWhitespace': {
862
			'type': 'boolean',
863
			'default': DEFAULT_TRIM_AUTO_WHITESPACE,
864 865
			'description': nls.localize('trimAutoWhitespace', "Remove trailing auto inserted whitespace")
		},
J
Johannes Rieken 已提交
866
		'editor.stablePeek': {
867
			'type': 'boolean',
868
			'default': false,
869
			'description': nls.localize('stablePeek', "Keep peek editors open even when double clicking their content or when hitting Escape.")
870
		},
871
		'editor.dragAndDrop': {
872
			'type': 'boolean',
873 874
			'default': DefaultConfig.editor.dragAndDrop,
			'description': nls.localize('dragAndDrop', "Controls if the editor should allow to move selections via drag and drop.")
875
		},
J
Johannes Rieken 已提交
876
		'diffEditor.renderSideBySide': {
E
Erich Gamma 已提交
877 878 879 880
			'type': 'boolean',
			'default': true,
			'description': nls.localize('sideBySide', "Controls if the diff editor shows the diff side by side or inline")
		},
J
Johannes Rieken 已提交
881
		'diffEditor.ignoreTrimWhitespace': {
E
Erich Gamma 已提交
882 883 884
			'type': 'boolean',
			'default': true,
			'description': nls.localize('ignoreTrimWhitespace', "Controls if the diff editor shows changes in leading or trailing whitespace as diffs")
885 886 887 888 889
		},
		'diffEditor.renderIndicators': {
			'type': 'boolean',
			'default': true,
			'description': nls.localize('renderIndicators', "Controls if the diff editor shows +/- indicators for added/removed changes")
E
Erich Gamma 已提交
890 891
		}
	}
A
Alex Dima 已提交
892 893 894 895 896 897 898 899 900 901
};

if (platform.isLinux) {
	editorConfiguration['properties']['editor.selectionClipboard'] = {
		'type': 'boolean',
		'default': DefaultConfig.editor.selectionClipboard,
		'description': nls.localize('selectionClipboard', "Controls if the Linux primary clipboard should be supported.")
	};
}

902
configurationRegistry.registerConfiguration(editorConfiguration);