extHostEditors.ts 20.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 URI from 'vs/base/common/uri';
J
Johannes Rieken 已提交
8
import { readonly, illegalArgument } from 'vs/base/common/errors';
9
import { equals as arrayEquals } from 'vs/base/common/arrays';
J
Johannes Rieken 已提交
10 11 12 13 14
import { IdGenerator } from 'vs/base/common/idGenerator';
import Event, { Emitter } from 'vs/base/common/event';
import { TPromise } from 'vs/base/common/winjs.base';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ExtHostDocuments, ExtHostDocumentData } from 'vs/workbench/api/node/extHostDocuments';
J
Joel Day 已提交
15
import { Selection, Range, Position, EndOfLine, TextEditorRevealType, TextEditorSelectionChangeKind, TextEditorLineNumbersStyle, SnippetString } from './extHostTypes';
16
import { ISingleEditOperation, TextEditorCursorStyle, IRange } from 'vs/editor/common/editorCommon';
17
import { IResolvedTextEditorConfiguration, ISelectionChangeEvent, ITextEditorConfigurationUpdate } from 'vs/workbench/api/node/mainThreadEditorsTracker';
18
import * as TypeConverters from './extHostTypeConverters';
J
Johannes Rieken 已提交
19
import { MainContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextEditorAddData, ITextEditorPositionData } from './extHost.protocol';
20
import * as vscode from 'vscode';
E
Erich Gamma 已提交
21

A
Alex Dima 已提交
22
export class ExtHostEditors extends ExtHostEditorsShape {
E
Erich Gamma 已提交
23

24 25
	public onDidChangeTextEditorSelection: Event<vscode.TextEditorSelectionChangeEvent>;
	private _onDidChangeTextEditorSelection: Emitter<vscode.TextEditorSelectionChangeEvent>;
E
Erich Gamma 已提交
26

27 28
	public onDidChangeTextEditorOptions: Event<vscode.TextEditorOptionsChangeEvent>;
	private _onDidChangeTextEditorOptions: Emitter<vscode.TextEditorOptionsChangeEvent>;
E
Erich Gamma 已提交
29

30 31
	public onDidChangeTextEditorViewColumn: Event<vscode.TextEditorViewColumnChangeEvent>;
	private _onDidChangeTextEditorViewColumn: Emitter<vscode.TextEditorViewColumnChangeEvent>;
32

J
Johannes Rieken 已提交
33
	private _editors: Map<string, ExtHostTextEditor>;
34
	private _proxy: MainThreadEditorsShape;
E
Erich Gamma 已提交
35
	private _onDidChangeActiveTextEditor: Emitter<vscode.TextEditor>;
36
	private _onDidChangeVisibleTextEditors: Emitter<vscode.TextEditor[]>;
37
	private _extHostDocuments: ExtHostDocuments;
E
Erich Gamma 已提交
38 39 40 41
	private _activeEditorId: string;
	private _visibleEditorIds: string[];

	constructor(
42
		threadService: IThreadService,
43
		extHostDocuments: ExtHostDocuments
E
Erich Gamma 已提交
44
	) {
A
Alex Dima 已提交
45
		super();
46
		this._onDidChangeTextEditorSelection = new Emitter<vscode.TextEditorSelectionChangeEvent>();
E
Erich Gamma 已提交
47 48
		this.onDidChangeTextEditorSelection = this._onDidChangeTextEditorSelection.event;

49
		this._onDidChangeTextEditorOptions = new Emitter<vscode.TextEditorOptionsChangeEvent>();
E
Erich Gamma 已提交
50 51
		this.onDidChangeTextEditorOptions = this._onDidChangeTextEditorOptions.event;

52
		this._onDidChangeTextEditorViewColumn = new Emitter<vscode.TextEditorViewColumnChangeEvent>();
53 54
		this.onDidChangeTextEditorViewColumn = this._onDidChangeTextEditorViewColumn.event;

55
		this._extHostDocuments = extHostDocuments;
56
		this._proxy = threadService.get(MainContext.MainThreadEditors);
E
Erich Gamma 已提交
57
		this._onDidChangeActiveTextEditor = new Emitter<vscode.TextEditor>();
58
		this._onDidChangeVisibleTextEditors = new Emitter<vscode.TextEditor[]>();
J
Johannes Rieken 已提交
59
		this._editors = new Map<string, ExtHostTextEditor>();
E
Erich Gamma 已提交
60 61 62 63 64

		this._visibleEditorIds = [];
	}

