viewModelImpl.ts 26.7 KB
Newer Older
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

J
Johannes Rieken 已提交
7 8
import { EmitterEvent, EventEmitter, IEventEmitter } from 'vs/base/common/eventEmitter';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
9
import * as strings from 'vs/base/common/strings';
J
Johannes Rieken 已提交
10 11 12
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
13
import * as editorCommon from 'vs/editor/common/editorCommon';
R
rebornix 已提交
14 15
import { TokenizationRegistry } from 'vs/editor/common/modes';
import { tokenizeLineToHTML } from 'vs/editor/common/modes/textToHtmlTokenizer';
J
Johannes Rieken 已提交
16 17
import { ViewModelCursors } from 'vs/editor/common/viewModel/viewModelCursors';
import { ViewModelDecorations } from 'vs/editor/common/viewModel/viewModelDecorations';
A
Alex Dima 已提交
18
import { ViewLineRenderingData, ViewModelDecoration, IViewModel, ICoordinatesConverter } from 'vs/editor/common/viewModel/viewModel';
19
import { SplitLinesCollection } from 'vs/editor/common/viewModel/splitLinesCollection';
20

A
Alex Dima 已提交
21 22 23 24
export class CoordinatesConverter implements ICoordinatesConverter {

	private readonly _lines: SplitLinesCollection;

A
Alex Dima 已提交
25
	constructor(lines: SplitLinesCollection) {
A
Alex Dima 已提交
26 27 28 29 30
		this._lines = lines;
	}

	// View -> Model conversion and related methods

A
Alex Dima 已提交
31 32
	public convertViewPositionToModelPosition(viewPosition: Position): Position {
		return this._lines.convertViewPositionToModelPosition(viewPosition.lineNumber, viewPosition.column);
A
Alex Dima 已提交
33 34 35 36 37 38 39 40 41 42 43 44 45 46
	}

	public convertViewRangeToModelRange(viewRange: Range): Range {
		let start = this._lines.convertViewPositionToModelPosition(viewRange.startLineNumber, viewRange.startColumn);
		let end = this._lines.convertViewPositionToModelPosition(viewRange.endLineNumber, viewRange.endColumn);
		return new Range(start.lineNumber, start.column, end.lineNumber, end.column);
	}

	public convertViewSelectionToModelSelection(viewSelection: Selection): Selection {
		let selectionStart = this._lines.convertViewPositionToModelPosition(viewSelection.selectionStartLineNumber, viewSelection.selectionStartColumn);
		let position = this._lines.convertViewPositionToModelPosition(viewSelection.positionLineNumber, viewSelection.positionColumn);
		return new Selection(selectionStart.lineNumber, selectionStart.column, position.lineNumber, position.column);
	}

A
Alex Dima 已提交
47 48
	public validateViewPosition(viewPosition: Position, expectedModelPosition: Position): Position {
		return this._lines.validateViewPosition(viewPosition.lineNumber, viewPosition.column, expectedModelPosition);
A
Alex Dima 已提交
49 50
	}

A
Alex Dima 已提交
51 52 53
	public validateViewRange(viewRange: Range, expectedModelRange: Range): Range {
		var validViewStart = this._lines.validateViewPosition(viewRange.startLineNumber, viewRange.startColumn, expectedModelRange.getStartPosition());
		var validViewEnd = this._lines.validateViewPosition(viewRange.endLineNumber, viewRange.endColumn, expectedModelRange.getEndPosition());
A
Alex Dima 已提交
54 55 56 57 58
		return new Range(validViewStart.lineNumber, validViewStart.column, validViewEnd.lineNumber, validViewEnd.column);
	}

	// Model -> View conversion and related methods

A
Alex Dima 已提交
59 60
	public convertModelPositionToViewPosition(modelPosition: Position): Position {
		return this._lines.convertModelPositionToViewPosition(modelPosition.lineNumber, modelPosition.column);
A
Alex Dima 已提交
61 62 63 64 65 66 67 68
	}

	public convertModelRangeToViewRange(modelRange: Range): Range {
		let start = this._lines.convertModelPositionToViewPosition(modelRange.startLineNumber, modelRange.startColumn);
		let end = this._lines.convertModelPositionToViewPosition(modelRange.endLineNumber, modelRange.endColumn);
		return new Range(start.lineNumber, start.column, end.lineNumber, end.column);
	}

A
Alex Dima 已提交
69 70
	public modelPositionIsVisible(modelPosition: Position): boolean {
		return this._lines.modelPositionIsVisible(modelPosition.lineNumber, modelPosition.column);
A
Alex Dima 已提交
71 72 73 74
	}

}

