codeEditorWidget.ts 19.0 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';
J
Johannes Rieken 已提交
23
import { Colorizer } from 'vs/editor/browser/standalone/colorizer';
A
Alex Dima 已提交
24
import { View, IOverlayWidgetData, IContentWidgetData } from 'vs/editor/browser/view/viewImpl';
J
Johannes Rieken 已提交
25
import { Disposable } from 'vs/base/common/lifecycle';
A
Alex Dima 已提交
26
import Event, { Emitter } from 'vs/base/common/event';
J
Johannes Rieken 已提交
27 28
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { InternalEditorAction } from 'vs/editor/common/editorAction';
29 30 31 32
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';
33
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
34 35
import { editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder } from 'vs/editor/common/view/editorColorRegistry';
import { Color } from 'vs/base/common/color';
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();
	}

J
Johannes Rieken 已提交
161
	public colorizeModelLine(lineNumber: number, model: editorCommon.IModel = this.model): string {
E
Erich Gamma 已提交
162 163 164
		if (!model) {
			return '';
		}
A
Alex Dima 已提交
165
		let content = model.getLineContent(lineNumber);
A
Alex Dima 已提交
166 167
		model.forceTokenization(lineNumber);
		let tokens = model.getLineTokens(lineNumber);
A
Alex Dima 已提交
168 169
		let inflatedTokens = tokens.inflate();
		let tabSize = model.getOptions().tabSize;
170
		return Colorizer.colorizeLine(content, model.mightContainRTL(), inflatedTokens, tabSize);
E
Erich Gamma 已提交
171
	}
A
Alex Dima 已提交
172 173 174

	public createOverviewRuler(cssClassName: string, minimumHeight: number, maximumHeight: number): editorBrowser.IOverviewRuler {
		return this._view.createOverviewRuler(cssClassName, minimumHeight, maximumHeight);
E
Erich Gamma 已提交
175 176 177 178 179 180
	}

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

A
Alex Dima 已提交
184
	public getCompletelyVisibleLinesRangeInViewport(): Range {
A
Alex Dima 已提交
185 186 187 188
		if (!this.hasView) {
			return null;
		}
		const viewRange = this.viewModel.getCompletelyVisibleViewRange();
A
Alex Dima 已提交
189
		return this.viewModel.coordinatesConverter.convertViewRangeToModelRange(viewRange);
190 191
	}

J
Johannes Rieken 已提交
192
	public delegateVerticalScrollbarMouseDown(browserEvent: MouseEvent): void {
E
Erich Gamma 已提交
193
		if (!this.hasView) {
194
			return;
E
Erich Gamma 已提交
195
		}
A
Alex Dima 已提交
196
		this._view.delegateVerticalScrollbarMouseDown(browserEvent);
E
Erich Gamma 已提交
197 198
	}

J
Johannes Rieken 已提交
199
	public layout(dimension?: editorCommon.IDimension): void {
E
Erich Gamma 已提交
200
		this._configuration.observeReferenceElement(dimension);
201
		this.render();
E
Erich Gamma 已提交
202 203 204 205 206 207 208 209 210 211 212 213 214
	}

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

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

215
	public hasWidgetFocus(): boolean {
216
		return this._focusTracker && this._focusTracker.hasFocus();
217 218
	}

A
Alex Dima 已提交
219
	public addContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
