codeEditorWidget.ts 23.0 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";
A
Alex Dima 已提交
34
import { IEditorWhitespace } from "vs/editor/common/viewLayout/whitespaceComputer";
E
Erich Gamma 已提交
35

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

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

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

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

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

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

A
Alex Dima 已提交
82
	_view: View;
E
Erich Gamma 已提交
83 84

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

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

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

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

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

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

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

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

A
Alex Dima 已提交
143
	protected _createConfiguration(options: IEditorOptions): CommonEditorConfiguration {
144
		return new Configuration(options, this.domElement);
E
Erich Gamma 已提交
145 146 147
	}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

A
Alex Dima 已提交
429
	public getWhitespaces(): IEditorWhitespace[] {
E
Erich Gamma 已提交
430 431 432 433 434 435 436 437 438 439
		if (!this.hasView) {
			return [];
		}
		return this._view.getWhitespaces();
	}

	public getTopForLineNumber(lineNumber: number): number {
		if (!this.hasView) {
			return -1;
		}
A
Alex Dima 已提交
440
		return this._view.getVerticalOffsetForPosition(lineNumber, 1);
E
Erich Gamma 已提交
441 442 443 444 445 446
	}

	public getTopForPosition(lineNumber: number, column: number): number {
		if (!this.hasView) {
			return -1;
		}
A
Alex Dima 已提交
447
		return this._view.getVerticalOffsetForPosition(lineNumber, column);
E
Erich Gamma 已提交
448 449
	}

450 451 452 453
	public getTargetAtClientPoint(clientX: number, clientY: number): editorBrowser.IMouseTarget {
		if (!this.hasView) {
			return null;
		}
A
Alex Dima 已提交
454
		return this._view.getTargetAtClientPoint(clientX, clientY);
455 456
	}

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

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

A
Alex Dima 已提交
465 466
		let top = this._view.getVerticalOffsetForPosition(position.lineNumber, position.column) - this._view.getScrollTop();
		let left = this._view.getOffsetForColumn(position.lineNumber, position.column) + layoutInfo.glyphMarginWidth + layoutInfo.lineNumbersWidth + layoutInfo.decorationsWidth - this._view.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
		if (!this.hasView) {
			return -1;
		}
A
Alex Dima 已提交
479
		return this._view.getOffsetForColumn(lineNumber, column);
E
Erich Gamma 已提交
480 481
	}

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
		);
	}
}