cursor.ts 62.4 KB
Newer Older
E
Erich Gamma 已提交
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';

A
Alex Dima 已提交
7
import * as nls from 'vs/nls';
8
import * as strings from 'vs/base/common/strings';
J
Johannes Rieken 已提交
9 10 11 12 13
import { onUnexpectedError } from 'vs/base/common/errors';
import { EventEmitter } from 'vs/base/common/eventEmitter';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand';
import { CursorCollection, ICursorCollectionState } from 'vs/editor/common/controller/cursorCollection';
A
Alex Dima 已提交
14 15 16 17 18
import {
	IViewModelHelper, OneCursor, OneCursorOp, CursorContext, CursorMovePosition,
	CursorMoveByUnit, RevealLineArguments, RevealLineAtArgument, EditorScrollArguments,
	EditorScrollDirection, EditorScrollByUnit
} from 'vs/editor/common/controller/oneCursor';
J
Johannes Rieken 已提交
19 20
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
A
Alex Dima 已提交
21
import { Selection, SelectionDirection, ISelection } from 'vs/editor/common/core/selection';
A
Alex Dima 已提交
22
import * as editorCommon from 'vs/editor/common/editorCommon';
A
Alex Dima 已提交
23
import { CursorColumns, EditOperationResult, CursorConfiguration } from 'vs/editor/common/controller/cursorCommon';
J
Johannes Rieken 已提交
24
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
25
import { ColumnSelection, IColumnSelectResult } from 'vs/editor/common/controller/cursorColumnSelection';
A
Alex Dima 已提交
26 27
import { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations';
import { TypeOperations } from 'vs/editor/common/controller/cursorTypeOperations';
28
import { TextModelEventType, ModelRawContentChangedEvent, RawContentChangedType } from 'vs/editor/common/model/textModelEvents';
A
Alex Dima 已提交
29 30 31 32 33 34 35

export const CursorEventType = {
	CursorPositionChanged: 'positionChanged',
	CursorSelectionChanged: 'selectionChanged',
	CursorRevealRange: 'revealRange',
	CursorScrollRequest: 'scrollRequest',
};
E
Erich Gamma 已提交
36

A
Alex Dima 已提交
37
const enum RevealTarget {
E
Erich Gamma 已提交
38 39 40 41 42
	Primary = 0,
	TopMost = 1,
	BottomMost = 2
}

A
Alex Dima 已提交
43 44 45 46 47 48 49 50 51
interface IOneCursorOperationContext {
	shouldReveal: boolean;
	shouldRevealHorizontal: boolean;
	shouldPushStackElementBefore: boolean;
	shouldPushStackElementAfter: boolean;
	executeCommand: editorCommon.ICommand;
	isAutoWhitespaceCommand: boolean;
}

E
Erich Gamma 已提交
52
interface IMultipleCursorOperationContext {
A
Alex Dima 已提交
53
	cursorPositionChangeReason: editorCommon.CursorChangeReason;
E
Erich Gamma 已提交
54 55 56 57 58 59 60 61 62 63
	shouldReveal: boolean;
	shouldRevealVerticalInCenter: boolean;
	shouldRevealHorizontal: boolean;
	shouldRevealTarget: RevealTarget;
	shouldPushStackElementBefore: boolean;
	shouldPushStackElementAfter: boolean;
	eventSource: string;
	eventData: any;
	hasExecutedCommands: boolean;
	isCursorUndo: boolean;
A
Alex Dima 已提交
64
	executeCommands: editorCommon.ICommand[];
65
	isAutoWhitespaceCommand: boolean[];
A
Alex Dima 已提交
66 67
	setColumnSelectToLineNumber: number;
	setColumnSelectToVisualColumn: number;
E
Erich Gamma 已提交
68 69 70 71 72 73 74 75
}

interface IExecContext {
	selectionStartMarkers: string[];
	positionMarkers: string[];
}

interface ICommandData {
A
Alex Dima 已提交
76
	operations: editorCommon.IIdentifiedSingleEditOperation[];
E
Erich Gamma 已提交
77 78 79 80
	hadTrackedRange: boolean;
}

interface ICommandsData {
A
Alex Dima 已提交
81
	operations: editorCommon.IIdentifiedSingleEditOperation[];
E
Erich Gamma 已提交
82 83 84 85 86 87
	hadTrackedRanges: boolean[];
	anyoneHadTrackedRange: boolean;
}

export class Cursor extends EventEmitter {

J
Johannes Rieken 已提交
88
	private configuration: editorCommon.IConfiguration;
A
Alex Dima 已提交
89
	private context: CursorContext;
J
Johannes Rieken 已提交
90
	private model: editorCommon.IModel;
E
Erich Gamma 已提交
91

J
Johannes Rieken 已提交
92
	private modelUnbinds: IDisposable[];
E
Erich Gamma 已提交
93 94 95

	private cursors: CursorCollection;
	private cursorUndoStack: ICursorCollectionState[];
J
Johannes Rieken 已提交
96
	private viewModelHelper: IViewModelHelper;
E
Erich Gamma 已提交
97

J
Johannes Rieken 已提交
98
	private _isHandling: boolean;
99
	private _isDoingComposition: boolean;
E
Erich Gamma 已提交
100

J
Johannes Rieken 已提交
101
	private enableEmptySelectionClipboard: boolean;
E
Erich Gamma 已提交
102

J
Johannes Rieken 已提交
103 104
	private _handlers: {
		[key: string]: (ctx: IMultipleCursorOperationContext) => boolean;
A
Alex Dima 已提交
105 106
	};

107
	constructor(configuration: editorCommon.IConfiguration, model: editorCommon.IModel, viewModelHelper: IViewModelHelper, enableEmptySelectionClipboard: boolean) {
E
Erich Gamma 已提交
108
		super([
A
Alex Dima 已提交
109 110 111 112
			CursorEventType.CursorPositionChanged,
			CursorEventType.CursorSelectionChanged,
			CursorEventType.CursorRevealRange,
			CursorEventType.CursorScrollRequest
E
Erich Gamma 已提交
113 114 115 116 117
		]);
		this.configuration = configuration;
		this.model = model;
		this.viewModelHelper = viewModelHelper;
		this.enableEmptySelectionClipboard = enableEmptySelectionClipboard;
A
Alex Dima 已提交
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137

		const createCursorContext = () => {
			const config = new CursorConfiguration(
				this.model.getLanguageIdentifier(),
				this.model.getOneIndent(),
				this.model.getOptions(),
				this.configuration
			);
			this.context = new CursorContext(
				this.model,
				this.viewModelHelper,
				config
			);
			if (this.cursors) {
				this.cursors.updateContext(this.context);
			}
		};
		createCursorContext();

		this.cursors = new CursorCollection(this.context);
E
Erich Gamma 已提交
138 139 140
		this.cursorUndoStack = [];

		this._isHandling = false;
141
		this._isDoingComposition = false;
E
Erich Gamma 已提交
142 143

		this.modelUnbinds = [];
144 145 146 147 148 149 150 151 152 153

		this.modelUnbinds.push(this.model.addBulkListener((events) => {
			if (this._isHandling) {
				return;
			}

			let hadContentChange = false;
			let hadFlushEvent = false;
			for (let i = 0, len = events.length; i < len; i++) {
				const event = events[i];
A
Alex Dima 已提交
154
				const eventType = event.type;
155

A
Alex Dima 已提交
156
				if (eventType === TextModelEventType.ModelRawContentChanged2) {
157
					hadContentChange = true;
158
					const changeEvent = <ModelRawContentChangedEvent>event.data;
159

160 161
					for (let j = 0, lenJ = changeEvent.changes.length; j < lenJ; j++) {
						const change = changeEvent.changes[j];
162
						if (change.changeType === RawContentChangedType.Flush) {
163 164
							hadFlushEvent = true;
						}
165 166 167 168 169 170 171 172 173
					}
				}
			}

			if (!hadContentChange) {
				return;
			}

			this._onModelContentChanged(hadFlushEvent);
E
Erich Gamma 已提交
174
		}));
A
Alex Dima 已提交
175

A
Alex Dima 已提交
176
		this.modelUnbinds.push(this.model.onDidChangeLanguage((e) => {
A
Alex Dima 已提交
177
			createCursorContext();
E
Erich Gamma 已提交
178
		}));
179 180
		this.modelUnbinds.push(LanguageConfigurationRegistry.onDidChange(() => {
			// TODO@Alex: react only if certain supports changed? (and if my model's mode changed)
A
Alex Dima 已提交
181 182 183 184 185 186 187 188 189
			createCursorContext();
		}));
		this.modelUnbinds.push(model.onDidChangeOptions(() => {
			createCursorContext();
		}));
		this.modelUnbinds.push(this.configuration.onDidChange((e) => {
			if (CursorConfiguration.shouldRecreate(e)) {
				createCursorContext();
			}
E
Erich Gamma 已提交
190 191
		}));

A
Alex Dima 已提交
192
		this._handlers = {};
E
Erich Gamma 已提交
193 194 195 196
		this._registerHandlers();
	}

	public dispose(): void {
J
Joao Moreno 已提交
197
		this.modelUnbinds = dispose(this.modelUnbinds);
E
Erich Gamma 已提交
198 199 200 201 202 203 204 205
		this.model = null;
		this.cursors.dispose();
		this.cursors = null;
		this.configuration = null;
		this.viewModelHelper = null;
		super.dispose();
	}

A
Alex Dima 已提交
206
	public saveState(): editorCommon.ICursorState[] {
E
Erich Gamma 已提交
207 208

		var selections = this.cursors.getSelections(),
J
Johannes Rieken 已提交
209
			result: editorCommon.ICursorState[] = [],
210
			selection: Selection;
E
Erich Gamma 已提交
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230

		for (var i = 0; i < selections.length; i++) {
			selection = selections[i];

			result.push({
				inSelectionMode: !selection.isEmpty(),
				selectionStart: {
					lineNumber: selection.selectionStartLineNumber,
					column: selection.selectionStartColumn,
				},
				position: {
					lineNumber: selection.positionLineNumber,
					column: selection.positionColumn,
				}
			});
		}

		return result;
	}

J
Johannes Rieken 已提交
231
	public restoreState(states: editorCommon.ICursorState[]): void {
E
Erich Gamma 已提交
232

A
Alex Dima 已提交
233
		var desiredSelections: ISelection[] = [],
J
Johannes Rieken 已提交
234
			state: editorCommon.ICursorState;
E
Erich Gamma 已提交
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266

		for (var i = 0; i < states.length; i++) {
			state = states[i];

			var positionLineNumber = 1, positionColumn = 1;

			// Avoid missing properties on the literal
			if (state.position && state.position.lineNumber) {
				positionLineNumber = state.position.lineNumber;
			}
			if (state.position && state.position.column) {
				positionColumn = state.position.column;
			}

			var selectionStartLineNumber = positionLineNumber, selectionStartColumn = positionColumn;

			// Avoid missing properties on the literal
			if (state.selectionStart && state.selectionStart.lineNumber) {
				selectionStartLineNumber = state.selectionStart.lineNumber;
			}
			if (state.selectionStart && state.selectionStart.column) {
				selectionStartColumn = state.selectionStart.column;
			}

			desiredSelections.push({
				selectionStartLineNumber: selectionStartLineNumber,
				selectionStartColumn: selectionStartColumn,
				positionLineNumber: positionLineNumber,
				positionColumn: positionColumn
			});
		}

J
Johannes Rieken 已提交
267
		this._onHandler('restoreState', (ctx: IMultipleCursorOperationContext) => {
E
Erich Gamma 已提交
268 269
			this.cursors.setSelections(desiredSelections);
			return false;
A
Alex Dima 已提交
270
		}, 'restoreState', null);
E
Erich Gamma 已提交
271 272
	}

273 274
	private _onModelContentChanged(hadFlushEvent: boolean): void {
		if (hadFlushEvent) {
E
Erich Gamma 已提交
275 276 277
			// a model.setValue() was called
			this.cursors.dispose();

A
Alex Dima 已提交
278
			this.cursors = new CursorCollection(this.context);
E
Erich Gamma 已提交
279

A
Alex Dima 已提交
280 281
			this.emitCursorPositionChanged('model', editorCommon.CursorChangeReason.ContentFlush);
			this.emitCursorSelectionChanged('model', editorCommon.CursorChangeReason.ContentFlush);
E
Erich Gamma 已提交
282 283
		} else {
			if (!this._isHandling) {
284 285 286
				// Read the markers before entering `_onHandler`, since that would validate
				// the position and ruin the markers
				let selections: Selection[] = this.cursors.getAll().map((cursor) => {
A
Alex Dima 已提交
287
					return cursor.beginRecoverSelectionFromMarkers(this.context);
288
				});
J
Johannes Rieken 已提交
289
				this._onHandler('recoverSelectionFromMarkers', (ctx: IMultipleCursorOperationContext) => {
A
Alex Dima 已提交
290 291 292 293 294 295 296 297 298
					ctx.shouldPushStackElementBefore = true;
					ctx.shouldPushStackElementAfter = true;
					var result = this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => {
						ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.RecoverFromMarkers;
						ctx.shouldPushStackElementBefore = true;
						ctx.shouldPushStackElementAfter = true;
						ctx.shouldReveal = false;
						ctx.shouldRevealHorizontal = false;

A
Alex Dima 已提交
299
						return oneCursor.endRecoverSelectionFromMarkers(this.context, selections[cursorIndex]);
A
Alex Dima 已提交
300
					});
E
Erich Gamma 已提交
301 302 303
					ctx.shouldPushStackElementBefore = false;
					ctx.shouldPushStackElementAfter = false;
					return result;
A
Alex Dima 已提交
304
				}, 'modelChange', null);
E
Erich Gamma 已提交
305 306 307 308 309 310
			}
		}
	}

	// ------ some getters/setters

311
	public getSelection(): Selection {
E
Erich Gamma 已提交
312 313 314
		return this.cursors.getSelection(0);
	}

315
	public getSelections(): Selection[] {
E
Erich Gamma 已提交
316 317 318
		return this.cursors.getSelections();
	}

A
Alex Dima 已提交
319
	public getPosition(): Position {
E
Erich Gamma 已提交
320 321 322
		return this.cursors.getPosition(0);
	}

A
Alex Dima 已提交
323
	public setSelections(source: string, selections: ISelection[]): void {
J
Johannes Rieken 已提交
324
		this._onHandler('setSelections', (ctx: IMultipleCursorOperationContext) => {
E
Erich Gamma 已提交
325 326 327
			ctx.shouldReveal = false;
			this.cursors.setSelections(selections);
			return false;
A
Alex Dima 已提交
328
		}, source, null);
E
Erich Gamma 已提交
329 330 331 332
	}

	// ------ auxiliary handling logic

J
Johannes Rieken 已提交
333
	private _createAndInterpretHandlerCtx(eventSource: string, eventData: any, callback: (currentHandlerCtx: IMultipleCursorOperationContext) => void): boolean {
E
Erich Gamma 已提交
334

J
Johannes Rieken 已提交
335
		var currentHandlerCtx: IMultipleCursorOperationContext = {
A
Alex Dima 已提交
336
			cursorPositionChangeReason: editorCommon.CursorChangeReason.NotSet,
E
Erich Gamma 已提交
337 338 339 340 341 342 343
			shouldReveal: true,
			shouldRevealVerticalInCenter: false,
			shouldRevealHorizontal: true,
			shouldRevealTarget: RevealTarget.Primary,
			eventSource: eventSource,
			eventData: eventData,
			executeCommands: [],
344
			isAutoWhitespaceCommand: [],
E
Erich Gamma 已提交
345 346 347
			hasExecutedCommands: false,
			isCursorUndo: false,
			shouldPushStackElementBefore: false,
348
			shouldPushStackElementAfter: false,
A
Alex Dima 已提交
349 350
			setColumnSelectToLineNumber: 0,
			setColumnSelectToVisualColumn: 0
E
Erich Gamma 已提交
351 352 353 354 355 356 357 358 359 360
		};

		callback(currentHandlerCtx);

		this._interpretHandlerContext(currentHandlerCtx);
		this.cursors.normalize();

		return currentHandlerCtx.hasExecutedCommands;
	}

J
Johannes Rieken 已提交
361
	private _onHandler(command: string, handler: (ctx: IMultipleCursorOperationContext) => boolean, source: string, data: any): boolean {
E
Erich Gamma 已提交
362 363 364 365 366 367

		this._isHandling = true;

		var handled = false;

		try {
368 369 370
			var oldSelections = this.cursors.getSelections();
			var oldViewSelections = this.cursors.getViewSelections();

A
Alex Dima 已提交
371 372 373
			// ensure valid state on all cursors
			this.cursors.ensureValidState();

E
Erich Gamma 已提交
374 375
			var prevCursorsState = this.cursors.saveState();

A
Alex Dima 已提交
376 377
			var eventSource = source;
			var cursorPositionChangeReason: editorCommon.CursorChangeReason;
E
Erich Gamma 已提交
378 379 380 381 382 383
			var shouldReveal: boolean;
			var shouldRevealVerticalInCenter: boolean;
			var shouldRevealHorizontal: boolean;
			var shouldRevealTarget: RevealTarget;
			var isCursorUndo: boolean;

J
Johannes Rieken 已提交
384
			var hasExecutedCommands = this._createAndInterpretHandlerCtx(eventSource, data, (currentHandlerCtx: IMultipleCursorOperationContext) => {
E
Erich Gamma 已提交
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
				handled = handler(currentHandlerCtx);

				cursorPositionChangeReason = currentHandlerCtx.cursorPositionChangeReason;
				shouldReveal = currentHandlerCtx.shouldReveal;
				shouldRevealTarget = currentHandlerCtx.shouldRevealTarget;
				shouldRevealVerticalInCenter = currentHandlerCtx.shouldRevealVerticalInCenter;
				shouldRevealHorizontal = currentHandlerCtx.shouldRevealHorizontal;
				isCursorUndo = currentHandlerCtx.isCursorUndo;
			});

			if (hasExecutedCommands) {
				this.cursorUndoStack = [];
			}

			var newSelections = this.cursors.getSelections();
			var newViewSelections = this.cursors.getViewSelections();

			var somethingChanged = false;
			if (oldSelections.length !== newSelections.length) {
				somethingChanged = true;
			} else {
				for (var i = 0, len = oldSelections.length; !somethingChanged && i < len; i++) {
					if (!oldSelections[i].equalsSelection(newSelections[i])) {
						somethingChanged = true;
					}
				}
				for (var i = 0, len = oldViewSelections.length; !somethingChanged && i < len; i++) {
					if (!oldViewSelections[i].equalsSelection(newViewSelections[i])) {
						somethingChanged = true;
					}
				}
			}


			if (somethingChanged) {
				if (!hasExecutedCommands && !isCursorUndo) {
					this.cursorUndoStack.push(prevCursorsState);
				}
				if (this.cursorUndoStack.length > 50) {
					this.cursorUndoStack = this.cursorUndoStack.splice(0, this.cursorUndoStack.length - 50);
				}
				this.emitCursorPositionChanged(eventSource, cursorPositionChangeReason);

				if (shouldReveal) {
429
					this.revealRange(shouldRevealTarget, shouldRevealVerticalInCenter ? editorCommon.VerticalRevealType.Center : editorCommon.VerticalRevealType.Simple, shouldRevealHorizontal);
E
Erich Gamma 已提交
430 431 432
				}
				this.emitCursorSelectionChanged(eventSource, cursorPositionChangeReason);
			}
433

E
Erich Gamma 已提交
434
		} catch (err) {
A
Alex Dima 已提交
435
			onUnexpectedError(err);
E
Erich Gamma 已提交
436 437 438 439 440 441 442 443 444 445 446 447 448
		}

		this._isHandling = false;

		return handled;
	}

	private _interpretHandlerContext(ctx: IMultipleCursorOperationContext): void {
		if (ctx.shouldPushStackElementBefore) {
			this.model.pushStackElement();
			ctx.shouldPushStackElementBefore = false;
		}

A
Alex Dima 已提交
449 450 451
		this._columnSelectToLineNumber = ctx.setColumnSelectToLineNumber;
		this._columnSelectToVisualColumn = ctx.setColumnSelectToVisualColumn;

A
Alex Dima 已提交
452
		ctx.hasExecutedCommands = this._internalExecuteCommands(ctx.executeCommands, ctx.isAutoWhitespaceCommand) || ctx.hasExecutedCommands;
E
Erich Gamma 已提交
453 454 455 456 457 458 459 460
		ctx.executeCommands = [];

		if (ctx.shouldPushStackElementAfter) {
			this.model.pushStackElement();
			ctx.shouldPushStackElementAfter = false;
		}
	}

J
Johannes Rieken 已提交
461
	private _interpretCommandResult(cursorState: Selection[]): boolean {
462
		if (!cursorState || cursorState.length === 0) {
E
Erich Gamma 已提交
463 464 465 466 467 468 469
			return false;
		}

		this.cursors.setSelections(cursorState);
		return true;
	}

J
Johannes Rieken 已提交
470
	private _getEditOperationsFromCommand(ctx: IExecContext, majorIdentifier: number, command: editorCommon.ICommand, isAutoWhitespaceCommand: boolean): ICommandData {
E
Erich Gamma 已提交
471 472
		// This method acts as a transaction, if the command fails
		// everything it has done is ignored
A
Alex Dima 已提交
473
		var operations: editorCommon.IIdentifiedSingleEditOperation[] = [],
E
Erich Gamma 已提交
474 475
			operationMinor = 0;

J
Johannes Rieken 已提交
476
		var addEditOperation = (selection: Range, text: string) => {
E
Erich Gamma 已提交
477 478 479 480 481 482 483 484 485 486 487
			if (selection.isEmpty() && text === '') {
				// This command wants to add a no-op => no thank you
				return;
			}
			operations.push({
				identifier: {
					major: majorIdentifier,
					minor: operationMinor++
				},
				range: selection,
				text: text,
488 489
				forceMoveMarkers: false,
				isAutoWhitespaceEdit: isAutoWhitespaceCommand
E
Erich Gamma 已提交
490 491 492 493
			});
		};

		var hadTrackedRange = false;
J
Johannes Rieken 已提交
494 495 496
		var trackSelection = (selection: Selection, trackPreviousOnEmpty?: boolean) => {
			var selectionMarkerStickToPreviousCharacter: boolean,
				positionMarkerStickToPreviousCharacter: boolean;
E
Erich Gamma 已提交
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513

			if (selection.isEmpty()) {
				// Try to lock it with surrounding text
				if (typeof trackPreviousOnEmpty === 'boolean') {
					selectionMarkerStickToPreviousCharacter = trackPreviousOnEmpty;
					positionMarkerStickToPreviousCharacter = trackPreviousOnEmpty;
				} else {
					var maxLineColumn = this.model.getLineMaxColumn(selection.startLineNumber);
					if (selection.startColumn === maxLineColumn) {
						selectionMarkerStickToPreviousCharacter = true;
						positionMarkerStickToPreviousCharacter = true;
					} else {
						selectionMarkerStickToPreviousCharacter = false;
						positionMarkerStickToPreviousCharacter = false;
					}
				}
			} else {
514
				if (selection.getDirection() === SelectionDirection.LTR) {
E
Erich Gamma 已提交
515 516 517 518 519 520 521 522 523
					selectionMarkerStickToPreviousCharacter = false;
					positionMarkerStickToPreviousCharacter = true;
				} else {
					selectionMarkerStickToPreviousCharacter = true;
					positionMarkerStickToPreviousCharacter = false;
				}
			}

			var l = ctx.selectionStartMarkers.length;
A
Alex Dima 已提交
524 525
			ctx.selectionStartMarkers[l] = this.model._addMarker(0, selection.selectionStartLineNumber, selection.selectionStartColumn, selectionMarkerStickToPreviousCharacter);
			ctx.positionMarkers[l] = this.model._addMarker(0, selection.positionLineNumber, selection.positionColumn, positionMarkerStickToPreviousCharacter);
E
Erich Gamma 已提交
526 527 528
			return l.toString();
		};

J
Johannes Rieken 已提交
529
		var editOperationBuilder: editorCommon.IEditOperationBuilder = {
E
Erich Gamma 已提交
530 531 532 533 534 535 536 537
			addEditOperation: addEditOperation,
			trackSelection: trackSelection
		};

		try {
			command.getEditOperations(this.model, editOperationBuilder);
		} catch (e) {
			e.friendlyMessage = nls.localize('corrupt.commands', "Unexpected exception while executing command.");
A
Alex Dima 已提交
538
			onUnexpectedError(e);
E
Erich Gamma 已提交
539 540 541 542 543 544 545 546 547 548 549 550
			return {
				operations: [],
				hadTrackedRange: false
			};
		}

		return {
			operations: operations,
			hadTrackedRange: hadTrackedRange
		};
	}

J
Johannes Rieken 已提交
551
	private _getEditOperations(ctx: IExecContext, commands: editorCommon.ICommand[], isAutoWhitespaceCommand: boolean[]): ICommandsData {
E
Erich Gamma 已提交
552
		var oneResult: ICommandData;
A
Alex Dima 已提交
553
		var operations: editorCommon.IIdentifiedSingleEditOperation[] = [];
E
Erich Gamma 已提交
554 555 556 557 558
		var hadTrackedRanges: boolean[] = [];
		var anyoneHadTrackedRange: boolean;

		for (var i = 0; i < commands.length; i++) {
			if (commands[i]) {
559
				oneResult = this._getEditOperationsFromCommand(ctx, i, commands[i], isAutoWhitespaceCommand[i]);
E
Erich Gamma 已提交
560 561 562 563 564 565 566 567 568 569 570 571 572 573
				operations = operations.concat(oneResult.operations);
				hadTrackedRanges[i] = oneResult.hadTrackedRange;
				anyoneHadTrackedRange = anyoneHadTrackedRange || hadTrackedRanges[i];
			} else {
				hadTrackedRanges[i] = false;
			}
		}
		return {
			operations: operations,
			hadTrackedRanges: hadTrackedRanges,
			anyoneHadTrackedRange: anyoneHadTrackedRange
		};
	}

A
Alex Dima 已提交
574
	private _getLoserCursorMap(operations: editorCommon.IIdentifiedSingleEditOperation[]): { [index: string]: boolean; } {
E
Erich Gamma 已提交
575 576 577 578
		// This is destructive on the array
		operations = operations.slice(0);

		// Sort operations with last one first
J
Johannes Rieken 已提交
579
		operations.sort((a: editorCommon.IIdentifiedSingleEditOperation, b: editorCommon.IIdentifiedSingleEditOperation): number => {
E
Erich Gamma 已提交
580 581 582 583 584
			// Note the minus!
			return -(Range.compareRangesUsingEnds(a.range, b.range));
		});

		// Operations can not overlap!
J
Johannes Rieken 已提交
585
		var loserCursorsMap: { [index: string]: boolean; } = {};
E
Erich Gamma 已提交
586

A
Alex Dima 已提交
587 588
		var previousOp: editorCommon.IIdentifiedSingleEditOperation;
		var currentOp: editorCommon.IIdentifiedSingleEditOperation;
E
Erich Gamma 已提交
589 590 591 592 593 594
		var loserMajor: number;

		for (var i = 1; i < operations.length; i++) {
			previousOp = operations[i - 1];
			currentOp = operations[i];

595
			if (previousOp.range.getStartPosition().isBefore(currentOp.range.getEndPosition())) {
E
Erich Gamma 已提交
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624

				if (previousOp.identifier.major > currentOp.identifier.major) {
					// previousOp loses the battle
					loserMajor = previousOp.identifier.major;
				} else {
					loserMajor = currentOp.identifier.major;
				}

				loserCursorsMap[loserMajor.toString()] = true;

				for (var j = 0; j < operations.length; j++) {
					if (operations[j].identifier.major === loserMajor) {
						operations.splice(j, 1);
						if (j < i) {
							i--;
						}
						j--;
					}
				}

				if (i > 0) {
					i--;
				}
			}
		}

		return loserCursorsMap;
	}

A
Alex Dima 已提交
625
	private _collapseDeleteCommands(rawCmds: editorCommon.ICommand[], isAutoWhitespaceCommand: boolean[]): boolean {
E
Erich Gamma 已提交
626
		if (rawCmds.length === 1) {
M
Matt Bierner 已提交
627
			return false;
E
Erich Gamma 已提交
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
		}

		// Merge adjacent delete commands
		var allAreDeleteCommands = rawCmds.every((command) => {
			if (!(command instanceof ReplaceCommand)) {
				return false;
			}
			var replCmd = (<ReplaceCommand>command);
			if (replCmd.getText().length > 0) {
				return false;
			}
			return true;
		});

		if (!allAreDeleteCommands) {
M
Matt Bierner 已提交
643
			return false;
E
Erich Gamma 已提交
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
		}

		var commands = <ReplaceCommand[]>rawCmds;
		var cursors = commands.map((cmd, i) => {
			return {
				range: commands[i].getRange(),
				order: i
			};
		});

		cursors.sort((a, b) => {
			return Range.compareRangesUsingStarts(a.range, b.range);
		});

		var previousCursor = cursors[0];
		for (var i = 1; i < cursors.length; i++) {
			if (previousCursor.range.endLineNumber === cursors[i].range.startLineNumber && previousCursor.range.endColumn === cursors[i].range.startColumn) {
				// Merge ranges
				var mergedRange = new Range(
					previousCursor.range.startLineNumber,
					previousCursor.range.startColumn,
					cursors[i].range.endLineNumber,
					cursors[i].range.endColumn
				);

				previousCursor.range = mergedRange;

				commands[cursors[i].order].setRange(mergedRange);
				commands[previousCursor.order].setRange(mergedRange);
			} else {
				// Push previous cursor
				previousCursor = cursors[i];
			}
		}
M
Matt Bierner 已提交
678
		return false;
E
Erich Gamma 已提交
679 680
	}

A
Alex Dima 已提交
681
	private _internalExecuteCommands(commands: editorCommon.ICommand[], isAutoWhitespaceCommand: boolean[]): boolean {
J
Johannes Rieken 已提交
682
		var ctx: IExecContext = {
E
Erich Gamma 已提交
683 684 685 686
			selectionStartMarkers: [],
			positionMarkers: []
		};

A
Alex Dima 已提交
687
		this._collapseDeleteCommands(commands, isAutoWhitespaceCommand);
E
Erich Gamma 已提交
688

A
Alex Dima 已提交
689
		var r = this._innerExecuteCommands(ctx, commands, isAutoWhitespaceCommand);
E
Erich Gamma 已提交
690 691 692 693 694 695 696
		for (var i = 0; i < ctx.selectionStartMarkers.length; i++) {
			this.model._removeMarker(ctx.selectionStartMarkers[i]);
			this.model._removeMarker(ctx.positionMarkers[i]);
		}
		return r;
	}

A
Alex Dima 已提交
697
	private _arrayIsEmpty(commands: editorCommon.ICommand[]): boolean {
J
Johannes Rieken 已提交
698 699
		var i: number,
			len: number;
E
Erich Gamma 已提交
700 701 702 703 704 705 706 707 708 709

		for (i = 0, len = commands.length; i < len; i++) {
			if (commands[i]) {
				return false;
			}
		}

		return true;
	}

A
Alex Dima 已提交
710
	private _innerExecuteCommands(ctx: IExecContext, commands: editorCommon.ICommand[], isAutoWhitespaceCommand: boolean[]): boolean {
E
Erich Gamma 已提交
711 712 713 714 715 716 717 718 719 720 721

		if (this.configuration.editor.readOnly) {
			return false;
		}

		if (this._arrayIsEmpty(commands)) {
			return false;
		}

		var selectionsBefore = this.cursors.getSelections();

722
		var commandsData = this._getEditOperations(ctx, commands, isAutoWhitespaceCommand);
E
Erich Gamma 已提交
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
		if (commandsData.operations.length === 0 && !commandsData.anyoneHadTrackedRange) {
			return false;
		}

		var rawOperations = commandsData.operations;

		var editableRange = this.model.getEditableRange();
		var editableRangeStart = editableRange.getStartPosition();
		var editableRangeEnd = editableRange.getEndPosition();
		for (var i = 0; i < rawOperations.length; i++) {
			var operationRange = rawOperations[i].range;
			if (!editableRangeStart.isBeforeOrEqual(operationRange.getStartPosition()) || !operationRange.getEndPosition().isBeforeOrEqual(editableRangeEnd)) {
				// These commands are outside of the editable range
				return false;
			}
		}

		var loserCursorsMap = this._getLoserCursorMap(rawOperations);
		if (loserCursorsMap.hasOwnProperty('0')) {
			// These commands are very messed up
			console.warn('Ignoring commands');
			return false;
		}

		// Remove operations belonging to losing cursors
A
Alex Dima 已提交
748
		var filteredOperations: editorCommon.IIdentifiedSingleEditOperation[] = [];
E
Erich Gamma 已提交
749 750 751 752 753 754
		for (var i = 0; i < rawOperations.length; i++) {
			if (!loserCursorsMap.hasOwnProperty(rawOperations[i].identifier.major.toString())) {
				filteredOperations.push(rawOperations[i]);
			}
		}

J
Johannes Rieken 已提交
755 756
		var selectionsAfter = this.model.pushEditOperations(selectionsBefore, filteredOperations, (inverseEditOperations: editorCommon.IIdentifiedSingleEditOperation[]): Selection[] => {
			var groupedInverseEditOperations: editorCommon.IIdentifiedSingleEditOperation[][] = [];
E
Erich Gamma 已提交
757 758 759 760 761
			for (var i = 0; i < selectionsBefore.length; i++) {
				groupedInverseEditOperations[i] = [];
			}
			for (var i = 0; i < inverseEditOperations.length; i++) {
				var op = inverseEditOperations[i];
762 763 764 765
				if (!op.identifier) {
					// perhaps auto whitespace trim edits
					continue;
				}
E
Erich Gamma 已提交
766 767
				groupedInverseEditOperations[op.identifier.major].push(op);
			}
J
Johannes Rieken 已提交
768
			var minorBasedSorter = (a: editorCommon.IIdentifiedSingleEditOperation, b: editorCommon.IIdentifiedSingleEditOperation) => {
E
Erich Gamma 已提交
769 770
				return a.identifier.minor - b.identifier.minor;
			};
771
			var cursorSelections: Selection[] = [];
E
Erich Gamma 已提交
772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
			for (var i = 0; i < selectionsBefore.length; i++) {
				if (groupedInverseEditOperations[i].length > 0 || commandsData.hadTrackedRanges[i]) {
					groupedInverseEditOperations[i].sort(minorBasedSorter);
					cursorSelections[i] = commands[i].computeCursorState(this.model, {
						getInverseEditOperations: () => {
							return groupedInverseEditOperations[i];
						},

						getTrackedSelection: (id: string) => {
							var idx = parseInt(id, 10);
							var selectionStartMarker = this.model._getMarker(ctx.selectionStartMarkers[idx]);
							var positionMarker = this.model._getMarker(ctx.positionMarkers[idx]);
							return new Selection(selectionStartMarker.lineNumber, selectionStartMarker.column, positionMarker.lineNumber, positionMarker.column);
						}
					});
				} else {
					cursorSelections[i] = selectionsBefore[i];
				}
			}
			return cursorSelections;
		});

		// Extract losing cursors
		var losingCursorIndex: string;
		var losingCursors: number[] = [];
		for (losingCursorIndex in loserCursorsMap) {
			if (loserCursorsMap.hasOwnProperty(losingCursorIndex)) {
				losingCursors.push(parseInt(losingCursorIndex, 10));
			}
		}

		// Sort losing cursors descending
J
Johannes Rieken 已提交
804
		losingCursors.sort((a: number, b: number): number => {
E
Erich Gamma 已提交
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
			return b - a;
		});

		// Remove losing cursors
		for (var i = 0; i < losingCursors.length; i++) {
			selectionsAfter.splice(losingCursors[i], 1);
		}

		return this._interpretCommandResult(selectionsAfter);
	}


	// -----------------------------------------------------------------------------------------------------------
	// ----- emitting events

J
Johannes Rieken 已提交
820
	private emitCursorPositionChanged(source: string, reason: editorCommon.CursorChangeReason): void {
E
Erich Gamma 已提交
821 822 823 824 825 826 827 828
		var positions = this.cursors.getPositions();
		var primaryPosition = positions[0];
		var secondaryPositions = positions.slice(1);

		var viewPositions = this.cursors.getViewPositions();
		var primaryViewPosition = viewPositions[0];
		var secondaryViewPositions = viewPositions.slice(1);

J
Johannes Rieken 已提交
829
		var isInEditableRange: boolean = true;
E
Erich Gamma 已提交
830 831 832 833 834 835
		if (this.model.hasEditableRange()) {
			var editableRange = this.model.getEditableRange();
			if (!editableRange.containsPosition(primaryPosition)) {
				isInEditableRange = false;
			}
		}
J
Johannes Rieken 已提交
836
		var e: editorCommon.ICursorPositionChangedEvent = {
E
Erich Gamma 已提交
837 838 839 840 841 842 843 844
			position: primaryPosition,
			viewPosition: primaryViewPosition,
			secondaryPositions: secondaryPositions,
			secondaryViewPositions: secondaryViewPositions,
			reason: reason,
			source: source,
			isInEditableRange: isInEditableRange
		};
A
Alex Dima 已提交
845
		this.emit(CursorEventType.CursorPositionChanged, e);
E
Erich Gamma 已提交
846 847
	}

J
Johannes Rieken 已提交
848
	private emitCursorSelectionChanged(source: string, reason: editorCommon.CursorChangeReason): void {
849 850 851
		let selections = this.cursors.getSelections();
		let primarySelection = selections[0];
		let secondarySelections = selections.slice(1);
E
Erich Gamma 已提交
852

853 854 855 856
		let viewSelections = this.cursors.getViewSelections();
		let primaryViewSelection = viewSelections[0];
		let secondaryViewSelections = viewSelections.slice(1);

J
Johannes Rieken 已提交
857
		let e: editorCommon.ICursorSelectionChangedEvent = {
E
Erich Gamma 已提交
858
			selection: primarySelection,
859
			viewSelection: primaryViewSelection,
E
Erich Gamma 已提交
860
			secondarySelections: secondarySelections,
861
			secondaryViewSelections: secondaryViewSelections,
E
Erich Gamma 已提交
862 863 864
			source: source,
			reason: reason
		};
A
Alex Dima 已提交
865
		this.emit(CursorEventType.CursorSelectionChanged, e);
E
Erich Gamma 已提交
866 867
	}

868
	private emitCursorScrollRequest(deltaLines: number, revealCursor: boolean): void {
J
Johannes Rieken 已提交
869
		var e: editorCommon.ICursorScrollRequestEvent = {
870 871
			deltaLines,
			revealCursor
872
		};
A
Alex Dima 已提交
873
		this.emit(CursorEventType.CursorScrollRequest, e);
874 875
	}

876
	private revealRange(revealTarget: RevealTarget, verticalType: editorCommon.VerticalRevealType, revealHorizontal: boolean): void {
E
Erich Gamma 已提交
877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905
		var positions = this.cursors.getPositions();
		var viewPositions = this.cursors.getViewPositions();

		var position = positions[0];
		var viewPosition = viewPositions[0];

		if (revealTarget === RevealTarget.TopMost) {
			for (var i = 1; i < positions.length; i++) {
				if (positions[i].isBefore(position)) {
					position = positions[i];
					viewPosition = viewPositions[i];
				}
			}
		} else if (revealTarget === RevealTarget.BottomMost) {
			for (var i = 1; i < positions.length; i++) {
				if (position.isBeforeOrEqual(positions[i])) {
					position = positions[i];
					viewPosition = viewPositions[i];
				}
			}
		} else {
			if (positions.length > 1) {
				// no revealing!
				return;
			}
		}

		var range = new Range(position.lineNumber, position.column, position.lineNumber, position.column);
		var viewRange = new Range(viewPosition.lineNumber, viewPosition.column, viewPosition.lineNumber, viewPosition.column);
906
		this.emitCursorRevealRange(range, viewRange, verticalType, revealHorizontal, false);
907 908
	}

909
	private emitCursorRevealRange(range: Range, viewRange: Range, verticalType: editorCommon.VerticalRevealType, revealHorizontal: boolean, revealCursor: boolean) {
J
Johannes Rieken 已提交
910
		var e: editorCommon.ICursorRevealRangeEvent = {
E
Erich Gamma 已提交
911 912 913
			range: range,
			viewRange: viewRange,
			verticalType: verticalType,
914 915
			revealHorizontal: revealHorizontal,
			revealCursor: revealCursor
E
Erich Gamma 已提交
916
		};
A
Alex Dima 已提交
917
		this.emit(CursorEventType.CursorRevealRange, e);
E
Erich Gamma 已提交
918 919 920 921 922
	}

	// -----------------------------------------------------------------------------------------------------------
	// ----- handlers beyond this point

J
Johannes Rieken 已提交
923
	public trigger(source: string, handlerId: string, payload: any): void {
A
Alex Dima 已提交
924 925 926 927 928 929 930
		if (!this._handlers.hasOwnProperty(handlerId)) {
			return;
		}
		let handler = this._handlers[handlerId];
		this._onHandler(handlerId, handler, source, payload);
	}

E
Erich Gamma 已提交
931
	private _registerHandlers(): void {
A
Alex Dima 已提交
932
		let H = editorCommon.Handler;
E
Erich Gamma 已提交
933

J
Johannes Rieken 已提交
934 935 936 937 938 939 940 941
		this._handlers[H.CursorMove] = (ctx) => this._cursorMove(ctx);
		this._handlers[H.MoveTo] = (ctx) => this._moveTo(false, ctx);
		this._handlers[H.MoveToSelect] = (ctx) => this._moveTo(true, ctx);
		this._handlers[H.ColumnSelect] = (ctx) => this._columnSelectMouse(ctx);
		this._handlers[H.AddCursorUp] = (ctx) => this._addCursorUp(ctx);
		this._handlers[H.AddCursorDown] = (ctx) => this._addCursorDown(ctx);
		this._handlers[H.CreateCursor] = (ctx) => this._createCursor(ctx);
		this._handlers[H.LastCursorMoveToSelect] = (ctx) => this._lastCursorMoveTo(ctx);
942 943


J
Johannes Rieken 已提交
944 945
		this._handlers[H.CursorLeft] = (ctx) => this._moveLeft(false, ctx);
		this._handlers[H.CursorLeftSelect] = (ctx) => this._moveLeft(true, ctx);
E
Erich Gamma 已提交
946

J
Johannes Rieken 已提交
947 948
		this._handlers[H.CursorRight] = (ctx) => this._moveRight(false, ctx);
		this._handlers[H.CursorRightSelect] = (ctx) => this._moveRight(true, ctx);
E
Erich Gamma 已提交
949

J
Johannes Rieken 已提交
950 951 952 953
		this._handlers[H.CursorUp] = (ctx) => this._moveUp(false, false, ctx);
		this._handlers[H.CursorUpSelect] = (ctx) => this._moveUp(true, false, ctx);
		this._handlers[H.CursorDown] = (ctx) => this._moveDown(false, false, ctx);
		this._handlers[H.CursorDownSelect] = (ctx) => this._moveDown(true, false, ctx);
E
Erich Gamma 已提交
954

J
Johannes Rieken 已提交
955 956 957 958
		this._handlers[H.CursorPageUp] = (ctx) => this._moveUp(false, true, ctx);
		this._handlers[H.CursorPageUpSelect] = (ctx) => this._moveUp(true, true, ctx);
		this._handlers[H.CursorPageDown] = (ctx) => this._moveDown(false, true, ctx);
		this._handlers[H.CursorPageDownSelect] = (ctx) => this._moveDown(true, true, ctx);
E
Erich Gamma 已提交
959

J
Johannes Rieken 已提交
960 961
		this._handlers[H.CursorHome] = (ctx) => this._moveToBeginningOfLine(false, ctx);
		this._handlers[H.CursorHomeSelect] = (ctx) => this._moveToBeginningOfLine(true, ctx);
E
Erich Gamma 已提交
962

J
Johannes Rieken 已提交
963 964
		this._handlers[H.CursorEnd] = (ctx) => this._moveToEndOfLine(false, ctx);
		this._handlers[H.CursorEndSelect] = (ctx) => this._moveToEndOfLine(true, ctx);
A
Alex Dima 已提交
965

J
Johannes Rieken 已提交
966 967 968 969
		this._handlers[H.CursorTop] = (ctx) => this._moveToBeginningOfBuffer(false, ctx);
		this._handlers[H.CursorTopSelect] = (ctx) => this._moveToBeginningOfBuffer(true, ctx);
		this._handlers[H.CursorBottom] = (ctx) => this._moveToEndOfBuffer(false, ctx);
		this._handlers[H.CursorBottomSelect] = (ctx) => this._moveToEndOfBuffer(true, ctx);
E
Erich Gamma 已提交
970

J
Johannes Rieken 已提交
971 972 973 974 975 976
		this._handlers[H.CursorColumnSelectLeft] = (ctx) => this._columnSelectLeft(ctx);
		this._handlers[H.CursorColumnSelectRight] = (ctx) => this._columnSelectRight(ctx);
		this._handlers[H.CursorColumnSelectUp] = (ctx) => this._columnSelectUp(false, ctx);
		this._handlers[H.CursorColumnSelectPageUp] = (ctx) => this._columnSelectUp(true, ctx);
		this._handlers[H.CursorColumnSelectDown] = (ctx) => this._columnSelectDown(false, ctx);
		this._handlers[H.CursorColumnSelectPageDown] = (ctx) => this._columnSelectDown(true, ctx);
E
Erich Gamma 已提交
977

J
Johannes Rieken 已提交
978
		this._handlers[H.SelectAll] = (ctx) => this._selectAll(ctx);
E
Erich Gamma 已提交
979

J
Johannes Rieken 已提交
980 981 982 983
		this._handlers[H.LineSelect] = (ctx) => this._line(false, ctx);
		this._handlers[H.LineSelectDrag] = (ctx) => this._line(true, ctx);
		this._handlers[H.LastCursorLineSelect] = (ctx) => this._lastCursorLine(false, ctx);
		this._handlers[H.LastCursorLineSelectDrag] = (ctx) => this._lastCursorLine(true, ctx);
E
Erich Gamma 已提交
984

J
Johannes Rieken 已提交
985 986 987
		this._handlers[H.LineInsertBefore] = (ctx) => this._lineInsertBefore(ctx);
		this._handlers[H.LineInsertAfter] = (ctx) => this._lineInsertAfter(ctx);
		this._handlers[H.LineBreakInsert] = (ctx) => this._lineBreakInsert(ctx);
E
Erich Gamma 已提交
988

J
Johannes Rieken 已提交
989 990 991 992 993
		this._handlers[H.WordSelect] = (ctx) => this._word(false, ctx);
		this._handlers[H.WordSelectDrag] = (ctx) => this._word(true, ctx);
		this._handlers[H.LastCursorWordSelect] = (ctx) => this._lastCursorWord(ctx);
		this._handlers[H.CancelSelection] = (ctx) => this._cancelSelection(ctx);
		this._handlers[H.RemoveSecondaryCursors] = (ctx) => this._removeSecondaryCursors(ctx);
994

J
Johannes Rieken 已提交
995 996
		this._handlers[H.Type] = (ctx) => this._type(ctx);
		this._handlers[H.ReplacePreviousChar] = (ctx) => this._replacePreviousChar(ctx);
997 998
		this._handlers[H.CompositionStart] = (ctx) => this._compositionStart(ctx);
		this._handlers[H.CompositionEnd] = (ctx) => this._compositionEnd(ctx);
J
Johannes Rieken 已提交
999 1000 1001 1002
		this._handlers[H.Tab] = (ctx) => this._tab(ctx);
		this._handlers[H.Indent] = (ctx) => this._indent(ctx);
		this._handlers[H.Outdent] = (ctx) => this._outdent(ctx);
		this._handlers[H.Paste] = (ctx) => this._paste(ctx);
1003

J
Johannes Rieken 已提交
1004
		this._handlers[H.EditorScroll] = (ctx) => this._editorScroll(ctx);
1005

J
Johannes Rieken 已提交
1006 1007 1008 1009
		this._handlers[H.ScrollLineUp] = (ctx) => this._scrollUp(false, ctx);
		this._handlers[H.ScrollLineDown] = (ctx) => this._scrollDown(false, ctx);
		this._handlers[H.ScrollPageUp] = (ctx) => this._scrollUp(true, ctx);
		this._handlers[H.ScrollPageDown] = (ctx) => this._scrollDown(true, ctx);
1010

J
Johannes Rieken 已提交
1011 1012
		this._handlers[H.DeleteLeft] = (ctx) => this._deleteLeft(ctx);
		this._handlers[H.DeleteRight] = (ctx) => this._deleteRight(ctx);
E
Erich Gamma 已提交
1013

J
Johannes Rieken 已提交
1014
		this._handlers[H.Cut] = (ctx) => this._cut(ctx);
E
Erich Gamma 已提交
1015

J
Johannes Rieken 已提交
1016
		this._handlers[H.ExpandLineSelection] = (ctx) => this._expandLineSelection(ctx);
E
Erich Gamma 已提交
1017

J
Johannes Rieken 已提交
1018 1019 1020
		this._handlers[H.Undo] = (ctx) => this._undo(ctx);
		this._handlers[H.CursorUndo] = (ctx) => this._cursorUndo(ctx);
		this._handlers[H.Redo] = (ctx) => this._redo(ctx);
E
Erich Gamma 已提交
1021

J
Johannes Rieken 已提交
1022 1023
		this._handlers[H.ExecuteCommand] = (ctx) => this._externalExecuteCommand(ctx);
		this._handlers[H.ExecuteCommands] = (ctx) => this._externalExecuteCommands(ctx);
1024

J
Johannes Rieken 已提交
1025
		this._handlers[H.RevealLine] = (ctx) => this._revealLine(ctx);
E
Erich Gamma 已提交
1026 1027
	}

A
Alex Dima 已提交
1028 1029
	private _invokeForAllSorted(ctx: IMultipleCursorOperationContext, callable: (cursorIndex: number, cursor: OneCursor, ctx: IOneCursorOperationContext) => boolean): boolean {
		return this._doInvokeForAll(ctx, true, callable);
1030 1031
	}

A
Alex Dima 已提交
1032 1033
	private _invokeForAll(ctx: IMultipleCursorOperationContext, callable: (cursorIndex: number, cursor: OneCursor, ctx: IOneCursorOperationContext) => boolean): boolean {
		return this._doInvokeForAll(ctx, false, callable);
1034 1035
	}

A
Alex Dima 已提交
1036
	private _doInvokeForAll(ctx: IMultipleCursorOperationContext, sorted: boolean, callable: (cursorIndex: number, cursor: OneCursor, ctx: IOneCursorOperationContext) => boolean): boolean {
1037 1038 1039 1040 1041
		let result = false;
		let cursors = this.cursors.getAll();

		if (sorted) {
			cursors = cursors.sort((a, b) => {
A
Alex Dima 已提交
1042
				return Range.compareRangesUsingStarts(a.modelState.selection, b.modelState.selection);
1043 1044 1045
			});
		}

J
Johannes Rieken 已提交
1046
		let context: IOneCursorOperationContext;
E
Erich Gamma 已提交
1047

1048
		for (let i = 0; i < cursors.length; i++) {
E
Erich Gamma 已提交
1049 1050 1051 1052
			context = {
				shouldReveal: true,
				shouldRevealHorizontal: true,
				executeCommand: null,
1053
				isAutoWhitespaceCommand: false,
E
Erich Gamma 已提交
1054
				shouldPushStackElementBefore: false,
1055
				shouldPushStackElementAfter: false
E
Erich Gamma 已提交
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
			};

			result = callable(i, cursors[i], context) || result;

			if (i === 0) {
				ctx.shouldRevealHorizontal = context.shouldRevealHorizontal;
				ctx.shouldReveal = context.shouldReveal;
			}

			ctx.shouldPushStackElementBefore = ctx.shouldPushStackElementBefore || context.shouldPushStackElementBefore;
			ctx.shouldPushStackElementAfter = ctx.shouldPushStackElementAfter || context.shouldPushStackElementAfter;

			ctx.executeCommands[i] = context.executeCommand;
1069
			ctx.isAutoWhitespaceCommand[i] = context.isAutoWhitespaceCommand;
E
Erich Gamma 已提交
1070 1071 1072 1073 1074
		}

		return result;
	}

J
Johannes Rieken 已提交
1075
	private _moveTo(inSelectionMode: boolean, ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1076 1077 1078 1079 1080 1081 1082 1083
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
		if (ctx.eventSource === 'api') {
			ctx.shouldRevealVerticalInCenter = true;
		}
		if (ctx.eventSource === 'mouse') {
			ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit;
		}
A
Alex Dima 已提交
1084
		const result = OneCursorOp.moveTo(this.context, this.cursors.getPrimaryCursor(), inSelectionMode, ctx.eventData.position, ctx.eventData.viewPosition);
A
Alex Dima 已提交
1085 1086
		this.cursors.setStates([result], false);
		return true;
E
Erich Gamma 已提交
1087 1088
	}

S
Sandeep Somavarapu 已提交
1089
	private _cursorMove(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1090 1091 1092 1093 1094
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit;
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
		ctx.shouldReveal = true;
		ctx.shouldRevealHorizontal = true;
A
Alex Dima 已提交
1095
		this.cursors.setStates(OneCursorOp.move(this.context, this.cursors.getAll(), ctx.eventData), true);
A
Alex Dima 已提交
1096
		return true;
1097 1098
	}

A
Alex Dima 已提交
1099 1100 1101
	private _columnSelectToLineNumber: number = 0;
	private _getColumnSelectToLineNumber(): number {
		if (!this._columnSelectToLineNumber) {
A
Alex Dima 已提交
1102
			let primaryCursor = this.cursors.getPrimaryCursor();
A
Alex Dima 已提交
1103
			let primaryPos = primaryCursor.viewState.position;
A
Alex Dima 已提交
1104
			return primaryPos.lineNumber;
A
Alex Dima 已提交
1105
		}
A
Alex Dima 已提交
1106 1107
		return this._columnSelectToLineNumber;
	}
A
Alex Dima 已提交
1108

A
Alex Dima 已提交
1109 1110 1111
	private _columnSelectToVisualColumn: number = 0;
	private _getColumnSelectToVisualColumn(): number {
		if (!this._columnSelectToVisualColumn) {
A
Alex Dima 已提交
1112
			let primaryCursor = this.cursors.getPrimaryCursor();
A
Alex Dima 已提交
1113
			let primaryPos = primaryCursor.viewState.position;
A
Alex Dima 已提交
1114
			return CursorColumns.visibleColumnFromColumn2(this.context.config, this.context.viewModel, primaryPos);
A
Alex Dima 已提交
1115 1116 1117 1118 1119
		}
		return this._columnSelectToVisualColumn;
	}

	private _columnSelectMouse(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1120
		let primary = this.cursors.getPrimaryCursor();
1121 1122

		// validate `eventData`
A
Alex Dima 已提交
1123
		let validatedPosition = this.context.model.validatePosition(ctx.eventData.position);
1124 1125
		let validatedViewPosition: Position;
		if (ctx.eventData.viewPosition) {
A
Alex Dima 已提交
1126
			validatedViewPosition = this.context.validateViewPosition(new Position(ctx.eventData.viewPosition.lineNumber, ctx.eventData.viewPosition.column), validatedPosition);
1127
		} else {
A
Alex Dima 已提交
1128
			validatedViewPosition = this.context.convertModelPositionToViewPosition(validatedPosition);
1129 1130
		}

A
Alex Dima 已提交
1131 1132
		let result = ColumnSelection.columnSelect(this.context.config, this.context.viewModel, primary.viewState.selection, validatedViewPosition.lineNumber, ctx.eventData.mouseColumn - 1);
		let selections = result.viewSelections.map(viewSel => this.context.convertViewSelectionToModelSelection(viewSel));
A
Alex Dima 已提交
1133 1134 1135 1136 1137 1138

		ctx.shouldRevealTarget = (result.reversed ? RevealTarget.TopMost : RevealTarget.BottomMost);
		ctx.shouldReveal = true;
		ctx.setColumnSelectToLineNumber = result.toLineNumber;
		ctx.setColumnSelectToVisualColumn = result.toVisualColumn;

1139
		this.cursors.setSelections(selections, result.viewSelections);
A
Alex Dima 已提交
1140 1141 1142
		return true;
	}

J
Johannes Rieken 已提交
1143
	private _columnSelectOp(ctx: IMultipleCursorOperationContext, op: (cursor: OneCursor, toViewLineNumber: number, toViewVisualColumn: number) => IColumnSelectResult): boolean {
A
Alex Dima 已提交
1144
		let primary = this.cursors.getPrimaryCursor();
A
Alex Dima 已提交
1145
		let result = op(primary, this._getColumnSelectToLineNumber(), this._getColumnSelectToVisualColumn());
A
Alex Dima 已提交
1146
		let selections = result.viewSelections.map(viewSel => this.context.convertViewSelectionToModelSelection(viewSel));
A
Alex Dima 已提交
1147 1148 1149

		ctx.shouldRevealTarget = (result.reversed ? RevealTarget.TopMost : RevealTarget.BottomMost);
		ctx.shouldReveal = true;
A
Alex Dima 已提交
1150 1151
		ctx.setColumnSelectToLineNumber = result.toLineNumber;
		ctx.setColumnSelectToVisualColumn = result.toVisualColumn;
A
Alex Dima 已提交
1152

1153
		this.cursors.setSelections(selections, result.viewSelections);
A
Alex Dima 已提交
1154 1155 1156
		return true;
	}

A
Alex Dima 已提交
1157
	private _columnSelectLeft(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1158
		return this._columnSelectOp(ctx, (cursor, toViewLineNumber, toViewVisualColumn) => ColumnSelection.columnSelectLeft(this.context.config, this.context.viewModel, cursor.viewState, toViewLineNumber, toViewVisualColumn));
A
Alex Dima 已提交
1159 1160 1161
	}

	private _columnSelectRight(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1162
		return this._columnSelectOp(ctx, (cursor, toViewLineNumber, toViewVisualColumn) => ColumnSelection.columnSelectRight(this.context.config, this.context.viewModel, cursor.viewState, toViewLineNumber, toViewVisualColumn));
A
Alex Dima 已提交
1163 1164
	}

J
Johannes Rieken 已提交
1165
	private _columnSelectUp(isPaged: boolean, ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1166
		return this._columnSelectOp(ctx, (cursor, toViewLineNumber, toViewVisualColumn) => ColumnSelection.columnSelectUp(this.context.config, this.context.viewModel, cursor.viewState, isPaged, toViewLineNumber, toViewVisualColumn));
A
Alex Dima 已提交
1167 1168
	}

J
Johannes Rieken 已提交
1169
	private _columnSelectDown(isPaged: boolean, ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1170
		return this._columnSelectOp(ctx, (cursor, toViewLineNumber, toViewVisualColumn) => ColumnSelection.columnSelectDown(this.context.config, this.context.viewModel, cursor.viewState, isPaged, toViewLineNumber, toViewVisualColumn));
A
Alex Dima 已提交
1171 1172
	}

E
Erich Gamma 已提交
1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184
	private _createCursor(ctx: IMultipleCursorOperationContext): boolean {
		if (this.configuration.editor.readOnly || this.model.hasEditableRange()) {
			return false;
		}

		this.cursors.addSecondaryCursor({
			selectionStartLineNumber: 1,
			selectionStartColumn: 1,
			positionLineNumber: 1,
			positionColumn: 1
		});

A
Alex Dima 已提交
1185 1186
		const lastAddedCursor = this.cursors.getLastAddedCursor();
		if (ctx.eventData.wholeLine) {
A
Alex Dima 已提交
1187 1188
			const result = OneCursorOp.line(this.context, lastAddedCursor, false, ctx.eventData.position, ctx.eventData.viewPosition);
			lastAddedCursor.setState(this.context, result.modelState, result.viewState, false);
A
Alex Dima 已提交
1189
		} else {
A
Alex Dima 已提交
1190 1191
			const result = OneCursorOp.moveTo(this.context, lastAddedCursor, false, ctx.eventData.position, ctx.eventData.viewPosition);
			lastAddedCursor.setState(this.context, result.modelState, result.viewState, false);
A
Alex Dima 已提交
1192
		}
E
Erich Gamma 已提交
1193

A
Alex Dima 已提交
1194 1195 1196
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit;
E
Erich Gamma 已提交
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
		ctx.shouldReveal = false;
		ctx.shouldRevealHorizontal = false;

		return true;
	}

	private _lastCursorMoveTo(ctx: IMultipleCursorOperationContext): boolean {
		if (this.configuration.editor.readOnly || this.model.hasEditableRange()) {
			return false;
		}

A
Alex Dima 已提交
1208 1209 1210 1211 1212
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
		if (ctx.eventSource === 'mouse') {
			ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit;
		}
E
Erich Gamma 已提交
1213 1214 1215
		ctx.shouldReveal = false;
		ctx.shouldRevealHorizontal = false;

A
Alex Dima 已提交
1216
		const lastAddedCursor = this.cursors.getLastAddedCursor();
A
Alex Dima 已提交
1217 1218
		const result = OneCursorOp.moveTo(this.context, lastAddedCursor, true, ctx.eventData.position, ctx.eventData.viewPosition);
		lastAddedCursor.setState(this.context, result.modelState, result.viewState, false);
A
Alex Dima 已提交
1219

E
Erich Gamma 已提交
1220 1221 1222 1223 1224 1225 1226
		return true;
	}

	private _addCursorUp(ctx: IMultipleCursorOperationContext): boolean {
		if (this.configuration.editor.readOnly) {
			return false;
		}
A
Alex Dima 已提交
1227
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit;
E
Erich Gamma 已提交
1228
		ctx.shouldRevealTarget = RevealTarget.TopMost;
A
Alex Dima 已提交
1229 1230
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
E
Erich Gamma 已提交
1231

A
Alex Dima 已提交
1232
		this.cursors.setStates(OneCursorOp.addCursorUp(this.context, this.cursors.getAll()), true);
A
Alex Dima 已提交
1233
		return true;
E
Erich Gamma 已提交
1234 1235 1236 1237 1238 1239
	}

	private _addCursorDown(ctx: IMultipleCursorOperationContext): boolean {
		if (this.configuration.editor.readOnly) {
			return false;
		}
A
Alex Dima 已提交
1240
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit;
E
Erich Gamma 已提交
1241
		ctx.shouldRevealTarget = RevealTarget.BottomMost;
A
Alex Dima 已提交
1242 1243
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
E
Erich Gamma 已提交
1244

A
Alex Dima 已提交
1245
		this.cursors.setStates(OneCursorOp.addCursorDown(this.context, this.cursors.getAll()), true);
A
Alex Dima 已提交
1246
		return true;
E
Erich Gamma 已提交
1247 1248
	}

J
Johannes Rieken 已提交
1249 1250
	private _moveLeft(inSelectionMode: boolean, ctx: IMultipleCursorOperationContext): boolean {
		ctx.eventData = ctx.eventData || {};
A
Alex Dima 已提交
1251
		ctx.eventData.to = CursorMovePosition.Left;
1252 1253 1254
		ctx.eventData.select = inSelectionMode;

		return this._cursorMove(ctx);
E
Erich Gamma 已提交
1255 1256
	}

1257
	private _moveRight(inSelectionMode: boolean, ctx: IMultipleCursorOperationContext): boolean {
J
Johannes Rieken 已提交
1258
		ctx.eventData = ctx.eventData || {};
A
Alex Dima 已提交
1259
		ctx.eventData.to = CursorMovePosition.Right;
1260 1261 1262
		ctx.eventData.select = inSelectionMode;

		return this._cursorMove(ctx);
E
Erich Gamma 已提交
1263 1264
	}

J
Johannes Rieken 已提交
1265 1266
	private _moveDown(inSelectionMode: boolean, isPaged: boolean, ctx: IMultipleCursorOperationContext): boolean {
		ctx.eventData = ctx.eventData || {};
A
Alex Dima 已提交
1267
		ctx.eventData.to = CursorMovePosition.Down;
1268
		ctx.eventData.select = inSelectionMode;
A
Alex Dima 已提交
1269
		ctx.eventData.by = CursorMoveByUnit.WrappedLine;
J
Johannes Rieken 已提交
1270
		ctx.eventData.isPaged = isPaged;
1271 1272

		return this._cursorMove(ctx);
E
Erich Gamma 已提交
1273 1274
	}

J
Johannes Rieken 已提交
1275 1276
	private _moveUp(inSelectionMode: boolean, isPaged: boolean, ctx: IMultipleCursorOperationContext): boolean {
		ctx.eventData = ctx.eventData || {};
A
Alex Dima 已提交
1277
		ctx.eventData.to = CursorMovePosition.Up;
J
Johannes Rieken 已提交
1278
		ctx.eventData.select = inSelectionMode;
A
Alex Dima 已提交
1279
		ctx.eventData.by = CursorMoveByUnit.WrappedLine;
J
Johannes Rieken 已提交
1280
		ctx.eventData.isPaged = isPaged;
1281 1282

		return this._cursorMove(ctx);
E
Erich Gamma 已提交
1283 1284
	}

J
Johannes Rieken 已提交
1285
	private _moveToBeginningOfLine(inSelectionMode: boolean, ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1286 1287 1288
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit;
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
A
Alex Dima 已提交
1289
		this.cursors.setStates(OneCursorOp.moveToBeginningOfLine(this.context, this.cursors.getAll(), inSelectionMode), true);
A
Alex Dima 已提交
1290
		return true;
E
Erich Gamma 已提交
1291 1292
	}

J
Johannes Rieken 已提交
1293
	private _moveToEndOfLine(inSelectionMode: boolean, ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1294 1295 1296
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit;
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
A
Alex Dima 已提交
1297
		this.cursors.setStates(OneCursorOp.moveToEndOfLine(this.context, this.cursors.getAll(), inSelectionMode), true);
A
Alex Dima 已提交
1298
		return true;
E
Erich Gamma 已提交
1299 1300
	}

J
Johannes Rieken 已提交
1301
	private _moveToBeginningOfBuffer(inSelectionMode: boolean, ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1302 1303 1304
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit;
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
A
Alex Dima 已提交
1305
		this.cursors.setStates(OneCursorOp.moveToBeginningOfBuffer(this.context, this.cursors.getAll(), inSelectionMode), true);
A
Alex Dima 已提交
1306
		return true;
E
Erich Gamma 已提交
1307 1308
	}

J
Johannes Rieken 已提交
1309
	private _moveToEndOfBuffer(inSelectionMode: boolean, ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1310 1311 1312
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit;
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
A
Alex Dima 已提交
1313
		this.cursors.setStates(OneCursorOp.moveToEndOfBuffer(this.context, this.cursors.getAll(), inSelectionMode), true);
A
Alex Dima 已提交
1314
		return true;
E
Erich Gamma 已提交
1315 1316 1317
	}

	private _selectAll(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1318 1319 1320 1321
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
		ctx.shouldReveal = false;
		ctx.shouldRevealHorizontal = false;
A
Alex Dima 已提交
1322
		const result = OneCursorOp.selectAll(this.context, this.cursors.getPrimaryCursor());
A
Alex Dima 已提交
1323 1324
		this.cursors.setStates([result], false);
		return true;
E
Erich Gamma 已提交
1325 1326
	}

J
Johannes Rieken 已提交
1327
	private _line(inSelectionMode: boolean, ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1328 1329 1330 1331 1332
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit;
		ctx.shouldRevealHorizontal = false;

A
Alex Dima 已提交
1333
		const r = OneCursorOp.line(this.context, this.cursors.getPrimaryCursor(), inSelectionMode, ctx.eventData.position, ctx.eventData.viewPosition);
A
Alex Dima 已提交
1334 1335
		this.cursors.setStates([r], false);
		return true;
E
Erich Gamma 已提交
1336 1337
	}

J
Johannes Rieken 已提交
1338
	private _lastCursorLine(inSelectionMode: boolean, ctx: IMultipleCursorOperationContext): boolean {
E
Erich Gamma 已提交
1339 1340 1341 1342
		if (this.configuration.editor.readOnly || this.model.hasEditableRange()) {
			return false;
		}

A
Alex Dima 已提交
1343 1344 1345
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit;
E
Erich Gamma 已提交
1346 1347 1348
		ctx.shouldReveal = false;
		ctx.shouldRevealHorizontal = false;

A
Alex Dima 已提交
1349
		const lastAddedCursor = this.cursors.getLastAddedCursor();
A
Alex Dima 已提交
1350 1351
		const result = OneCursorOp.line(this.context, lastAddedCursor, inSelectionMode, ctx.eventData.position, ctx.eventData.viewPosition);
		lastAddedCursor.setState(this.context, result.modelState, result.viewState, false);
E
Erich Gamma 已提交
1352 1353 1354
		return true;
	}

1355
	private _expandLineSelection(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1356 1357 1358
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit;
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
A
Alex Dima 已提交
1359
		this.cursors.setStates(OneCursorOp.expandLineSelection(this.context, this.cursors.getAll()), true);
A
Alex Dima 已提交
1360
		return true;
1361 1362
	}

J
Johannes Rieken 已提交
1363
	private _word(inSelectionMode: boolean, ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1364 1365 1366 1367 1368
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit;
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;

		const primaryCursor = this.cursors.getPrimaryCursor();
A
Alex Dima 已提交
1369
		const r = OneCursorOp.word(this.context, primaryCursor, inSelectionMode, ctx.eventData.position);
A
Alex Dima 已提交
1370 1371 1372
		this.cursors.setStates([r], false);

		return true;
E
Erich Gamma 已提交
1373 1374 1375 1376 1377 1378 1379
	}

	private _lastCursorWord(ctx: IMultipleCursorOperationContext): boolean {
		if (this.configuration.editor.readOnly || this.model.hasEditableRange()) {
			return false;
		}

A
Alex Dima 已提交
1380 1381 1382
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit;
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
E
Erich Gamma 已提交
1383 1384 1385
		ctx.shouldReveal = false;
		ctx.shouldRevealHorizontal = false;

A
Alex Dima 已提交
1386
		const lastAddedCursor = this.cursors.getLastAddedCursor();
A
Alex Dima 已提交
1387 1388
		const r = OneCursorOp.word(this.context, lastAddedCursor, true, ctx.eventData.position);
		lastAddedCursor.setState(this.context, r.modelState, r.viewState, false);
E
Erich Gamma 已提交
1389 1390 1391 1392 1393 1394 1395 1396 1397
		return true;
	}

	private _removeSecondaryCursors(ctx: IMultipleCursorOperationContext): boolean {
		this.cursors.killSecondaryCursors();
		return true;
	}

	private _cancelSelection(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1398 1399
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
A
Alex Dima 已提交
1400
		const r = OneCursorOp.cancelSelection(this.context, this.cursors.getPrimaryCursor());
A
Alex Dima 已提交
1401 1402
		this.cursors.setStates([r], false);
		return true;
E
Erich Gamma 已提交
1403 1404
	}

A
Alex Dima 已提交
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419
	// -------------------- START editing operations

	private _doApplyEdit(cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext, callable: (oneCursor: OneCursor, cursorIndex: number) => EditOperationResult): boolean {
		let r = callable(oneCursor, cursorIndex);
		if (r) {
			oneCtx.executeCommand = r.command;
			oneCtx.shouldPushStackElementBefore = r.shouldPushStackElementBefore;
			oneCtx.shouldPushStackElementAfter = r.shouldPushStackElementAfter;
			oneCtx.isAutoWhitespaceCommand = r.isAutoWhitespaceCommand;
			oneCtx.shouldRevealHorizontal = r.shouldRevealHorizontal;
		}
		return true;
	}

	private _applyEditForAll(ctx: IMultipleCursorOperationContext, callable: (oneCursor: OneCursor, cursorIndex: number) => EditOperationResult): boolean {
A
Alex Dima 已提交
1420 1421 1422
		ctx.shouldPushStackElementBefore = false;
		ctx.shouldPushStackElementAfter = false;
		return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => this._doApplyEdit(cursorIndex, oneCursor, oneCtx, callable));
A
Alex Dima 已提交
1423 1424 1425
	}

	private _applyEditForAllSorted(ctx: IMultipleCursorOperationContext, callable: (oneCursor: OneCursor, cursorIndex: number) => EditOperationResult): boolean {
A
Alex Dima 已提交
1426 1427 1428
		ctx.shouldPushStackElementBefore = false;
		ctx.shouldPushStackElementAfter = false;
		return this._invokeForAllSorted(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => this._doApplyEdit(cursorIndex, oneCursor, oneCtx, callable));
A
Alex Dima 已提交
1429 1430 1431
	}

	private _lineInsertBefore(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1432
		return this._applyEditForAll(ctx, (cursor) => TypeOperations.lineInsertBefore(this.context.config, this.context.model, cursor.modelState));
A
Alex Dima 已提交
1433 1434 1435
	}

	private _lineInsertAfter(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1436
		return this._applyEditForAll(ctx, (cursor) => TypeOperations.lineInsertAfter(this.context.config, this.context.model, cursor.modelState));
A
Alex Dima 已提交
1437 1438 1439
	}

	private _lineBreakInsert(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1440
		return this._applyEditForAll(ctx, (cursor) => TypeOperations.lineBreakInsert(this.context.config, this.context.model, cursor.modelState));
A
Alex Dima 已提交
1441 1442
	}