220
		let widgetData: IContentWidgetData = {
E
Erich Gamma 已提交
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
			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 已提交
236
	public layoutContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
237
		let widgetId = widget.getId();
E
Erich Gamma 已提交
238
		if (this.contentWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
239
			let widgetData = this.contentWidgets[widgetId];
E
Erich Gamma 已提交
240 241 242 243 244 245 246
			widgetData.position = widget.getPosition();
			if (this.hasView) {
				this._view.layoutContentWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
247
	public removeContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
248
		let widgetId = widget.getId();
E
Erich Gamma 已提交
249
		if (this.contentWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
250
			let widgetData = this.contentWidgets[widgetId];
E
Erich Gamma 已提交
251 252 253 254 255 256 257
			delete this.contentWidgets[widgetId];
			if (this.hasView) {
				this._view.removeContentWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
258
	public addOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
259
		let widgetData: IOverlayWidgetData = {
E
Erich Gamma 已提交
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
			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 已提交
275
	public layoutOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
276
		let widgetId = widget.getId();
E
Erich Gamma 已提交
277
		if (this.overlayWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
278
			let widgetData = this.overlayWidgets[widgetId];
E
Erich Gamma 已提交
279 280 281 282 283 284 285
			widgetData.position = widget.getPosition();
			if (this.hasView) {
				this._view.layoutOverlayWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
286
	public removeOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
287
		let widgetId = widget.getId();
E
Erich Gamma 已提交
288
		if (this.overlayWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
289
			let widgetData = this.overlayWidgets[widgetId];
E
Erich Gamma 已提交
290 291 292 293 294 295 296
			delete this.overlayWidgets[widgetId];
			if (this.hasView) {
				this._view.removeOverlayWidget(widgetData);
			}
		}
	}

J
Johannes Rieken 已提交
297
	public changeViewZones(callback: (accessor: editorBrowser.IViewZoneChangeAccessor) => void): void {
E
Erich Gamma 已提交
298 299 300
		if (!this.hasView) {
			return;
		}
A
Alex Dima 已提交
301
		let hasChanges = this._view.change(callback);
E
Erich Gamma 已提交
302
		if (hasChanges) {
A
Alex Dima 已提交
303
			this._onDidChangeViewZones.fire();
E
Erich Gamma 已提交
304 305 306
		}
	}

A
Alex Dima 已提交
307
	public getWhitespaces(): IEditorWhitespace[] {
E
Erich Gamma 已提交
308 309 310
		if (!this.hasView) {
			return [];
		}
311
		return this.viewModel.viewLayout.getWhitespaces();
E
Erich Gamma 已提交
312 313
	}

314 315 316 317 318 319
	private _getVerticalOffsetForPosition(modelLineNumber: number, modelColumn: number): number {
		let modelPosition = this.model.validatePosition({
			lineNumber: modelLineNumber,
			column: modelColumn
		});
		let viewPosition = this.viewModel.coordinatesConverter.convertModelPositionToViewPosition(modelPosition);
320
		return this.viewModel.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber);
321 322
	}

E
Erich Gamma 已提交
323 324 325 326
	public getTopForLineNumber(lineNumber: number): number {
		if (!this.hasView) {
			return -1;
		}
327
		return this._getVerticalOffsetForPosition(lineNumber, 1);
E
Erich Gamma 已提交
328 329 330 331 332 333
	}

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

337 338 339 340
	public getTargetAtClientPoint(clientX: number, clientY: number): editorBrowser.IMouseTarget {
		if (!this.hasView) {
			return null;
		}
A
Alex Dima 已提交
341
		return this._view.getTargetAtClientPoint(clientX, clientY);
342 343
	}

A
Alex Dima 已提交
344
	public getScrolledVisiblePosition(rawPosition: IPosition): { top: number; left: number; height: number; } {
E
Erich Gamma 已提交
345 346 347 348
		if (!this.hasView) {
			return null;
		}

A
Alex Dima 已提交
349 350
		let position = this.model.validatePosition(rawPosition);
		let layoutInfo = this._configuration.editor.layoutInfo;
E
Erich Gamma 已提交
351

352 353
		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 已提交
354 355 356 357 358 359 360 361

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

J
Johannes Rieken 已提交
362
	public getOffsetForColumn(lineNumber: number, column: number): number {
E
Erich Gamma 已提交
363 364 365
		if (!this.hasView) {
			return -1;
		}
A
Alex Dima 已提交
366
		return this._view.getOffsetForColumn(lineNumber, column);
E
Erich Gamma 已提交
367 368
	}

369 370 371 372
	public render(): void {
		if (!this.hasView) {
			return;
		}
373
		this._view.render(true, false);
374 375
	}

A
Alex Dima 已提交
376
	public setHiddenAreas(ranges: IRange[]): void {
M
Martin Aeschlimann 已提交
377
		if (this.viewModel) {
A
Alex Dima 已提交
378
			this.viewModel.setHiddenAreas(ranges.map(r => Range.lift(r)));
M
Martin Aeschlimann 已提交
379 380 381
		}
	}

J
Johannes Rieken 已提交
382
	public setAriaActiveDescendant(id: string): void {
A
Alex Dima 已提交
383 384 385 386 387 388
		if (!this.hasView) {
			return;
		}
		this._view.setAriaActiveDescendant(id);
	}

J
Johannes Rieken 已提交
389
	public applyFontInfo(target: HTMLElement): void {
390 391 392
		Configuration.applyFontInfoSlow(target, this._configuration.editor.fontInfo);
	}

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

396
		super._attachModel(model);
E
Erich Gamma 已提交
397

398
		if (this._view) {
A
Alex Dima 已提交
399
			this.domElement.appendChild(this._view.domNode.domNode);
E
Erich Gamma 已提交
400

A
Alex Dima 已提交
401 402 403 404 405
			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 已提交
406

A
Alex Dima 已提交
407 408 409 410 411
			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 已提交
412

A
Alex Dima 已提交
413 414
			this._view.render(false, true);
			this.hasView = true;
E
Erich Gamma 已提交
415 416 417
		}
	}

418 419
	protected _createView(): void {
		this._view = new View(
420
			this._commandService,
421
			this._configuration,
422
			this._themeService,
423
			this.viewModel,
424
			this.cursor,
425
			(editorCommand: CoreEditorCommand, args: any) => {
A
Alex Dima 已提交
426 427 428
				if (!this.cursor) {
					return;
				}
429
				editorCommand.runCoreEditorCommand(this.cursor, args);
A
Alex Dima 已提交
430
			}
431
		);
E
Erich Gamma 已提交
432

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

A
Alex Dima 已提交
435 436 437 438 439
		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 已提交
440

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

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

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

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

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

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

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

A
Alex Dima 已提交
469 470 471
		this.listenersToRemove.push(viewEventBus.onKeyUp((e) => {
			this._onKeyUp.fire(e);
		}));
A
Alex Dima 已提交
472

A
Alex Dima 已提交
473 474 475
		this.listenersToRemove.push(viewEventBus.onMouseMove((e) => {
			this._onMouseMove.fire(e);
		}));
A
Alex Dima 已提交
476

A
Alex Dima 已提交
477 478 479
		this.listenersToRemove.push(viewEventBus.onMouseLeave((e) => {
			this._onMouseLeave.fire(e);
		}));
A
Alex Dima 已提交
480

A
Alex Dima 已提交
481 482
		this.listenersToRemove.push(viewEventBus.onKeyDown((e) => {
			this._onKeyDown.fire(e);
A
Alex Dima 已提交
483
		}));
484
	}
E
Erich Gamma 已提交
485

A
Alex Dima 已提交
486
	protected _detachModel(): editorCommon.IModel {
A
Alex Dima 已提交
487
		let removeDomNode: HTMLElement = null;
E
Erich Gamma 已提交
488 489 490

		if (this._view) {
			this._view.dispose();
A
Alex Dima 已提交
491
			removeDomNode = this._view.domNode.domNode;
E
Erich Gamma 已提交
492 493 494
			this._view = null;
		}

495
		let result = super._detachModel();
E
Erich Gamma 已提交
496 497 498 499 500 501 502

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

		return result;
	}
503 504 505

	// BEGIN decorations

J
Johannes Rieken 已提交
506
	protected _registerDecorationType(key: string, options: editorCommon.IDecorationRenderOptions, parentTypeKey?: string): void {
507 508 509
		this._codeEditorService.registerDecorationType(key, options, parentTypeKey);
	}

J
Johannes Rieken 已提交
510
	protected _removeDecorationType(key: string): void {
511 512 513
		this._codeEditorService.removeDecorationType(key);
	}

J
Johannes Rieken 已提交
514
	protected _resolveDecorationOptions(typeKey: string, writable: boolean): editorCommon.IModelDecorationOptions {
515 516 517 518
		return this._codeEditorService.resolveDecorationOptions(typeKey, writable);
	}

	// END decorations
E
Erich Gamma 已提交
519 520
}

521 522
class CodeEditorWidgetFocusTracker extends Disposable {

523 524
	private _hasFocus: boolean;
	private _domFocusTracker: dom.IFocusTracker;
525 526

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

J
Johannes Rieken 已提交
529
	constructor(domElement: HTMLElement) {
530 531
		super();

532 533
		this._hasFocus = false;
		this._domFocusTracker = this._register(dom.trackFocus(domElement));
534

535 536 537
		this._domFocusTracker.addFocusListener(() => {
			this._hasFocus = true;
			this._onChange.fire(void 0);
538
		});
539 540 541
		this._domFocusTracker.addBlurListener(() => {
			this._hasFocus = false;
			this._onChange.fire(void 0);
542 543 544 545
		});
	}

	public hasFocus(): boolean {
546
		return this._hasFocus;
547 548
	}
}
549

550 551
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>`);
552

553 554 555
function getSquigglySVGData(color: Color) {
	return squigglyStart + encodeURIComponent(color.toString()) + squigglyEnd;
}
556

557 558 559 560 561 562 563 564
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; }`);
565 566
	}

567 568 569 570 571 572 573
	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; }`);
574 575
	}
});