codeEditorWidget.ts 23.1 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  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';
8
import 'vs/editor/common/view/editorColorRegistry'; // initialze editor theming partcicpants
E
Erich Gamma 已提交
9
import 'vs/css!./media/tokens';
J
Johannes Rieken 已提交
10
import { onUnexpectedError } from 'vs/base/common/errors';
11
import { TPromise } from 'vs/base/common/winjs.base';
A
Alex Dima 已提交
12 13
import * as browser from 'vs/base/browser/browser';
import * as dom from 'vs/base/browser/dom';
J
Johannes Rieken 已提交
14 15 16 17 18 19 20
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';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
A
Alex Dima 已提交
21
import * as editorCommon from 'vs/editor/common/editorCommon';
J
Johannes Rieken 已提交
22 23 24
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 已提交
25
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
J
Johannes Rieken 已提交
26 27
import { Colorizer } from 'vs/editor/browser/standalone/colorizer';
import { View } from 'vs/editor/browser/view/viewImpl';
J
Johannes Rieken 已提交
28
import { Disposable } from 'vs/base/common/lifecycle';
A
Alex Dima 已提交
29
import Event, { Emitter } from 'vs/base/common/event';
J
Johannes Rieken 已提交
30 31
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { InternalEditorAction } from 'vs/editor/common/editorAction';
E
Erich Gamma 已提交
32

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

A
Alex Dima 已提交
35 36 37 38 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
	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 已提交
67

68
	private _codeEditorService: ICodeEditorService;
69
	private _commandService: ICommandService;
70

J
Johannes Rieken 已提交
71
	protected domElement: HTMLElement;
72
	private _focusTracker: CodeEditorWidgetFocusTracker;
E
Erich Gamma 已提交
73

J
Johannes Rieken 已提交
74
	_configuration: Configuration;
75

J
Johannes Rieken 已提交
76 77
	private contentWidgets: { [key: string]: editorBrowser.IContentWidgetData; };
	private overlayWidgets: { [key: string]: editorBrowser.IOverlayWidgetData; };
E
Erich Gamma 已提交
78

J
Johannes Rieken 已提交
79
	_view: editorBrowser.IView;
E
Erich Gamma 已提交
80 81

	constructor(
J
Johannes Rieken 已提交
82 83
		domElement: HTMLElement,
		options: editorCommon.IEditorOptions,
E
Erich Gamma 已提交
84 85
		@IInstantiationService instantiationService: IInstantiationService,
		@ICodeEditorService codeEditorService: ICodeEditorService,
86
		@ICommandService commandService: ICommandService,
87
		@IContextKeyService contextKeyService: IContextKeyService
E
Erich Gamma 已提交
88
	) {
89
		super(domElement, options, instantiationService, contextKeyService);
90
		this._codeEditorService = codeEditorService;
91
		this._commandService = commandService;
E
Erich Gamma 已提交
92

93 94 95
		this._focusTracker = new CodeEditorWidgetFocusTracker(domElement);
		this._focusTracker.onChage(() => {
			let hasFocus = this._focusTracker.hasFocus();
96

97
			if (hasFocus) {
A
Alex Dima 已提交
98
				this._onDidFocusEditor.fire();
99
			} else {
A
Alex Dima 已提交
100
				this._onDidBlurEditor.fire();
E
Erich Gamma 已提交
101 102 103 104 105 106
			}
		});

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

107 108 109
		let contributions = this._getContributions();
		for (let i = 0, len = contributions.length; i < len; i++) {
			let ctor = contributions[i];
E
Erich Gamma 已提交
110
			try {
111
				let contribution = this._instantiationService.createInstance(ctor, this);
A
Alex Dima 已提交
112
				this._contributions[contribution.getId()] = contribution;
E
Erich Gamma 已提交
113
			} catch (err) {
114
				onUnexpectedError(err);
E
Erich Gamma 已提交
115 116
			}
		}
117

118
		this._getActions().forEach((action) => {
119 120 121 122 123 124 125 126 127 128 129 130
			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 已提交
131
			this._actions[internalAction.id] = internalAction;
132
		});
133 134

		this._codeEditorService.addCodeEditor(this);
E
Erich Gamma 已提交
135 136
	}