	getActiveTextEditor(): vscode.TextEditor {
J
Johannes Rieken 已提交
65
		return this._editors.get(this._activeEditorId);
E
Erich Gamma 已提交
66 67 68
	}

	getVisibleTextEditors(): vscode.TextEditor[] {
J
Johannes Rieken 已提交
69
		return this._visibleEditorIds.map(id => this._editors.get(id));
E
Erich Gamma 已提交
70 71 72 73 74 75
	}

	get onDidChangeActiveTextEditor(): Event<vscode.TextEditor> {
		return this._onDidChangeActiveTextEditor && this._onDidChangeActiveTextEditor.event;
	}

76 77 78 79
	get onDidChangeVisibleTextEditors(): Event<vscode.TextEditor[]> {
		return this._onDidChangeVisibleTextEditors && this._onDidChangeVisibleTextEditors.event;
	}

80
	showTextDocument(document: vscode.TextDocument, column: vscode.ViewColumn, preserveFocus: boolean): TPromise<vscode.TextEditor> {
J
Johannes Rieken 已提交
81
		return this._proxy.$tryShowTextDocument(<URI>document.uri, TypeConverters.fromViewColumn(column), preserveFocus).then(id => {
J
Johannes Rieken 已提交
82
			let editor = this._editors.get(id);
E
Erich Gamma 已提交
83 84 85
			if (editor) {
				return editor;
			} else {
86
				throw new Error(`Failed to show text document ${document.uri.toString()}, should show in editor #${id}`);
E
Erich Gamma 已提交
87 88 89 90 91 92 93 94 95 96
			}
		});
	}

	createTextEditorDecorationType(options: vscode.DecorationRenderOptions): vscode.TextEditorDecorationType {
		return new TextEditorDecorationType(this._proxy, options);
	}

	// --- called from main thread

97
	$acceptTextEditorAdd(data: ITextEditorAddData): void {
98
		let document = this._extHostDocuments.getDocumentData(data.document);
99
		let newEditor = new ExtHostTextEditor(this._proxy, data.id, document, data.selections.map(TypeConverters.toSelection), data.options, TypeConverters.toViewColumn(data.editorPosition));
J
Johannes Rieken 已提交
100
		this._editors.set(data.id, newEditor);
E
Erich Gamma 已提交
101 102
	}

103
	$acceptOptionsChanged(id: string, opts: IResolvedTextEditorConfiguration): void {
J
Johannes Rieken 已提交
104
		let editor = this._editors.get(id);
E
Erich Gamma 已提交
105 106 107 108 109 110 111
		editor._acceptOptions(opts);
		this._onDidChangeTextEditorOptions.fire({
			textEditor: editor,
			options: opts
		});
	}

112
	$acceptSelectionsChanged(id: string, event: ISelectionChangeEvent): void {
113 114
		const kind = TextEditorSelectionChangeKind.fromValue(event.source);
		const selections = event.selections.map(TypeConverters.toSelection);
J
Johannes Rieken 已提交
115
		const textEditor = this._editors.get(id);
116
		textEditor._acceptSelections(selections);
E
Erich Gamma 已提交
117
		this._onDidChangeTextEditorSelection.fire({
118 119 120
			textEditor,
			selections,
			kind
E
Erich Gamma 已提交
121 122 123
		});
	}

124
	$acceptActiveEditorAndVisibleEditors(id: string, visibleIds: string[]): void {
125 126 127 128 129 130 131
		let visibleChanged = false;
		let activeChanged = false;

		if (!arrayEquals(this._visibleEditorIds, visibleIds)) {
			this._visibleEditorIds = visibleIds;
			visibleChanged = true;
		}
E
Erich Gamma 已提交
132

133 134 135 136 137 138 139 140 141 142
		if (this._activeEditorId !== id) {
			this._activeEditorId = id;
			activeChanged = true;
		}

		if (visibleChanged) {
			this._onDidChangeVisibleTextEditors.fire(this.getVisibleTextEditors());
		}
		if (activeChanged) {
			this._onDidChangeActiveTextEditor.fire(this.getActiveTextEditor());
E
Erich Gamma 已提交
143 144 145
		}
	}

146
	$acceptEditorPositionData(data: ITextEditorPositionData): void {
147
		for (let id in data) {
J
Johannes Rieken 已提交
148
			let textEditor = this._editors.get(id);
149 150 151 152
			let viewColumn = TypeConverters.toViewColumn(data[id]);
			if (textEditor.viewColumn !== viewColumn) {
				textEditor._acceptViewColumn(viewColumn);
				this._onDidChangeTextEditorViewColumn.fire({ textEditor, viewColumn });
153 154 155 156
			}
		}
	}

157
	$acceptTextEditorRemove(id: string): void {
E
Erich Gamma 已提交
158
		// make sure the removed editor is not visible
B
Benjamin Pasero 已提交
159
		let newVisibleEditors = this._visibleEditorIds.filter(visibleEditorId => visibleEditorId !== id);
E
Erich Gamma 已提交
160 161 162

		if (this._activeEditorId === id) {
			// removing the current active editor
163
			this.$acceptActiveEditorAndVisibleEditors(undefined, newVisibleEditors);
E
Erich Gamma 已提交
164
		} else {
165
			this.$acceptActiveEditorAndVisibleEditors(this._activeEditorId, newVisibleEditors);
E
Erich Gamma 已提交
166 167
		}

J
Johannes Rieken 已提交
168
		let editor = this._editors.get(id);
E
Erich Gamma 已提交
169
		editor.dispose();
J
Johannes Rieken 已提交
170
		this._editors.delete(id);
E
Erich Gamma 已提交
171 172 173 174 175
	}
}

