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

import 'vs/css!./media/editor';
import 'vs/css!./media/tokens';
J
Johannes Rieken 已提交
9
import { onUnexpectedError } from 'vs/base/common/errors';
10
import { TPromise } from 'vs/base/common/winjs.base';
A
Alex Dima 已提交
11
import * as dom from 'vs/base/browser/dom';
J
Johannes Rieken 已提交
12 13 14 15 16
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { CommonCodeEditor } from 'vs/editor/common/commonCodeEditor';
import { CommonEditorConfiguration } from 'vs/editor/common/config/commonEditorConfig';
A
Alex Dima 已提交
17
import { Range, IRange } from 'vs/editor/common/core/range';
A
Alex Dima 已提交
18
import * as editorCommon from 'vs/editor/common/editorCommon';
J
Johannes Rieken 已提交
19 20 21
import { EditorAction } from 'vs/editor/common/editorCommonExtensions';
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
import { Configuration } from 'vs/editor/browser/config/configuration';
A
Alex Dima 已提交
22
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
A
Alex Dima 已提交
23
import { View, IOverlayWidgetData, IContentWidgetData } from 'vs/editor/browser/view/viewImpl';
J
Johannes Rieken 已提交
24
import { Disposable } from 'vs/base/common/lifecycle';
A
Alex Dima 已提交
25
import Event, { Emitter } from 'vs/base/common/event';
J
Johannes Rieken 已提交
26 27
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { InternalEditorAction } from 'vs/editor/common/editorAction';
28 29 30 31
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { IPosition } from 'vs/editor/common/core/position';
import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer';
import { CoreEditorCommand } from 'vs/editor/common/controller/coreCommands';
32
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
33 34
import { editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder } from 'vs/editor/common/view/editorColorRegistry';
import { Color } from 'vs/base/common/color';
B
Benjamin Pasero 已提交
35
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
E
Erich Gamma 已提交
36

37
export abstract class CodeEditorWidget extends CommonCodeEditor implements editorBrowser.ICodeEditor {
E
Erich Gamma 已提交
38

A
Alex Dima 已提交
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
	private readonly _onMouseUp: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
	public readonly onMouseUp: Event<editorBrowser.IEditorMouseEvent> = this._onMouseUp.event;

	private readonly _onMouseDown: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
	public readonly onMouseDown: Event<editorBrowser.IEditorMouseEvent> = this._onMouseDown.event;

	private readonly _onMouseDrag: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
	public readonly onMouseDrag: Event<editorBrowser.IEditorMouseEvent> = this._onMouseDrag.event;

	private readonly _onMouseDrop: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
	public readonly onMouseDrop: Event<editorBrowser.IEditorMouseEvent> = this._onMouseDrop.event;

	private readonly _onContextMenu: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
	public readonly onContextMenu: Event<editorBrowser.IEditorMouseEvent> = this._onContextMenu.event;

	private readonly _onMouseMove: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
	public readonly onMouseMove: Event<editorBrowser.IEditorMouseEvent> = this._onMouseMove.event;

	private readonly _onMouseLeave: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
	public readonly onMouseLeave: Event<editorBrowser.IEditorMouseEvent> = this._onMouseLeave.event;

	private readonly _onKeyUp: Emitter<IKeyboardEvent> = this._register(new Emitter<IKeyboardEvent>());
	public readonly onKeyUp: Event<IKeyboardEvent> = this._onKeyUp.event;

	private readonly _onKeyDown: Emitter<IKeyboardEvent> = this._register(new Emitter<IKeyboardEvent>());
	public readonly onKeyDown: Event<IKeyboardEvent> = this._onKeyDown.event;

	private readonly _onDidScrollChange: Emitter<editorCommon.IScrollEvent> = this._register(new Emitter<editorCommon.IScrollEvent>());
	public readonly onDidScrollChange: Event<editorCommon.IScrollEvent> = this._onDidScrollChange.event;