75 76
export class ViewModel extends EventEmitter implements IViewModel {

A
Alex Dima 已提交
77 78 79 80 81
	private readonly lines: SplitLinesCollection;
	private readonly editorId: number;
	private readonly configuration: editorCommon.IConfiguration;
	private readonly model: editorCommon.IModel;
	public readonly coordinatesConverter: ICoordinatesConverter;
82

J
Johannes Rieken 已提交
83
	private listenersToRemove: IDisposable[];
84
	private _toDispose: IDisposable[];
A
Alex Dima 已提交
85 86
	private readonly decorations: ViewModelDecorations;
	private readonly cursors: ViewModelCursors;
87

J
Johannes Rieken 已提交
88
	private _renderCustomLineNumbers: (lineNumber: number) => string;
89 90 91
	private _renderRelativeLineNumbers: boolean;
	private _lastCursorPosition: Position;

A
Alex Dima 已提交
92
	private _centeredViewLine: number;
93

A
Alex Dima 已提交
94
	constructor(lines: SplitLinesCollection, editorId: number, configuration: editorCommon.IConfiguration, model: editorCommon.IModel) {
95 96 97 98 99 100
		super();
		this.lines = lines;

		this.editorId = editorId;
		this.configuration = configuration;
		this.model = model;
A
Alex Dima 已提交
101
		this.configuration.setMaxLineNumber(this.model.getLineCount());
102

A
Alex Dima 已提交
103
		this.coordinatesConverter = new CoordinatesConverter(this.lines);
A
Alex Dima 已提交
104

J
Johannes Rieken 已提交
105
		this._lastCursorPosition = new Position(1, 1);
106 107 108
		this._renderCustomLineNumbers = this.configuration.editor.viewInfo.renderCustomLineNumbers;
		this._renderRelativeLineNumbers = this.configuration.editor.viewInfo.renderRelativeLineNumbers;

A
Alex Dima 已提交
109
		this._centeredViewLine = -1;
110

A
Alex Dima 已提交
111
		this.decorations = new ViewModelDecorations(this.editorId, this.model, this.configuration, this.coordinatesConverter);
112
		this.decorations.reset();
113

A
Alex Dima 已提交
114
		this.cursors = new ViewModelCursors(this.configuration);
115 116 117

		this.listenersToRemove = [];
		this._toDispose = [];
J
Johannes Rieken 已提交
118
		this.listenersToRemove.push(this.model.addBulkListener((events: EmitterEvent[]) => this.onEvents(events)));
119 120 121 122 123
		this._toDispose.push(this.configuration.onDidChange((e) => {
			this.onEvents([new EmitterEvent(editorCommon.EventType.ConfigurationChanged, e)]);
		}));
	}

J
Johannes Rieken 已提交
124
	public setHiddenAreas(ranges: editorCommon.IRange[]): void {
A
Alex Dima 已提交
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
		try {
			this._beginDeferredEmit();
			this._setHiddenAreas(ranges);
		} finally {
			this._endDeferredEmit();
		}
	}

	private _setHiddenAreas(ranges: editorCommon.IRange[]): void {
		let lineMappingChanged = this.lines.setHiddenAreas(ranges, (eventType: string, payload: any) => this.emit(eventType, payload));
		if (lineMappingChanged) {
			this.emit(editorCommon.ViewEventNames.LineMappingChangedEvent);
			this.decorations.onLineMappingChanged((eventType: string, payload: any) => this.emit(eventType, payload));
			this.cursors.onLineMappingChanged((eventType: string, payload: any) => this.emit(eventType, payload));
		}
140 141 142
	}

