codeEditorWidget.ts 19.9 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';
9 10
import {onUnexpectedError} from 'vs/base/common/errors';
import {IEventEmitter} from 'vs/base/common/eventEmitter';
A
Alex Dima 已提交
11 12
import * as browser from 'vs/base/browser/browser';
import * as dom from 'vs/base/browser/dom';
E
Erich Gamma 已提交
13
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
14
import {IKeybindingService} from 'vs/platform/keybinding/common/keybindingService';
A
Alex Dima 已提交
15
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
16
import {CommonCodeEditor} from 'vs/editor/common/commonCodeEditor';
17
import {CommonEditorConfiguration} from 'vs/editor/common/config/commonEditorConfig';
A
Alex Dima 已提交
18 19 20 21 22 23 24 25 26 27
import {Range} from 'vs/editor/common/core/range';
import {Selection} from 'vs/editor/common/core/selection';
import * as editorCommon from 'vs/editor/common/editorCommon';
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
import {ICodeEditorService} from 'vs/editor/common/services/codeEditorService';
import {Configuration} from 'vs/editor/browser/config/configuration';
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
import {EditorBrowserRegistry} from 'vs/editor/browser/editorBrowserExtensions';
import {Colorizer} from 'vs/editor/browser/standalone/colorizer';
import {View} from 'vs/editor/browser/view/viewImpl';
A
Alex Dima 已提交
28
import {Disposable, IDisposable} from 'vs/base/common/lifecycle';
29
import Event, {Emitter} from 'vs/base/common/event';
A
Alex Dima 已提交
30
import {IKeyboardEvent} from 'vs/base/browser/keyboardEvent';
E
Erich Gamma 已提交
31

A
Alex Dima 已提交
32
export class CodeEditorWidget extends CommonCodeEditor implements editorBrowser.ICodeEditor {
E
Erich Gamma 已提交
33

A
Alex Dima 已提交
34 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
	public onMouseUp(listener: (e:editorBrowser.IEditorMouseEvent)=>void): IDisposable {
		return this.addListener2(editorCommon.EventType.MouseUp, listener);
	}
	public onMouseDown(listener: (e:editorBrowser.IEditorMouseEvent)=>void): IDisposable {
		return this.addListener2(editorCommon.EventType.MouseDown, listener);
	}
	public onContextMenu(listener: (e:editorBrowser.IEditorMouseEvent)=>void): IDisposable {
		return this.addListener2(editorCommon.EventType.ContextMenu, listener);
	}
	public onMouseMove(listener: (e:editorBrowser.IEditorMouseEvent)=>void): IDisposable {
		return this.addListener2(editorCommon.EventType.MouseMove, listener);
	}
	public onMouseLeave(listener: (e:editorBrowser.IEditorMouseEvent)=>void): IDisposable {
		return this.addListener2(editorCommon.EventType.MouseLeave, listener);
	}
	public onKeyUp(listener: (e:IKeyboardEvent)=>void): IDisposable {
		return this.addListener2(editorCommon.EventType.KeyUp, listener);
	}
	public onKeyDown(listener: (e:IKeyboardEvent)=>void): IDisposable {
		return this.addListener2(editorCommon.EventType.KeyDown, listener);
	}
	public onDidLayoutChange(listener: (e:editorCommon.EditorLayoutInfo)=>void): IDisposable {
		return this.addListener2(editorCommon.EventType.EditorLayout, listener);
	}
	public onDidScrollChange(listener: (e:editorCommon.IScrollEvent)=>void): IDisposable {
		return this.addListener2('scroll', listener);
	}

62
	protected domElement:HTMLElement;
63
	private _focusTracker: CodeEditorWidgetFocusTracker;
E
Erich Gamma 已提交
64

65 66
	_configuration:Configuration;

A
Alex Dima 已提交
67 68
	private contentWidgets:{ [key:string]:editorBrowser.IContentWidgetData; };
	private overlayWidgets:{ [key:string]:editorBrowser.IOverlayWidgetData; };
E
Erich Gamma 已提交
69

A
Alex Dima 已提交
70
	_view:editorBrowser.IView;
E
Erich Gamma 已提交
71 72 73