class TextEditorDecorationType implements vscode.TextEditorDecorationType {

J
Johannes Rieken 已提交
176
	private static _Keys = new IdGenerator('TextEditorDecorationType');
E
Erich Gamma 已提交
177

178
	private _proxy: MainThreadEditorsShape;
E
Erich Gamma 已提交
179 180
	public key: string;

181
	constructor(proxy: MainThreadEditorsShape, options: vscode.DecorationRenderOptions) {
J
Johannes Rieken 已提交
182
		this.key = TextEditorDecorationType._Keys.nextId();
E
Erich Gamma 已提交
183
		this._proxy = proxy;
184
		this._proxy.$registerTextEditorDecorationType(this.key, <any>/* URI vs Uri */ options);
E
Erich Gamma 已提交
185 186 187
	}

	public dispose(): void {
188
		this._proxy.$removeTextEditorDecorationType(this.key);
E
Erich Gamma 已提交
189 190 191 192 193 194 195 196 197 198 199 200
	}
}

export interface ITextEditOperation {
	range: Range;
	text: string;
	forceMoveMarkers: boolean;
}

export interface IEditData {
	documentVersionId: number;
	edits: ITextEditOperation[];
201
	setEndOfLine: EndOfLine;
J
Johannes Rieken 已提交
202 203
	undoStopBefore: boolean;
	undoStopAfter: boolean;
E
Erich Gamma 已提交
204 205 206 207 208 209
}

export class TextEditorEdit {

	private _documentVersionId: number;
	private _collectedEdits: ITextEditOperation[];
210
	private _setEndOfLine: EndOfLine;
211 212
	private _undoStopBefore: boolean;
	private _undoStopAfter: boolean;
E
Erich Gamma 已提交
213

J
Johannes Rieken 已提交
214
	constructor(document: vscode.TextDocument, options: { undoStopBefore: boolean; undoStopAfter: boolean; }) {
E
Erich Gamma 已提交
215 216
		this._documentVersionId = document.version;
		this._collectedEdits = [];
217
		this._setEndOfLine = 0;
218 219
		this._undoStopBefore = options.undoStopBefore;
		this._undoStopAfter = options.undoStopAfter;
E
Erich Gamma 已提交
220 221 222 223 224
	}

