commonEditorConfig.ts 30.0 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 8
import * as nls from 'vs/nls';
import Event, {Emitter} from 'vs/base/common/event';
A
Alex Dima 已提交
9 10
import {Disposable} from 'vs/base/common/lifecycle';
import * as objects from 'vs/base/common/objects';
A
Alex Dima 已提交
11 12
import * as platform from 'vs/base/common/platform';
import {Extensions, IConfigurationRegistry, IConfigurationNode} from 'vs/platform/configuration/common/configurationRegistry';
E
Erich Gamma 已提交
13
import {Registry} from 'vs/platform/platform';
14
import {DefaultConfig, DEFAULT_INDENTATION, DEFAULT_TRIM_AUTO_WHITESPACE, GOLDEN_LINE_HEIGHT_RATIO} 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';
17
import {ScrollbarVisibility} from 'vs/base/common/scrollable';
E
Erich Gamma 已提交
18

19 20 21 22 23 24 25 26 27 28 29
// TODO@Alex: investigate if it is better to stick to 31 bits (see smi = SMall Integer)
// See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values
/**
 * MAX_INT that fits in 32 bits
 */
const MAX_SAFE_INT = 0x7fffffff;
/**
 * MIN_INT that fits in 32 bits
 */
const MIN_SAFE_INT = -0x80000000;

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
export interface IEditorZoom {
	onDidChangeZoomLevel:Event<number>;
	getZoomLevel(): number;
	setZoomLevel(zoomLevel:number): void;
}