	public dispose(): void {
A
Alex Dima 已提交
143
		this.listenersToRemove = dispose(this.listenersToRemove);
144 145 146 147 148
		this._toDispose = dispose(this._toDispose);
		this.decorations.dispose();
		this.lines.dispose();
	}

J
Johannes Rieken 已提交
149 150
	private _onTabSizeChange(newTabSize: number): boolean {
		var lineMappingChanged = this.lines.setTabSize(newTabSize, (eventType: string, payload: any) => this.emit(eventType, payload));
151 152
		if (lineMappingChanged) {
			this.emit(editorCommon.ViewEventNames.LineMappingChangedEvent);
J
Johannes Rieken 已提交
153
			this.decorations.onLineMappingChanged((eventType: string, payload: any) => this.emit(eventType, payload));
154 155 156 157 158
			this.cursors.onLineMappingChanged((eventType: string, payload: any) => this.emit(eventType, payload));
		}
		return lineMappingChanged;
	}

J
Johannes Rieken 已提交
159 160
	private _onWrappingIndentChange(newWrappingIndent: editorCommon.WrappingIndent): boolean {
		var lineMappingChanged = this.lines.setWrappingIndent(newWrappingIndent, (eventType: string, payload: any) => this.emit(eventType, payload));
161 162
		if (lineMappingChanged) {
			this.emit(editorCommon.ViewEventNames.LineMappingChangedEvent);
J
Johannes Rieken 已提交
163
			this.decorations.onLineMappingChanged((eventType: string, payload: any) => this.emit(eventType, payload));
164 165 166 167 168
			this.cursors.onLineMappingChanged((eventType: string, payload: any) => this.emit(eventType, payload));
		}
		return lineMappingChanged;
	}

J
Johannes Rieken 已提交
169
	private _restoreCenteredModelRange(range: Range): void {
170
		// modelLine -> viewLine
A
Alex Dima 已提交
171
		var newCenteredViewRange = this.coordinatesConverter.convertModelRangeToViewRange(range);
172 173

		// Send a reveal event to restore the centered content
J
Johannes Rieken 已提交
174
		var restoreRevealEvent: editorCommon.IViewRevealRangeEvent = {
175 176
			range: newCenteredViewRange,
			verticalType: editorCommon.VerticalRevealType.Center,
177 178
			revealHorizontal: false,
			revealCursor: false
179 180 181 182
		};
		this.emit(editorCommon.ViewEventNames.RevealRangeEvent, restoreRevealEvent);
	}

J
Johannes Rieken 已提交
183 184
	private _onWrappingColumnChange(newWrappingColumn: number, columnsForFullWidthChar: number): boolean {
		let lineMappingChanged = this.lines.setWrappingColumn(newWrappingColumn, columnsForFullWidthChar, (eventType: string, payload: any) => this.emit(eventType, payload));
185 186
		if (lineMappingChanged) {
			this.emit(editorCommon.ViewEventNames.LineMappingChangedEvent);
J
Johannes Rieken 已提交
187
			this.decorations.onLineMappingChanged((eventType: string, payload: any) => this.emit(eventType, payload));
188 189 190 191 192
			this.cursors.onLineMappingChanged((eventType: string, payload: any) => this.emit(eventType, payload));
		}
		return lineMappingChanged;
	}

J
Johannes Rieken 已提交
193 194
	public addEventSource(eventSource: IEventEmitter): void {
		this.listenersToRemove.push(eventSource.addBulkListener2((events: EmitterEvent[]) => this.onEvents(events)));
195 196
	}

J
Johannes Rieken 已提交
197
	private onEvents(events: EmitterEvent[]): void {
A
Alex Dima 已提交
198 199 200 201 202 203 204
		try {
			this._beginDeferredEmit();
			this._onEvents(events);
		} finally {
			this._endDeferredEmit();
		}
	}
205

206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
	private static _containsModelContentChangeEvent(events: EmitterEvent[]): boolean {
		for (let i = 0, len = events.length; i < len; i++) {
			let eventType = events[i].getType();
			if (eventType === editorCommon.EventType.ModelRawContentChanged) {
				return true;
			}
		}
		return false;
	}