137
	protected abstract _getContributions(): editorBrowser.IEditorContributionCtor[];
138 139
	protected abstract _getActions(): EditorAction[];

J
Johannes Rieken 已提交
140
	protected _createConfiguration(options: editorCommon.ICodeEditorWidgetCreationOptions): CommonEditorConfiguration {
141
		return new Configuration(options, this.domElement);
E
Erich Gamma 已提交
142 143 144
	}

	public dispose(): void {
145 146
		this._codeEditorService.removeCodeEditor(this);

E
Erich Gamma 已提交
147 148 149
		this.contentWidgets = {};
		this.overlayWidgets = {};

150
		this._focusTracker.dispose();
E
Erich Gamma 已提交
151 152 153
		super.dispose();
	}

J
Johannes Rieken 已提交
154
	public updateOptions(newOptions: editorCommon.IEditorOptions): void {
155
		let oldTheme = this._configuration.editor.viewInfo.theme;
156
		super.updateOptions(newOptions);
157
		let newTheme = this._configuration.editor.viewInfo.theme;
158 159 160 161 162 163

		if (oldTheme !== newTheme) {
			this.render();
		}
	}

J
Johannes Rieken 已提交
164
	public colorizeModelLine(lineNumber: number, model: editorCommon.IModel = this.model): string {
E
Erich Gamma 已提交
165 166 167
		if (!model) {
			return '';
		}
A
Alex Dima 已提交
168
		let content = model.getLineContent(lineNumber);
A
Alex Dima 已提交
169 170
		model.forceTokenization(lineNumber);
		let tokens = model.getLineTokens(lineNumber);
A
Alex Dima 已提交
171 172
		let inflatedTokens = tokens.inflate();
		let tabSize = model.getOptions().tabSize;
173
		return Colorizer.colorizeLine(content, model.mightContainRTL(), inflatedTokens, tabSize);
E
Erich Gamma 已提交
174
	}
A
Alex Dima 已提交
175
	public getView(): editorBrowser.IView {
E
Erich Gamma 已提交
176 177 178 179 180 181 182
		return this._view;
	}

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

186
	public getCenteredRangeInViewport(): Range {
E
Erich Gamma 已提交
187 188 189
		if (!this.hasView) {
			return null;
		}
A
Alex Dima 已提交
190
		return this.viewModel.getCenteredRangeInViewport();
E
Erich Gamma 已提交
191 192
	}

A
Alex Dima 已提交
193
	protected _getCompletelyVisibleViewRange(): Range {
194 195 196
		if (!this.hasView) {
			return null;
		}
A
Alex Dima 已提交
197 198 199 200 201 202
		return this._view.getCodeEditorHelper().getCompletelyVisibleViewRange();
	}

	public getCompletelyVisibleLinesRangeInViewport(): Range {
		const viewRange = this._getCompletelyVisibleViewRange();
		return this.viewModel.coordinatesConverter.convertViewRangeToModelRange(viewRange);
203 204
	}

205
	public getScrollWidth(): number {
E
Erich Gamma 已提交
206
		if (!this.hasView) {
207
			return -1;
E
Erich Gamma 已提交
208
		}
209 210 211 212 213
		return this._view.getCodeEditorHelper().getScrollWidth();
	}
	public getScrollLeft(): number {
		if (!this.hasView) {
			return -1;
E
Erich Gamma 已提交
214
		}
215
		return this._view.getCodeEditorHelper().getScrollLeft();
E
Erich Gamma 已提交
216 217
	}

218
	public getScrollHeight(): number {
E
Erich Gamma 已提交
219 220 221
		if (!this.hasView) {
			return -1;
		}
222
		return this._view.getCodeEditorHelper().getScrollHeight();
E
Erich Gamma 已提交
223
	}
224
	public getScrollTop(): number {
E
Erich Gamma 已提交
225
		if (!this.hasView) {
226
			return -1;
E
Erich Gamma 已提交
227
		}
228
		return this._view.getCodeEditorHelper().getScrollTop();
E
Erich Gamma 已提交
229 230
	}