export const EditorZoom: IEditorZoom = new class {

	private _zoomLevel: number = 0;

	private _onDidChangeZoomLevel: Emitter<number> = new Emitter<number>();
	public onDidChangeZoomLevel:Event<number> = this._onDidChangeZoomLevel.event;

	public getZoomLevel(): number {
		return this._zoomLevel;
	}

	public setZoomLevel(zoomLevel:number): void {
		zoomLevel = Math.min(Math.max(-9, zoomLevel), 9);
		if (this._zoomLevel === zoomLevel) {
			return;
		}

		this._zoomLevel = zoomLevel;
		this._onDidChangeZoomLevel.fire(this._zoomLevel);
	}
};
E
Erich Gamma 已提交
57

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
/**
 * 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 {
	onDidChangeTabFocus:Event<boolean>;
	getTabFocusMode(): boolean;
	setTabFocusMode(tabFocusMode:boolean): void;
}

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

	private _onDidChangeTabFocus: Emitter<boolean> = new Emitter<boolean>();
	public onDidChangeTabFocus:Event<boolean> = this._onDidChangeTabFocus.event;

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

	public setTabFocusMode(tabFocusMode:boolean): void {
		if (this._tabFocus === tabFocusMode) {
			return;
		}

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

90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
/**
 * 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;
	}

	public static setValue(value:boolean): void {
		if (this._value === value) {
			return;
		}
		this._value = value;
		this._onChange.fire(this._value);
	}
}

E
Erich Gamma 已提交
112 113
export class ConfigurationWithDefaults {

A
Alex Dima 已提交
114
	private _editor:editorCommon.IEditorOptions;
E
Erich Gamma 已提交
115

A
Alex Dima 已提交
116 117
	constructor(options:editorCommon.IEditorOptions) {
		this._editor = <editorCommon.IEditorOptions>objects.clone(DefaultConfig.editor);
E
Erich Gamma 已提交
118 119 120 121

		this._mergeOptionsIn(options);
	}

A
Alex Dima 已提交
122
	public getEditorOptions(): editorCommon.IEditorOptions {
E
Erich Gamma 已提交
123 124 125
		return this._editor;
	}

A
Alex Dima 已提交
126 127
	private _mergeOptionsIn(newOptions:editorCommon.IEditorOptions): void {
		this._editor = objects.mixin(this._editor, newOptions || {});
E
Erich Gamma 已提交
128 129
	}

A
Alex Dima 已提交
130
	public updateOptions(newOptions:editorCommon.IEditorOptions): void {
E
Erich Gamma 已提交
131 132 133 134 135 136 137 138 139 140 141
		// Apply new options
		this._mergeOptionsIn(newOptions);
	}
}

class InternalEditorOptionsHelper {

	constructor() {
	}

	public static createInternalEditorOptions(
142
		outerWidth:number, outerHeight:number,
A
Alex Dima 已提交
143
		opts:editorCommon.IEditorOptions,
144 145
		fontInfo: editorCommon.FontInfo,
		editorClassName:string,
E
Erich Gamma 已提交
146
		isDominatedByLongLines:boolean,
147
		maxLineNumber: number,
148
		canUseTranslate3d: boolean
149
	): editorCommon.InternalEditorOptions {
E
Erich Gamma 已提交
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168

		let wrappingColumn = toInteger(opts.wrappingColumn, -1);

		let stopRenderingLineAfter:number;
		if (typeof opts.stopRenderingLineAfter !== 'undefined') {
			stopRenderingLineAfter = toInteger(opts.stopRenderingLineAfter, -1);
		} else if (wrappingColumn >= 0) {
			stopRenderingLineAfter = -1;
		} else {
			stopRenderingLineAfter = 10000;
		}

		let mouseWheelScrollSensitivity = toFloat(opts.mouseWheelScrollSensitivity, 1);
		let scrollbar = this._sanitizeScrollbarOpts(opts.scrollbar, mouseWheelScrollSensitivity);

		let glyphMargin = toBoolean(opts.glyphMargin);
		let lineNumbers = opts.lineNumbers;
		let lineNumbersMinChars = toInteger(opts.lineNumbersMinChars, 1);
		let lineDecorationsWidth = toInteger(opts.lineDecorationsWidth, 0);
M
Martin Aeschlimann 已提交
169
		if (opts.folding) {
170
			lineDecorationsWidth += 16;
M
Martin Aeschlimann 已提交
171
		}
E
Erich Gamma 已提交
172 173 174 175
		let layoutInfo = EditorLayoutProvider.compute({
			outerWidth: outerWidth,
			outerHeight: outerHeight,
			showGlyphMargin: glyphMargin,
176
			lineHeight: fontInfo.lineHeight,
E
Erich Gamma 已提交
177 178 179
			showLineNumbers: !!lineNumbers,
			lineNumbersMinChars: lineNumbersMinChars,
			lineDecorationsWidth: lineDecorationsWidth,
180
			maxDigitWidth: fontInfo.maxDigitWidth,
181
			maxLineNumber: maxLineNumber,
E
Erich Gamma 已提交
182 183 184 185 186 187 188 189 190 191 192
			verticalScrollbarWidth: scrollbar.verticalScrollbarSize,
			horizontalScrollbarHeight: scrollbar.horizontalScrollbarSize,
			scrollbarArrowSize: scrollbar.arrowSize,
			verticalScrollbarHasArrows: scrollbar.verticalHasArrows
		});

		if (isDominatedByLongLines && wrappingColumn > 0) {
			// Force viewport width wrapping if model is dominated by long lines
			wrappingColumn = 0;
		}

193
		let bareWrappingInfo: { isViewportWrapping: boolean; wrappingColumn: number; };
E
Erich Gamma 已提交
194 195
		if (wrappingColumn === 0) {
			// If viewport width wrapping is enabled
196
			bareWrappingInfo = {
E
Erich Gamma 已提交
197
				isViewportWrapping: true,
198
				wrappingColumn: Math.max(1, Math.floor((layoutInfo.contentWidth - layoutInfo.verticalScrollbarWidth) / fontInfo.typicalHalfwidthCharacterWidth))
E
Erich Gamma 已提交
199 200 201
			};
		} else if (wrappingColumn > 0) {
			// Wrapping is enabled
202
			bareWrappingInfo = {
E
Erich Gamma 已提交
203 204 205 206
				isViewportWrapping: false,
				wrappingColumn: wrappingColumn
			};
		} else {
207
			bareWrappingInfo = {
E
Erich Gamma 已提交
208 209 210 211
				isViewportWrapping: false,
				wrappingColumn: -1
			};
		}
212 213 214 215 216 217 218 219
		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 已提交
220

221 222
		let readOnly = toBoolean(opts.readOnly);

223
		let tabFocusMode = TabFocus.getTabFocusMode();
224 225 226 227
		if (readOnly) {
			tabFocusMode = true;
		}

228
		let viewInfo = new editorCommon.InternalEditorViewOptions({
229
			theme: opts.theme,
230
			canUseTranslate3d: canUseTranslate3d,
231 232 233
			experimentalScreenReader: toBoolean(opts.experimentalScreenReader),
			rulers: toSortedIntegerArray(opts.rulers),
			ariaLabel: String(opts.ariaLabel),
E
Erich Gamma 已提交
234 235 236 237 238 239
			lineNumbers: lineNumbers,
			selectOnLineNumbers: toBoolean(opts.selectOnLineNumbers),
			glyphMargin: glyphMargin,
			revealHorizontalRightPadding: toInteger(opts.revealHorizontalRightPadding, 0),
			roundedSelection: toBoolean(opts.roundedSelection),
			overviewRulerLanes: toInteger(opts.overviewRulerLanes, 0, 3),
240
			cursorBlinking: cursorBlinkingStyleFromString(opts.cursorBlinking),
241
			mouseWheelZoom: toBoolean(opts.mouseWheelZoom),
A
Alex Dima 已提交
242
			cursorStyle: cursorStyleFromString(opts.cursorStyle),
E
Erich Gamma 已提交
243 244
			hideCursorInOverviewRuler: toBoolean(opts.hideCursorInOverviewRuler),
			scrollBeyondLastLine: toBoolean(opts.scrollBeyondLastLine),
245 246
			editorClassName: editorClassName,
			stopRenderingLineAfter: stopRenderingLineAfter,
247
			renderWhitespace: opts.renderWhitespace,
248
			renderControlCharacters: toBoolean(opts.renderControlCharacters),
249
			renderIndentGuides: toBoolean(opts.renderIndentGuides),
250
			renderLineHighlight: toBoolean(opts.renderLineHighlight),
251 252 253
			scrollbar: scrollbar,
		});

A
Alex Dima 已提交
254
		let contribInfo = new editorCommon.EditorContribOptions({
255
			selectionClipboard: toBoolean(opts.selectionClipboard),
E
Erich Gamma 已提交
256 257 258 259
			hover: toBoolean(opts.hover),
			contextmenu: toBoolean(opts.contextmenu),
			quickSuggestions: toBoolean(opts.quickSuggestions),
			quickSuggestionsDelay: toInteger(opts.quickSuggestionsDelay),
J
Joao Moreno 已提交
260
			parameterHints: toBoolean(opts.parameterHints),
E
Erich Gamma 已提交
261 262 263
			iconsInSuggestions: toBoolean(opts.iconsInSuggestions),
			formatOnType: toBoolean(opts.formatOnType),
			suggestOnTriggerCharacters: toBoolean(opts.suggestOnTriggerCharacters),
264
			acceptSuggestionOnEnter: toBoolean(opts.acceptSuggestionOnEnter),
265
			snippetSuggestions: opts.snippetSuggestions,
266
			tabCompletion: opts.tabCompletion,
267
			wordBasedSuggestions: opts.wordBasedSuggestions,
E
Erich Gamma 已提交
268
			selectionHighlight: toBoolean(opts.selectionHighlight),
269
			codeLens: opts.referenceInfos && opts.codeLens,
M
Martin Aeschlimann 已提交
270
			folding: toBoolean(opts.folding),
A
Alex Dima 已提交
271 272
		});

273 274 275 276
		return new editorCommon.InternalEditorOptions({
			lineHeight: fontInfo.lineHeight, // todo -> duplicated in styling
			readOnly: readOnly,
			wordSeparators: String(opts.wordSeparators),
A
Alex Dima 已提交
277
			autoClosingBrackets: toBoolean(opts.autoClosingBrackets),
278
			useTabStops: toBoolean(opts.useTabStops),
279
			tabFocusMode: tabFocusMode,
E
Erich Gamma 已提交
280
			layoutInfo: layoutInfo,
281
			fontInfo: fontInfo,
282
			viewInfo: viewInfo,
E
Erich Gamma 已提交
283
			wrappingInfo: wrappingInfo,
A
Alex Dima 已提交
284
			contribInfo: contribInfo,
285
		});
E
Erich Gamma 已提交
286 287
	}

A
Alex Dima 已提交
288 289 290 291 292 293 294 295 296 297 298 299 300
	private static _sanitizeScrollbarOpts(raw:editorCommon.IEditorScrollbarOptions, mouseWheelScrollSensitivity:number): editorCommon.InternalEditorScrollbarOptions {

		var visibilityFromString = (visibility: string) => {
			switch (visibility) {
				case 'hidden':
					return ScrollbarVisibility.Hidden;
				case 'visible':
					return ScrollbarVisibility.Visible;
				default:
					return ScrollbarVisibility.Auto;
			}
		};

A
Alex Dima 已提交
301 302
		let horizontalScrollbarSize = toIntegerWithDefault(raw.horizontalScrollbarSize, 10);
		let verticalScrollbarSize = toIntegerWithDefault(raw.verticalScrollbarSize, 14);
A
Alex Dima 已提交
303 304 305
		return new editorCommon.InternalEditorScrollbarOptions({
			vertical: visibilityFromString(raw.vertical),
			horizontal: visibilityFromString(raw.horizontal),
E
Erich Gamma 已提交
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320

			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 已提交
321
		});
E
Erich Gamma 已提交
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
	}
}

function toBoolean(value:any): boolean {
	return value === 'false' ? false : Boolean(value);
}

function toBooleanWithDefault(value:any, defaultValue:boolean): boolean {
	if (typeof value === 'undefined') {
		return defaultValue;
	}
	return toBoolean(value);
}

function toFloat(source: any, defaultValue: number): number {
A
Alex Dima 已提交
337
	let r = parseFloat(source);
E
Erich Gamma 已提交
338 339 340 341 342 343
	if (isNaN(r)) {
		r = defaultValue;
	}
	return r;
}

344
function toInteger(source:any, minimum:number = MIN_SAFE_INT, maximum:number = MAX_SAFE_INT): number {
A
Alex Dima 已提交
345
	let r = parseInt(source, 10);
E
Erich Gamma 已提交
346 347 348
	if (isNaN(r)) {
		r = 0;
	}
349 350 351
	r = Math.max(minimum, r);
	r = Math.min(maximum, r);
	return r | 0;
E
Erich Gamma 已提交
352 353
}

354 355 356 357 358 359 360 361 362 363
function toSortedIntegerArray(source:any): number[] {
	if (!Array.isArray(source)) {
		return [];
	}
	let arrSource = <any[]>source;
	let r = arrSource.map(el => toInteger(el));
	r.sort();
	return r;
}

A
Alex Dima 已提交
364 365 366 367 368 369 370 371 372 373
function wrappingIndentFromString(wrappingIndent:string): editorCommon.WrappingIndent {
	if (wrappingIndent === 'indent') {
		return editorCommon.WrappingIndent.Indent;
	} else if (wrappingIndent === 'same') {
		return editorCommon.WrappingIndent.Same;
	} else {
		return editorCommon.WrappingIndent.None;
	}
}

A
Alex Dima 已提交
374 375 376 377 378 379 380 381 382 383 384
function cursorStyleFromString(cursorStyle:string): editorCommon.TextEditorCursorStyle {
	if (cursorStyle === 'line') {
		return editorCommon.TextEditorCursorStyle.Line;
	} else if (cursorStyle === 'block') {
		return editorCommon.TextEditorCursorStyle.Block;
	} else if (cursorStyle === 'underline') {
		return editorCommon.TextEditorCursorStyle.Underline;
	}
	return editorCommon.TextEditorCursorStyle.Line;
}

385
function cursorBlinkingStyleFromString(cursorBlinkingStyle: string): editorCommon.TextEditorCursorBlinkingStyle {
386 387 388 389 390 391 392 393 394 395 396 397
	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;
398 399 400 401
	}
	return editorCommon.TextEditorCursorBlinkingStyle.Blink;
}

E
Erich Gamma 已提交
402 403 404 405 406 407 408
function toIntegerWithDefault(source:any, defaultValue:number): number {
	if (typeof source === 'undefined') {
		return defaultValue;
	}
	return toInteger(source);
}

409 410 411 412 413 414 415 416
export interface IElementSizeObserver {
	startObserving(): void;
	observe(dimension?:editorCommon.IDimension): void;
	dispose(): void;
	getWidth(): number;
	getHeight(): number;
}

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

419 420
	public editor:editorCommon.InternalEditorOptions;
	public editorClone:editorCommon.InternalEditorOptions;
E
Erich Gamma 已提交
421 422

	protected _configWithDefaults:ConfigurationWithDefaults;
423
	protected _elementSizeObserver: IElementSizeObserver;
E
Erich Gamma 已提交
424
	private _isDominatedByLongLines:boolean;
425
	private _maxLineNumber:number;
E
Erich Gamma 已提交
426

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

430
	constructor(options:editorCommon.IEditorOptions, elementSizeObserver: IElementSizeObserver = null) {
A
Alex Dima 已提交
431
		super();
E
Erich Gamma 已提交
432
		this._configWithDefaults = new ConfigurationWithDefaults(options);
433
		this._elementSizeObserver = elementSizeObserver;
E
Erich Gamma 已提交
434
		this._isDominatedByLongLines = false;
435
		this._maxLineNumber = 1;
E
Erich Gamma 已提交
436
		this.editor = this._computeInternalOptions();
437
		this.editorClone = this.editor.clone();
438
		this._register(EditorZoom.onDidChangeZoomLevel(_ => this._recomputeOptions()));
439
		this._register(TabFocus.onDidChangeTabFocus(_ => this._recomputeOptions()));
E
Erich Gamma 已提交
440 441 442 443 444 445 446
	}

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

	protected _recomputeOptions(): void {
447 448
		this._setOptions(this._computeInternalOptions());
	}
449

450 451 452
	private _setOptions(newOptions:editorCommon.InternalEditorOptions): void {
		if (this.editor && this.editor.equals(newOptions)) {
			return;
E
Erich Gamma 已提交
453 454
		}

455 456 457 458
		let changeEvent = this.editor.createChangeEvent(newOptions);
		this.editor = newOptions;
		this.editorClone = this.editor.clone();
		this._onDidChange.fire(changeEvent);
E
Erich Gamma 已提交
459 460
	}

A
Alex Dima 已提交
461
	public getRawOptions(): editorCommon.IEditorOptions {
E
Erich Gamma 已提交
462 463 464
		return this._configWithDefaults.getEditorOptions();
	}

465
	private _computeInternalOptions(): editorCommon.InternalEditorOptions {
E
Erich Gamma 已提交
466 467
		let opts = this._configWithDefaults.getEditorOptions();

468
		let editorClassName = this._getEditorClassName(opts.theme, toBoolean(opts.fontLigatures));
469
		let fontFamily = String(opts.fontFamily) || DefaultConfig.editor.fontFamily;
470
		let fontWeight = String(opts.fontWeight) || DefaultConfig.editor.fontWeight;
471 472 473
		let fontSize = toFloat(opts.fontSize, DefaultConfig.editor.fontSize);
		fontSize = Math.max(0, fontSize);
		fontSize = Math.min(100, fontSize);
E
Erich Gamma 已提交
474

475 476
		let lineHeight = toInteger(opts.lineHeight, 0, 150);
		if (lineHeight === 0) {
477
			lineHeight = Math.round(GOLDEN_LINE_HEIGHT_RATIO * fontSize);
E
Erich Gamma 已提交
478
		}
479
		let editorZoomLevelMultiplier = 1 + (EditorZoom.getZoomLevel() * 0.1);
480 481
		fontSize *= editorZoomLevelMultiplier;
		lineHeight *= editorZoomLevelMultiplier;
E
Erich Gamma 已提交
482

483 484 485 486 487 488
		let disableTranslate3d = toBoolean(opts.disableTranslate3d);
		let canUseTranslate3d = this._getCanUseTranslate3d();
		if (disableTranslate3d) {
			canUseTranslate3d = false;
		}

489
		return InternalEditorOptionsHelper.createInternalEditorOptions(
E
Erich Gamma 已提交
490 491 492
			this.getOuterWidth(),
			this.getOuterHeight(),
			opts,
A
Alex Dima 已提交
493 494
			this.readConfiguration(new editorCommon.BareFontInfo({
				fontFamily: fontFamily,
495
				fontWeight: fontWeight,
A
Alex Dima 已提交
496 497 498
				fontSize: fontSize,
				lineHeight: lineHeight
			})),
499
			editorClassName,
E
Erich Gamma 已提交
500
			this._isDominatedByLongLines,
501
			this._maxLineNumber,
502
			canUseTranslate3d
E
Erich Gamma 已提交
503 504 505
		);
	}

A
Alex Dima 已提交
506
	public updateOptions(newOptions:editorCommon.IEditorOptions): void {
E
Erich Gamma 已提交
507 508 509 510 511 512 513 514 515
		this._configWithDefaults.updateOptions(newOptions);
		this._recomputeOptions();
	}

	public setIsDominatedByLongLines(isDominatedByLongLines:boolean): void {
		this._isDominatedByLongLines = isDominatedByLongLines;
		this._recomputeOptions();
	}

516 517
	public setMaxLineNumber(maxLineNumber:number): void {
		this._maxLineNumber = maxLineNumber;
E
Erich Gamma 已提交
518 519 520
		this._recomputeOptions();
	}

521
	protected abstract _getEditorClassName(theme:string, fontLigatures:boolean): string;
E
Erich Gamma 已提交
522

523
	protected abstract getOuterWidth(): number;
E
Erich Gamma 已提交
524

525
	protected abstract getOuterHeight(): number;
E
Erich Gamma 已提交
526

527 528
	protected abstract _getCanUseTranslate3d(): boolean;

529
	protected abstract readConfiguration(styling: editorCommon.BareFontInfo): editorCommon.FontInfo;
E
Erich Gamma 已提交
530 531 532 533 534 535 536 537 538 539 540 541
}

/**
 * Helper to update Monaco Editor Settings from configurations service.
 */
