codeEditorWidget.ts 23.3 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
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 已提交
19
import { Range, IRange } from 'vs/editor/common/core/range';
J
Johannes Rieken 已提交
20
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';
32
import { IEditorOptions } from "vs/editor/common/config/editorOptions";
A
Alex Dima 已提交
33
import { IPosition } from "vs/editor/common/core/position";
E
Erich Gamma 已提交
34

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

A
Alex Dima 已提交
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 67 68
	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 已提交
69

70
	private _codeEditorService: ICodeEditorService;
71
	private _commandService: ICommandService;
72

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

J
Johannes Rieken 已提交
76
	_configuration: Configuration;
77

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

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

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

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

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

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

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

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

		this._codeEditorService.addCodeEditor(this);
E
Erich Gamma 已提交
137 138
	}

139
	protected abstract _getContributions(): editorBrowser.IEditorContributionCtor[];
140 141
	protected abstract _getActions(): EditorAction[];

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

	public dispose(): void {
147 148
		this._codeEditorService.removeCodeEditor(this);

E
Erich Gamma 已提交
149 150 151
		this.contentWidgets = {};
		this.overlayWidgets = {};

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

156
	public updateOptions(newOptions: IEditorOptions): void {
157
		let oldTheme = this._configuration.editor.viewInfo.theme;
158
		super.updateOptions(newOptions);
159
		let newTheme = this._configuration.editor.viewInfo.theme;
160 161 162 163 164 165

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

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

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

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

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

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

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

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

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

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

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

		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];
279 280 281 282 283
			if (typeof contribution.saveViewState === 'function') {
				contributionsState[id] = contribution.saveViewState();
			}
		}

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

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

B
Benjamin Pasero 已提交
308
			let contributionsState = s.contributionsState || {};
A
Alex Dima 已提交
309 310 311 312
			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];
313 314 315 316
				if (typeof contribution.restoreViewState === 'function') {
					contribution.restoreViewState(contributionsState[id]);
				}
			}
E
Erich Gamma 已提交
317 318 319
		}
	}

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

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

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

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

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

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

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

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

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

A
Alex Dima 已提交
428
	public getWhitespaces(): editorCommon.IEditorWhitespace[] {
E
Erich Gamma 已提交
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
		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);
	}

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

A
Alex Dima 已提交
456
	public getScrolledVisiblePosition(rawPosition: IPosition): { top: number; left: number; height: number; } {
E
Erich Gamma 已提交
457 458 459 460
		if (!this.hasView) {
			return null;
		}

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

A
Alex Dima 已提交
465 466
		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 已提交
467 468 469 470 471 472 473 474

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

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

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

A
Alex Dima 已提交
489
	public setHiddenAreas(ranges: IRange[]): void {
M
Martin Aeschlimann 已提交
490
		if (this.viewModel) {
A
Alex Dima 已提交
491
			this.viewModel.setHiddenAreas(ranges.map(r => Range.lift(r)));
M
Martin Aeschlimann 已提交
492 493 494
		}
	}

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

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

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

509
		super._attachModel(model);
E
Erich Gamma 已提交
510

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		return result;
	}
618 619 620

	// BEGIN decorations

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

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

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

	// END decorations
E
Erich Gamma 已提交
634 635
}

636 637
class CodeEditorWidgetFocusTracker extends Disposable {

638 639
	private _hasFocus: boolean;
	private _domFocusTracker: dom.IFocusTracker;
640 641 642 643

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

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

647 648
		this._hasFocus = false;
		this._domFocusTracker = this._register(dom.trackFocus(domElement));
649

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

	public hasFocus(): boolean {
661
		return this._hasFocus;
662 663 664
	}
}

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

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

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

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

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

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

export enum EditCursorState {
	EndOfLastEditOperation = 0
}

A
Alex Dima 已提交
695 696
class SingleEditOperation {

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

J
Johannes Rieken 已提交
701
	constructor(source: editorCommon.ISingleEditOperation) {
A
Alex Dima 已提交
702 703 704 705 706 707 708
		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 已提交
709
export class CommandRunner implements editorCommon.ICommand {
E
Erich Gamma 已提交
710

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

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

A
Alex Dima 已提交
719
	public getEditOperations(model: editorCommon.ITokenizedModel, builder: editorCommon.IEditOperationBuilder): void {
E
Erich Gamma 已提交
720 721 722 723 724 725 726 727 728 729
		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 已提交
730 731 732
		let resultOps: editorCommon.ISingleEditOperation[] = [];
		let previousOp = this._ops[0];
		for (let i = 1; i < this._ops.length; i++) {
E
Erich Gamma 已提交
733 734 735 736 737 738 739 740 741 742 743
			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 已提交
744
		for (let i = 0; i < resultOps.length; i++) {
E
Erich Gamma 已提交
745 746 747 748
			builder.addEditOperation(Range.lift(resultOps[i].range), resultOps[i].text);
		}
	}

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