codeEditorWidget.ts 20.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';
J
Johannes Rieken 已提交
11
import { IEventEmitter } from 'vs/base/common/eventEmitter';
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 29
import { Disposable } from 'vs/base/common/lifecycle';
import Event, { Emitter, fromEventEmitter } 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

J
Johannes Rieken 已提交
35 36
	public readonly onMouseUp: Event<editorBrowser.IEditorMouseEvent> = fromEventEmitter(this, editorCommon.EventType.MouseUp);
	public readonly onMouseDown: Event<editorBrowser.IEditorMouseEvent> = fromEventEmitter(this, editorCommon.EventType.MouseDown);
37
	public readonly onMouseDrag: Event<editorBrowser.IEditorMouseEvent> = fromEventEmitter(this, editorCommon.EventType.MouseDrag);
38
	public readonly onMouseDrop: Event<editorBrowser.IEditorMouseEvent> = fromEventEmitter(this, editorCommon.EventType.MouseDrop);
J
Johannes Rieken 已提交
39 40 41 42 43 44 45
	public readonly onContextMenu: Event<editorBrowser.IEditorMouseEvent> = fromEventEmitter(this, editorCommon.EventType.ContextMenu);
	public readonly onMouseMove: Event<editorBrowser.IEditorMouseEvent> = fromEventEmitter(this, editorCommon.EventType.MouseMove);
	public readonly onMouseLeave: Event<editorBrowser.IEditorMouseEvent> = fromEventEmitter(this, editorCommon.EventType.MouseLeave);
	public readonly onKeyUp: Event<IKeyboardEvent> = fromEventEmitter(this, editorCommon.EventType.KeyUp);
	public readonly onKeyDown: Event<IKeyboardEvent> = fromEventEmitter(this, editorCommon.EventType.KeyDown);
	public readonly onDidLayoutChange: Event<editorCommon.EditorLayoutInfo> = fromEventEmitter(this, editorCommon.EventType.EditorLayout);
	public readonly onDidScrollChange: Event<editorCommon.IScrollEvent> = fromEventEmitter(this, 'scroll');
A
Alex Dima 已提交
46

47
	private _codeEditorService: ICodeEditorService;
48
	private _commandService: ICommandService;
49

J
Johannes Rieken 已提交
50
	protected domElement: HTMLElement;
51
	private _focusTracker: CodeEditorWidgetFocusTracker;
E
Erich Gamma 已提交
52

J
Johannes Rieken 已提交
53
	_configuration: Configuration;
54

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

J
Johannes Rieken 已提交
58
	_view: editorBrowser.IView;
E
Erich Gamma 已提交
59 60

	constructor(
J
Johannes Rieken 已提交
61 62
		domElement: HTMLElement,
		options: editorCommon.IEditorOptions,
E
Erich Gamma 已提交
63 64
		@IInstantiationService instantiationService: IInstantiationService,
		@ICodeEditorService codeEditorService: ICodeEditorService,
65
		@ICommandService commandService: ICommandService,
66
		@IContextKeyService contextKeyService: IContextKeyService
E
Erich Gamma 已提交
67
	) {
68
		super(domElement, options, instantiationService, contextKeyService);
69
		this._codeEditorService = codeEditorService;
70
		this._commandService = commandService;
E
Erich Gamma 已提交
71

72 73 74
		this._focusTracker = new CodeEditorWidgetFocusTracker(domElement);
		this._focusTracker.onChage(() => {
			let hasFocus = this._focusTracker.hasFocus();
75

76
			if (hasFocus) {
A
Alex Dima 已提交
77
				this.emit(editorCommon.EventType.EditorFocus, {});
78
			} else {
A
Alex Dima 已提交
79
				this.emit(editorCommon.EventType.EditorBlur, {});
E
Erich Gamma 已提交
80 81 82 83 84 85
			}
		});

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

86 87 88
		let contributions = this._getContributions();
		for (let i = 0, len = contributions.length; i < len; i++) {
			let ctor = contributions[i];
E
Erich Gamma 已提交
89
			try {
90
				let contribution = this._instantiationService.createInstance(ctor, this);
A
Alex Dima 已提交
91
				this._contributions[contribution.getId()] = contribution;
E
Erich Gamma 已提交
92
			} catch (err) {
93
				onUnexpectedError(err);
E
Erich Gamma 已提交
94 95
			}
		}
96

97
		this._getActions().forEach((action) => {
98 99 100 101 102 103 104 105 106 107 108 109
			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 已提交
110
			this._actions[internalAction.id] = internalAction;
111
		});
112 113

		this._codeEditorService.addCodeEditor(this);
E
Erich Gamma 已提交
114 115
	}

