Refresh master with initial release/0.24 snapshot (#332)

* Initial port of release/0.24 source code

* Fix additional headers

* Fix a typo in launch.json
This commit is contained in:
Karl Burtram
2017-12-15 15:38:57 -08:00
committed by GitHub
parent 271b3a0b82
commit 6ad0df0e3e
7118 changed files with 107999 additions and 56466 deletions

View File

@@ -8,7 +8,7 @@
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { CursorState, ICursors, RevealTarget, IColumnSelectData, CursorContext } from 'vs/editor/common/controller/cursorCommon';
import { CursorState, ICursors, RevealTarget, IColumnSelectData, CursorContext, EditOperationType } from 'vs/editor/common/controller/cursorCommon';
import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';
import { CursorMoveCommands, CursorMove as CursorMove_ } from 'vs/editor/common/controller/cursorMoveCommands';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
@@ -1273,7 +1273,8 @@ export namespace CoreNavigationCommands {
const lastAddedCursorIndex = cursors.getLastAddedCursorIndex();
let newStates = cursors.getAll().slice(0);
newStates[lastAddedCursorIndex] = CursorMoveCommands.word(context, newStates[lastAddedCursorIndex], true, args.position);
let lastAddedState = newStates[lastAddedCursorIndex];
newStates[lastAddedCursorIndex] = CursorMoveCommands.word(context, lastAddedState, lastAddedState.modelState.hasSelection(), args.position);
context.model.pushStackElement();
cursors.setStates(
@@ -1613,11 +1614,13 @@ export namespace CoreEditingCommands {
}
public runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void {
const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteLeft(editor._getCursorConfiguration(), editor.getModel(), editor.getSelections());
const cursors = editor._getCursors();
const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteLeft(cursors.getPrevEditOperationType(), editor._getCursorConfiguration(), editor.getModel(), editor.getSelections());
if (shouldPushStackElementBefore) {
editor.pushUndoStop();
}
editor.executeCommands(this.id, commands);
cursors.setPrevEditOperationType(EditOperationType.DeletingLeft);
}
});
@@ -1636,11 +1639,13 @@ export namespace CoreEditingCommands {
}
public runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void {
const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteRight(editor._getCursorConfiguration(), editor.getModel(), editor.getSelections());
const cursors = editor._getCursors();
const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteRight(cursors.getPrevEditOperationType(), editor._getCursorConfiguration(), editor.getModel(), editor.getSelections());
if (shouldPushStackElementBefore) {
editor.pushUndoStop();
}
editor.executeCommands(this.id, commands);
cursors.setPrevEditOperationType(EditOperationType.DeletingRight);
}
});

View File