E
Erich Gamma 已提交
1443 1444 1445
	private _type(ctx: IMultipleCursorOperationContext): boolean {
		var text = ctx.eventData.text;

1446
		if (!this._isDoingComposition && ctx.eventSource === 'keyboard') {
E
Erich Gamma 已提交
1447 1448
			// If this event is coming straight from the keyboard, look for electric characters and enter

1449 1450 1451 1452 1453 1454 1455 1456 1457
			for (let i = 0, len = text.length; i < len; i++) {
				let charCode = text.charCodeAt(i);
				let chr: string;
				if (strings.isHighSurrogate(charCode) && i + 1 < len) {
					chr = text.charAt(i) + text.charAt(i + 1);
					i++;
				} else {
					chr = text.charAt(i);
				}
E
Erich Gamma 已提交
1458 1459

				// Here we must interpret each typed character individually, that's why we create a new context
J
Johannes Rieken 已提交
1460
				ctx.hasExecutedCommands = this._createAndInterpretHandlerCtx(ctx.eventSource, ctx.eventData, (charHandlerCtx: IMultipleCursorOperationContext) => {
E
Erich Gamma 已提交
1461

1462 1463 1464
					// Decide what all cursors will do up-front
					const cursors = this.cursors.getAll();
					const states = cursors.map(cursor => cursor.modelState);
A
Alex Dima 已提交
1465
					const editOperations = TypeOperations.typeWithInterceptors(this.context.config, this.context.model, states, chr);
1466
					this._applyEditForAll(charHandlerCtx, (cursor, cursorIndex) => editOperations[cursorIndex]);
E
Erich Gamma 已提交
1467 1468 1469 1470 1471 1472 1473 1474 1475 1476

					// The last typed character gets to win
					ctx.cursorPositionChangeReason = charHandlerCtx.cursorPositionChangeReason;
					ctx.shouldReveal = charHandlerCtx.shouldReveal;
					ctx.shouldRevealVerticalInCenter = charHandlerCtx.shouldRevealVerticalInCenter;
					ctx.shouldRevealHorizontal = charHandlerCtx.shouldRevealHorizontal;
				}) || ctx.hasExecutedCommands;

			}
		} else {
A
Alex Dima 已提交
1477
			this._applyEditForAll(ctx, (cursor) => TypeOperations.typeWithoutInterceptors(this.context.config, this.context.model, cursor.modelState, text));
E
Erich Gamma 已提交
1478 1479 1480 1481 1482 1483
		}

		return true;
	}

	private _replacePreviousChar(ctx: IMultipleCursorOperationContext): boolean {
1484 1485
		let text = ctx.eventData.text;
		let replaceCharCnt = ctx.eventData.replaceCharCnt;
A
Alex Dima 已提交
1486
		return this._applyEditForAll(ctx, (cursor) => TypeOperations.replacePreviousChar(this.context.config, this.context.model, cursor.modelState, text, replaceCharCnt));
E
Erich Gamma 已提交
1487 1488
	}