	private static _containsWrappingRelatedEvents(events: EmitterEvent[]): boolean {
		for (let i = 0, len = events.length; i < len; i++) {
			let eventType = events[i].getType();
			if (eventType === editorCommon.EventType.ModelOptionsChanged) {
				return true;
			}
			if (eventType === editorCommon.EventType.ConfigurationChanged) {
				return true;
			}
		}
		return false;
	}

A
Alex Dima 已提交
229 230 231 232 233 234 235
	public getCenteredRangeInViewport(): Range {
		if (this._centeredViewLine === -1) {
			// Never got rendered
			return null;
		}
		let viewLineNumber = this._centeredViewLine;
		let currentCenteredViewRange = new Range(viewLineNumber, this.getLineMinColumn(viewLineNumber), viewLineNumber, this.getLineMaxColumn(viewLineNumber));
A
Alex Dima 已提交
236
		return this.coordinatesConverter.convertViewRangeToModelRange(currentCenteredViewRange);
A
Alex Dima 已提交
237 238
	}

A
Alex Dima 已提交
239
	private _onEvents(events: EmitterEvent[]): void {
240

A
Alex Dima 已提交
241 242 243 244 245
		const containsModelContentChangeEvent = ViewModel._containsModelContentChangeEvent(events);
		if (containsModelContentChangeEvent) {
			this.configuration.setMaxLineNumber(this.model.getLineCount());
		}

246 247 248 249 250 251 252 253 254 255
		// We might need to restore the current centered view range in the following circumstances:
		// All of these changes might lead to a new line mapping:
		// (a) model tabSize changed
		// (b) wrappingIndent changed
		// (c) wrappingColumn changed
		// (d) fontInfo changed
		// However, we cannot restore the current centered line if the model has changed its content
		// because we cannot convert the view range to a model range.

		let previousCenteredModelRange: Range = null;
A
Alex Dima 已提交
256
		if (!containsModelContentChangeEvent && ViewModel._containsWrappingRelatedEvents(events)) {
A
Alex Dima 已提交
257
			previousCenteredModelRange = this.getCenteredRangeInViewport();
A
Alex Dima 已提交
258
		}
259

A
Alex Dima 已提交
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
		let i: number,
			len: number,
			e: EmitterEvent,
			data: any,
			modelContentChangedEvent: editorCommon.IModelContentChangedEvent,
			hadOtherModelChange = false,
			hadModelLineChangeThatChangedLineMapping = false,
			revealPreviousCenteredModelRange = false;

		for (i = 0, len = events.length; i < len; i++) {
			e = events[i];
			data = e.getData();

			switch (e.getType()) {

				case editorCommon.EventType.ModelRawContentChanged:
					modelContentChangedEvent = <editorCommon.IModelContentChangedEvent>data;

					switch (modelContentChangedEvent.changeType) {
						case editorCommon.EventType.ModelRawContentChangedFlush:
							this.onModelFlushed(<editorCommon.IModelContentChangedFlushEvent>modelContentChangedEvent);
							hadOtherModelChange = true;
							break;

						case editorCommon.EventType.ModelRawContentChangedLinesDeleted:
							this.onModelLinesDeleted(<editorCommon.IModelContentChangedLinesDeletedEvent>modelContentChangedEvent);
							hadOtherModelChange = true;
							break;

						case editorCommon.EventType.ModelRawContentChangedLinesInserted:
							this.onModelLinesInserted(<editorCommon.IModelContentChangedLinesInsertedEvent>modelContentChangedEvent);
							hadOtherModelChange = true;
							break;

						case editorCommon.EventType.ModelRawContentChangedLineChanged:
							hadModelLineChangeThatChangedLineMapping = this.onModelLineChanged(<editorCommon.IModelContentChangedLineChangedEvent>modelContentChangedEvent);
							break;

						default:
							console.info('ViewModel received unknown event: ');
							console.info(e);
					}
					break;

				case editorCommon.EventType.ModelTokensChanged:
					this.onModelTokensChanged(<editorCommon.IModelTokensChangedEvent>data);
					break;

A
Alex Dima 已提交
308
				case editorCommon.EventType.ModelLanguageChanged:
A
Alex Dima 已提交
309 310 311 312 313 314 315 316 317
					// That's ok, a model tokens changed event will follow shortly
					break;

				case editorCommon.EventType.ModelContentChanged2:
					// Ignore
					break;

				case editorCommon.EventType.ModelOptionsChanged:
					// A tab size change causes a line mapping changed event => all view parts will repaint OK, no further event needed here
A
Alex Dima 已提交
318
					let prevLineCount = this.lines.getViewLineCount();
A
Alex Dima 已提交
319
					let tabSizeChanged = this._onTabSizeChange(this.model.getOptions().tabSize);
A
Alex Dima 已提交
320
					let newLineCount = this.lines.getViewLineCount();
A
Alex Dima 已提交
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
					if (tabSizeChanged && prevLineCount !== newLineCount) {
						revealPreviousCenteredModelRange = true;
					}

					break;

				case editorCommon.EventType.ModelDecorationsChanged:
					this.onModelDecorationsChanged(<editorCommon.IModelDecorationsChangedEvent>data);
					break;

				case editorCommon.EventType.ModelDispose:
					// Ignore, since the editor will take care of this and destroy the view shortly
					break;

				case editorCommon.EventType.CursorPositionChanged:
					this.onCursorPositionChanged(<editorCommon.ICursorPositionChangedEvent>data);
					this._lastCursorPosition = (<editorCommon.ICursorPositionChangedEvent>data).position;
					break;

				case editorCommon.EventType.CursorSelectionChanged:
					this.onCursorSelectionChanged(<editorCommon.ICursorSelectionChangedEvent>data);
					break;

				case editorCommon.EventType.CursorRevealRange:
					this.onCursorRevealRange(<editorCommon.ICursorRevealRangeEvent>data);
					break;

				case editorCommon.EventType.CursorScrollRequest:
					this.onCursorScrollRequest(<editorCommon.ICursorScrollRequestEvent>data);
					break;

				case editorCommon.EventType.ConfigurationChanged:
					revealPreviousCenteredModelRange = this._onWrappingIndentChange(this.configuration.editor.wrappingInfo.wrappingIndent) || revealPreviousCenteredModelRange;
					revealPreviousCenteredModelRange = this._onWrappingColumnChange(this.configuration.editor.wrappingInfo.wrappingColumn, this.configuration.editor.fontInfo.typicalFullwidthCharacterWidth / this.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth) || revealPreviousCenteredModelRange;

					this._renderCustomLineNumbers = this.configuration.editor.viewInfo.renderCustomLineNumbers;
					this._renderRelativeLineNumbers = this.configuration.editor.viewInfo.renderRelativeLineNumbers;

					if ((<editorCommon.IConfigurationChangedEvent>data).readOnly) {
						// Must read again all decorations due to readOnly filtering
361 362
						this.decorations.reset();
						this.emit(editorCommon.ViewEventNames.DecorationsChangedEvent, {});
A
Alex Dima 已提交
363 364 365 366 367 368 369
					}
					this.emit(e.getType(), <editorCommon.IConfigurationChangedEvent>data);
					break;

				default:
					console.info('View received unknown event: ');
					console.info(e);
370
			}
A
Alex Dima 已提交
371
		}
372

A
Alex Dima 已提交
373 374 375 376 377
		if (!hadOtherModelChange && hadModelLineChangeThatChangedLineMapping) {
			this.emit(editorCommon.ViewEventNames.LineMappingChangedEvent);
			this.decorations.onLineMappingChanged((eventType: string, payload: any) => this.emit(eventType, payload));
			this.cursors.onLineMappingChanged((eventType: string, payload: any) => this.emit(eventType, payload));
		}
378

A
Alex Dima 已提交
379 380 381
		if (revealPreviousCenteredModelRange && previousCenteredModelRange) {
			this._restoreCenteredModelRange(previousCenteredModelRange);
		}
382 383 384
	}