export class EditorConfiguration {
	public static EDITOR_SECTION = 'editor';
	public static DIFF_EDITOR_SECTION = 'diffEditor';

	/**
	 * Ask the provided configuration service to apply its configuration to the provided editor.
	 */
542
	public static apply(config: any, editor: editorCommon.IEditor): void {
E
Erich Gamma 已提交
543 544 545 546
		if (!config) {
			return;
		}

547 548 549 550 551 552
		// Editor Settings (Code Editor, Diff, Terminal)
		if (editor && typeof editor.updateOptions === 'function') {
			let type = editor.getEditorType();
			if (type !== editorCommon.EditorType.ICodeEditor && type !== editorCommon.EditorType.IDiffEditor) {
				return;
			}
E
Erich Gamma 已提交
553

554 555 556 557 558 559 560 561
			let editorConfig = config[EditorConfiguration.EDITOR_SECTION];
			if (type === editorCommon.EditorType.IDiffEditor) {
				let diffEditorConfig = config[EditorConfiguration.DIFF_EDITOR_SECTION];
				if (diffEditorConfig) {
					if (!editorConfig) {
						editorConfig = diffEditorConfig;
					} else {
						editorConfig = objects.mixin(editorConfig, diffEditorConfig);
E
Erich Gamma 已提交
562 563
					}
				}
564
			}
E
Erich Gamma 已提交
565

566 567 568
			if (editorConfig) {
				delete editorConfig.readOnly; // Prevent someone from making editor readonly
				editor.updateOptions(editorConfig);
E
Erich Gamma 已提交
569 570 571 572 573
			}
		}
	}
}