	private readonly _onDidChangeViewZones: Emitter<void> = this._register(new Emitter<void>());
	public readonly onDidChangeViewZones: Event<void> = this._onDidChangeViewZones.event;
A
Alex Dima 已提交
71

72
	private _codeEditorService: ICodeEditorService;
73
	private _commandService: ICommandService;
74
	private _themeService: IThemeService;
75

J
Johannes Rieken 已提交
76
	protected domElement: HTMLElement;
77
	private _focusTracker: CodeEditorWidgetFocusTracker;
E
Erich Gamma 已提交
78

J
Johannes Rieken 已提交
79
	_configuration: Configuration;
80

A
Alex Dima 已提交
81 82
	private contentWidgets: { [key: string]: IContentWidgetData; };
	private overlayWidgets: { [key: string]: IOverlayWidgetData; };
E
Erich Gamma 已提交
83

A
Alex Dima 已提交
84
	_view: View;
E
Erich Gamma 已提交
85 86

	constructor(
J
Johannes Rieken 已提交
87
		domElement: HTMLElement,
88
		options: IEditorOptions,
E
Erich Gamma 已提交
89 90
		@IInstantiationService instantiationService: IInstantiationService,
		@ICodeEditorService codeEditorService: ICodeEditorService,
91
		@ICommandService commandService: ICommandService,
92 93
		@IContextKeyService contextKeyService: IContextKeyService,
		@IThemeService themeService: IThemeService
E
Erich Gamma 已提交
94
	) {
95
		super(domElement, options, instantiationService, contextKeyService);
96
		this._codeEditorService = codeEditorService;
97
		this._commandService = commandService;
98
		this._themeService = themeService;
E
Erich Gamma 已提交
99

100
		this._focusTracker = new CodeEditorWidgetFocusTracker(domElement);
A
Alex Dima 已提交
101
		this._focusTracker.onChange(() => {
102
			let hasFocus = this._focusTracker.hasFocus();
103

104
			if (hasFocus) {
A
Alex Dima 已提交
105
				this._onDidFocusEditor.fire();
106
			} else {
A
Alex Dima 已提交
107
				this._onDidBlurEditor.fire();
E
Erich Gamma 已提交
108 109 110 111 112 113
			}
		});

		this.contentWidgets = {};
		this.overlayWidgets = {};

114 115 116
		let contributions = this._getContributions();
		for (let i = 0, len = contributions.length; i < len; i++) {
			let ctor = contributions[i];
E
Erich Gamma 已提交
117
			try {
118
				let contribution = this._instantiationService.createInstance(ctor, this);
A
Alex Dima 已提交
119
				this._contributions[contribution.getId()] = contribution;
E
Erich Gamma 已提交
120
			} catch (err) {
121
				onUnexpectedError(err);
E
Erich Gamma 已提交
122 123
			}
		}
124

125
		this._getActions().forEach((action) => {
126 127 128 129 130 131 132 133 134 135 136 137
			const internalAction = new InternalEditorAction(
				action.id,
				action.label,
				action.alias,
				action.precondition,
				(): void | TPromise<void> => {
					return this._instantiationService.invokeFunction((accessor) => {
						return action.runEditorCommand(accessor, this, null);
					});
				},
				this._contextKeyService
			);
A
Alex Dima 已提交
138
			this._actions[internalAction.id] = internalAction;
139
		});
140 141

		this._codeEditorService.addCodeEditor(this);
E
Erich Gamma 已提交
142 143
	}

144
	protected abstract _getContributions(): editorBrowser.IEditorContributionCtor[];
145 146
	protected abstract _getActions(): EditorAction[];

A
Alex Dima 已提交
147
	protected _createConfiguration(options: IEditorOptions): CommonEditorConfiguration {
148
		return new Configuration(options, this.domElement);
E
Erich Gamma 已提交
149 150 151
	}

	public dispose(): void {
152 153
		this._codeEditorService.removeCodeEditor(this);

E
Erich Gamma 已提交
154 155 156
		this.contentWidgets = {};
		this.overlayWidgets = {};

157
		this._focusTracker.dispose();
E
Erich Gamma 已提交
158 159 160
		super.dispose();
	}

A
Alex Dima 已提交
161 162
	public createOverviewRuler(cssClassName: string, minimumHeight: number, maximumHeight: number): editorBrowser.IOverviewRuler {
		return this._view.createOverviewRuler(cssClassName, minimumHeight, maximumHeight);
E
Erich Gamma 已提交
163 164 165 166 167 168
	}