	finalize(): IEditData {
		return {
			documentVersionId: this._documentVersionId,
225
			edits: this._collectedEdits,
226 227 228
			setEndOfLine: this._setEndOfLine,
			undoStopBefore: this._undoStopBefore,
			undoStopAfter: this._undoStopAfter
E
Erich Gamma 已提交
229 230 231 232 233 234 235 236 237 238
		};
	}

	replace(location: Position | Range | Selection, value: string): void {
		let range: Range = null;

		if (location instanceof Position) {
			range = new Range(location, location);
		} else if (location instanceof Range) {
			range = location;
A
Alex Dima 已提交
239
		} else {
E
Erich Gamma 已提交
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
			throw new Error('Unrecognized location');
		}

		this._collectedEdits.push({
			range: range,
			text: value,
			forceMoveMarkers: false
		});
	}

	insert(location: Position, value: string): void {
		this._collectedEdits.push({
			range: new Range(location, location),
			text: value,
			forceMoveMarkers: true
		});
	}

	delete(location: Range | Selection): void {
		let range: Range = null;

		if (location instanceof Range) {
			range = location;
A
Alex Dima 已提交
263
		} else {
E
Erich Gamma 已提交
264 265 266 267 268 269 270 271 272
			throw new Error('Unrecognized location');
		}

		this._collectedEdits.push({
			range: range,
			text: null,
			forceMoveMarkers: true
		});
	}
273

J
Johannes Rieken 已提交
274
	setEndOfLine(endOfLine: EndOfLine): void {
275
		if (endOfLine !== EndOfLine.LF && endOfLine !== EndOfLine.CRLF) {
J
Johannes Rieken 已提交
276
			throw illegalArgument('endOfLine');
277 278 279 280
		}

		this._setEndOfLine = endOfLine;
	}
E
Erich Gamma 已提交
281 282 283
}


J
Johannes Rieken 已提交
284
function deprecated(name: string, message: string = 'Refer to the documentation for further details.') {
E
Erich Gamma 已提交
285 286
	return (target: Object, key: string, descriptor: TypedPropertyDescriptor<any>) => {
		const originalMethod = descriptor.value;
J
Johannes Rieken 已提交
287
		descriptor.value = function (...args: any[]) {
E
Erich Gamma 已提交
288 289
			console.warn(`[Deprecation Warning] method '${name}' is deprecated and should no longer be used. ${message}`);
			return originalMethod.apply(this, args);
B
Benjamin Pasero 已提交
290
		};
E
Erich Gamma 已提交
291 292

		return descriptor;
B
Benjamin Pasero 已提交
293
	};
E
Erich Gamma 已提交
294 295
}

296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 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 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 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 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
export class ExtHostTextEditorOptions implements vscode.TextEditorOptions {

	private _proxy: MainThreadEditorsShape;
	private _id: string;

	private _tabSize: number;
	private _insertSpaces: boolean;
	private _cursorStyle: TextEditorCursorStyle;
	private _lineNumbers: TextEditorLineNumbersStyle;

	constructor(proxy: MainThreadEditorsShape, id: string, source: IResolvedTextEditorConfiguration) {
		this._proxy = proxy;
		this._id = id;
		this._accept(source);
	}

	public _accept(source: IResolvedTextEditorConfiguration): void {
		this._tabSize = source.tabSize;
		this._insertSpaces = source.insertSpaces;
		this._cursorStyle = source.cursorStyle;
		this._lineNumbers = source.lineNumbers;
	}

	public get tabSize(): number | string {
		return this._tabSize;
	}

	private _validateTabSize(value: number | string): number | 'auto' | null {
		if (value === 'auto') {
			return 'auto';
		}
		if (typeof value === 'number') {
			let r = Math.floor(value);
			return (r > 0 ? r : null);
		}
		if (typeof value === 'string') {
			let r = parseInt(value, 10);
			if (isNaN(r)) {
				return null;
			}
			return (r > 0 ? r : null);
		}
		return null;
	}