J
Johannes Rieken 已提交
231
	public setScrollLeft(newScrollLeft: number): void {
E
Erich Gamma 已提交
232 233 234 235 236 237
		if (!this.hasView) {
			return;
		}
		if (typeof newScrollLeft !== 'number') {
			throw new Error('Invalid arguments');
		}
238 239 240
		this._view.getCodeEditorHelper().setScrollPosition({
			scrollLeft: newScrollLeft
		});
E
Erich Gamma 已提交
241
	}
J
Johannes Rieken 已提交
242
	public setScrollTop(newScrollTop: number): void {
E
Erich Gamma 已提交
243
		if (!this.hasView) {
244
			return;
E
Erich Gamma 已提交
245
		}
246 247 248 249 250 251
		if (typeof newScrollTop !== 'number') {
			throw new Error('Invalid arguments');
		}
		this._view.getCodeEditorHelper().setScrollPosition({
			scrollTop: newScrollTop
		});
E
Erich Gamma 已提交
252
	}
253
	public setScrollPosition(position: editorCommon.INewScrollPosition): void {
E
Erich Gamma 已提交
254
		if (!this.hasView) {
255
			return;
E
Erich Gamma 已提交
256
		}
257
		this._view.getCodeEditorHelper().setScrollPosition(position);
E
Erich Gamma 已提交
258 259
	}

J
Johannes Rieken 已提交
260
	public delegateVerticalScrollbarMouseDown(browserEvent: MouseEvent): void {
E
Erich Gamma 已提交
261
		if (!this.hasView) {
262
			return;
E
Erich Gamma 已提交
263
		}
264
		this._view.getCodeEditorHelper().delegateVerticalScrollbarMouseDown(browserEvent);
E
Erich Gamma 已提交
265 266
	}

A
Alex Dima 已提交
267
	public saveViewState(): editorCommon.ICodeEditorViewState {
E
Erich Gamma 已提交
268 269 270
		if (!this.cursor || !this.hasView) {
			return null;
		}
J
Johannes Rieken 已提交
271
		let contributionsState: { [key: string]: any } = {};
A
Alex Dima 已提交
272 273 274 275 276

		let keys = Object.keys(this._contributions);
		for (let i = 0, len = keys.length; i < len; i++) {
			let id = keys[i];
			let contribution = this._contributions[id];
277 278 279 280 281
			if (typeof contribution.saveViewState === 'function') {
				contributionsState[id] = contribution.saveViewState();
			}
		}

A
Alex Dima 已提交
282 283
		let cursorState = this.cursor.saveState();
		let viewState = this._view.saveState();
E
Erich Gamma 已提交
284 285
		return {
			cursorState: cursorState,
286 287
			viewState: viewState,
			contributionsState: contributionsState
E
Erich Gamma 已提交
288 289 290
		};
	}

A
Alex Dima 已提交
291
	public restoreViewState(s: editorCommon.ICodeEditorViewState): void {
E
Erich Gamma 已提交
292 293 294
		if (!this.cursor || !this.hasView) {
			return;
		}
B
Benjamin Pasero 已提交
295
		if (s && s.cursorState && s.viewState) {
A
Alex Dima 已提交
296 297
			let codeEditorState = <editorCommon.ICodeEditorViewState>s;
			let cursorState = <any>codeEditorState.cursorState;
B
Benjamin Pasero 已提交
298 299 300 301 302
			if (Array.isArray(cursorState)) {
				this.cursor.restoreState(<editorCommon.ICursorState[]>cursorState);
			} else {
				// Backwards compatibility
				this.cursor.restoreState([<editorCommon.ICursorState>cursorState]);
E
Erich Gamma 已提交
303
			}
B
Benjamin Pasero 已提交
304
			this._view.restoreState(codeEditorState.viewState);
305

B
Benjamin Pasero 已提交
306
			let contributionsState = s.contributionsState || {};
A
Alex Dima 已提交
307 308 309 310
			let keys = Object.keys(this._contributions);
			for (let i = 0, len = keys.length; i < len; i++) {
				let id = keys[i];
				let contribution = this._contributions[id];
311 312 313 314
				if (typeof contribution.restoreViewState === 'function') {
					contribution.restoreViewState(contributionsState[id]);
				}
			}
E
Erich Gamma 已提交
315 316 317
		}
	}