1489 1490 1491 1492 1493 1494 1495 1496 1497 1498
	private _compositionStart(ctx: IMultipleCursorOperationContext): boolean {
		this._isDoingComposition = true;
		return true;
	}

	private _compositionEnd(ctx: IMultipleCursorOperationContext): boolean {
		this._isDoingComposition = false;
		return true;
	}

E
Erich Gamma 已提交
1499
	private _tab(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1500
		return this._applyEditForAll(ctx, (cursor) => TypeOperations.tab(this.context.config, this.context.model, cursor.modelState));
E
Erich Gamma 已提交
1501 1502 1503
	}

	private _indent(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1504
		this._applyEditForAll(ctx, (cursor) => TypeOperations.indent(this.context.config, this.context.model, cursor.modelState));
A
Alex Dima 已提交
1505
		return true;
E
Erich Gamma 已提交
1506 1507 1508
	}

	private _outdent(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1509
		this._applyEditForAll(ctx, (cursor) => TypeOperations.outdent(this.context.config, this.context.model, cursor.modelState));
A
Alex Dima 已提交
1510
		return true;
A
Alex Dima 已提交
1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534
	}

	private _distributePasteToCursors(ctx: IMultipleCursorOperationContext): string[] {
		if (ctx.eventData.pasteOnNewLine) {
			return null;
		}

		var selections = this.cursors.getSelections();
		if (selections.length === 1) {
			return null;
		}

		for (var i = 0; i < selections.length; i++) {
			if (selections[i].startLineNumber !== selections[i].endLineNumber) {
				return null;
			}
		}

		var pastePieces = ctx.eventData.text.split(/\r\n|\r|\n/);
		if (pastePieces.length !== selections.length) {
			return null;
		}

		return pastePieces;
E
Erich Gamma 已提交
1535 1536 1537 1538 1539
	}

	private _paste(ctx: IMultipleCursorOperationContext): boolean {
		var distributedPaste = this._distributePasteToCursors(ctx);

A
Alex Dima 已提交
1540
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Paste;
E
Erich Gamma 已提交
1541
		if (distributedPaste) {
A
Alex Dima 已提交
1542
			return this._applyEditForAllSorted(ctx, (cursor, cursorIndex) => TypeOperations.paste(this.context.config, this.context.model, cursor.modelState, distributedPaste[cursorIndex], false));
E
Erich Gamma 已提交
1543
		} else {
A
Alex Dima 已提交
1544
			return this._applyEditForAll(ctx, (cursor) => TypeOperations.paste(this.context.config, this.context.model, cursor.modelState, ctx.eventData.text, ctx.eventData.pasteOnNewLine));
E
Erich Gamma 已提交
1545 1546 1547
		}
	}