	public set tabSize(value: number | string) {
		let tabSize = this._validateTabSize(value);
		if (tabSize === null) {
			// ignore invalid call
			return;
		}
		if (typeof tabSize === 'number') {
			if (this._tabSize === tabSize) {
				// nothing to do
				return;
			}
			// reflect the new tabSize value immediately
			this._tabSize = tabSize;
		}
		warnOnError(this._proxy.$trySetOptions(this._id, {
			tabSize: tabSize
		}));
	}

	public get insertSpaces(): boolean | string {
		return this._insertSpaces;
	}

	private _validateInsertSpaces(value: boolean | string): boolean | 'auto' {
		if (value === 'auto') {
			return 'auto';
		}
		return (value === 'false' ? false : Boolean(value));
	}

	public set insertSpaces(value: boolean | string) {
		let insertSpaces = this._validateInsertSpaces(value);
		if (typeof insertSpaces === 'boolean') {
			if (this._insertSpaces === insertSpaces) {
				// nothing to do
				return;
			}
			// reflect the new insertSpaces value immediately
			this._insertSpaces = insertSpaces;
		}
		warnOnError(this._proxy.$trySetOptions(this._id, {
			insertSpaces: insertSpaces
		}));
	}

	public get cursorStyle(): TextEditorCursorStyle {
		return this._cursorStyle;
	}

	public set cursorStyle(value: TextEditorCursorStyle) {
		if (this._cursorStyle === value) {
			// nothing to do
			return;
		}
		this._cursorStyle = value;
		warnOnError(this._proxy.$trySetOptions(this._id, {
			cursorStyle: value
		}));
	}

	public get lineNumbers(): TextEditorLineNumbersStyle {
		return this._lineNumbers;
	}

	public set lineNumbers(value: TextEditorLineNumbersStyle) {
		if (this._lineNumbers === value) {
			// nothing to do
			return;
		}
		this._lineNumbers = value;
		warnOnError(this._proxy.$trySetOptions(this._id, {
			lineNumbers: value
		}));
	}

	public assign(newOptions: vscode.TextEditorOptions) {
		let bulkConfigurationUpdate: ITextEditorConfigurationUpdate = {};
		let hasUpdate = false;

		if (typeof newOptions.tabSize !== 'undefined') {
			let tabSize = this._validateTabSize(newOptions.tabSize);
			if (tabSize === 'auto') {
				hasUpdate = true;
				bulkConfigurationUpdate.tabSize = tabSize;
			} else if (typeof tabSize === 'number' && this._tabSize !== tabSize) {
				// reflect the new tabSize value immediately
				this._tabSize = tabSize;
				hasUpdate = true;
				bulkConfigurationUpdate.tabSize = tabSize;
			}
		}

		if (typeof newOptions.insertSpaces !== 'undefined') {
			let insertSpaces = this._validateInsertSpaces(newOptions.insertSpaces);
			if (insertSpaces === 'auto') {
				hasUpdate = true;
				bulkConfigurationUpdate.insertSpaces = insertSpaces;
			} else if (this._insertSpaces !== insertSpaces) {
				// reflect the new insertSpaces value immediately
				this._insertSpaces = insertSpaces;
				hasUpdate = true;
				bulkConfigurationUpdate.insertSpaces = insertSpaces;
			}
		}

		if (typeof newOptions.cursorStyle !== 'undefined') {
			if (this._cursorStyle !== newOptions.cursorStyle) {
				this._cursorStyle = newOptions.cursorStyle;
				hasUpdate = true;
				bulkConfigurationUpdate.cursorStyle = newOptions.cursorStyle;
			}
		}

		if (typeof newOptions.lineNumbers !== 'undefined') {
			if (this._lineNumbers !== newOptions.lineNumbers) {
				this._lineNumbers = newOptions.lineNumbers;
				hasUpdate = true;
				bulkConfigurationUpdate.lineNumbers = newOptions.lineNumbers;
			}
		}

		if (hasUpdate) {
			warnOnError(this._proxy.$trySetOptions(this._id, bulkConfigurationUpdate));
		}
	}


}