	// --- begin inbound event conversion
J
Johannes Rieken 已提交
385 386
	private onModelFlushed(e: editorCommon.IModelContentChangedFlushEvent): void {
		this.lines.onModelFlushed(e.versionId, (eventType: string, payload: any) => this.emit(eventType, payload));
387
		this.decorations.reset();
388
	}
J
Johannes Rieken 已提交
389 390
	private onModelDecorationsChanged(e: editorCommon.IModelDecorationsChangedEvent): void {
		this.decorations.onModelDecorationsChanged(e, (eventType: string, payload: any) => this.emit(eventType, payload));
391
	}
J
Johannes Rieken 已提交
392 393
	private onModelLinesDeleted(e: editorCommon.IModelContentChangedLinesDeletedEvent): void {
		this.lines.onModelLinesDeleted(e.versionId, e.fromLineNumber, e.toLineNumber, (eventType: string, payload: any) => this.emit(eventType, payload));
394
	}
J
Johannes Rieken 已提交
395
	private onModelTokensChanged(e: editorCommon.IModelTokensChangedEvent): void {
A
Alex Dima 已提交
396 397 398 399
		let viewRanges: { fromLineNumber: number; toLineNumber: number; }[] = [];

		for (let i = 0, len = e.ranges.length; i < len; i++) {
			let modelRange = e.ranges[i];
A
Alex Dima 已提交
400 401
			let viewStartLineNumber = this.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.fromLineNumber, 1)).lineNumber;
			let viewEndLineNumber = this.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.toLineNumber, this.model.getLineMaxColumn(modelRange.toLineNumber))).lineNumber;