A
Alex Dima 已提交
574
let configurationRegistry = <IConfigurationRegistry>Registry.as(Extensions.Configuration);
A
Alex Dima 已提交
575
let editorConfiguration:IConfigurationNode = {
E
Erich Gamma 已提交
576 577 578
	'id': 'editor',
	'order': 5,
	'type': 'object',
579
	'title': nls.localize('editorConfigurationTitle', "Editor"),
E
Erich Gamma 已提交
580 581 582 583 584 585
	'properties' : {
		'editor.fontFamily' : {
			'type': 'string',
			'default': DefaultConfig.editor.fontFamily,
			'description': nls.localize('fontFamily', "Controls the font family.")
		},
586 587 588 589 590
		'editor.fontWeight' : {
			'type': 'string',
			'default': DefaultConfig.editor.fontWeight,
			'description': nls.localize('fontWeight', "Controls the font weight.")
		},
E
Erich Gamma 已提交
591 592 593 594 595 596 597 598
		'editor.fontSize' : {
			'type': 'number',
			'default': DefaultConfig.editor.fontSize,
			'description': nls.localize('fontSize', "Controls the font size.")
		},
		'editor.lineHeight' : {
			'type': 'number',
			'default': DefaultConfig.editor.lineHeight,
599
			'description': nls.localize('lineHeight', "Controls the line height. Use 0 to compute the lineHeight from the fontSize.")
E
Erich Gamma 已提交
600 601 602 603 604 605 606 607 608 609 610
		},
		'editor.lineNumbers' : {
			'type': 'boolean',
			'default': DefaultConfig.editor.lineNumbers,
			'description': nls.localize('lineNumbers', "Controls visibility of line numbers")
		},
		'editor.glyphMargin' : {
			'type': 'boolean',
			'default': DefaultConfig.editor.glyphMargin,
			'description': nls.localize('glyphMargin', "Controls visibility of the glyph margin")
		},
611 612 613 614 615 616 617 618
		'editor.rulers' : {
			'type': 'array',
			'items': {
				'type': 'number'
			},
			'default': DefaultConfig.editor.rulers,
			'description': nls.localize('rulers', "Columns at which to show vertical rulers")
		},
A
Alex Dima 已提交
619 620 621 622 623
		'editor.wordSeparators' : {
			'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")
		},
E
Erich Gamma 已提交
624
		'editor.tabSize' : {
625 626
			'type': 'number',
			'default': DEFAULT_INDENTATION.tabSize,
E
Erich Gamma 已提交
627
			'minimum': 1,
628
			'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."),
629
			'errorMessage': nls.localize('tabSize.errorMessage', "Expected 'number'. Note that the value \"auto\" has been replaced by the `editor.detectIndentation` setting.")
E
Erich Gamma 已提交
630 631
		},
		'editor.insertSpaces' : {
632 633
			'type': 'boolean',
			'default': DEFAULT_INDENTATION.insertSpaces,
634
			'description': nls.localize('insertSpaces', "Insert spaces when pressing Tab. This setting is overriden based on the file contents when `editor.detectIndentation` is on."),
635
			'errorMessage': nls.localize('insertSpaces.errorMessage', "Expected 'boolean'. Note that the value \"auto\" has been replaced by the `editor.detectIndentation` setting.")
E
Erich Gamma 已提交
636
		},
637 638 639
		'editor.detectIndentation' : {
			'type': 'boolean',
			'default': DEFAULT_INDENTATION.detectIndentation,
A
Alex Dima 已提交
640
			'description': nls.localize('detectIndentation', "When opening a file, `editor.tabSize` and `editor.insertSpaces` will be detected based on the file contents.")
641
		},
E
Erich Gamma 已提交
642 643 644 645 646 647 648 649 650 651 652 653 654 655
		'editor.roundedSelection' : {
			'type': 'boolean',
			'default': DefaultConfig.editor.roundedSelection,
			'description': nls.localize('roundedSelection', "Controls if selections have rounded corners")
		},
		'editor.scrollBeyondLastLine' : {
			'type': 'boolean',
			'default': DefaultConfig.editor.scrollBeyondLastLine,
			'description': nls.localize('scrollBeyondLastLine', "Controls if the editor will scroll beyond the last line")
		},
		'editor.wrappingColumn' : {
			'type': 'integer',
			'default': DefaultConfig.editor.wrappingColumn,
			'minimum': -1,
656
			'description': nls.localize('wrappingColumn', "Controls after how many characters the editor will wrap to the next line. Setting this to 0 turns on viewport width wrapping (word wrapping). Setting this to -1 forces the editor to never wrap.")
E
Erich Gamma 已提交
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
		},
		'editor.wrappingIndent' : {
			'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'.")
		},
		'editor.mouseWheelScrollSensitivity' : {
			'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")
		},
		'editor.quickSuggestions' : {
			'type': 'boolean',
			'default': DefaultConfig.editor.quickSuggestions,
			'description': nls.localize('quickSuggestions', "Controls if quick suggestions should show up or not while typing")
		},
		'editor.quickSuggestionsDelay' : {
			'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
Joao Moreno 已提交
680 681 682 683 684
		'editor.parameterHints' : {
			'type': 'boolean',
			'default': DefaultConfig.editor.parameterHints,
			'description': nls.localize('parameterHints', "Enables parameter hints")
		},
E
Erich Gamma 已提交
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
		'editor.autoClosingBrackets' : {
			'type': 'boolean',
			'default': DefaultConfig.editor.autoClosingBrackets,
			'description': nls.localize('autoClosingBrackets', "Controls if the editor should automatically close brackets after opening them")
		},
		'editor.formatOnType' : {
			'type': 'boolean',
			'default': DefaultConfig.editor.formatOnType,
			'description': nls.localize('formatOnType', "Controls if the editor should automatically format the line after typing")
		},
		'editor.suggestOnTriggerCharacters' : {
			'type': 'boolean',
			'default': DefaultConfig.editor.suggestOnTriggerCharacters,
			'description': nls.localize('suggestOnTriggerCharacters', "Controls if suggestions should automatically show up when typing trigger characters")
		},
700 701 702 703 704
		'editor.acceptSuggestionOnEnter' : {
			'type': 'boolean',
			'default': DefaultConfig.editor.acceptSuggestionOnEnter,
			'description': nls.localize('acceptSuggestionOnEnter', "Controls if suggestions should be accepted 'Enter' - in addition to 'Tab'. Helps to avoid ambiguity between inserting new lines or accepting suggestions.")
		},
705
		'editor.snippetSuggestions': {
706
			'type': 'string',
707 708 709
			'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.")
710
		},
711 712 713 714 715
		'editor.wordBasedSuggestions': {
			'type': 'boolean',
			'default': DefaultConfig.editor.wordBasedSuggestions,
			'description': nls.localize('wordBasedSuggestions', "Enable word based suggestions.")
		},
716 717 718
		'editor.tabCompletion': {
			'type': 'boolean',
			'default': DefaultConfig.editor.tabCompletion,
719
			'description': nls.localize('tabCompletion', "Insert snippets when their prefix matches. Works best when 'quickSuggestions' aren't enabled.")
720
		},
E
Erich Gamma 已提交
721 722 723 724 725 726 727 728 729 730
		'editor.selectionHighlight' : {
			'type': 'boolean',
			'default': DefaultConfig.editor.selectionHighlight,
			'description': nls.localize('selectionHighlight', "Controls whether the editor should highlight similar matches to the selection")
		},
		'editor.overviewRulerLanes' : {
			'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")
		},
731 732
		'editor.cursorBlinking' : {
			'type': 'string',
733
			'enum': ['blink', 'smooth', 'phase', 'expand', 'solid'],
734
			'default': DefaultConfig.editor.cursorBlinking,
735
			'description': nls.localize('cursorBlinking', "Control the cursor animation style, possible values are 'blink', 'smooth', 'phase', 'expand' and 'solid'")
736
		},
737 738 739 740 741
		'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")
		},
M
markrendle 已提交
742 743
		'editor.cursorStyle' : {
			'type': 'string',
744
			'enum': ['block', 'line', 'underline'],
M
markrendle 已提交
745
			'default': DefaultConfig.editor.cursorStyle,
746
			'description': nls.localize('cursorStyle', "Controls the cursor style, accepted values are 'block', 'line' and 'underline'")
M
markrendle 已提交
747
		},
748 749 750 751 752
		'editor.fontLigatures' : {
			'type': 'boolean',
			'default': DefaultConfig.editor.fontLigatures,
			'description': nls.localize('fontLigatures', "Enables font ligatures")
		},
E
Erich Gamma 已提交
753 754 755 756 757 758
		'editor.hideCursorInOverviewRuler' : {
			'type': 'boolean',
			'default': DefaultConfig.editor.hideCursorInOverviewRuler,
			'description': nls.localize('hideCursorInOverviewRuler', "Controls if the cursor should be hidden in the overview ruler.")
		},
		'editor.renderWhitespace': {
759 760
			'type': 'string',
			'enum': ['none', 'boundary', 'all'],
E
Erich Gamma 已提交
761
			default: DefaultConfig.editor.renderWhitespace,
762
			description: nls.localize('renderWhitespace', "Controls how the editor should render whitespace characters, posibilties are 'none', 'boundary', and 'all'. The 'boundary' option does not render single spaces between words.")
E
Erich Gamma 已提交
763
		},
764 765 766 767 768
		'editor.renderControlCharacters': {
			'type': 'boolean',
			default: DefaultConfig.editor.renderControlCharacters,
			description: nls.localize('renderControlCharacters', "Controls whether the editor should render control characters")
		},
769 770 771 772 773
		'editor.renderIndentGuides': {
			'type': 'boolean',
			default: DefaultConfig.editor.renderIndentGuides,
			description: nls.localize('renderIndentGuides', "Controls whether the editor should render indent guides")
		},
774 775 776 777 778
		'editor.renderLineHighlight': {
			'type': 'boolean',
			default: DefaultConfig.editor.renderLineHighlight,
			description: nls.localize('renderLineHighlight', "Controls whether the editor should render the current line highlight")
		},
779
		'editor.codeLens' : {
E
Erich Gamma 已提交
780
			'type': 'boolean',
781 782
			'default': DefaultConfig.editor.codeLens,
			'description': nls.localize('codeLens', "Controls if the editor shows code lenses")
E
Erich Gamma 已提交
783
		},
M
Martin Aeschlimann 已提交
784 785 786
		'editor.folding' : {
			'type': 'boolean',
			'default': DefaultConfig.editor.folding,
787
			'description': nls.localize('folding', "Controls whether the editor has code folding enabled")
M
Martin Aeschlimann 已提交
788
		},
789 790 791 792 793 794 795
		'editor.useTabStops' : {
			'type': 'boolean',
			'default': DefaultConfig.editor.useTabStops,
			'description': nls.localize('useTabStops', "Inserting and deleting whitespace follows tab stops")
		},
		'editor.trimAutoWhitespace' : {
			'type': 'boolean',
796
			'default': DEFAULT_TRIM_AUTO_WHITESPACE,
797 798
			'description': nls.localize('trimAutoWhitespace', "Remove trailing auto inserted whitespace")
		},
799
		'editor.stablePeek' : {
800
			'type': 'boolean',
801
			'default': false,
802
			'description': nls.localize('stablePeek', "Keep peek editors open even when double clicking their content or when hitting Escape.")
803
		},
E
Erich Gamma 已提交
804 805 806 807 808 809 810 811 812 813 814
		'diffEditor.renderSideBySide' : {
			'type': 'boolean',
			'default': true,
			'description': nls.localize('sideBySide', "Controls if the diff editor shows the diff side by side or inline")
		},
		'diffEditor.ignoreTrimWhitespace' : {
			'type': 'boolean',
			'default': true,
			'description': nls.localize('ignoreTrimWhitespace', "Controls if the diff editor shows changes in leading or trailing whitespace as diffs")
		}
	}
A
Alex Dima 已提交
815 816 817 818 819 820 821 822 823 824 825
};

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.")
	};
}

configurationRegistry.registerConfiguration(editorConfiguration);