470
class ExtHostTextEditor implements vscode.TextEditor {
E
Erich Gamma 已提交
471

472
	private _proxy: MainThreadEditorsShape;
E
Erich Gamma 已提交
473 474
	private _id: string;

475
	private _documentData: ExtHostDocumentData;
E
Erich Gamma 已提交
476
	private _selections: Selection[];
477
	private _options: ExtHostTextEditorOptions;
478
	private _viewColumn: vscode.ViewColumn;
E
Erich Gamma 已提交
479

480
	constructor(proxy: MainThreadEditorsShape, id: string, document: ExtHostDocumentData, selections: Selection[], options: IResolvedTextEditorConfiguration, viewColumn: vscode.ViewColumn) {
E
Erich Gamma 已提交
481 482
		this._proxy = proxy;
		this._id = id;
483
		this._documentData = document;
E
Erich Gamma 已提交
484
		this._selections = selections;
485
		this._options = new ExtHostTextEditorOptions(this._proxy, this._id, options);
486
		this._viewColumn = viewColumn;
E
Erich Gamma 已提交
487 488 489
	}

	dispose() {
490
		this._documentData = null;
E
Erich Gamma 已提交
491 492 493
	}

	@deprecated('TextEditor.show') show(column: vscode.ViewColumn) {
494
		this._proxy.$tryShowEditor(this._id, TypeConverters.fromViewColumn(column));
E
Erich Gamma 已提交
495 496 497
	}

	@deprecated('TextEditor.hide') hide() {
498
		this._proxy.$tryHideEditor(this._id);
E
Erich Gamma 已提交
499 500 501 502 503
	}

	// ---- the document

	get document(): vscode.TextDocument {
504 505 506
		return this._documentData
			? this._documentData.document
			: undefined;
E
Erich Gamma 已提交
507 508 509 510 511 512 513 514
	}

	set document(value) {
		throw readonly('document');
	}

	// ---- options

515
	get options(): vscode.TextEditorOptions {
E
Erich Gamma 已提交
516 517 518
		return this._options;
	}

519
	set options(value: vscode.TextEditorOptions) {
520
		this._options.assign(value);
E
Erich Gamma 已提交
521 522
	}

523 524
	_acceptOptions(options: IResolvedTextEditorConfiguration): void {
		this._options._accept(options);
E
Erich Gamma 已提交
525 526
	}

527 528 529 530 531 532 533 534 535 536 537 538 539 540
	// ---- view column

	get viewColumn(): vscode.ViewColumn {
		return this._viewColumn;
	}

	set viewColumn(value) {
		throw readonly('viewColumn');
	}

	_acceptViewColumn(value: vscode.ViewColumn) {
		this._viewColumn = value;
	}

E
Erich Gamma 已提交
541 542 543 544 545 546 547 548
	// ---- selections

	get selection(): Selection {
		return this._selections && this._selections[0];
	}

	set selection(value: Selection) {
		if (!(value instanceof Selection)) {
J
Johannes Rieken 已提交
549
			throw illegalArgument('selection');
E
Erich Gamma 已提交
550 551 552 553 554 555 556 557 558 559 560
		}
		this._selections = [value];
		this._trySetSelection(true);
	}

	get selections(): Selection[] {
		return this._selections;
	}

	set selections(value: Selection[]) {
		if (!Array.isArray(value) || value.some(a => !(a instanceof Selection))) {
J
Johannes Rieken 已提交
561
			throw illegalArgument('selections');
E
Erich Gamma 已提交
562 563 564 565 566
		}
		this._selections = value;
		this._trySetSelection(true);
	}

J
Johannes Rieken 已提交
567
	setDecorations(decorationType: vscode.TextEditorDecorationType, ranges: Range[] | vscode.DecorationOptions[]): void {
E
Erich Gamma 已提交
568
		this._runOnProxy(
569
			() => this._proxy.$trySetDecorations(
E
Erich Gamma 已提交
570 571 572 573 574 575 576 577
				this._id,
				decorationType.key,
				TypeConverters.fromRangeOrRangeWithMessage(ranges)
			),
			true
		);
	}

J
Johannes Rieken 已提交
578
	revealRange(range: Range, revealType: vscode.TextEditorRevealType): void {
E
Erich Gamma 已提交
579
		this._runOnProxy(
580
			() => this._proxy.$tryRevealRange(
E
Erich Gamma 已提交
581 582
				this._id,
				TypeConverters.fromRange(range),
A
Alex Dima 已提交
583
				(revealType || TextEditorRevealType.Default)
E
Erich Gamma 已提交
584 585 586 587 588 589 590
			),
			true
		);
	}