A
Alex Dima 已提交
402 403 404 405 406
			viewRanges[i] = {
				fromLineNumber: viewStartLineNumber,
				toLineNumber: viewEndLineNumber
			};
		}
407

J
Johannes Rieken 已提交
408
		var e: editorCommon.IViewTokensChangedEvent = {
A
Alex Dima 已提交
409
			ranges: viewRanges
410 411 412
		};
		this.emit(editorCommon.ViewEventNames.TokensChangedEvent, e);
	}
J
Johannes Rieken 已提交
413 414
	private onModelLineChanged(e: editorCommon.IModelContentChangedLineChangedEvent): boolean {
		var lineMappingChanged = this.lines.onModelLineChanged(e.versionId, e.lineNumber, e.detail, (eventType: string, payload: any) => this.emit(eventType, payload));
415 416
		return lineMappingChanged;
	}
J
Johannes Rieken 已提交
417 418
	private onModelLinesInserted(e: editorCommon.IModelContentChangedLinesInsertedEvent): void {
		this.lines.onModelLinesInserted(e.versionId, e.fromLineNumber, e.toLineNumber, e.detail.split('\n'), (eventType: string, payload: any) => this.emit(eventType, payload));
419 420
	}

J
Johannes Rieken 已提交
421 422
	private onCursorPositionChanged(e: editorCommon.ICursorPositionChangedEvent): void {
		this.cursors.onCursorPositionChanged(e, (eventType: string, payload: any) => this.emit(eventType, payload));
423
	}
J
Johannes Rieken 已提交
424 425
	private onCursorSelectionChanged(e: editorCommon.ICursorSelectionChangedEvent): void {
		this.cursors.onCursorSelectionChanged(e, (eventType: string, payload: any) => this.emit(eventType, payload));
426
	}
J
Johannes Rieken 已提交
427
	private onCursorRevealRange(e: editorCommon.ICursorRevealRangeEvent): void {
A
Alex Dima 已提交
428 429 430 431
		// Ensure event has viewRange
		if (!e.viewRange) {
			e = {
				range: e.range,
A
Alex Dima 已提交
432
				viewRange: this.coordinatesConverter.convertModelRangeToViewRange(e.range),
A
Alex Dima 已提交
433 434 435 436 437
				verticalType: e.verticalType,
				revealHorizontal: e.revealHorizontal,
				revealCursor: e.revealCursor,
			};
		}
J
Johannes Rieken 已提交
438
		this.cursors.onCursorRevealRange(e, (eventType: string, payload: any) => this.emit(eventType, payload));
439
	}
J
Johannes Rieken 已提交
440 441
	private onCursorScrollRequest(e: editorCommon.ICursorScrollRequestEvent): void {
		this.cursors.onCursorScrollRequest(e, (eventType: string, payload: any) => this.emit(eventType, payload));
442 443 444 445 446 447 448 449
	}
	// --- end inbound event conversion

	public getTabSize(): number {
		return this.model.getOptions().tabSize;
	}

	public getLineCount(): number {
A
Alex Dima 已提交
450 451 452 453 454 455 456 457 458
		return this.lines.getViewLineCount();
	}

	/**
	 * Gives a hint that a lot of requests are about to come in for these line numbers.
	 */
	public setViewport(startLineNumber: number, endLineNumber: number, centeredLineNumber: number): void {
		this._centeredViewLine = centeredLineNumber;
		this.lines.warmUpLookupCache(startLineNumber, endLineNumber);
459 460
	}

461
	public getLineIndentGuide(lineNumber: number): number {
A
Alex Dima 已提交
462
		return this.lines.getViewLineIndentGuide(lineNumber);
463 464
	}