A
Alex Dima 已提交
1548
	private _deleteLeft(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1549
		return this._applyEditForAll(ctx, (cursor) => DeleteOperations.deleteLeft(this.context.config, this.context.model, cursor.modelState));
A
Alex Dima 已提交
1550 1551 1552
	}

	private _deleteRight(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1553
		return this._applyEditForAll(ctx, (cursor) => DeleteOperations.deleteRight(this.context.config, this.context.model, cursor.modelState));
A
Alex Dima 已提交
1554 1555 1556
	}

	private _cut(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1557
		return this._applyEditForAll(ctx, (cursor) => DeleteOperations.cut(this.context.config, this.context.model, cursor.modelState, this.enableEmptySelectionClipboard));
A
Alex Dima 已提交
1558 1559 1560 1561 1562
	}

	// -------------------- END editing operations


1563
	private _revealLine(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1564
		const revealLineArg: RevealLineArguments = ctx.eventData;
1565
		const lineNumber = revealLineArg.lineNumber + 1;
1566
		let range = this.model.validateRange({
1567 1568 1569 1570 1571
			startLineNumber: lineNumber,
			startColumn: 1,
			endLineNumber: lineNumber,
			endColumn: 1
		});
1572
		range = new Range(range.startLineNumber, range.startColumn, range.endLineNumber, this.model.getLineMaxColumn(range.endLineNumber));
1573 1574 1575 1576

		let revealAt = editorCommon.VerticalRevealType.Simple;
		if (revealLineArg.at) {
			switch (revealLineArg.at) {
A
Alex Dima 已提交
1577
				case RevealLineAtArgument.Top:
1578 1579
					revealAt = editorCommon.VerticalRevealType.Top;
					break;
A
Alex Dima 已提交
1580
				case RevealLineAtArgument.Center:
1581 1582
					revealAt = editorCommon.VerticalRevealType.Center;
					break;
A
Alex Dima 已提交
1583
				case RevealLineAtArgument.Bottom:
1584 1585 1586 1587 1588 1589 1590
					revealAt = editorCommon.VerticalRevealType.Bottom;
					break;
				default:
					break;
			}
		}

1591
		this.emitCursorRevealRange(range, null, revealAt, false, false);
1592 1593 1594
		return true;
	}