J
Johannes Rieken 已提交
318
	public layout(dimension?: editorCommon.IDimension): void {
E
Erich Gamma 已提交
319
		this._configuration.observeReferenceElement(dimension);
320
		this.render();
E
Erich Gamma 已提交
321 322 323 324 325 326 327 328 329 330 331 332 333
	}

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

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

334
	public hasWidgetFocus(): boolean {
335
		return this._focusTracker && this._focusTracker.hasFocus();
336 337
	}

A
Alex Dima 已提交
338
	public addContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
339
		let widgetData: editorBrowser.IContentWidgetData = {
E
Erich Gamma 已提交
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
			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 已提交
355
	public layoutContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
356
		let widgetId = widget.getId();
E
Erich Gamma 已提交
357
		if (this.contentWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
358
			let widgetData = this.contentWidgets[widgetId];
E
Erich Gamma 已提交
359 360 361 362 363 364 365
			widgetData.position = widget.getPosition();
			if (this.hasView) {
				this._view.layoutContentWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
366
	public removeContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
367
		let widgetId = widget.getId();
E
Erich Gamma 已提交
368
		if (this.contentWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
369
			let widgetData = this.contentWidgets[widgetId];
E
Erich Gamma 已提交
370 371 372 373 374 375 376
			delete this.contentWidgets[widgetId];
			if (this.hasView) {
				this._view.removeContentWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
377
	public addOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
378
		let widgetData: editorBrowser.IOverlayWidgetData = {
E
Erich Gamma 已提交
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
			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 已提交
394
	public layoutOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
395
		let widgetId = widget.getId();
E
Erich Gamma 已提交
396
		if (this.overlayWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
397
			let widgetData = this.overlayWidgets[widgetId];
E
Erich Gamma 已提交
398 399 400 401 402 403 404
			widgetData.position = widget.getPosition();
			if (this.hasView) {
				this._view.layoutOverlayWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
405
	public removeOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
406
		let widgetId = widget.getId();
E
Erich Gamma 已提交
407
		if (this.overlayWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
408
			let widgetData = this.overlayWidgets[widgetId];
E
Erich Gamma 已提交
409 410 411 412 413 414 415
			delete this.overlayWidgets[widgetId];
			if (this.hasView) {
				this._view.removeOverlayWidget(widgetData);
			}
		}
	}

J
Johannes Rieken 已提交
416
	public changeViewZones(callback: (accessor: editorBrowser.IViewZoneChangeAccessor) => void): void {
E
Erich Gamma 已提交
417 418 419
		if (!this.hasView) {
			return;
		}
A
Alex Dima 已提交
420
		let hasChanges = this._view.change(callback);
E
Erich Gamma 已提交
421
		if (hasChanges) {
A
Alex Dima 已提交
422
			this._onDidChangeViewZones.fire();
E
Erich Gamma 已提交
423 424 425
		}
	}

A
Alex Dima 已提交
426
	public getWhitespaces(): editorCommon.IEditorWhitespace[] {
E
Erich Gamma 已提交
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
		if (!this.hasView) {
			return [];
		}
		return this._view.getWhitespaces();
	}

	public getTopForLineNumber(lineNumber: number): number {
		if (!this.hasView) {
			return -1;
		}
		return this._view.getCodeEditorHelper().getVerticalOffsetForPosition(lineNumber, 1);
	}

	public getTopForPosition(lineNumber: number, column: number): number {
		if (!this.hasView) {
			return -1;
		}
		return this._view.getCodeEditorHelper().getVerticalOffsetForPosition(lineNumber, column);
	}

447 448 449 450 451 452 453
	public getTargetAtClientPoint(clientX: number, clientY: number): editorBrowser.IMouseTarget {
		if (!this.hasView) {
			return null;
		}
		return this._view.getCodeEditorHelper().getTargetAtClientPoint(clientX, clientY);
	}

J
Johannes Rieken 已提交
454
	public getScrolledVisiblePosition(rawPosition: editorCommon.IPosition): { top: number; left: number; height: number; } {
E
Erich Gamma 已提交
455 456 457 458
		if (!this.hasView) {
			return null;
		}

A
Alex Dima 已提交
459 460 461
		let position = this.model.validatePosition(rawPosition);
		let helper = this._view.getCodeEditorHelper();
		let layoutInfo = this._configuration.editor.layoutInfo;
E
Erich Gamma 已提交
462

A
Alex Dima 已提交
463 464
		let top = helper.getVerticalOffsetForPosition(position.lineNumber, position.column) - helper.getScrollTop();
		let left = helper.getOffsetForColumn(position.lineNumber, position.column) + layoutInfo.glyphMarginWidth + layoutInfo.lineNumbersWidth + layoutInfo.decorationsWidth - helper.getScrollLeft();
E
Erich Gamma 已提交
465 466 467 468 469 470 471 472

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

J
Johannes Rieken 已提交
473
	public getOffsetForColumn(lineNumber: number, column: number): number {
E
Erich Gamma 已提交
474 475 476 477 478 479
		if (!this.hasView) {
			return -1;
		}
		return this._view.getCodeEditorHelper().getOffsetForColumn(lineNumber, column);
	}

480 481 482 483
	public render(): void {
		if (!this.hasView) {
			return;
		}
484
		this._view.render(true, false);
485 486
	}

J
Johannes Rieken 已提交
487
	public setHiddenAreas(ranges: editorCommon.IRange[]): void {
M
Martin Aeschlimann 已提交
488 489 490 491 492
		if (this.viewModel) {
			this.viewModel.setHiddenAreas(ranges);
		}
	}

J
Johannes Rieken 已提交
493
	public setAriaActiveDescendant(id: string): void {
A
Alex Dima 已提交
494 495 496 497 498 499
		if (!this.hasView) {
			return;
		}
		this._view.setAriaActiveDescendant(id);
	}

J
Johannes Rieken 已提交
500
	public applyFontInfo(target: HTMLElement): void {
501 502 503
		Configuration.applyFontInfoSlow(target, this._configuration.editor.fontInfo);
	}

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

507
		super._attachModel(model);
E
Erich Gamma 已提交
508

509
		if (this._view) {
A
Alex Dima 已提交
510
			this.domElement.appendChild(this._view.domNode.domNode);
E
Erich Gamma 已提交
511

A
Alex Dima 已提交
512 513 514 515 516
			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 已提交
517

A
Alex Dima 已提交
518 519 520 521 522
			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 已提交
523

A
Alex Dima 已提交
524 525
			this._view.render(false, true);
			this.hasView = true;
E
Erich Gamma 已提交
526 527 528
		}
	}

529
	protected _enableEmptySelectionClipboard(): boolean {
A
Alex Dima 已提交
530
		return browser.enableEmptySelectionClipboard;
E
Erich Gamma 已提交
531 532
	}

533 534
	protected _createView(): void {
		this._view = new View(
535
			this._commandService,
536 537
			this._configuration,
			this.viewModel,
J
Johannes Rieken 已提交
538
			(source: string, handlerId: string, payload: any) => {
A
Alex Dima 已提交
539 540 541 542 543
				if (!this.cursor) {
					return;
				}
				this.cursor.trigger(source, handlerId, payload);
			}
544
		);
E
Erich Gamma 已提交
545

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

A
Alex Dima 已提交
548 549 550 551 552
		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 已提交
553

A
Alex Dima 已提交
554 555 556
		this.listenersToRemove.push(viewEventBus.onDidScroll((e) => {
			this._onDidScrollChange.fire(e);
		}));
A
Alex Dima 已提交
557

A
Alex Dima 已提交
558 559 560
		this.listenersToRemove.push(viewEventBus.onDidLoseFocus(() => {
			this._onDidBlurEditorText.fire();
		}));
A
Alex Dima 已提交
561

A
Alex Dima 已提交
562 563 564
		this.listenersToRemove.push(viewEventBus.onContextMenu((e) => {
			this._onContextMenu.fire(e);
		}));
A
Alex Dima 已提交
565

A
Alex Dima 已提交
566 567 568
		this.listenersToRemove.push(viewEventBus.onMouseDown((e) => {
			this._onMouseDown.fire(e);
		}));
A
Alex Dima 已提交
569

A
Alex Dima 已提交
570 571 572
		this.listenersToRemove.push(viewEventBus.onMouseUp((e) => {
			this._onMouseUp.fire(e);
		}));
A
Alex Dima 已提交
573

A
Alex Dima 已提交
574 575 576
		this.listenersToRemove.push(viewEventBus.onMouseDrag((e) => {
			this._onMouseDrag.fire(e);
		}));
A
Alex Dima 已提交
577

A
Alex Dima 已提交
578 579 580
		this.listenersToRemove.push(viewEventBus.onMouseDrop((e) => {
			this._onMouseDrop.fire(e);
		}));
A
Alex Dima 已提交
581

A
Alex Dima 已提交
582 583 584
		this.listenersToRemove.push(viewEventBus.onKeyUp((e) => {
			this._onKeyUp.fire(e);
		}));
A
Alex Dima 已提交
585

A
Alex Dima 已提交
586 587 588
		this.listenersToRemove.push(viewEventBus.onMouseMove((e) => {
			this._onMouseMove.fire(e);
		}));
A
Alex Dima 已提交
589

A
Alex Dima 已提交
590 591 592
		this.listenersToRemove.push(viewEventBus.onMouseLeave((e) => {
			this._onMouseLeave.fire(e);
		}));
A
Alex Dima 已提交
593

A
Alex Dima 已提交
594 595
		this.listenersToRemove.push(viewEventBus.onKeyDown((e) => {
			this._onKeyDown.fire(e);
A
Alex Dima 已提交
596
		}));
597
	}
E
Erich Gamma 已提交
598

A
Alex Dima 已提交
599
	protected _detachModel(): editorCommon.IModel {
A
Alex Dima 已提交
600
		let removeDomNode: HTMLElement = null;
E
Erich Gamma 已提交
601 602 603

		if (this._view) {
			this._view.dispose();
A
Alex Dima 已提交
604
			removeDomNode = this._view.domNode.domNode;
E
Erich Gamma 已提交
605 606 607
			this._view = null;
		}

608
		let result = super._detachModel();
E
Erich Gamma 已提交
609 610 611 612 613 614 615

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

		return result;
	}
616 617 618

	// BEGIN decorations

J
Johannes Rieken 已提交
619
	protected _registerDecorationType(key: string, options: editorCommon.IDecorationRenderOptions, parentTypeKey?: string): void {
620 621 622
		this._codeEditorService.registerDecorationType(key, options, parentTypeKey);
	}

J
Johannes Rieken 已提交
623
	protected _removeDecorationType(key: string): void {
624 625 626
		this._codeEditorService.removeDecorationType(key);
	}

J
Johannes Rieken 已提交
627
	protected _resolveDecorationOptions(typeKey: string, writable: boolean): editorCommon.IModelDecorationOptions {
628 629 630 631
		return this._codeEditorService.resolveDecorationOptions(typeKey, writable);
	}

	// END decorations
E
Erich Gamma 已提交
632 633
}

634 635
class CodeEditorWidgetFocusTracker extends Disposable {

636 637
	private _hasFocus: boolean;
	private _domFocusTracker: dom.IFocusTracker;
638 639 640 641

	private _onChange: Emitter<void> = this._register(new Emitter<void>());
	public onChage: Event<void> = this._onChange.event;

J
Johannes Rieken 已提交
642
	constructor(domElement: HTMLElement) {
643 644
		super();

645 646
		this._hasFocus = false;
		this._domFocusTracker = this._register(dom.trackFocus(domElement));
647

648 649 650
		this._domFocusTracker.addFocusListener(() => {
			this._hasFocus = true;
			this._onChange.fire(void 0);
651
		});
652 653 654
		this._domFocusTracker.addBlurListener(() => {
			this._hasFocus = false;
			this._onChange.fire(void 0);
655 656 657 658
		});
	}

	public hasFocus(): boolean {
659
		return this._hasFocus;
660 661 662
	}
}

A
Alex Dima 已提交
663
class OverlayWidget2 implements editorBrowser.IOverlayWidget {
E
Erich Gamma 已提交
664 665

	private _id: string;
A
Alex Dima 已提交
666
	private _position: editorBrowser.IOverlayWidgetPosition;
E
Erich Gamma 已提交
667 668
	private _domNode: HTMLElement;

J
Johannes Rieken 已提交
669
	constructor(id: string, position: editorBrowser.IOverlayWidgetPosition) {
E
Erich Gamma 已提交
670 671 672
		this._id = id;
		this._position = position;
		this._domNode = document.createElement('div');
J
Johannes Rieken 已提交
673
		this._domNode.className = this._id.replace(/\./g, '-').replace(/[^a-z0-9\-]/, '');
E
Erich Gamma 已提交
674 675 676 677 678 679 680 681 682 683
	}

	public getId(): string {
		return this._id;
	}

	public getDomNode(): HTMLElement {
		return this._domNode;
	}

A
Alex Dima 已提交
684
	public getPosition(): editorBrowser.IOverlayWidgetPosition {
E
Erich Gamma 已提交
685 686 687 688 689 690 691 692
		return this._position;
	}
}

export enum EditCursorState {
	EndOfLastEditOperation = 0
}

A
Alex Dima 已提交
693 694
class SingleEditOperation {

695
	range: Range;
A
Alex Dima 已提交
696 697 698
	text: string;
	forceMoveMarkers: boolean;

J
Johannes Rieken 已提交
699
	constructor(source: editorCommon.ISingleEditOperation) {
A
Alex Dima 已提交
700 701 702 703 704 705 706
		this.range = new Range(source.range.startLineNumber, source.range.startColumn, source.range.endLineNumber, source.range.endColumn);
		this.text = source.text;
		this.forceMoveMarkers = source.forceMoveMarkers || false;
	}

}

A
Alex Dima 已提交
707
export class CommandRunner implements editorCommon.ICommand {
E
Erich Gamma 已提交
708

A
Alex Dima 已提交
709
	private _ops: SingleEditOperation[];
E
Erich Gamma 已提交
710 711
	private _editCursorState: EditCursorState;

A
Alex Dima 已提交
712
	constructor(ops: editorCommon.ISingleEditOperation[], editCursorState: EditCursorState) {
A
Alex Dima 已提交
713
		this._ops = ops.map(op => new SingleEditOperation(op));
E
Erich Gamma 已提交
714 715 716
		this._editCursorState = editCursorState;
	}

A
Alex Dima 已提交
717
	public getEditOperations(model: editorCommon.ITokenizedModel, builder: editorCommon.IEditOperationBuilder): void {
E
Erich Gamma 已提交
718 719 720 721 722 723 724 725 726 727
		if (this._ops.length === 0) {
			return;
		}

		// Sort them in ascending order by range starts
		this._ops.sort((o1, o2) => {
			return Range.compareRangesUsingStarts(o1.range, o2.range);
		});

		// Merge operations that touch each other
A
Alex Dima 已提交
728 729 730
		let resultOps: editorCommon.ISingleEditOperation[] = [];
		let previousOp = this._ops[0];
		for (let i = 1; i < this._ops.length; i++) {
E
Erich Gamma 已提交
731 732 733 734 735 736 737 738 739 740 741
			if (previousOp.range.endLineNumber === this._ops[i].range.startLineNumber && previousOp.range.endColumn === this._ops[i].range.startColumn) {
				// These operations are one after another and can be merged
				previousOp.range = Range.plusRange(previousOp.range, this._ops[i].range);
				previousOp.text = previousOp.text + this._ops[i].text;
			} else {
				resultOps.push(previousOp);
				previousOp = this._ops[i];
			}
		}
		resultOps.push(previousOp);

A
Alex Dima 已提交
742
		for (let i = 0; i < resultOps.length; i++) {
E
Erich Gamma 已提交
743 744 745 746
			builder.addEditOperation(Range.lift(resultOps[i].range), resultOps[i].text);
		}
	}

747
	public computeCursorState(model: editorCommon.ITokenizedModel, helper: editorCommon.ICursorStateComputerData): Selection {
A
Alex Dima 已提交
748 749
		let inverseEditOperations = helper.getInverseEditOperations();
		let srcRange = inverseEditOperations[inverseEditOperations.length - 1].range;
A
Alex Dima 已提交
750
		return new Selection(
E
Erich Gamma 已提交
751 752 753 754 755 756 757
			srcRange.endLineNumber,
			srcRange.endColumn,
			srcRange.endLineNumber,
			srcRange.endColumn
		);
	}
}