J
Johannes Rieken 已提交
465
	public getLineContent(lineNumber: number): string {
A
Alex Dima 已提交
466
		return this.lines.getViewLineContent(lineNumber);
467 468
	}

J
Johannes Rieken 已提交
469
	public getLineMinColumn(lineNumber: number): number {
A
Alex Dima 已提交
470
		return this.lines.getViewLineMinColumn(lineNumber);
471 472
	}

J
Johannes Rieken 已提交
473
	public getLineMaxColumn(lineNumber: number): number {
A
Alex Dima 已提交
474
		return this.lines.getViewLineMaxColumn(lineNumber);
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
	}

	public getLineFirstNonWhitespaceColumn(lineNumber: number): number {
		var result = strings.firstNonWhitespaceIndex(this.getLineContent(lineNumber));
		if (result === -1) {
			return 0;
		}
		return result + 1;
	}

	public getLineLastNonWhitespaceColumn(lineNumber: number): number {
		var result = strings.lastNonWhitespaceIndex(this.getLineContent(lineNumber));
		if (result === -1) {
			return 0;
		}
		return result + 2;
	}

J
Johannes Rieken 已提交
493
	public getLineRenderLineNumber(viewLineNumber: number): string {
A
Alex Dima 已提交
494
		let modelPosition = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(viewLineNumber, 1));
495 496 497
		if (modelPosition.column !== 1) {
			return '';
		}
498
		let modelLineNumber = modelPosition.lineNumber;
499

500 501 502 503 504 505 506 507 508 509
		if (this._renderCustomLineNumbers) {
			return this._renderCustomLineNumbers(modelLineNumber);
		}

		if (this._renderRelativeLineNumbers) {
			let diff = Math.abs(this._lastCursorPosition.lineNumber - modelLineNumber);
			if (diff === 0) {
				return '<span class="relative-current-line-number">' + modelLineNumber + '</span>';
			}
			return String(diff);
510 511
		}

512
		return String(modelLineNumber);
513 514
	}

515 516 517 518 519 520 521 522
	public getDecorationsInViewport(visibleRange: Range): ViewModelDecoration[] {
		return this.decorations.getDecorationsViewportData(visibleRange).decorations;
	}

	public getViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData {
		let mightContainRTL = this.model.mightContainRTL();
		let mightContainNonBasicASCII = this.model.mightContainNonBasicASCII();
		let tabSize = this.getTabSize();
A
Alex Dima 已提交
523
		let lineData = this.lines.getViewLineRenderingData(lineNumber);
524 525 526 527 528 529 530 531 532 533 534 535
		let allInlineDecorations = this.decorations.getDecorationsViewportData(visibleRange).inlineDecorations;
		let inlineDecorations = allInlineDecorations[lineNumber - visibleRange.startLineNumber];

		return new ViewLineRenderingData(
			lineData.minColumn,
			lineData.maxColumn,
			lineData.content,
			mightContainRTL,
			mightContainNonBasicASCII,
			lineData.tokens,
			inlineDecorations,
			tabSize
536
		);
537 538
	}

539 540
	public getAllOverviewRulerDecorations(): ViewModelDecoration[] {
		return this.decorations.getAllOverviewRulerDecorations();
541 542 543 544 545 546
	}

	public getEOL(): string {
		return this.model.getEOL();
	}

547
	public getValueInRange(range: Range, eol: editorCommon.EndOfLinePreference): string {
A
Alex Dima 已提交
548
		var modelRange = this.coordinatesConverter.convertViewRangeToModelRange(range);
549 550 551
		return this.model.getValueInRange(modelRange, eol);
	}

J
Johannes Rieken 已提交
552
	public getModelLineContent(modelLineNumber: number): string {
553 554 555
		return this.model.getLineContent(modelLineNumber);
	}

J
Johannes Rieken 已提交
556
	public getModelLineMaxColumn(modelLineNumber: number): number {
557 558 559
		return this.model.getLineMaxColumn(modelLineNumber);
	}

J
Johannes Rieken 已提交
560
	public validateModelPosition(position: editorCommon.IPosition): Position {
561 562
		return this.model.validatePosition(position);
	}