116
	protected abstract _getContributions(): editorBrowser.IEditorContributionCtor[];
117 118
	protected abstract _getActions(): EditorAction[];

J
Johannes Rieken 已提交
119
	protected _createConfiguration(options: editorCommon.ICodeEditorWidgetCreationOptions): CommonEditorConfiguration {
120
		return new Configuration(options, this.domElement);
E
Erich Gamma 已提交
121 122 123
	}

	public dispose(): void {
124 125
		this._codeEditorService.removeCodeEditor(this);

E
Erich Gamma 已提交
126 127 128
		this.contentWidgets = {};
		this.overlayWidgets = {};

129
		this._focusTracker.dispose();
E
Erich Gamma 已提交
130 131 132
		super.dispose();
	}

J
Johannes Rieken 已提交
133
	public updateOptions(newOptions: editorCommon.IEditorOptions): void {
134
		let oldTheme = this._configuration.editor.viewInfo.theme;
135
		super.updateOptions(newOptions);
136
		let newTheme = this._configuration.editor.viewInfo.theme;
137 138 139 140 141 142

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

J
Johannes Rieken 已提交
143
	public colorizeModelLine(lineNumber: number, model: editorCommon.IModel = this.model): string {
E
Erich Gamma 已提交
144 145 146
		if (!model) {
			return '';
		}
A
Alex Dima 已提交
147 148 149 150
		let content = model.getLineContent(lineNumber);
		let tokens = model.getLineTokens(lineNumber, false);
		let inflatedTokens = tokens.inflate();
		let tabSize = model.getOptions().tabSize;
151
		return Colorizer.colorizeLine(content, model.mightContainRTL(), inflatedTokens, tabSize);
E
Erich Gamma 已提交
152
	}
A
Alex Dima 已提交
153
	public getView(): editorBrowser.IView {
E
Erich Gamma 已提交
154 155 156 157 158 159 160
		return this._view;
	}

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

164
	public getCenteredRangeInViewport(): Range {
E
Erich Gamma 已提交
165 166 167
		if (!this.hasView) {
			return null;
		}
A
Alex Dima 已提交
168
		return this.viewModel.getCenteredRangeInViewport();
E
Erich Gamma 已提交
169 170
	}

171
	public getCompletelyVisibleLinesRangeInViewport(): Range {
172 173 174
		if (!this.hasView) {
			return null;
		}
175
		return this._view.getCompletelyVisibleLinesRangeInViewport();
176 177
	}

178
	public getScrollWidth(): number {
E
Erich Gamma 已提交
179
		if (!this.hasView) {
180
			return -1;
E
Erich Gamma 已提交
181
		}
182 183 184 185 186
		return this._view.getCodeEditorHelper().getScrollWidth();
	}
	public getScrollLeft(): number {
		if (!this.hasView) {
			return -1;
E
Erich Gamma 已提交
187
		}
188
		return this._view.getCodeEditorHelper().getScrollLeft();
E
Erich Gamma 已提交
189 190
	}

191
	public getScrollHeight(): number {
E
Erich Gamma 已提交
192 193 194
		if (!this.hasView) {
			return -1;
		}
195
		return this._view.getCodeEditorHelper().getScrollHeight();
E
Erich Gamma 已提交
196
	}
197
	public getScrollTop(): number {
E
Erich Gamma 已提交
198
		if (!this.hasView) {
199
			return -1;
E
Erich Gamma 已提交
200
		}
201
		return this._view.getCodeEditorHelper().getScrollTop();
E
Erich Gamma 已提交
202 203
	}

J
Johannes Rieken 已提交
204
	public setScrollLeft(newScrollLeft: number): void {
E
Erich Gamma 已提交
205 206 207 208 209 210
		if (!this.hasView) {
			return;
		}
		if (typeof newScrollLeft !== 'number') {
			throw new Error('Invalid arguments');
		}
211 212 213
		this._view.getCodeEditorHelper().setScrollPosition({
			scrollLeft: newScrollLeft
		});
E
Erich Gamma 已提交
214
	}
J
Johannes Rieken 已提交
215
	public setScrollTop(newScrollTop: number): void {
E
Erich Gamma 已提交
216
		if (!this.hasView) {
217
			return;
E
Erich Gamma 已提交
218
		}
219 220 221 222 223 224
		if (typeof newScrollTop !== 'number') {
			throw new Error('Invalid arguments');
		}
		this._view.getCodeEditorHelper().setScrollPosition({
			scrollTop: newScrollTop
		});
E
Erich Gamma 已提交
225
	}
226
	public setScrollPosition(position: editorCommon.INewScrollPosition): void {
E
Erich Gamma 已提交
227
		if (!this.hasView) {
228
			return;
E
Erich Gamma 已提交
229
		}
230
		this._view.getCodeEditorHelper().setScrollPosition(position);
E
Erich Gamma 已提交
231 232
	}

J
Johannes Rieken 已提交
233
	public delegateVerticalScrollbarMouseDown(browserEvent: MouseEvent): void {
E
Erich Gamma 已提交
234
		if (!this.hasView) {
235
			return;
E
Erich Gamma 已提交
236
		}
237
		this._view.getCodeEditorHelper().delegateVerticalScrollbarMouseDown(browserEvent);
E
Erich Gamma 已提交
238 239
	}

A
Alex Dima 已提交
240
	public saveViewState(): editorCommon.ICodeEditorViewState {
E
Erich Gamma 已提交
241 242 243
		if (!this.cursor || !this.hasView) {
			return null;
		}
J
Johannes Rieken 已提交
244
		let contributionsState: { [key: string]: any } = {};
A
Alex Dima 已提交
245 246 247 248 249

		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];
250 251 252 253 254
			if (typeof contribution.saveViewState === 'function') {
				contributionsState[id] = contribution.saveViewState();
			}
		}