	constructor(
		domElement:HTMLElement,
74
		options:editorCommon.IEditorOptions,
E
Erich Gamma 已提交
75 76 77 78 79
		@IInstantiationService instantiationService: IInstantiationService,
		@ICodeEditorService codeEditorService: ICodeEditorService,
		@IKeybindingService keybindingService: IKeybindingService,
		@ITelemetryService telemetryService: ITelemetryService
	) {
80
		super(domElement, options, instantiationService, codeEditorService, keybindingService, telemetryService);
E
Erich Gamma 已提交
81

82 83 84
		this._focusTracker = new CodeEditorWidgetFocusTracker(domElement);
		this._focusTracker.onChage(() => {
			let hasFocus = this._focusTracker.hasFocus();
85

86
			if (hasFocus) {
E
Erich Gamma 已提交
87
				this._editorFocusContextKey.set(true);
A
Alex Dima 已提交
88
				this.emit(editorCommon.EventType.EditorFocus, {});
89
			} else {
E
Erich Gamma 已提交
90
				this._editorFocusContextKey.reset();
A
Alex Dima 已提交
91
				this.emit(editorCommon.EventType.EditorBlur, {});
E
Erich Gamma 已提交
92 93 94 95 96 97 98 99 100 101 102 103 104
			}
		});

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

		var contributionDescriptors = [].concat(EditorBrowserRegistry.getEditorContributions()).concat(CommonEditorRegistry.getEditorContributions());
		for (var i = 0, len = contributionDescriptors.length; i < len; i++) {
			try {
				var contribution = contributionDescriptors[i].createInstance(this._instantiationService, this);
				this.contributions[contribution.getId()] = contribution;
			} catch (err) {
				console.error('Could not instantiate contribution ' + contribution.getId());
105
				onUnexpectedError(err);
E
Erich Gamma 已提交
106 107 108 109
			}
		}
	}

110 111
	protected _createConfiguration(options:editorCommon.ICodeEditorWidgetCreationOptions): CommonEditorConfiguration {
		return new Configuration(options, this.domElement);
E
Erich Gamma 已提交
112 113 114 115 116 117
	}