	private _trySetSelection(silent: boolean): TPromise<vscode.TextEditor> {
		let selection = this._selections.map(TypeConverters.fromSelection);
591
		return this._runOnProxy(() => this._proxy.$trySetSelections(this._id, selection), silent);
E
Erich Gamma 已提交
592 593
	}

J
Johannes Rieken 已提交
594
	_acceptSelections(selections: Selection[]): void {
E
Erich Gamma 已提交
595 596 597 598 599
		this._selections = selections;
	}

	// ---- editing

600 601 602 603
	edit(callback: (edit: TextEditorEdit) => void, options: { undoStopBefore: boolean; undoStopAfter: boolean; } = { undoStopBefore: true, undoStopAfter: true }): Thenable<boolean> {
		let edit = new TextEditorEdit(this._documentData.document, options);
		callback(edit);
		return this._applyEdit(edit);
E
Erich Gamma 已提交
604 605
	}

J
Johannes Rieken 已提交
606 607
	_applyEdit(editBuilder: TextEditorEdit): TPromise<boolean> {
		let editData = editBuilder.finalize();
E
Erich Gamma 已提交
608 609

		// prepare data for serialization
B
Benjamin Pasero 已提交
610
		let edits: ISingleEditOperation[] = editData.edits.map((edit) => {
E
Erich Gamma 已提交
611 612 613 614 615 616 617
			return {
				range: TypeConverters.fromRange(edit.range),
				text: edit.text,
				forceMoveMarkers: edit.forceMoveMarkers
			};
		});

618 619 620 621 622
		return this._proxy.$tryApplyEdits(this._id, editData.documentVersionId, edits, {
			setEndOfLine: editData.setEndOfLine,
			undoStopBefore: editData.undoStopBefore,
			undoStopAfter: editData.undoStopAfter
		});
E
Erich Gamma 已提交
623 624
	}

625 626 627
	insertSnippet(snippet: SnippetString, where?: Position | Position[] | Range | Range[], options: { undoStopBefore: boolean; undoStopAfter: boolean; } = { undoStopBefore: true, undoStopAfter: true }): Thenable<boolean> {

		let ranges: IRange[];
628 629

		if (!where || (Array.isArray(where) && where.length === 0)) {
630 631 632 633 634
			ranges = this._selections.map(TypeConverters.fromRange);

		} else if (where instanceof Position) {
			const {lineNumber, column} = TypeConverters.fromPosition(where);
			ranges = [{ startLineNumber: lineNumber, startColumn: column, endLineNumber: lineNumber, endColumn: column }];
635

636 637 638 639 640 641 642 643 644 645 646 647 648
		} else if (where instanceof Range) {
			ranges = [TypeConverters.fromRange(where)];
		} else {
			ranges = [];
			for (const posOrRange of where) {
				if (posOrRange instanceof Range) {
					ranges.push(TypeConverters.fromRange(posOrRange));
				} else {
					const {lineNumber, column} = TypeConverters.fromPosition(posOrRange);
					ranges.push({ startLineNumber: lineNumber, startColumn: column, endLineNumber: lineNumber, endColumn: column });
				}
			}
		}
649

650
		return this._proxy.$tryInsertSnippet(this._id, snippet.value, ranges, options);
651 652
	}

E
Erich Gamma 已提交
653 654
	// ---- util

J
Johannes Rieken 已提交
655
	private _runOnProxy(callback: () => TPromise<any>, silent: boolean): TPromise<ExtHostTextEditor> {
E
Erich Gamma 已提交
656 657 658 659 660
		return callback().then(() => this, err => {
			if (!silent) {
				return TPromise.wrapError(silent);
			}
			console.warn(err);
661
			return undefined;
E
Erich Gamma 已提交
662 663 664
		});
	}
}
665 666 667 668 669 670

function warnOnError(promise: TPromise<any>): void {
	promise.then(null, (err) => {
		console.warn(err);
	});
}