A
Alex Dima 已提交
255 256
		let cursorState = this.cursor.saveState();
		let viewState = this._view.saveState();
E
Erich Gamma 已提交
257 258
		return {
			cursorState: cursorState,
259 260
			viewState: viewState,
			contributionsState: contributionsState
E
Erich Gamma 已提交
261 262 263
		};
	}

A
Alex Dima 已提交
264
	public restoreViewState(s: editorCommon.ICodeEditorViewState): void {
E
Erich Gamma 已提交
265 266 267
		if (!this.cursor || !this.hasView) {
			return;
		}
B
Benjamin Pasero 已提交
268
		if (s && s.cursorState && s.viewState) {
A
Alex Dima 已提交
269 270
			let codeEditorState = <editorCommon.ICodeEditorViewState>s;
			let cursorState = <any>codeEditorState.cursorState;
B
Benjamin Pasero 已提交
271 272 273 274 275
			if (Array.isArray(cursorState)) {
				this.cursor.restoreState(<editorCommon.ICursorState[]>cursorState);
			} else {
				// Backwards compatibility
				this.cursor.restoreState([<editorCommon.ICursorState>cursorState]);
E
Erich Gamma 已提交
276
			}
B
Benjamin Pasero 已提交
277
			this._view.restoreState(codeEditorState.viewState);
278

B
Benjamin Pasero 已提交
279
			let contributionsState = s.contributionsState || {};
A
Alex Dima 已提交
280 281 282 283
			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];
284 285 286 287
				if (typeof contribution.restoreViewState === 'function') {
					contribution.restoreViewState(contributionsState[id]);
				}
			}
E
Erich Gamma 已提交
288 289 290
		}
	}