	public dispose(): void {
		this.contentWidgets = {};
		this.overlayWidgets = {};

118
		this._focusTracker.dispose();
E
Erich Gamma 已提交
119 120 121
		super.dispose();
	}

122
	public updateOptions(newOptions:editorCommon.IEditorOptions): void {
123
		let oldTheme = this._configuration.editor.viewInfo.theme;
124
		super.updateOptions(newOptions);
125
		let newTheme = this._configuration.editor.viewInfo.theme;
126 127 128 129 130 131

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

A
Alex Dima 已提交
132
	public colorizeModelLine(lineNumber:number, model:editorCommon.IModel = this.model): string {
E
Erich Gamma 已提交
133 134 135 136 137
		if (!model) {
			return '';
		}
		var content = model.getLineContent(lineNumber);
		var tokens = model.getLineTokens(lineNumber, false);
A
Alex Dima 已提交
138
		var inflatedTokens = tokens.inflate();
139 140
		var tabSize = model.getOptions().tabSize;
		return Colorizer.colorizeLine(content, inflatedTokens, tabSize);
E
Erich Gamma 已提交
141
	}
A
Alex Dima 已提交
142
	public getView(): editorBrowser.IView {
E
Erich Gamma 已提交
143 144 145 146 147 148 149 150 151 152
		return this._view;
	}

	public getDomNode(): HTMLElement {
		if (!this.hasView) {
			return null;
		}
		return this._view.domNode;
	}

153
	public getCenteredRangeInViewport(): Range {
E
Erich Gamma 已提交
154 155 156 157 158 159
		if (!this.hasView) {
			return null;
		}
		return this._view.getCenteredRangeInViewport();
	}

160
	public getScrollWidth(): number {
E
Erich Gamma 已提交
161
		if (!this.hasView) {
162
			return -1;
E
Erich Gamma 已提交
163
		}
164 165 166 167 168
		return this._view.getCodeEditorHelper().getScrollWidth();
	}
	public getScrollLeft(): number {
		if (!this.hasView) {
			return -1;
E
Erich Gamma 已提交
169
		}
170
		return this._view.getCodeEditorHelper().getScrollLeft();
E
Erich Gamma 已提交
171 172
	}

173
	public getScrollHeight(): number {
E
Erich Gamma 已提交
174 175 176
		if (!this.hasView) {
			return -1;
		}
177
		return this._view.getCodeEditorHelper().getScrollHeight();
E
Erich Gamma 已提交
178
	}
179
	public getScrollTop(): number {
E
Erich Gamma 已提交
180
		if (!this.hasView) {
181
			return -1;
E
Erich Gamma 已提交
182
		}
183
		return this._view.getCodeEditorHelper().getScrollTop();
E
Erich Gamma 已提交
184 185 186 187 188 189 190 191 192
	}

	public setScrollLeft(newScrollLeft:number): void {
		if (!this.hasView) {
			return;
		}
		if (typeof newScrollLeft !== 'number') {
			throw new Error('Invalid arguments');
		}
193 194 195
		this._view.getCodeEditorHelper().setScrollPosition({
			scrollLeft: newScrollLeft
		});
E
Erich Gamma 已提交
196
	}
197
	public setScrollTop(newScrollTop:number): void {
E
Erich Gamma 已提交
198
		if (!this.hasView) {
199
			return;
E
Erich Gamma 已提交
200
		}
201 202 203 204 205 206
		if (typeof newScrollTop !== 'number') {
			throw new Error('Invalid arguments');
		}
		this._view.getCodeEditorHelper().setScrollPosition({
			scrollTop: newScrollTop
		});
E
Erich Gamma 已提交
207
	}
208
	public setScrollPosition(position: editorCommon.INewScrollPosition): void {
E
Erich Gamma 已提交
209
		if (!this.hasView) {
210
			return;
E
Erich Gamma 已提交
211
		}
212
		this._view.getCodeEditorHelper().setScrollPosition(position);
E
Erich Gamma 已提交
213 214
	}

215
	public delegateVerticalScrollbarMouseDown(browserEvent:MouseEvent): void {
E
Erich Gamma 已提交
216
		if (!this.hasView) {
217
			return;
E
Erich Gamma 已提交
218
		}
219
		this._view.getCodeEditorHelper().delegateVerticalScrollbarMouseDown(browserEvent);
E
Erich Gamma 已提交
220 221
	}

A
Alex Dima 已提交
222
	public saveViewState(): editorCommon.ICodeEditorViewState {
E
Erich Gamma 已提交
223 224 225
		if (!this.cursor || !this.hasView) {
			return null;
		}
226 227 228 229 230 231 232 233
		let contributionsState: {[key:string]:any} = {};
		for (let id in this.contributions) {
			let contribution = this.contributions[id];
			if (typeof contribution.saveViewState === 'function') {
				contributionsState[id] = contribution.saveViewState();
			}
		}

E
Erich Gamma 已提交
234 235 236 237
		var cursorState = this.cursor.saveState();
		var viewState = this._view.saveState();
		return {
			cursorState: cursorState,
238 239
			viewState: viewState,
			contributionsState: contributionsState
E
Erich Gamma 已提交
240 241 242
		};
	}

A
Alex Dima 已提交
243
	public restoreViewState(state:editorCommon.IEditorViewState): void {
E
Erich Gamma 已提交
244 245 246 247 248
		if (!this.cursor || !this.hasView) {
			return;
		}
		var s = <any>state;
		if (s && s.cursorState && s.viewState) {
A
Alex Dima 已提交
249
			var codeEditorState = <editorCommon.ICodeEditorViewState>s;
E
Erich Gamma 已提交
250 251
			var cursorState = <any>codeEditorState.cursorState;
			if (Array.isArray(cursorState)) {
A
Alex Dima 已提交
252
				this.cursor.restoreState(<editorCommon.ICursorState[]>cursorState);
E
Erich Gamma 已提交
253 254
			} else {
				// Backwards compatibility
A
Alex Dima 已提交
255
				this.cursor.restoreState([<editorCommon.ICursorState>cursorState]);
E
Erich Gamma 已提交
256 257
			}
			this._view.restoreState(codeEditorState.viewState);
258 259 260 261 262 263 264 265

			let contributionsState = s.contributionsState || {};
			for (let id in this.contributions) {
				let contribution = this.contributions[id];
				if (typeof contribution.restoreViewState === 'function') {
					contribution.restoreViewState(contributionsState[id]);
				}
			}
E
Erich Gamma 已提交
266 267 268
		}
	}

A
Alex Dima 已提交
269
	public layout(dimension?:editorCommon.IDimension): void {
E
Erich Gamma 已提交
270
		this._configuration.observeReferenceElement(dimension);
271
		this.render();
E
Erich Gamma 已提交
272 273 274 275 276 277 278 279 280
	}

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

281 282 283 284 285 286 287 288
	public beginForcedWidgetFocus(): void {
		this._focusTracker.beginForcedFocus();
	}

	public endForcedWidgetFocus(): void {
		this._focusTracker.endForcedFocus();
	}

E
Erich Gamma 已提交
289 290 291 292
	public isFocused(): boolean {
		return this.hasView && this._view.isFocused();
	}

293
	public hasWidgetFocus(): boolean {
294
		return this._focusTracker.hasFocus();
295 296
	}

A
Alex Dima 已提交
297 298
	public addContentWidget(widget: editorBrowser.IContentWidget): void {
		var widgetData: editorBrowser.IContentWidgetData = {
E
Erich Gamma 已提交
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
			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 已提交
314
	public layoutContentWidget(widget: editorBrowser.IContentWidget): void {
E
Erich Gamma 已提交
315 316 317 318 319 320 321 322 323 324
		var widgetId = widget.getId();
		if (this.contentWidgets.hasOwnProperty(widgetId)) {
			var widgetData = this.contentWidgets[widgetId];
			widgetData.position = widget.getPosition();
			if (this.hasView) {
				this._view.layoutContentWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
325
	public removeContentWidget(widget: editorBrowser.IContentWidget): void {
E
Erich Gamma 已提交
326 327 328 329 330 331 332 333 334 335
		var widgetId = widget.getId();
		if (this.contentWidgets.hasOwnProperty(widgetId)) {
			var widgetData = this.contentWidgets[widgetId];
			delete this.contentWidgets[widgetId];
			if (this.hasView) {
				this._view.removeContentWidget(widgetData);
			}
		}
	}

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

A
Alex Dima 已提交
364
	public removeOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
E
Erich Gamma 已提交
365 366 367 368 369 370 371 372 373 374
		var widgetId = widget.getId();
		if (this.overlayWidgets.hasOwnProperty(widgetId)) {
			var widgetData = this.overlayWidgets[widgetId];
			delete this.overlayWidgets[widgetId];
			if (this.hasView) {
				this._view.removeOverlayWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
375
	public changeViewZones(callback:(accessor:editorBrowser.IViewZoneChangeAccessor)=>void): void {
E
Erich Gamma 已提交
376 377 378 379 380 381
		if (!this.hasView) {
//			console.warn('Cannot change view zones on editor that is not attached to a model, since there is no view.');
			return;
		}
		var hasChanges = this._view.change(callback);
		if (hasChanges) {
A
Alex Dima 已提交
382
			this.emit(editorCommon.EventType.ViewZonesChanged);
E
Erich Gamma 已提交
383 384 385
		}
	}

A
Alex Dima 已提交
386
	public getWhitespaces(): editorCommon.IEditorWhitespace[] {
E
Erich Gamma 已提交
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
		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);
	}

A
Alex Dima 已提交
407
	public getScrolledVisiblePosition(rawPosition:editorCommon.IPosition): { top:number; left:number; height:number; } {
E
Erich Gamma 已提交
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
		if (!this.hasView) {
			return null;
		}

		var position = this.model.validatePosition(rawPosition);
		var helper = this._view.getCodeEditorHelper();
		var layoutInfo = this._configuration.editor.layoutInfo;

		var top = helper.getVerticalOffsetForPosition(position.lineNumber, position.column) - helper.getScrollTop();
		var left = helper.getOffsetForColumn(position.lineNumber, position.column) + layoutInfo.glyphMarginWidth + layoutInfo.lineNumbersWidth + layoutInfo.decorationsWidth - helper.getScrollLeft();

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

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

433 434 435 436
	public render(): void {
		if (!this.hasView) {
			return;
		}
437
		this._view.render(true, false);
438 439
	}

A
Alex Dima 已提交
440
	public setHiddenAreas(ranges:editorCommon.IRange[]): void {
M
Martin Aeschlimann 已提交
441 442 443 444 445
		if (this.viewModel) {
			this.viewModel.setHiddenAreas(ranges);
		}
	}

A
Alex Dima 已提交
446 447 448 449 450 451 452
	public setAriaActiveDescendant(id:string): void {
		if (!this.hasView) {
			return;
		}
		this._view.setAriaActiveDescendant(id);
	}

453 454 455 456
	public applyFontInfo(target:HTMLElement): void {
		Configuration.applyFontInfoSlow(target, this._configuration.editor.fontInfo);
	}

A
Alex Dima 已提交
457
	_attachModel(model:editorCommon.IModel): void {
E
Erich Gamma 已提交
458 459
		this._view = null;

460
		super._attachModel(model);
E
Erich Gamma 已提交
461

462
		if (this._view) {
E
Erich Gamma 已提交
463 464 465 466
			this.domElement.appendChild(this._view.domNode);

			this._view.renderOnce(() => {

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

A
Alex Dima 已提交
473 474 475 476
				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 已提交
477 478
				}

479
				this._view.render(false, true);
E
Erich Gamma 已提交
480 481 482 483 484
				this.hasView = true;
			});
		}
	}

485
	protected _enableEmptySelectionClipboard(): boolean {
A
Alex Dima 已提交
486
		return browser.enableEmptySelectionClipboard;
E
Erich Gamma 已提交
487 488
	}

489 490
	protected _createView(): void {
		this._view = new View(
A
Alex Dima 已提交
491
			this._keybindingService,
492 493
			this._configuration,
			this.viewModel,
A
Alex Dima 已提交
494 495 496 497 498 499
			(source:string, handlerId:string, payload:any) => {
				if (!this.cursor) {
					return;
				}
				this.cursor.trigger(source, handlerId, payload);
			}
500 501
		);
	}
E
Erich Gamma 已提交
502

503 504 505
	protected _getViewInternalEventBus(): IEventEmitter {
		return this._view.getInternalEventBus();
	}
E
Erich Gamma 已提交
506

A
Alex Dima 已提交
507
	protected _detachModel(): editorCommon.IModel {
E
Erich Gamma 已提交
508 509 510 511 512 513 514 515
		var removeDomNode:HTMLElement = null;

		if (this._view) {
			this._view.dispose();
			removeDomNode = this._view.domNode;
			this._view = null;
		}

516
		let result = super._detachModel();
E
Erich Gamma 已提交
517 518 519 520 521 522 523 524 525

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

		return result;
	}
}

526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
class CodeEditorWidgetFocusTracker extends Disposable {

	private _forcedWidgetFocusCount: number;
	private _focusTrackerHasFocus: boolean;
	private _focusTracker: dom.IFocusTracker;
	private _actualHasFocus: boolean;

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

	constructor(domElement:HTMLElement) {
		super();

		this._focusTrackerHasFocus = false;
		this._forcedWidgetFocusCount = 0;
		this._actualHasFocus = false;
		this._focusTracker = this._register(dom.trackFocus(domElement));

		this._focusTracker.addFocusListener(() => {
			this._focusTrackerHasFocus = true;
			this._update();
		});
		this._focusTracker.addBlurListener(() => {
			this._focusTrackerHasFocus = false;
			this._update();
		});
	}

	public hasFocus(): boolean {
		return this._actualHasFocus;
	}

	public beginForcedFocus(): void {
		this._forcedWidgetFocusCount++;
		this._update();
	}

	public endForcedFocus(): void {
		this._forcedWidgetFocusCount--;
		this._update();
	}

	private _update(): void {
		let newActualHasFocus = this._focusTrackerHasFocus;
		if (this._forcedWidgetFocusCount > 0) {
			newActualHasFocus = true;
		}

		if (this._actualHasFocus === newActualHasFocus) {
			// no change
			return;
		}

		this._actualHasFocus = newActualHasFocus;
		this._onChange.fire(void 0);
	}
}

A
Alex Dima 已提交
584
class OverlayWidget2 implements editorBrowser.IOverlayWidget {
E
Erich Gamma 已提交
585 586

	private _id: string;
A
Alex Dima 已提交
587
	private _position: editorBrowser.IOverlayWidgetPosition;
E
Erich Gamma 已提交
588 589
	private _domNode: HTMLElement;

A
Alex Dima 已提交
590
	constructor(id:string, position:editorBrowser.IOverlayWidgetPosition) {
E
Erich Gamma 已提交
591 592 593 594 595 596 597 598 599 600 601 602 603 604
		this._id = id;
		this._position = position;
		this._domNode = document.createElement('div');
		this._domNode.className = this._id.replace(/\./g, '-').replace(/[^a-z0-9\-]/,'');
	}

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

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

A
Alex Dima 已提交
605
	public getPosition(): editorBrowser.IOverlayWidgetPosition {
E
Erich Gamma 已提交
606 607 608 609 610 611 612 613
		return this._position;
	}
}

export enum EditCursorState {
	EndOfLastEditOperation = 0
}

A
Alex Dima 已提交
614 615
class SingleEditOperation {

616
	range: Range;
A
Alex Dima 已提交
617 618 619 620 621 622 623 624 625 626 627
	text: string;
	forceMoveMarkers: boolean;

	constructor(source:editorCommon.ISingleEditOperation) {
		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 已提交
628
export class CommandRunner implements editorCommon.ICommand {
E
Erich Gamma 已提交
629

A
Alex Dima 已提交
630
	private _ops: SingleEditOperation[];
E
Erich Gamma 已提交
631 632
	private _editCursorState: EditCursorState;

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

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

		for (var i = 0; i < resultOps.length; i++) {
			builder.addEditOperation(Range.lift(resultOps[i].range), resultOps[i].text);
		}
	}

668
	public computeCursorState(model: editorCommon.ITokenizedModel, helper: editorCommon.ICursorStateComputerData): Selection {
E
Erich Gamma 已提交
669 670 671 672 673 674 675 676 677 678
		var inverseEditOperations = helper.getInverseEditOperations();
		var srcRange = inverseEditOperations[inverseEditOperations.length - 1].range;
		return Selection.createSelection(
			srcRange.endLineNumber,
			srcRange.endColumn,
			srcRange.endLineNumber,
			srcRange.endColumn
		);
	}
}