R
rebornix 已提交
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590

	public getPlainTextToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string {
		let newLineCharacter = this.getEOL();

		if (ranges.length === 1) {
			let range: Range = ranges[0];
			if (range.isEmpty()) {
				if (enableEmptySelectionClipboard) {
					let modelLineNumber = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(range.startLineNumber, 1)).lineNumber;
					return this.getModelLineContent(modelLineNumber) + newLineCharacter;
				} else {
					return '';
				}
			}

			return this.getValueInRange(range, editorCommon.EndOfLinePreference.TextDefined);
		} else {
			ranges = ranges.slice(0).sort(Range.compareRangesUsingStarts);
			let result: string[] = [];
			for (let i = 0; i < ranges.length; i++) {
				result.push(this.getValueInRange(ranges[i], editorCommon.EndOfLinePreference.TextDefined));
			}

			return result.join(newLineCharacter);
		}
	}

	public getHTMLToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string {
R
rebornix 已提交
591
		// TODO: adopt new view line tokens.
R
rebornix 已提交
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
		let rules: { [key: string]: string } = {};
		let colorMap = TokenizationRegistry.getColorMap();
		for (let i = 1, len = colorMap.length; i < len; i++) {
			let color = colorMap[i];
			if (/^(?:[0-9a-fA-F]{3}){1,2}$/.test(color)) {
				color = '#' + color;
			}
			rules[`mtk${i}`] = `color: ${color};`;
		}
		rules['mtki'] = 'font-style: italic;';
		rules['mtkb'] = 'font-weight: bold;';
		rules['mtku'] = 'text-decoration: underline;';

		let defaultForegroundColor = /^(?:[0-9a-fA-F]{3}){1,2}$/.test(colorMap[1]) ? '#' + colorMap[1] : colorMap[1];
		let defaultBackgroundColor = /^(?:[0-9a-fA-F]{3}){1,2}$/.test(colorMap[2]) ? '#' + colorMap[2] : colorMap[2];

608 609 610
		let fontInfo = this.configuration.editor.fontInfo;

		let output = `<div style="color: ${defaultForegroundColor}; background-color: ${defaultBackgroundColor};` +
611
			`font-family: ${fontInfo.fontFamily}; font-weight: ${fontInfo.fontWeight}; font-size: ${fontInfo.fontSize}px; line-height: ${fontInfo.lineHeight}px">`;
R
rebornix 已提交
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629

		if (ranges.length === 1) {
			let range: Range = ranges[0];

			if (range.isEmpty()) {
				if (enableEmptySelectionClipboard) {
					let modelLineNumber = this.coordinatesConverter.convertViewPositionToModelPosition(new Position(range.startLineNumber, 1)).lineNumber;
					let viewLineStart = new Position(range.startLineNumber, 1);
					let viewLineEnd = new Position(range.startLineNumber, this.getLineMaxColumn(range.startLineNumber));
					let startOffset = this.coordinatesConverter.convertViewPositionToModelPosition(viewLineStart).column - 1;
					let endOffset = this.coordinatesConverter.convertViewPositionToModelPosition(viewLineEnd).column - 1;
					let viewLineRenderingData = this.getViewLineRenderingData(new Range(viewLineStart.lineNumber, viewLineStart.column, viewLineEnd.lineNumber, viewLineEnd.column), modelLineNumber);
					let html = tokenizeLineToHTML(this.getModelLineContent(modelLineNumber),
						viewLineRenderingData.tokens,
						rules,
						{
							startOffset: startOffset,
							endOffset: endOffset,
630
							tabSize: this.getTabSize()
R
rebornix 已提交
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
						});
					output += `${html}`;
				} else {
					return '';
				}
			} else {
				for (let i = 0, lineCount = range.endLineNumber - range.startLineNumber; i <= lineCount; i++) {
					let viewLineRenderingData = this.getViewLineRenderingData(range, range.startLineNumber + i);
					let lineContent = viewLineRenderingData.content;
					let startOffset = i === 0 ? range.startColumn - 1 : 0;
					let endOffset = i === lineCount ? range.endColumn - 1 : lineContent.length;

					let html = tokenizeLineToHTML(lineContent, viewLineRenderingData.tokens, rules,
						{
							startOffset: startOffset,
							endOffset: endOffset,
647
							tabSize: this.getTabSize()
R
rebornix 已提交
648 649 650 651 652 653 654 655 656 657
						});
					output += `${html}`;
				}
			}
		}

		output += '</div>';

		return output;
	}
A
Alex Dima 已提交
658
}