J
Johannes Rieken 已提交
291
	public layout(dimension?: editorCommon.IDimension): void {
E
Erich Gamma 已提交
292
		this._configuration.observeReferenceElement(dimension);
293
		this.render();
E
Erich Gamma 已提交
294 295 296 297 298 299 300 301 302 303 304 305 306
	}

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

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

307
	public hasWidgetFocus(): boolean {
308
		return this._focusTracker && this._focusTracker.hasFocus();
309 310
	}

A
Alex Dima 已提交
311
	public addContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
312
		let widgetData: editorBrowser.IContentWidgetData = {
E
Erich Gamma 已提交
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
			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 已提交
328
	public layoutContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
329
		let widgetId = widget.getId();
E
Erich Gamma 已提交
330
		if (this.contentWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
331
			let widgetData = this.contentWidgets[widgetId];
E
Erich Gamma 已提交
332 333 334 335 336 337 338
			widgetData.position = widget.getPosition();
			if (this.hasView) {
				this._view.layoutContentWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
339
	public removeContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
340
		let widgetId = widget.getId();
E
Erich Gamma 已提交
341
		if (this.contentWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
342
			let widgetData = this.contentWidgets[widgetId];
E
Erich Gamma 已提交
343 344 345 346 347 348 349
			delete this.contentWidgets[widgetId];
			if (this.hasView) {
				this._view.removeContentWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
350
	public addOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
351
		let widgetData: editorBrowser.IOverlayWidgetData = {
E
Erich Gamma 已提交
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
			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 已提交
367
	public layoutOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
368
		let widgetId = widget.getId();
E
Erich Gamma 已提交
369
		if (this.overlayWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
370
			let widgetData = this.overlayWidgets[widgetId];
E
Erich Gamma 已提交
371 372 373 374 375 376 377
			widgetData.position = widget.getPosition();
			if (this.hasView) {
				this._view.layoutOverlayWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
378
	public removeOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
379
		let widgetId = widget.getId();
E
Erich Gamma 已提交
380
		if (this.overlayWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
381
			let widgetData = this.overlayWidgets[widgetId];
E
Erich Gamma 已提交
382 383 384 385 386 387 388
			delete this.overlayWidgets[widgetId];
			if (this.hasView) {
				this._view.removeOverlayWidget(widgetData);
			}
		}
	}

J
Johannes Rieken 已提交
389
	public changeViewZones(callback: (accessor: editorBrowser.IViewZoneChangeAccessor) => void): void {
E
Erich Gamma 已提交
390 391 392
		if (!this.hasView) {
			return;
		}
A
Alex Dima 已提交
393
		let hasChanges = this._view.change(callback);
E
Erich Gamma 已提交
394
		if (hasChanges) {
A
Alex Dima 已提交
395
			this.emit(editorCommon.EventType.ViewZonesChanged);
E
Erich Gamma 已提交
396 397 398
		}
	}

A
Alex Dima 已提交
399
	public getWhitespaces(): editorCommon.IEditorWhitespace[] {
E
Erich Gamma 已提交
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
		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);
	}

420 421 422 423 424 425 426
	public getTargetAtClientPoint(clientX: number, clientY: number): editorBrowser.IMouseTarget {
		if (!this.hasView) {
			return null;
		}
		return this._view.getCodeEditorHelper().getTargetAtClientPoint(clientX, clientY);
	}

J
Johannes Rieken 已提交
427
	public getScrolledVisiblePosition(rawPosition: editorCommon.IPosition): { top: number; left: number; height: number; } {
E
Erich Gamma 已提交
428 429 430 431
		if (!this.hasView) {
			return null;
		}

A
Alex Dima 已提交
432 433 434
		let position = this.model.validatePosition(rawPosition);
		let helper = this._view.getCodeEditorHelper();
		let layoutInfo = this._configuration.editor.layoutInfo;
E
Erich Gamma 已提交
435

A
Alex Dima 已提交
436 437
		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 已提交
438 439 440 441 442 443 444 445

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

J
Johannes Rieken 已提交
446
	public getOffsetForColumn(lineNumber: number, column: number): number {
E
Erich Gamma 已提交
447 448 449 450 451 452
		if (!this.hasView) {
			return -1;
		}
		return this._view.getCodeEditorHelper().getOffsetForColumn(lineNumber, column);
	}

453 454 455 456
	public render(): void {
		if (!this.hasView) {
			return;
		}
457
		this._view.render(true, false);
458 459
	}

J
Johannes Rieken 已提交
460
	public setHiddenAreas(ranges: editorCommon.IRange[]): void {
M
Martin Aeschlimann 已提交
461 462 463 464 465
		if (this.viewModel) {
			this.viewModel.setHiddenAreas(ranges);
		}
	}

J
Johannes Rieken 已提交
466
	public setAriaActiveDescendant(id: string): void {
A
Alex Dima 已提交
467 468 469 470 471 472
		if (!this.hasView) {
			return;
		}
		this._view.setAriaActiveDescendant(id);
	}

J
Johannes Rieken 已提交
473
	public applyFontInfo(target: HTMLElement): void {
474 475 476
		Configuration.applyFontInfoSlow(target, this._configuration.editor.fontInfo);
	}

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

480
		super._attachModel(model);
E
Erich Gamma 已提交
481

482
		if (this._view) {
A
Alex Dima 已提交
483
			this.domElement.appendChild(this._view.domNode.domNode);
E
Erich Gamma 已提交
484

A
Alex Dima 已提交
485 486 487 488 489
			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 已提交
490

A
Alex Dima 已提交
491 492 493 494 495
			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 已提交
496

A
Alex Dima 已提交
497 498
			this._view.render(false, true);
			this.hasView = true;
E
Erich Gamma 已提交
499 500 501
		}
	}

502
	protected _enableEmptySelectionClipboard(): boolean {
A
Alex Dima 已提交
503
		return browser.enableEmptySelectionClipboard;
E
Erich Gamma 已提交
504 505
	}

506 507
	protected _createView(): void {
		this._view = new View(
508
			this._commandService,
509 510
			this._configuration,
			this.viewModel,
J
Johannes Rieken 已提交
511
			(source: string, handlerId: string, payload: any) => {
A
Alex Dima 已提交
512 513 514 515 516
				if (!this.cursor) {
					return;
				}
				this.cursor.trigger(source, handlerId, payload);
			}
517 518
		);
	}
E
Erich Gamma 已提交
519

520 521 522
	protected _getViewInternalEventBus(): IEventEmitter {
		return this._view.getInternalEventBus();
	}
E
Erich Gamma 已提交
523

A
Alex Dima 已提交
524
	protected _detachModel(): editorCommon.IModel {
A
Alex Dima 已提交
525
		let removeDomNode: HTMLElement = null;
E
Erich Gamma 已提交
526 527 528

		if (this._view) {
			this._view.dispose();
A
Alex Dima 已提交
529
			removeDomNode = this._view.domNode.domNode;
E
Erich Gamma 已提交
530 531 532
			this._view = null;
		}

533
		let result = super._detachModel();
E
Erich Gamma 已提交
534 535 536 537 538 539 540

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

		return result;
	}
541 542 543

	// BEGIN decorations

J
Johannes Rieken 已提交
544
	protected _registerDecorationType(key: string, options: editorCommon.IDecorationRenderOptions, parentTypeKey?: string): void {
545 546 547
		this._codeEditorService.registerDecorationType(key, options, parentTypeKey);
	}

J
Johannes Rieken 已提交
548
	protected _removeDecorationType(key: string): void {
549 550 551
		this._codeEditorService.removeDecorationType(key);
	}

J
Johannes Rieken 已提交
552
	protected _resolveDecorationOptions(typeKey: string, writable: boolean): editorCommon.IModelDecorationOptions {
553 554 555 556
		return this._codeEditorService.resolveDecorationOptions(typeKey, writable);
	}

	// END decorations
E
Erich Gamma 已提交
557 558
}

559 560
class CodeEditorWidgetFocusTracker extends Disposable {

561 562
	private _hasFocus: boolean;
	private _domFocusTracker: dom.IFocusTracker;
563 564 565 566

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

J
Johannes Rieken 已提交
567
	constructor(domElement: HTMLElement) {
568 569
		super();

570 571
		this._hasFocus = false;
		this._domFocusTracker = this._register(dom.trackFocus(domElement));
572

573 574 575
		this._domFocusTracker.addFocusListener(() => {
			this._hasFocus = true;
			this._onChange.fire(void 0);
576
		});
577 578 579
		this._domFocusTracker.addBlurListener(() => {
			this._hasFocus = false;
			this._onChange.fire(void 0);
580 581 582 583
		});
	}

	public hasFocus(): boolean {
584
		return this._hasFocus;
585 586 587
	}
}

A
Alex Dima 已提交
588
class OverlayWidget2 implements editorBrowser.IOverlayWidget {
E
Erich Gamma 已提交
589 590

	private _id: string;
A
Alex Dima 已提交
591
	private _position: editorBrowser.IOverlayWidgetPosition;
E
Erich Gamma 已提交
592 593
	private _domNode: HTMLElement;

J
Johannes Rieken 已提交
594
	constructor(id: string, position: editorBrowser.IOverlayWidgetPosition) {
E
Erich Gamma 已提交
595 596 597
		this._id = id;
		this._position = position;
		this._domNode = document.createElement('div');
J
Johannes Rieken 已提交
598
		this._domNode.className = this._id.replace(/\./g, '-').replace(/[^a-z0-9\-]/, '');
E
Erich Gamma 已提交
599 600 601 602 603 604 605 606 607 608
	}

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

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

A
Alex Dima 已提交
609
	public getPosition(): editorBrowser.IOverlayWidgetPosition {
E
Erich Gamma 已提交
610 611 612 613 614 615 616 617
		return this._position;
	}
}

export enum EditCursorState {
	EndOfLastEditOperation = 0
}

A
Alex Dima 已提交
618 619
class SingleEditOperation {

620
	range: Range;
A
Alex Dima 已提交
621 622 623
	text: string;
	forceMoveMarkers: boolean;

J
Johannes Rieken 已提交
624
	constructor(source: editorCommon.ISingleEditOperation) {
A
Alex Dima 已提交
625 626 627 628 629 630 631
		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 已提交
632
export class CommandRunner implements editorCommon.ICommand {
E
Erich Gamma 已提交
633

A
Alex Dima 已提交
634
	private _ops: SingleEditOperation[];
E
Erich Gamma 已提交
635 636
	private _editCursorState: EditCursorState;

A
Alex Dima 已提交
637
	constructor(ops: editorCommon.ISingleEditOperation[], editCursorState: EditCursorState) {
A
Alex Dima 已提交
638
		this._ops = ops.map(op => new SingleEditOperation(op));
E
Erich Gamma 已提交
639 640 641
		this._editCursorState = editCursorState;
	}

A
Alex Dima 已提交
642
	public getEditOperations(model: editorCommon.ITokenizedModel, builder: editorCommon.IEditOperationBuilder): void {
E
Erich Gamma 已提交
643 644 645 646 647 648 649 650 651 652
		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 已提交
653 654 655
		let resultOps: editorCommon.ISingleEditOperation[] = [];
		let previousOp = this._ops[0];
		for (let i = 1; i < this._ops.length; i++) {
E
Erich Gamma 已提交
656 657 658 659 660 661 662 663 664 665 666
			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 已提交
667
		for (let i = 0; i < resultOps.length; i++) {
E
Erich Gamma 已提交
668 669 670 671
			builder.addEditOperation(Range.lift(resultOps[i].range), resultOps[i].text);
		}
	}

672
	public computeCursorState(model: editorCommon.ITokenizedModel, helper: editorCommon.ICursorStateComputerData): Selection {
A
Alex Dima 已提交
673 674
		let inverseEditOperations = helper.getInverseEditOperations();
		let srcRange = inverseEditOperations[inverseEditOperations.length - 1].range;
A
Alex Dima 已提交
675
		return new Selection(
E
Erich Gamma 已提交
676 677 678 679 680 681 682
			srcRange.endLineNumber,
			srcRange.endColumn,
			srcRange.endLineNumber,
			srcRange.endColumn
		);
	}
}