mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-14 18:46:34 -05:00
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:
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user