1595
	private _editorScroll(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1596
		let editorScrollArg: EditorScrollArguments = ctx.eventData;
1597
		editorScrollArg.value = editorScrollArg.value || 1;
1598
		switch (editorScrollArg.to) {
A
Alex Dima 已提交
1599 1600
			case EditorScrollDirection.Up:
			case EditorScrollDirection.Down:
1601 1602 1603 1604 1605
				return this._scrollUpOrDown(editorScrollArg, ctx);
		}
		return true;
	}

A
Alex Dima 已提交
1606
	private _scrollUpOrDown(editorScrollArg: EditorScrollArguments, ctx: IMultipleCursorOperationContext): boolean {
1607
		if (this._scrollByReveal(editorScrollArg, ctx)) {
1608 1609
			return true;
		}
A
Alex Dima 已提交
1610
		let up = editorScrollArg.to === EditorScrollDirection.Up;
1611
		let noOfLines = editorScrollArg.value || 1;
1612
		switch (editorScrollArg.by) {
A
Alex Dima 已提交
1613
			case EditorScrollByUnit.Page:
A
Alex Dima 已提交
1614
				noOfLines = this.context.config.pageSize * noOfLines;
1615
				break;
A
Alex Dima 已提交
1616
			case EditorScrollByUnit.HalfPage:
A
Alex Dima 已提交
1617
				noOfLines = Math.round(this.context.config.pageSize / 2) * noOfLines;
1618 1619
				break;
		}
1620
		this.emitCursorScrollRequest((up ? -1 : 1) * noOfLines, !!editorScrollArg.revealCursor);
B
Benjamin Pasero 已提交
1621
		return true;
1622 1623
	}