	public getDomNode(): HTMLElement {
		if (!this.hasView) {
			return null;
		}
A
Alex Dima 已提交
169
		return this._view.domNode.domNode;
E
Erich Gamma 已提交
170 171
	}

A
Alex Dima 已提交
172
	public getCompletelyVisibleLinesRangeInViewport(): Range {
A
Alex Dima 已提交
173 174 175 176
		if (!this.hasView) {
			return null;
		}
		const viewRange = this.viewModel.getCompletelyVisibleViewRange();
A
Alex Dima 已提交
177
		return this.viewModel.coordinatesConverter.convertViewRangeToModelRange(viewRange);
178 179
	}

180
	public delegateVerticalScrollbarMouseDown(browserEvent: IMouseEvent): void {
E
Erich Gamma 已提交
181
		if (!this.hasView) {
182
			return;
E
Erich Gamma 已提交
183
		}
A
Alex Dima 已提交
184
		this._view.delegateVerticalScrollbarMouseDown(browserEvent);
E
Erich Gamma 已提交
185 186
	}

J
Johannes Rieken 已提交
187
	public layout(dimension?: editorCommon.IDimension): void {
E
Erich Gamma 已提交
188
		this._configuration.observeReferenceElement(dimension);
189
		this.render();
E
Erich Gamma 已提交
190 191 192 193 194 195 196 197 198 199 200 201 202
	}

	public focus(): void {
		if (!this.hasView) {
			return;
		}
		this._view.focus();
	}

	public isFocused(): boolean {
		return this.hasView && this._view.isFocused();
	}

203
	public hasWidgetFocus(): boolean {
204
		return this._focusTracker && this._focusTracker.hasFocus();
205 206
	}

A
Alex Dima 已提交
207
	public addContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
208
		let widgetData: IContentWidgetData = {
E
Erich Gamma 已提交
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
			widget: widget,
			position: widget.getPosition()
		};

		if (this.contentWidgets.hasOwnProperty(widget.getId())) {
			console.warn('Overwriting a content widget with the same id.');
		}

		this.contentWidgets[widget.getId()] = widgetData;

		if (this.hasView) {
			this._view.addContentWidget(widgetData);
		}
	}

A
Alex Dima 已提交
224
	public layoutContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
225
		let widgetId = widget.getId();