@@ -12,8 +12,7 @@ import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { Selection, SelectionDirection, ISelection } from 'vs/editor/common/core/selection';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { CursorColumns, CursorConfiguration, EditOperationResult, CursorContext, CursorState, RevealTarget, IColumnSelectData, ICursors } from 'vs/editor/common/controller/cursorCommon';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { CursorColumns, CursorConfiguration, EditOperationResult, CursorContext, CursorState, RevealTarget, IColumnSelectData, ICursors, EditOperationType } from 'vs/editor/common/controller/cursorCommon';
import { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations';
import { TypeOperations } from 'vs/editor/common/controller/cursorTypeOperations';
import { TextModelEventType, ModelRawContentChangedEvent, RawContentChangedType } from 'vs/editor/common/model/textModelEvents';
@@ -21,7 +20,6 @@ import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import Event, { Emitter } from 'vs/base/common/event';
// import { ScreenReaderMessageGenerator } from "vs/editor/common/controller/accGenerator";
function containsLineMappingChanged(events: viewEvents.ViewEvent[]): boolean {
for (let i = 0, len = events.length; i < len; i++) {
@@ -100,6 +98,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
private _isHandling: boolean;
private _isDoingComposition: boolean;
private _columnSelectData: IColumnSelectData;
private _prevEditOperationType: EditOperationType;
constructor(configuration: editorCommon.IConfiguration, model: editorCommon.IModel, viewModel: IViewModel) {
super();
@@ -112,6 +111,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
this._isHandling = false;
this._isDoingComposition = false;
this._columnSelectData = null;
this._prevEditOperationType = EditOperationType.Other;
this._register(this._model.addBulkListener((events) => {
if (this._isHandling) {
@@ -151,11 +151,10 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
this.context = new CursorContext(this._configuration, this._model, this._viewModel);
this._cursors.updateContext(this.context);
};
this._register(this._model.onDidChangeLanguage((e) => {
this._register(model.onDidChangeLanguage((e) => {
updateCursorContext();
}));
this._register(LanguageConfigurationRegistry.onDidChange(() => {
// TODO@Alex: react only if certain supports changed? (and if my model's mode changed)
this._register(model.onDidChangeLanguageConfiguration(() => {
updateCursorContext();
}));
this._register(model.onDidChangeOptions(() => {
@@ -281,6 +280,9 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
}
private _onModelContentChanged(hadFlushEvent: boolean): void {
this._prevEditOperationType = EditOperationType.Other;
if (hadFlushEvent) {
// a model.setValue() was called
this._cursors.dispose();
@@ -325,6 +327,14 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
this.setStates(source, CursorChangeReason.NotSet, CursorState.fromModelSelections(selections));
}
public getPrevEditOperationType(): EditOperationType {
return this._prevEditOperationType;
}
public setPrevEditOperationType(type: EditOperationType): void {
this._prevEditOperationType = type;
}
// ------ auxiliary handling logic
private _executeEditOperation(opResult: EditOperationResult): void {
@@ -347,6 +357,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
if (result) {
// The commands were applied correctly
this._interpretCommandResult(result);
this._prevEditOperationType = opResult.type;
}
if (opResult.shouldPushStackElementAfter) {
@@ -518,16 +530,16 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
}
// Here we must interpret each typed character individually, that's why we create a new context
this._executeEditOperation(TypeOperations.typeWithInterceptors(this.context.config, this.context.model, this.getSelections(), chr));
this._executeEditOperation(TypeOperations.typeWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), chr));
}
} else {
this._executeEditOperation(TypeOperations.typeWithoutInterceptors(this.context.config, this.context.model, this.getSelections(), text));
this._executeEditOperation(TypeOperations.typeWithoutInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), text));
}
}
private _replacePreviousChar(text: string, replaceCharCnt: number): void {
this._executeEditOperation(TypeOperations.replacePreviousChar(this.context.config, this.context.model, this.getSelections(), text, replaceCharCnt));
this._executeEditOperation(TypeOperations.replacePreviousChar(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), text, replaceCharCnt));
}
private _paste(text: string, pasteOnNewLine: boolean): void {
@@ -541,14 +553,14 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
private _externalExecuteCommand(command: editorCommon.ICommand): void {
this._cursors.killSecondaryCursors();
this._executeEditOperation(new EditOperationResult([command], {
this._executeEditOperation(new EditOperationResult(EditOperationType.Other, [command], {
shouldPushStackElementBefore: false,
shouldPushStackElementAfter: false
}));
}
private _externalExecuteCommands(commands: editorCommon.ICommand[]): void {
this._executeEditOperation(new EditOperationResult(commands, {
this._executeEditOperation(new EditOperationResult(EditOperationType.Other, commands, {
shouldPushStackElementBefore: false,
shouldPushStackElementAfter: false
}));
@@ -558,8 +570,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
interface IExecContext {
readonly model: editorCommon.IModel;
readonly selectionsBefore: Selection[];
readonly selectionStartMarkers: string[];
readonly positionMarkers: string[];
readonly trackedRanges: string[];
readonly trackedRangesDirection: SelectionDirection[];
}
interface ICommandData {
@@ -579,15 +591,14 @@ class CommandExecutor {
const ctx: IExecContext = {
model: model,
selectionsBefore: selectionsBefore,
selectionStartMarkers: [],
positionMarkers: []
trackedRanges: [],
trackedRangesDirection: []
};
const result = this._innerExecuteCommands(ctx, commands);
for (let i = 0; i < ctx.selectionStartMarkers.length; i++) {
ctx.model._removeMarker(ctx.selectionStartMarkers[i]);
ctx.model._removeMarker(ctx.positionMarkers[i]);
for (let i = 0, len = ctx.trackedRanges.length; i < len; i++) {
ctx.model._setTrackedRange(ctx.trackedRanges[i], null, editorCommon.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges);
}
return result;
@@ -664,9 +675,11 @@ class CommandExecutor {
getTrackedSelection: (id: string) => {
const idx = parseInt(id, 10);
const selectionStartMarker = ctx.model._getMarker(ctx.selectionStartMarkers[idx]);
const positionMarker = ctx.model._getMarker(ctx.positionMarkers[idx]);
return new Selection(selectionStartMarker.lineNumber, selectionStartMarker.column, positionMarker.lineNumber, positionMarker.column);
const range = ctx.model._getTrackedRange(ctx.trackedRanges[idx]);
if (ctx.trackedRangesDirection[idx] === SelectionDirection.LTR) {
return new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);
}
return new Selection(range.endLineNumber, range.endColumn, range.startLineNumber, range.startColumn);
}
});
} else {
@@ -753,37 +766,31 @@ class CommandExecutor {
};
const trackSelection = (selection: Selection, trackPreviousOnEmpty?: boolean) => {
let selectionMarkerStickToPreviousCharacter: boolean;
let positionMarkerStickToPreviousCharacter: boolean;
let stickiness: editorCommon.TrackedRangeStickiness;
if (selection.isEmpty()) {
// Try to lock it with surrounding text
if (typeof trackPreviousOnEmpty === 'boolean') {
selectionMarkerStickToPreviousCharacter = trackPreviousOnEmpty;
positionMarkerStickToPreviousCharacter = trackPreviousOnEmpty;
if (trackPreviousOnEmpty) {
stickiness = editorCommon.TrackedRangeStickiness.GrowsOnlyWhenTypingBefore;
} else {
stickiness = editorCommon.TrackedRangeStickiness.GrowsOnlyWhenTypingAfter;
}
} else {
// Try to lock it with surrounding text
const maxLineColumn = ctx.model.getLineMaxColumn(selection.startLineNumber);
if (selection.startColumn === maxLineColumn) {
selectionMarkerStickToPreviousCharacter = true;
positionMarkerStickToPreviousCharacter = true;
stickiness = editorCommon.TrackedRangeStickiness.GrowsOnlyWhenTypingBefore;
} else {
selectionMarkerStickToPreviousCharacter = false;
positionMarkerStickToPreviousCharacter = false;
stickiness = editorCommon.TrackedRangeStickiness.GrowsOnlyWhenTypingAfter;
}
}
} else {
if (selection.getDirection() === SelectionDirection.LTR) {
selectionMarkerStickToPreviousCharacter = false;
positionMarkerStickToPreviousCharacter = true;
} else {
selectionMarkerStickToPreviousCharacter = true;
positionMarkerStickToPreviousCharacter = false;
}
stickiness = editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges;
}
const l = ctx.selectionStartMarkers.length;
ctx.selectionStartMarkers[l] = ctx.model._addMarker(0, selection.selectionStartLineNumber, selection.selectionStartColumn, selectionMarkerStickToPreviousCharacter);
ctx.positionMarkers[l] = ctx.model._addMarker(0, selection.positionLineNumber, selection.positionColumn, positionMarkerStickToPreviousCharacter);
const l = ctx.trackedRanges.length;
const id = ctx.model._setTrackedRange(null, selection, stickiness);
ctx.trackedRanges[l] = id;
ctx.trackedRangesDirection[l] = selection.getDirection();
return l.toString();
};

View File

@@ -31,6 +31,17 @@ export const enum RevealTarget {
BottomMost = 2
}
/**
* This is an operation type that will be recorded for undo/redo purposes.
* The goal is to introduce an undo stop when the controller switches between different operation types.
*/
export const enum EditOperationType {
Other = 0,
Typing = 1,
DeletingLeft = 2,
DeletingRight = 3
}
export interface ICursors {
readonly context: CursorContext;
getPrimaryCursor(): CursorState;
@@ -45,6 +56,9 @@ export interface ICursors {
revealRange(revealHorizontal: boolean, viewRange: Range, verticalType: VerticalRevealType, scrollType: ScrollType): void;
scrollTo(desiredScrollTop: number): void;
getPrevEditOperationType(): EditOperationType;
setPrevEditOperationType(type: EditOperationType): void;
}
export interface CharacterMap {
@@ -422,17 +436,20 @@ export class CursorState {
export class EditOperationResult {
_editOperationResultBrand: void;
readonly type: EditOperationType;
readonly commands: ICommand[];
readonly shouldPushStackElementBefore: boolean;
readonly shouldPushStackElementAfter: boolean;
constructor(
type: EditOperationType,
commands: ICommand[],
opts: {
shouldPushStackElementBefore: boolean;
shouldPushStackElementAfter: boolean;
}
) {
this.type = type;
this.commands = commands;
this.shouldPushStackElementBefore = opts.shouldPushStackElementBefore;
this.shouldPushStackElementAfter = opts.shouldPushStackElementAfter;

View File

@@ -5,7 +5,7 @@
'use strict';
import { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand';
import { CursorColumns, CursorConfiguration, ICursorSimpleModel, EditOperationResult } from 'vs/editor/common/controller/cursorCommon';
import { CursorColumns, CursorConfiguration, ICursorSimpleModel, EditOperationResult, EditOperationType } from 'vs/editor/common/controller/cursorCommon';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { MoveOperations } from 'vs/editor/common/controller/cursorMoveOperations';
@@ -14,9 +14,9 @@ import { ICommand } from 'vs/editor/common/editorCommon';
export class DeleteOperations {
public static deleteRight(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, ICommand[]] {
public static deleteRight(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, ICommand[]] {
let commands: ICommand[] = [];
let shouldPushStackElementBefore = false;
let shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.DeletingRight);
for (let i = 0, len = selections.length; i < len; i++) {
const selection = selections[i];
@@ -94,14 +94,14 @@ export class DeleteOperations {
return [true, commands];
}
public static deleteLeft(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, ICommand[]] {
public static deleteLeft(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, ICommand[]] {
if (this._isAutoClosingPairDelete(config, model, selections)) {
return this._runAutoClosingPairDelete(config, model, selections);
}
let commands: ICommand[] = [];
let shouldPushStackElementBefore = false;
let shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.DeletingLeft);
for (let i = 0, len = selections.length; i < len; i++) {
const selection = selections[i];
@@ -210,7 +210,7 @@ export class DeleteOperations {
commands[i] = new ReplaceCommand(selection, '');
}
}
return new EditOperationResult(commands, {
return new EditOperationResult(EditOperationType.Other, commands, {
shouldPushStackElementBefore: true,
shouldPushStackElementAfter: true
});

View File

@@ -418,7 +418,19 @@ export class CursorMoveCommands {
let result: CursorState[] = [];
for (let i = 0, len = cursors.length; i < len; i++) {
const cursor = cursors[i];
result[i] = CursorState.fromViewState(MoveOperations.moveLeft(context.config, context.viewModel, cursor.viewState, inSelectionMode, noOfColumns));
let newViewState = MoveOperations.moveLeft(context.config, context.viewModel, cursor.viewState, inSelectionMode, noOfColumns);
if (noOfColumns === 1 && newViewState.position.lineNumber !== cursor.viewState.position.lineNumber) {
// moved over to the previous view line
const newViewModelPosition = context.viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position);
if (newViewModelPosition.lineNumber === cursor.modelState.position.lineNumber) {
// stayed on the same model line => pass wrapping point where 2 view positions map to a single model position
newViewState = MoveOperations.moveLeft(context.config, context.viewModel, newViewState, inSelectionMode, 1);
}
}
result[i] = CursorState.fromViewState(newViewState);
}
return result;
}
@@ -438,7 +450,18 @@ export class CursorMoveCommands {
let result: CursorState[] = [];
for (let i = 0, len = cursors.length; i < len; i++) {
const cursor = cursors[i];
result[i] = CursorState.fromViewState(MoveOperations.moveRight(context.config, context.viewModel, cursor.viewState, inSelectionMode, noOfColumns));
let newViewState = MoveOperations.moveRight(context.config, context.viewModel, cursor.viewState, inSelectionMode, noOfColumns);
if (noOfColumns === 1 && newViewState.position.lineNumber !== cursor.viewState.position.lineNumber) {
// moved over to the next view line
const newViewModelPosition = context.viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position);
if (newViewModelPosition.lineNumber === cursor.modelState.position.lineNumber) {
// stayed on the same model line => pass wrapping point where 2 view positions map to a single model position
newViewState = MoveOperations.moveRight(context.config, context.viewModel, newViewState, inSelectionMode, 1);
}
}
result[i] = CursorState.fromViewState(newViewState);
}
return result;
}

View File

@@ -6,7 +6,7 @@
import { onUnexpectedError } from 'vs/base/common/errors';
import { ReplaceCommand, ReplaceCommandWithoutChangingPosition, ReplaceCommandWithOffsetCursorState } from 'vs/editor/common/commands/replaceCommand';
import { CursorColumns, CursorConfiguration, ICursorSimpleModel, EditOperationResult } from 'vs/editor/common/controller/cursorCommon';
import { CursorColumns, CursorConfiguration, ICursorSimpleModel, EditOperationResult, EditOperationType } from 'vs/editor/common/controller/cursorCommon';
import { Range } from 'vs/editor/common/core/range';
import { ICommand, ITokenizedModel } from 'vs/editor/common/editorCommon';
import * as strings from 'vs/base/common/strings';
@@ -73,7 +73,7 @@ export class TypeOperations {
for (let i = 0, len = selections.length; i < len; i++) {
commands[i] = new ReplaceCommand(selections[i], text[i]);
}
return new EditOperationResult(commands, {
return new EditOperationResult(EditOperationType.Other, commands, {
shouldPushStackElementBefore: true,
shouldPushStackElementAfter: true
});
@@ -103,7 +103,7 @@ export class TypeOperations {
commands[i] = new ReplaceCommand(selection, text);
}
}
return new EditOperationResult(commands, {
return new EditOperationResult(EditOperationType.Other, commands, {
shouldPushStackElementBefore: true,
shouldPushStackElementAfter: true
});
@@ -255,7 +255,7 @@ export class TypeOperations {
return commands;
}
public static replacePreviousChar(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], txt: string, replaceCharCnt: number): EditOperationResult {
public static replacePreviousChar(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], txt: string, replaceCharCnt: number): EditOperationResult {
let commands: ICommand[] = [];
for (let i = 0, len = selections.length; i < len; i++) {
const selection = selections[i];
@@ -271,8 +271,8 @@ export class TypeOperations {
let range = new Range(pos.lineNumber, startColumn, pos.lineNumber, pos.column);
commands[i] = new ReplaceCommand(range, txt);
}
return new EditOperationResult(commands, {
shouldPushStackElementBefore: false,
return new EditOperationResult(EditOperationType.Typing, commands, {
shouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing),
shouldPushStackElementAfter: false
});
}
@@ -324,6 +324,13 @@ export class TypeOperations {
}
// no enter rules applied, we should check indentation rules then.
if (!config.autoIndent) {
// Nothing special
let lineText = model.getLineContent(range.startLineNumber);
let indentation = strings.getLeadingWhitespace(lineText).substring(0, range.startColumn - 1);
return TypeOperations._typeCommand(range, '\n' + config.normalizeIndentation(indentation), keepPosition);
}
let ir = LanguageConfigurationRegistry.getIndentForEnter(model, range, {
unshiftIndent: (indent) => {
return TypeOperations.unshiftIndent(config, indent);
@@ -468,7 +475,7 @@ export class TypeOperations {
return cnt;
}
private static _runAutoClosingCloseCharType(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult {
private static _runAutoClosingCloseCharType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult {
let commands: ICommand[] = [];
for (let i = 0, len = selections.length; i < len; i++) {
const selection = selections[i];
@@ -476,8 +483,8 @@ export class TypeOperations {
const typeSelection = new Range(position.lineNumber, position.column, position.lineNumber, position.column + 1);
commands[i] = new ReplaceCommand(typeSelection, ch);
}
return new EditOperationResult(commands, {
shouldPushStackElementBefore: false,
return new EditOperationResult(EditOperationType.Typing, commands, {
shouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing),
shouldPushStackElementAfter: false
});
}
@@ -550,14 +557,14 @@ export class TypeOperations {
return true;
}
private static _runAutoClosingOpenCharType(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult {
private static _runAutoClosingOpenCharType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult {
let commands: ICommand[] = [];
for (let i = 0, len = selections.length; i < len; i++) {
const selection = selections[i];
const closeCharacter = config.autoClosingPairsOpen[ch];
commands[i] = new ReplaceCommandWithOffsetCursorState(selection, ch + closeCharacter, 0, -closeCharacter.length);
}
return new EditOperationResult(commands, {
return new EditOperationResult(EditOperationType.Typing, commands, {
shouldPushStackElementBefore: true,
shouldPushStackElementAfter: false
});
@@ -597,14 +604,14 @@ export class TypeOperations {
return true;
}
private static _runSurroundSelectionType(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult {
private static _runSurroundSelectionType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult {
let commands: ICommand[] = [];
for (let i = 0, len = selections.length; i < len; i++) {
const selection = selections[i];
const closeCharacter = config.surroundingPairs[ch];
commands[i] = new SurroundSelectionCommand(selection, ch, closeCharacter);
}
return new EditOperationResult(commands, {
return new EditOperationResult(EditOperationType.Other, commands, {
shouldPushStackElementBefore: true,
shouldPushStackElementAfter: true
});
@@ -617,7 +624,7 @@ export class TypeOperations {
return false;
}
private static _typeInterceptorElectricChar(config: CursorConfiguration, model: ITokenizedModel, selection: Selection, ch: string): EditOperationResult {
private static _typeInterceptorElectricChar(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selection: Selection, ch: string): EditOperationResult {
if (!config.electricChars.hasOwnProperty(ch) || !selection.isEmpty()) {
return null;
}
@@ -639,7 +646,7 @@ export class TypeOperations {
if (electricAction.appendText) {
const command = new ReplaceCommandWithOffsetCursorState(selection, ch + electricAction.appendText, 0, -electricAction.appendText.length);
return new EditOperationResult([command], {
return new EditOperationResult(EditOperationType.Typing, [command], {
shouldPushStackElementBefore: false,
shouldPushStackElementAfter: true
});
@@ -670,7 +677,7 @@ export class TypeOperations {
let typeSelection = new Range(position.lineNumber, 1, position.lineNumber, position.column);
const command = new ReplaceCommand(typeSelection, typeText);
return new EditOperationResult([command], {
return new EditOperationResult(EditOperationType.Typing, [command], {
shouldPushStackElementBefore: false,
shouldPushStackElementAfter: true
});
@@ -680,23 +687,31 @@ export class TypeOperations {
return null;
}
public static typeWithInterceptors(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult {
public static typeWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], ch: string): EditOperationResult {
if (ch === '\n') {
let commands: ICommand[] = [];
for (let i = 0, len = selections.length; i < len; i++) {
commands[i] = TypeOperations._enter(config, model, false, selections[i]);
}
return new EditOperationResult(commands, {
return new EditOperationResult(EditOperationType.Typing, commands, {
shouldPushStackElementBefore: true,
shouldPushStackElementAfter: false,
});
}
if (this._isAutoIndentType(config, model, selections)) {
let indentCommand = this._runAutoIndentType(config, model, selections[0], ch);
if (indentCommand) {
return new EditOperationResult([indentCommand], {
let commands: ICommand[] = [];
let autoIndentFails = false;
for (let i = 0, len = selections.length; i < len; i++) {
commands[i] = this._runAutoIndentType(config, model, selections[i], ch);
if (!commands[i]) {
autoIndentFails = true;
break;
}
}
if (!autoIndentFails) {
return new EditOperationResult(EditOperationType.Typing, commands, {
shouldPushStackElementBefore: true,
shouldPushStackElementAfter: false,
});
@@ -704,36 +719,48 @@ export class TypeOperations {
}
if (this._isAutoClosingCloseCharType(config, model, selections, ch)) {
return this._runAutoClosingCloseCharType(config, model, selections, ch);
return this._runAutoClosingCloseCharType(prevEditOperationType, config, model, selections, ch);
}
if (this._isAutoClosingOpenCharType(config, model, selections, ch)) {
return this._runAutoClosingOpenCharType(config, model, selections, ch);
return this._runAutoClosingOpenCharType(prevEditOperationType, config, model, selections, ch);
}
if (this._isSurroundSelectionType(config, model, selections, ch)) {
return this._runSurroundSelectionType(config, model, selections, ch);
return this._runSurroundSelectionType(prevEditOperationType, config, model, selections, ch);
}
// Electric characters make sense only when dealing with a single cursor,
// as multiple cursors typing brackets for example would interfer with bracket matching
if (this._isTypeInterceptorElectricChar(config, model, selections)) {
const r = this._typeInterceptorElectricChar(config, model, selections[0], ch);
const r = this._typeInterceptorElectricChar(prevEditOperationType, config, model, selections[0], ch);
if (r) {
return r;
}
}
return this.typeWithoutInterceptors(config, model, selections, ch);
// A simple character type
let commands: ICommand[] = [];
for (let i = 0, len = selections.length; i < len; i++) {
commands[i] = new ReplaceCommand(selections[i], ch);
}
let shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.Typing);
if (ch === ' ') {
shouldPushStackElementBefore = true;
}
return new EditOperationResult(EditOperationType.Typing, commands, {
shouldPushStackElementBefore: shouldPushStackElementBefore,
shouldPushStackElementAfter: false
});
}
public static typeWithoutInterceptors(config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], str: string): EditOperationResult {
public static typeWithoutInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITokenizedModel, selections: Selection[], str: string): EditOperationResult {
let commands: ICommand[] = [];
for (let i = 0, len = selections.length; i < len; i++) {
commands[i] = new ReplaceCommand(selections[i], str);
}
return new EditOperationResult(commands, {
shouldPushStackElementBefore: false,
return new EditOperationResult(EditOperationType.Typing, commands, {
shouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing),
shouldPushStackElementAfter: false
});
}

View File

@@ -378,7 +378,7 @@ export class WordOperations {
let nextWord = WordOperations._findNextWordOnLine(wordSeparators, model, position);
let isInNextWord = (nextWord && nextWord.wordType === WordType.Regular && nextWord.start < position.column - 1 && position.column - 1 <= nextWord.end);
if (!inSelectionMode || !cursor.hasSelection()) {
if (!inSelectionMode) {
// Entering word selection for the first time
let startColumn: number;
@@ -425,7 +425,9 @@ export class WordOperations {
let lineNumber = position.lineNumber;
let column: number;
if (position.isBeforeOrEqual(cursor.selectionStart.getStartPosition())) {
if (cursor.selectionStart.containsPosition(position)) {
column = cursor.selectionStart.endColumn;
} else if (position.isBeforeOrEqual(cursor.selectionStart.getStartPosition())) {
column = startColumn;
let possiblePosition = new Position(lineNumber, column);
if (cursor.selectionStart.containsPosition(possiblePosition)) {
@@ -439,6 +441,6 @@ export class WordOperations {
}
}
return cursor.move(cursor.hasSelection(), lineNumber, column, 0);
return cursor.move(true, lineNumber, column, 0);
}
}

View File

@@ -8,16 +8,21 @@ import { SingleCursorState, CursorContext, CursorState } from 'vs/editor/common/
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { Selection, SelectionDirection } from 'vs/editor/common/core/selection';
import { TrackedRangeStickiness } from 'vs/editor/common/editorCommon';
export class OneCursor {
public modelState: SingleCursorState;
public viewState: SingleCursorState;
private _selStartMarker: string;
private _selEndMarker: string;
private _selTrackedRange: string;
constructor(context: CursorContext) {
this.modelState = null;
this.viewState = null;
this._selTrackedRange = null;
this._setState(
context,
new SingleCursorState(new Range(1, 1, 1, 1), 0, new Position(1, 1), 0),
@@ -26,8 +31,7 @@ export class OneCursor {
}
public dispose(context: CursorContext): void {
context.model._removeMarker(this._selStartMarker);
context.model._removeMarker(this._selEndMarker);
this._selTrackedRange = context.model._setTrackedRange(this._selTrackedRange, null, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges);
}
public asCursorState(): CursorState {
@@ -35,14 +39,11 @@ export class OneCursor {
}
public readSelectionFromMarkers(context: CursorContext): Selection {
const start = context.model._getMarker(this._selStartMarker);
const end = context.model._getMarker(this._selEndMarker);
const range = context.model._getTrackedRange(this._selTrackedRange);
if (this.modelState.selection.getDirection() === SelectionDirection.LTR) {
return new Selection(start.lineNumber, start.column, end.lineNumber, end.column);
return new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);
}
return new Selection(end.lineNumber, end.column, start.lineNumber, start.column);
return new Selection(range.endLineNumber, range.endColumn, range.startLineNumber, range.startColumn);
}
public ensureValidState(context: CursorContext): void {
@@ -100,17 +101,6 @@ export class OneCursor {
this.modelState = modelState;
this.viewState = viewState;
this._selStartMarker = this._ensureMarker(context, this._selStartMarker, this.modelState.selection.startLineNumber, this.modelState.selection.startColumn, true);
this._selEndMarker = this._ensureMarker(context, this._selEndMarker, this.modelState.selection.endLineNumber, this.modelState.selection.endColumn, false);
}
private _ensureMarker(context: CursorContext, markerId: string, lineNumber: number, column: number, stickToPreviousCharacter: boolean): string {
if (!markerId) {
return context.model._addMarker(0, lineNumber, column, stickToPreviousCharacter);
} else {
context.model._changeMarker(markerId, lineNumber, column);
context.model._changeMarkerStickiness(markerId, stickToPreviousCharacter);
return markerId;
}
this._selTrackedRange = context.model._setTrackedRange(this._selTrackedRange, this.modelState.selection, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges);
}
}