A
Alex Dima 已提交
1624 1625 1626
	private _scrollByReveal(editorScrollArg: EditorScrollArguments, ctx: IMultipleCursorOperationContext): boolean {
		let up = editorScrollArg.to === EditorScrollDirection.Up;
		if (EditorScrollByUnit.Line !== editorScrollArg.by) {
1627 1628 1629
			// Scroll by reveal is done only when unit is line.
			return false;
		}
A
Alex Dima 已提交
1630
		if (!up && this.context.isLastLineVisibleInViewPort()) {
1631 1632 1633
			// Scroll by reveal is not done if last line is visible and scrolling down.
			return false;
		}
A
Alex Dima 已提交
1634
		let range = up ? this.context.getRangeToRevealModelLinesBeforeViewPortTop(editorScrollArg.value) : this.context.getRangeToRevealModelLinesAfterViewPortBottom(editorScrollArg.value);
1635 1636 1637 1638
		this.emitCursorRevealRange(range, null, up ? editorCommon.VerticalRevealType.Top : editorCommon.VerticalRevealType.Bottom, false, true);
		return true;
	}

1639
	private _scrollUp(isPaged: boolean, ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1640 1641
		ctx.eventData = <EditorScrollArguments>{ to: EditorScrollDirection.Up, value: 1 };
		ctx.eventData.by = isPaged ? EditorScrollByUnit.Page : EditorScrollByUnit.WrappedLine;
1642 1643 1644
		return this._editorScroll(ctx);
	}