E
Erich Gamma 已提交
226
		if (this.contentWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
227
			let widgetData = this.contentWidgets[widgetId];
E
Erich Gamma 已提交
228 229 230 231 232 233 234
			widgetData.position = widget.getPosition();
			if (this.hasView) {
				this._view.layoutContentWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
235
	public removeContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
236
		let widgetId = widget.getId();
E
Erich Gamma 已提交
237
		if (this.contentWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
238
			let widgetData = this.contentWidgets[widgetId];
E
Erich Gamma 已提交
239 240 241 242 243 244 245
			delete this.contentWidgets[widgetId];
			if (this.hasView) {
				this._view.removeContentWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
246
	public addOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
247
		let widgetData: IOverlayWidgetData = {
E
Erich Gamma 已提交
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
			widget: widget,
			position: widget.getPosition()
		};

		if (this.overlayWidgets.hasOwnProperty(widget.getId())) {
			console.warn('Overwriting an overlay widget with the same id.');
		}

		this.overlayWidgets[widget.getId()] = widgetData;

		if (this.hasView) {
			this._view.addOverlayWidget(widgetData);
		}
	}

A
Alex Dima 已提交
263
	public layoutOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
264
		let widgetId = widget.getId();
E
Erich Gamma 已提交
265
		if (this.overlayWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
266
			let widgetData = this.overlayWidgets[widgetId];
E
Erich Gamma 已提交
267 268 269 270 271 272 273
			widgetData.position = widget.getPosition();
			if (this.hasView) {
				this._view.layoutOverlayWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
274
	public removeOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
275
		let widgetId = widget.getId();
E
Erich Gamma 已提交
276
		if (this.overlayWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
277
			let widgetData = this.overlayWidgets[widgetId];
E
Erich Gamma 已提交
278 279 280 281 282 283 284
			delete this.overlayWidgets[widgetId];
			if (this.hasView) {
				this._view.removeOverlayWidget(widgetData);
			}
		}
	}

J
Johannes Rieken 已提交
285
	public changeViewZones(callback: (accessor: editorBrowser.IViewZoneChangeAccessor) => void): void {
E
Erich Gamma 已提交
286 287 288
		if (!this.hasView) {
			return;
		}
A
Alex Dima 已提交
289
		let hasChanges = this._view.change(callback);
E
Erich Gamma 已提交
290
		if (hasChanges) {
A
Alex Dima 已提交
291
			this._onDidChangeViewZones.fire();
E
Erich Gamma 已提交
292 293 294
		}
	}

A
Alex Dima 已提交
295
	public getWhitespaces(): IEditorWhitespace[] {
E
Erich Gamma 已提交
296 297 298
		if (!this.hasView) {
			return [];
		}
299
		return this.viewModel.viewLayout.getWhitespaces();
E
Erich Gamma 已提交
300 301
	}

302 303 304 305 306 307
	private _getVerticalOffsetForPosition(modelLineNumber: number, modelColumn: number): number {
		let modelPosition = this.model.validatePosition({
			lineNumber: modelLineNumber,
			column: modelColumn
		});
		let viewPosition = this.viewModel.coordinatesConverter.convertModelPositionToViewPosition(modelPosition);
308
		return this.viewModel.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber);
309 310
	}

E
Erich Gamma 已提交
311 312 313 314
	public getTopForLineNumber(lineNumber: number): number {
		if (!this.hasView) {
			return -1;
		}
315
		return this._getVerticalOffsetForPosition(lineNumber, 1);
E
Erich Gamma 已提交
316 317 318 319 320 321
	}

	public getTopForPosition(lineNumber: number, column: number): number {
		if (!this.hasView) {
			return -1;
		}
322
		return this._getVerticalOffsetForPosition(lineNumber, column);
E
Erich Gamma 已提交
323 324
	}

325 326 327 328
	public getTargetAtClientPoint(clientX: number, clientY: number): editorBrowser.IMouseTarget {
		if (!this.hasView) {
			return null;
		}
A
Alex Dima 已提交
329
		return this._view.getTargetAtClientPoint(clientX, clientY);
330 331
	}

A
Alex Dima 已提交
332
	public getScrolledVisiblePosition(rawPosition: IPosition): { top: number; left: number; height: number; } {
E
Erich Gamma 已提交
333 334 335 336
		if (!this.hasView) {
			return null;
		}

A
Alex Dima 已提交
337 338
		let position = this.model.validatePosition(rawPosition);
		let layoutInfo = this._configuration.editor.layoutInfo;
E
Erich Gamma 已提交
339

340 341
		let top = this._getVerticalOffsetForPosition(position.lineNumber, position.column) - this.getScrollTop();
		let left = this._view.getOffsetForColumn(position.lineNumber, position.column) + layoutInfo.glyphMarginWidth + layoutInfo.lineNumbersWidth + layoutInfo.decorationsWidth - this.getScrollLeft();
E
Erich Gamma 已提交
342 343 344 345 346 347 348 349

		return {
			top: top,
			left: left,
			height: this._configuration.editor.lineHeight
		};
	}

J
Johannes Rieken 已提交
350
	public getOffsetForColumn(lineNumber: number, column: number): number {
E
Erich Gamma 已提交
351 352 353
		if (!this.hasView) {
			return -1;
		}
A
Alex Dima 已提交
354
		return this._view.getOffsetForColumn(lineNumber, column);
E
Erich Gamma 已提交
355 356
	}

357 358 359 360
	public render(): void {
		if (!this.hasView) {
			return;
		}
361
		this._view.render(true, false);
362 363
	}

A
Alex Dima 已提交
364
	public setHiddenAreas(ranges: IRange[]): void {
M
Martin Aeschlimann 已提交
365
		if (this.viewModel) {
A
Alex Dima 已提交
366
			this.viewModel.setHiddenAreas(ranges.map(r => Range.lift(r)));
M
Martin Aeschlimann 已提交
367 368 369
		}
	}

J
Johannes Rieken 已提交
370
	public setAriaActiveDescendant(id: string): void {
A
Alex Dima 已提交
371 372 373 374 375 376
		if (!this.hasView) {
			return;
		}
		this._view.setAriaActiveDescendant(id);
	}

J
Johannes Rieken 已提交
377
	public applyFontInfo(target: HTMLElement): void {
378 379 380
		Configuration.applyFontInfoSlow(target, this._configuration.editor.fontInfo);
	}

J
Johannes Rieken 已提交
381
	_attachModel(model: editorCommon.IModel): void {
E
Erich Gamma 已提交
382 383
		this._view = null;

384
		super._attachModel(model);
E
Erich Gamma 已提交
385

386
		if (this._view) {
A
Alex Dima 已提交
387
			this.domElement.appendChild(this._view.domNode.domNode);
E
Erich Gamma 已提交
388

A
Alex Dima 已提交
389 390 391 392 393
			let keys = Object.keys(this.contentWidgets);
			for (let i = 0, len = keys.length; i < len; i++) {
				let widgetId = keys[i];
				this._view.addContentWidget(this.contentWidgets[widgetId]);
			}
E
Erich Gamma 已提交
394

A
Alex Dima 已提交
395 396 397 398 399
			keys = Object.keys(this.overlayWidgets);
			for (let i = 0, len = keys.length; i < len; i++) {
				let widgetId = keys[i];
				this._view.addOverlayWidget(this.overlayWidgets[widgetId]);
			}
E
Erich Gamma 已提交
400

A
Alex Dima 已提交
401 402
			this._view.render(false, true);
			this.hasView = true;
E
Erich Gamma 已提交
403 404 405
		}
	}

406 407
	protected _createView(): void {
		this._view = new View(
408
			this._commandService,
409
			this._configuration,
410
			this._themeService,
411
			this.viewModel,
412
			this.cursor,
413
			(editorCommand: CoreEditorCommand, args: any) => {
A
Alex Dima 已提交
414 415 416
				if (!this.cursor) {
					return;
				}
417
				editorCommand.runCoreEditorCommand(this.cursor, args);
A
Alex Dima 已提交
418
			}
419
		);
E
Erich Gamma 已提交
420

A
Alex Dima 已提交
421
		const viewEventBus = this._view.getInternalEventBus();
A
Alex Dima 已提交
422

A
Alex Dima 已提交
423 424 425 426 427
		this.listenersToRemove.push(viewEventBus.onDidGainFocus(() => {
			this._onDidFocusEditorText.fire();
			// In IE, the focus is not synchronous, so we give it a little help
			this._onDidFocusEditor.fire();
		}));
A
Alex Dima 已提交
428

A
Alex Dima 已提交
429 430 431
		this.listenersToRemove.push(viewEventBus.onDidScroll((e) => {
			this._onDidScrollChange.fire(e);
		}));
A
Alex Dima 已提交
432

A
Alex Dima 已提交
433 434 435
		this.listenersToRemove.push(viewEventBus.onDidLoseFocus(() => {
			this._onDidBlurEditorText.fire();
		}));
A
Alex Dima 已提交
436

A
Alex Dima 已提交
437 438 439
		this.listenersToRemove.push(viewEventBus.onContextMenu((e) => {
			this._onContextMenu.fire(e);
		}));
A
Alex Dima 已提交
440

A
Alex Dima 已提交
441 442 443
		this.listenersToRemove.push(viewEventBus.onMouseDown((e) => {
			this._onMouseDown.fire(e);
		}));
A
Alex Dima 已提交
444

A
Alex Dima 已提交
445 446 447
		this.listenersToRemove.push(viewEventBus.onMouseUp((e) => {
			this._onMouseUp.fire(e);
		}));
A
Alex Dima 已提交
448

A
Alex Dima 已提交
449 450 451
		this.listenersToRemove.push(viewEventBus.onMouseDrag((e) => {
			this._onMouseDrag.fire(e);
		}));
A
Alex Dima 已提交
452

A
Alex Dima 已提交
453 454 455
		this.listenersToRemove.push(viewEventBus.onMouseDrop((e) => {
			this._onMouseDrop.fire(e);
		}));
A
Alex Dima 已提交
456

A
Alex Dima 已提交
457 458 459
		this.listenersToRemove.push(viewEventBus.onKeyUp((e) => {
			this._onKeyUp.fire(e);
		}));
A
Alex Dima 已提交
460

A
Alex Dima 已提交
461 462 463
		this.listenersToRemove.push(viewEventBus.onMouseMove((e) => {
			this._onMouseMove.fire(e);
		}));
A
Alex Dima 已提交
464

A
Alex Dima 已提交
465 466 467
		this.listenersToRemove.push(viewEventBus.onMouseLeave((e) => {
			this._onMouseLeave.fire(e);
		}));
A
Alex Dima 已提交
468

A
Alex Dima 已提交
469 470
		this.listenersToRemove.push(viewEventBus.onKeyDown((e) => {
			this._onKeyDown.fire(e);
A
Alex Dima 已提交
471
		}));
472
	}
E
Erich Gamma 已提交
473

A
Alex Dima 已提交
474
	protected _detachModel(): editorCommon.IModel {
A
Alex Dima 已提交
475
		let removeDomNode: HTMLElement = null;
E
Erich Gamma 已提交
476 477 478

		if (this._view) {
			this._view.dispose();
A
Alex Dima 已提交
479
			removeDomNode = this._view.domNode.domNode;
E
Erich Gamma 已提交
480 481 482
			this._view = null;
		}

483
		let result = super._detachModel();
E
Erich Gamma 已提交
484 485 486 487 488 489 490

		if (removeDomNode) {
			this.domElement.removeChild(removeDomNode);
		}

		return result;
	}
491 492 493

	// BEGIN decorations

J
Johannes Rieken 已提交
494
	protected _registerDecorationType(key: string, options: editorCommon.IDecorationRenderOptions, parentTypeKey?: string): void {
495 496 497
		this._codeEditorService.registerDecorationType(key, options, parentTypeKey);
	}

J
Johannes Rieken 已提交
498
	protected _removeDecorationType(key: string): void {
499 500 501
		this._codeEditorService.removeDecorationType(key);
	}

J
Johannes Rieken 已提交
502
	protected _resolveDecorationOptions(typeKey: string, writable: boolean): editorCommon.IModelDecorationOptions {
503 504 505 506
		return this._codeEditorService.resolveDecorationOptions(typeKey, writable);
	}

	// END decorations
E
Erich Gamma 已提交
507 508
}

509 510
class CodeEditorWidgetFocusTracker extends Disposable {

511 512
	private _hasFocus: boolean;
	private _domFocusTracker: dom.IFocusTracker;
513 514

	private _onChange: Emitter<void> = this._register(new Emitter<void>());
A
Alex Dima 已提交
515
	public onChange: Event<void> = this._onChange.event;
516

J
Johannes Rieken 已提交
517
	constructor(domElement: HTMLElement) {
518 519
		super();

520 521
		this._hasFocus = false;
		this._domFocusTracker = this._register(dom.trackFocus(domElement));
522

523 524 525
		this._domFocusTracker.addFocusListener(() => {
			this._hasFocus = true;
			this._onChange.fire(void 0);
526
		});
527 528 529
		this._domFocusTracker.addBlurListener(() => {
			this._hasFocus = false;
			this._onChange.fire(void 0);
530 531 532 533
		});
	}

	public hasFocus(): boolean {
534
		return this._hasFocus;
535 536
	}
}
537

538 539
const squigglyStart = encodeURIComponent(`<svg xmlns='http://www.w3.org/2000/svg' height='3' width='6'><g fill='`);
const squigglyEnd = encodeURIComponent(`'><polygon points='5.5,0 2.5,3 1.1,3 4.1,0'/><polygon points='4,0 6,2 6,0.6 5.4,0'/><polygon points='0,2 1,3 2.4,3 0,0.6'/></g></svg>`);
540

541 542 543
function getSquigglySVGData(color: Color) {
	return squigglyStart + encodeURIComponent(color.toString()) + squigglyEnd;
}
544

545 546 547 548 549 550 551 552
registerThemingParticipant((theme, collector) => {
	let errorBorderColor = theme.getColor(editorErrorBorder);
	if (errorBorderColor) {
		collector.addRule(`.monaco-editor .redsquiggly { border-bottom: 4px double ${errorBorderColor}; }`);
	}
	let errorForeground = theme.getColor(editorErrorForeground);
	if (errorForeground) {
		collector.addRule(`.monaco-editor .redsquiggly { background: url("data:image/svg+xml,${getSquigglySVGData(errorForeground)}") repeat-x bottom left; }`);
553 554
	}

555 556 557 558 559 560 561
	let warningBorderColor = theme.getColor(editorWarningBorder);
	if (warningBorderColor) {
		collector.addRule(`.monaco-editor .greensquiggly { border-bottom: 4px double ${warningBorderColor}; }`);
	}
	let warningForeground = theme.getColor(editorWarningForeground);
	if (warningForeground) {
		collector.addRule(`.monaco-editor .greensquiggly { background: url("data:image/svg+xml;utf8,${getSquigglySVGData(warningForeground)}") repeat-x bottom left; }`);
562 563
	}
});