1645
	private _scrollDown(isPaged: boolean, ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1646 1647
		ctx.eventData = <EditorScrollArguments>{ to: EditorScrollDirection.Down, value: 1 };
		ctx.eventData.by = isPaged ? EditorScrollByUnit.Page : EditorScrollByUnit.WrappedLine;
1648
		return this._editorScroll(ctx);
1649 1650
	}

E
Erich Gamma 已提交
1651
	private _undo(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1652
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Undo;
E
Erich Gamma 已提交
1653 1654 1655 1656 1657 1658 1659 1660 1661
		ctx.hasExecutedCommands = true;
		this._interpretCommandResult(this.model.undo());
		return true;
	}

	private _cursorUndo(ctx: IMultipleCursorOperationContext): boolean {
		if (this.cursorUndoStack.length === 0) {
			return false;
		}
A
Alex Dima 已提交
1662
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Undo;
E
Erich Gamma 已提交
1663 1664 1665 1666 1667 1668
		ctx.isCursorUndo = true;
		this.cursors.restoreState(this.cursorUndoStack.pop());
		return true;
	}

	private _redo(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1669
		ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Redo;
E
Erich Gamma 已提交
1670 1671 1672 1673 1674 1675 1676
		ctx.hasExecutedCommands = true;
		this._interpretCommandResult(this.model.redo());
		return true;
	}

	private _externalExecuteCommand(ctx: IMultipleCursorOperationContext): boolean {
		this.cursors.killSecondaryCursors();
A
Alex Dima 已提交
1677 1678
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
E
Erich Gamma 已提交
1679 1680 1681 1682 1683 1684 1685 1686 1687
		return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => {
			oneCtx.shouldPushStackElementBefore = true;
			oneCtx.shouldPushStackElementAfter = true;
			oneCtx.executeCommand = ctx.eventData;
			return false;
		});
	}

	private _externalExecuteCommands(ctx: IMultipleCursorOperationContext): boolean {
A
Alex Dima 已提交
1688 1689
		ctx.shouldPushStackElementBefore = true;
		ctx.shouldPushStackElementAfter = true;
E
Erich Gamma 已提交
1690 1691 1692 1693 1694 1695 1696 1697
		return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => {
			oneCtx.shouldPushStackElementBefore = true;
			oneCtx.shouldPushStackElementAfter = true;
			oneCtx.executeCommand = ctx.eventData[cursorIndex];
			return false;
		});
	}
}