diff --git a/src/vs/editor/common/commonCodeEditor.ts b/src/vs/editor/common/commonCodeEditor.ts index 3c8ecce71b1..1f652adcaf2 100644 --- a/src/vs/editor/common/commonCodeEditor.ts +++ b/src/vs/editor/common/commonCodeEditor.ts @@ -29,6 +29,7 @@ import * as editorOptions from 'vs/editor/common/config/editorOptions'; import { CursorEventType, ICursorPositionChangedEvent, VerticalRevealType, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ViewModelCursors } from "vs/editor/common/viewModel/viewModelCursors"; +import { CommonEditorRegistry } from "vs/editor/common/editorCommonExtensions"; let EDITOR_ID = 0; @@ -667,6 +668,7 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo return; } + // Special case for pasting if (handlerId === editorCommon.Handler.Paste) { if (!this.cursor || typeof payload.text !== 'string' || payload.text.length === 0) { // nothing to do @@ -683,15 +685,25 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo return; } - let candidate = this.getAction(handlerId); - if (candidate !== null) { - TPromise.as(candidate.run()).done(null, onUnexpectedError); - } else { - if (!this.cursor) { - return; - } - this.cursor.trigger(source, handlerId, payload); + const action = this.getAction(handlerId); + if (action) { + TPromise.as(action.run()).done(null, onUnexpectedError); + return; } + + if (!this.cursor) { + return; + } + + const command = CommonEditorRegistry.getEditorCommand(handlerId); + if (command) { + payload = payload || {}; + payload.source = source; + TPromise.as(command.runEditorCommand(null, this, payload)).done(null, onUnexpectedError); + return; + } + + this.cursor.trigger(source, handlerId, payload); } public _getCursors(): ICursors { diff --git a/src/vs/editor/common/controller/coreCommands.ts b/src/vs/editor/common/controller/coreCommands.ts index ae8a6e85e1a..3ca21fe60b7 100644 --- a/src/vs/editor/common/controller/coreCommands.ts +++ b/src/vs/editor/common/controller/coreCommands.ts @@ -24,6 +24,8 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import * as types from 'vs/base/common/types'; import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; import { IEditorService } from 'vs/platform/editor/common/editor'; +import { TypeOperations } from "vs/editor/common/controller/cursorTypeOperations"; +import { DeleteOperations } from "vs/editor/common/controller/cursorDeleteOperations"; const CORE_WEIGHT = KeybindingsRegistry.WEIGHT.editorCore(); @@ -1398,6 +1400,120 @@ export namespace CoreNavigationCommands { } export namespace CoreEditingCommands { + + export const LineBreakInsert: EditorCommand = registerEditorCommand(new class extends EditorCommand { + constructor() { + super({ + id: 'lineBreakInsert', + precondition: EditorContextKeys.writable, + kbOpts: { + weight: CORE_WEIGHT, + kbExpr: EditorContextKeys.textFocus, + primary: null, + mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_O } + } + }); + } + + public runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void { + editor.pushUndoStop(); + editor.executeCommands(this.id, TypeOperations.lineBreakInsert(editor._getCursorConfiguration(), editor.getModel(), editor.getSelections())); + } + }); + + export const Outdent: EditorCommand = registerEditorCommand(new class extends EditorCommand { + constructor() { + super({ + id: 'outdent', + precondition: EditorContextKeys.writable, + kbOpts: { + weight: CORE_WEIGHT, + kbExpr: ContextKeyExpr.and( + EditorContextKeys.textFocus, + EditorContextKeys.tabDoesNotMoveFocus + ), + primary: KeyMod.Shift | KeyCode.Tab + } + }); + } + + public runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void { + editor.pushUndoStop(); + editor.executeCommands(this.id, TypeOperations.outdent(editor._getCursorConfiguration(), editor.getModel(), editor.getSelections())); + editor.pushUndoStop(); + } + }); + + export const Tab: EditorCommand = registerEditorCommand(new class extends EditorCommand { + constructor() { + super({ + id: 'tab', + precondition: EditorContextKeys.writable, + kbOpts: { + weight: CORE_WEIGHT, + kbExpr: ContextKeyExpr.and( + EditorContextKeys.textFocus, + EditorContextKeys.tabDoesNotMoveFocus + ), + primary: KeyCode.Tab + } + }); + } + + public runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void { + editor.pushUndoStop(); + editor.executeCommands(this.id, TypeOperations.tab(editor._getCursorConfiguration(), editor.getModel(), editor.getSelections())); + editor.pushUndoStop(); + } + }); + + export const DeleteLeft: EditorCommand = registerEditorCommand(new class extends EditorCommand { + constructor() { + super({ + id: 'deleteLeft', + precondition: EditorContextKeys.writable, + kbOpts: { + weight: CORE_WEIGHT, + kbExpr: EditorContextKeys.textFocus, + primary: KeyCode.Backspace, + secondary: [KeyMod.Shift | KeyCode.Backspace], + mac: { primary: KeyCode.Backspace, secondary: [KeyMod.Shift | KeyCode.Backspace, KeyMod.WinCtrl | KeyCode.KEY_H, KeyMod.WinCtrl | KeyCode.Backspace] } + } + }); + } + + public runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void { + const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteLeft(editor._getCursorConfiguration(), editor.getModel(), editor.getSelections()); + if (shouldPushStackElementBefore) { + editor.pushUndoStop(); + } + editor.executeCommands(this.id, commands); + } + }); + + export const DeleteRight: EditorCommand = registerEditorCommand(new class extends EditorCommand { + constructor() { + super({ + id: 'deleteRight', + precondition: EditorContextKeys.writable, + kbOpts: { + weight: CORE_WEIGHT, + kbExpr: EditorContextKeys.textFocus, + primary: KeyCode.Delete, + mac: { primary: KeyCode.Delete, secondary: [KeyMod.WinCtrl | KeyCode.KEY_D, KeyMod.WinCtrl | KeyCode.Delete] } + } + }); + } + + public runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void { + const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteRight(editor._getCursorConfiguration(), editor.getModel(), editor.getSelections()); + if (shouldPushStackElementBefore) { + editor.pushUndoStop(); + } + editor.executeCommands(this.id, commands); + } + }); + } namespace Config { @@ -1412,88 +1528,10 @@ namespace Config { return getCodeEditor(activeEditor); } - function withCodeEditorFromCommandHandler(accessor: ServicesAccessor, callback: (editor: editorCommon.ICommonCodeEditor) => void): void { - let editor = findFocusedEditor(accessor); - if (editor) { - callback(editor); - } - } - - function triggerEditorHandler(handlerId: string, accessor: ServicesAccessor, args: any): void { - withCodeEditorFromCommandHandler(accessor, (editor) => { - editor.trigger('keyboard', handlerId, args); - }); - } - - class CoreCommand extends Command { - public runCommand(accessor: ServicesAccessor, args: any): void { - triggerEditorHandler(this.id, accessor, args); - } - } - function registerCommand(command: Command) { KeybindingsRegistry.registerCommandAndKeybindingRule(command.toCommandAndKeybindingRule(CORE_WEIGHT)); } - registerCommand(new CoreCommand({ - id: H.Tab, - precondition: EditorContextKeys.writable, - kbOpts: { - weight: CORE_WEIGHT, - kbExpr: ContextKeyExpr.and( - EditorContextKeys.textFocus, - EditorContextKeys.tabDoesNotMoveFocus - ), - primary: KeyCode.Tab - } - })); - registerCommand(new CoreCommand({ - id: H.Outdent, - precondition: EditorContextKeys.writable, - kbOpts: { - weight: CORE_WEIGHT, - kbExpr: ContextKeyExpr.and( - EditorContextKeys.textFocus, - EditorContextKeys.tabDoesNotMoveFocus - ), - primary: KeyMod.Shift | KeyCode.Tab - } - })); - - registerCommand(new CoreCommand({ - id: H.DeleteLeft, - precondition: EditorContextKeys.writable, - kbOpts: { - weight: CORE_WEIGHT, - kbExpr: EditorContextKeys.textFocus, - primary: KeyCode.Backspace, - secondary: [KeyMod.Shift | KeyCode.Backspace], - mac: { primary: KeyCode.Backspace, secondary: [KeyMod.Shift | KeyCode.Backspace, KeyMod.WinCtrl | KeyCode.KEY_H, KeyMod.WinCtrl | KeyCode.Backspace] } - } - })); - registerCommand(new CoreCommand({ - id: H.DeleteRight, - precondition: EditorContextKeys.writable, - kbOpts: { - weight: CORE_WEIGHT, - kbExpr: EditorContextKeys.textFocus, - primary: KeyCode.Delete, - mac: { primary: KeyCode.Delete, secondary: [KeyMod.WinCtrl | KeyCode.KEY_D, KeyMod.WinCtrl | KeyCode.Delete] } - } - })); - - registerCommand(new CoreCommand({ - id: H.LineBreakInsert, - precondition: EditorContextKeys.writable, - kbOpts: { - weight: CORE_WEIGHT, - kbExpr: EditorContextKeys.textFocus, - primary: null, - mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_O } - } - })); - - class BaseTextInputAwareCommand extends Command { private readonly _editorHandler: string | EditorCommand; diff --git a/src/vs/editor/common/controller/cursor.ts b/src/vs/editor/common/controller/cursor.ts index 42b712abd33..5c05fddaa84 100644 --- a/src/vs/editor/common/controller/cursor.ts +++ b/src/vs/editor/common/controller/cursor.ts @@ -504,21 +504,12 @@ export class Cursor extends Disposable implements ICursors { private _registerHandlers(): void { let H = editorCommon.Handler; - this._handlers[H.LineInsertAfter] = (args) => this._lineInsertAfter(args); - this._handlers[H.LineBreakInsert] = (args) => this._lineBreakInsert(args); - this._handlers[H.Type] = (args) => this._type(args); this._handlers[H.ReplacePreviousChar] = (args) => this._replacePreviousChar(args); this._handlers[H.CompositionStart] = (args) => this._compositionStart(args); this._handlers[H.CompositionEnd] = (args) => this._compositionEnd(args); - this._handlers[H.Tab] = (args) => this._tab(args); - this._handlers[H.Indent] = (args) => this._indent(args); - this._handlers[H.Outdent] = (args) => this._outdent(args); this._handlers[H.Paste] = (args) => this._paste(args); - this._handlers[H.DeleteLeft] = (args) => this._deleteLeft(args); - this._handlers[H.DeleteRight] = (args) => this._deleteRight(args); - this._handlers[H.Cut] = (args) => this._cut(args); this._handlers[H.Undo] = (args) => this._undo(args); @@ -542,6 +533,7 @@ export class Cursor extends Disposable implements ICursors { // -------------------- START editing operations + // TODO@Alex: remove private _getAllCursorsModelState(sorted: boolean = false): SingleCursorState[] { let cursors = this._cursors.getAll(); @@ -558,14 +550,6 @@ export class Cursor extends Disposable implements ICursors { return r; } - private _lineInsertAfter(args: CursorOperationArgs): EditOperationResult { - return TypeOperations.lineInsertAfter(this.context.config, this.context.model, this._getAllCursorsModelState()); - } - - private _lineBreakInsert(args: CursorOperationArgs): EditOperationResult { - return TypeOperations.lineBreakInsert(this.context.config, this.context.model, this._getAllCursorsModelState()); - } - private _type(args: CursorOperationArgs<{ text: string; }>): EditOperationResult { const text = args.eventData.text; @@ -613,18 +597,6 @@ export class Cursor extends Disposable implements ICursors { return null; } - private _tab(args: CursorOperationArgs): EditOperationResult { - return TypeOperations.tab(this.context.config, this.context.model, this._getAllCursorsModelState()); - } - - private _indent(args: CursorOperationArgs): EditOperationResult { - return TypeOperations.indent(this.context.config, this.context.model, this._getAllCursorsModelState()); - } - - private _outdent(args: CursorOperationArgs): EditOperationResult { - return TypeOperations.outdent(this.context.config, this.context.model, this._getAllCursorsModelState()); - } - private _distributePasteToCursors(args: CursorOperationArgs<{ pasteOnNewLine: boolean; text: string; }>): string[] { if (args.eventData.pasteOnNewLine) { return null; @@ -659,14 +631,6 @@ export class Cursor extends Disposable implements ICursors { } } - private _deleteLeft(args: CursorOperationArgs): EditOperationResult { - return DeleteOperations.deleteLeft(this.context.config, this.context.model, this._getAllCursorsModelState()); - } - - private _deleteRight(args: CursorOperationArgs): EditOperationResult { - return DeleteOperations.deleteRight(this.context.config, this.context.model, this._getAllCursorsModelState()); - } - private _cut(args: CursorOperationArgs): EditOperationResult { return DeleteOperations.cut(this.context.config, this.context.model, this._getAllCursorsModelState()); } diff --git a/src/vs/editor/common/controller/cursorDeleteOperations.ts b/src/vs/editor/common/controller/cursorDeleteOperations.ts index 68b006b107e..b6552f40e5d 100644 --- a/src/vs/editor/common/controller/cursorDeleteOperations.ts +++ b/src/vs/editor/common/controller/cursorDeleteOperations.ts @@ -7,22 +7,23 @@ import { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand'; import { SingleCursorState, CursorColumns, CursorConfiguration, ICursorSimpleModel, EditOperationResult } 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'; import * as strings from 'vs/base/common/strings'; import { ICommand } from "vs/editor/common/editorCommon"; export class DeleteOperations { - public static deleteRight(config: CursorConfiguration, model: ICursorSimpleModel, cursors: SingleCursorState[]): EditOperationResult { + public static deleteRight(config: CursorConfiguration, model: ICursorSimpleModel, cursors: Selection[]): [boolean, ICommand[]] { let commands: ICommand[] = []; let shouldPushStackElementBefore = false; for (let i = 0, len = cursors.length; i < len; i++) { const cursor = cursors[i]; - let deleteSelection: Range = cursor.selection; + let deleteSelection: Range = cursor; if (deleteSelection.isEmpty()) { - let position = cursor.position; + let position = cursor.getPosition(); let rightOfPosition = MoveOperations.right(config, model, position.lineNumber, position.column); deleteSelection = new Range( rightOfPosition.lineNumber, @@ -44,21 +45,17 @@ export class DeleteOperations { commands[i] = new ReplaceCommand(deleteSelection, ''); } - return new EditOperationResult(commands, { - shouldPushStackElementBefore: shouldPushStackElementBefore, - shouldPushStackElementAfter: false - }); + return [shouldPushStackElementBefore, commands]; } - private static _isAutoClosingPairDelete(config: CursorConfiguration, model: ICursorSimpleModel, cursors: SingleCursorState[]): boolean { + private static _isAutoClosingPairDelete(config: CursorConfiguration, model: ICursorSimpleModel, cursors: Selection[]): boolean { if (!config.autoClosingBrackets) { return false; } for (let i = 0, len = cursors.length; i < len; i++) { - const cursor = cursors[i]; - const selection = cursor.selection; - const position = cursor.position; + const selection = cursors[i]; + const position = selection.getPosition(); if (!selection.isEmpty()) { return false; @@ -82,11 +79,11 @@ export class DeleteOperations { return true; } - private static _runAutoClosingPairDelete(config: CursorConfiguration, model: ICursorSimpleModel, cursors: SingleCursorState[]): EditOperationResult { + private static _runAutoClosingPairDelete(config: CursorConfiguration, model: ICursorSimpleModel, cursors: Selection[]): [boolean, ICommand[]] { let commands: ICommand[] = []; for (let i = 0, len = cursors.length; i < len; i++) { const cursor = cursors[i]; - const position = cursor.position; + const position = cursor.getPosition(); const deleteSelection = new Range( position.lineNumber, position.column - 1, @@ -95,13 +92,10 @@ export class DeleteOperations { ); commands[i] = new ReplaceCommand(deleteSelection, ''); } - return new EditOperationResult(commands, { - shouldPushStackElementBefore: true, - shouldPushStackElementAfter: false - }); + return [true, commands]; } - public static deleteLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursors: SingleCursorState[]): EditOperationResult { + public static deleteLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursors: Selection[]): [boolean, ICommand[]] { if (this._isAutoClosingPairDelete(config, model, cursors)) { return this._runAutoClosingPairDelete(config, model, cursors); @@ -112,10 +106,10 @@ export class DeleteOperations { for (let i = 0, len = cursors.length; i < len; i++) { const cursor = cursors[i]; - let deleteSelection: Range = cursor.selection; + let deleteSelection: Range = cursor; if (deleteSelection.isEmpty()) { - let position = cursor.position; + let position = cursor.getPosition(); if (config.useTabStops && position.column > 1) { let lineContent = model.getLineContent(position.lineNumber); @@ -158,10 +152,7 @@ export class DeleteOperations { commands[i] = new ReplaceCommand(deleteSelection, ''); } - return new EditOperationResult(commands, { - shouldPushStackElementBefore: shouldPushStackElementBefore, - shouldPushStackElementAfter: false - }); + return [shouldPushStackElementBefore, commands]; } public static cut(config: CursorConfiguration, model: ICursorSimpleModel, cursors: SingleCursorState[]): EditOperationResult { diff --git a/src/vs/editor/common/controller/cursorTypeOperations.ts b/src/vs/editor/common/controller/cursorTypeOperations.ts index 7d9346cf06d..4b8237f13eb 100644 --- a/src/vs/editor/common/controller/cursorTypeOperations.ts +++ b/src/vs/editor/common/controller/cursorTypeOperations.ts @@ -21,38 +21,32 @@ import { CursorChangeReason } from "vs/editor/common/controller/cursorEvents"; export class TypeOperations { - public static indent(config: CursorConfiguration, model: ICursorSimpleModel, cursors: SingleCursorState[]): EditOperationResult { + public static indent(config: CursorConfiguration, model: ICursorSimpleModel, cursors: Selection[]): ICommand[] { let commands: ICommand[] = []; for (let i = 0, len = cursors.length; i < len; i++) { const cursor = cursors[i]; - commands[i] = new ShiftCommand(cursor.selection, { + commands[i] = new ShiftCommand(cursor, { isUnshift: false, tabSize: config.tabSize, oneIndent: config.oneIndent, useTabStops: config.useTabStops }); } - return new EditOperationResult(commands, { - shouldPushStackElementBefore: true, - shouldPushStackElementAfter: true - }); + return commands; } - public static outdent(config: CursorConfiguration, model: ICursorSimpleModel, cursors: SingleCursorState[]): EditOperationResult { + public static outdent(config: CursorConfiguration, model: ICursorSimpleModel, cursors: Selection[]): ICommand[] { let commands: ICommand[] = []; for (let i = 0, len = cursors.length; i < len; i++) { const cursor = cursors[i]; - commands[i] = new ShiftCommand(cursor.selection, { + commands[i] = new ShiftCommand(cursor, { isUnshift: true, tabSize: config.tabSize, oneIndent: config.oneIndent, useTabStops: config.useTabStops }); } - return new EditOperationResult(commands, { - shouldPushStackElementBefore: true, - shouldPushStackElementAfter: true - }); + return commands; } public static shiftIndent(config: CursorConfiguration, indentation: string, count?: number): string { @@ -172,11 +166,10 @@ export class TypeOperations { return new ReplaceCommand(selection, typeText, insertsAutoWhitespace); } - public static tab(config: CursorConfiguration, model: ITokenizedModel, cursors: SingleCursorState[]): EditOperationResult { + public static tab(config: CursorConfiguration, model: ITokenizedModel, cursors: Selection[]): ICommand[] { let commands: ICommand[] = []; for (let i = 0, len = cursors.length; i < len; i++) { - const cursor = cursors[i]; - let selection = cursor.selection; + const selection = cursors[i]; if (selection.isEmpty()) { @@ -211,10 +204,7 @@ export class TypeOperations { }); } } - return new EditOperationResult(commands, { - shouldPushStackElementBefore: true, - shouldPushStackElementAfter: true - }); + return commands; } public static replacePreviousChar(config: CursorConfiguration, model: ITokenizedModel, cursors: SingleCursorState[], txt: string, replaceCharCnt: number): EditOperationResult { @@ -600,29 +590,23 @@ export class TypeOperations { return commands; } - public static lineInsertAfter(config: CursorConfiguration, model: ITokenizedModel, cursors: SingleCursorState[]): EditOperationResult { + public static lineInsertAfter(config: CursorConfiguration, model: ITokenizedModel, cursors: Selection[]): ICommand[] { let commands: ICommand[] = []; for (let i = 0, len = cursors.length; i < len; i++) { const cursor = cursors[i]; - let position = cursor.position; - let column = model.getLineMaxColumn(position.lineNumber); - commands[i] = this._enter(config, model, false, new Range(position.lineNumber, column, position.lineNumber, column)); + let lineNumber = cursor.positionLineNumber; + let column = model.getLineMaxColumn(lineNumber); + commands[i] = this._enter(config, model, false, new Range(lineNumber, column, lineNumber, column)); } - return new EditOperationResult(commands, { - shouldPushStackElementBefore: true, - shouldPushStackElementAfter: false, - }); + return commands; } - public static lineBreakInsert(config: CursorConfiguration, model: ITokenizedModel, cursors: SingleCursorState[]): EditOperationResult { + public static lineBreakInsert(config: CursorConfiguration, model: ITokenizedModel, cursors: Selection[]): ICommand[] { let commands: ICommand[] = []; for (let i = 0, len = cursors.length; i < len; i++) { const cursor = cursors[i]; - commands[i] = this._enter(config, model, true, cursor.selection); + commands[i] = this._enter(config, model, true, cursor); } - return new EditOperationResult(commands, { - shouldPushStackElementBefore: true, - shouldPushStackElementAfter: false, - }); + return commands; } } diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index bca8965eafb..bec905e6cf2 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -2071,18 +2071,8 @@ export var Handler = { CompositionEnd: 'compositionEnd', Paste: 'paste', - Tab: 'tab', - Indent: 'indent', - Outdent: 'outdent', - - DeleteLeft: 'deleteLeft', - DeleteRight: 'deleteRight', - Cut: 'cut', Undo: 'undo', Redo: 'redo', - - LineInsertAfter: 'lineInsertAfter', - LineBreakInsert: 'lineBreakInsert', }; diff --git a/src/vs/editor/common/editorCommonExtensions.ts b/src/vs/editor/common/editorCommonExtensions.ts index cc2cac81cef..c80f219223d 100644 --- a/src/vs/editor/common/editorCommonExtensions.ts +++ b/src/vs/editor/common/editorCommonExtensions.ts @@ -74,22 +74,6 @@ export abstract class EditorAction extends ConfigEditorCommand { public abstract run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void | TPromise; } -export interface IHandlerActionOptions extends IActionOptions { - handlerId: string; -} -export abstract class HandlerEditorAction extends EditorAction { - private _handlerId: string; - - constructor(opts: IHandlerActionOptions) { - super(opts); - this._handlerId = opts.handlerId; - } - - public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { - editor.trigger(this.id, this._handlerId, null); - } -} - // --- Editor Actions export function editorAction(ctor: { new (): EditorAction; }): void { diff --git a/src/vs/editor/contrib/linesOperations/common/linesOperations.ts b/src/vs/editor/contrib/linesOperations/common/linesOperations.ts index 0cb23b50393..54143b106ba 100644 --- a/src/vs/editor/contrib/linesOperations/common/linesOperations.ts +++ b/src/vs/editor/contrib/linesOperations/common/linesOperations.ts @@ -9,16 +9,17 @@ import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes'; import { SortLinesCommand } from 'vs/editor/contrib/linesOperations/common/sortLinesCommand'; import { EditOperation } from 'vs/editor/common/core/editOperation'; import { TrimTrailingWhitespaceCommand } from 'vs/editor/common/commands/trimTrailingWhitespaceCommand'; -import { Handler, ICommand, ICommonCodeEditor, IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon'; +import { ICommand, ICommonCodeEditor, IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { ReplaceCommand, ReplaceCommandThatPreservesSelection } from 'vs/editor/common/commands/replaceCommand'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; -import { editorAction, ServicesAccessor, IActionOptions, EditorAction, HandlerEditorAction } from 'vs/editor/common/editorCommonExtensions'; +import { editorAction, ServicesAccessor, IActionOptions, EditorAction } from 'vs/editor/common/editorCommonExtensions'; import { CopyLinesCommand } from './copyLinesCommand'; import { DeleteLinesCommand } from './deleteLinesCommand'; import { MoveLinesCommand } from './moveLinesCommand'; import { TypeOperations } from 'vs/editor/common/controller/cursorTypeOperations'; +import { CoreEditingCommands } from "vs/editor/common/controller/coreCommands"; // copy lines @@ -296,37 +297,45 @@ class DeleteLinesAction extends AbstractRemoveLinesAction { } @editorAction -class IndentLinesAction extends HandlerEditorAction { +export class IndentLinesAction extends EditorAction { constructor() { super({ id: 'editor.action.indentLines', label: nls.localize('lines.indent', "Indent Line"), alias: 'Indent Line', precondition: EditorContextKeys.writable, - handlerId: Handler.Indent, kbOpts: { kbExpr: EditorContextKeys.textFocus, primary: KeyMod.CtrlCmd | KeyCode.US_CLOSE_SQUARE_BRACKET } }); } + + public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { + editor.pushUndoStop(); + editor.executeCommands(this.id, TypeOperations.indent(editor._getCursorConfiguration(), editor.getModel(), editor.getSelections())); + editor.pushUndoStop(); + } } @editorAction -class OutdentLinesAction extends HandlerEditorAction { +class OutdentLinesAction extends EditorAction { constructor() { super({ id: 'editor.action.outdentLines', label: nls.localize('lines.outdent', "Outdent Line"), alias: 'Outdent Line', precondition: EditorContextKeys.writable, - handlerId: Handler.Outdent, kbOpts: { kbExpr: EditorContextKeys.textFocus, primary: KeyMod.CtrlCmd | KeyCode.US_OPEN_SQUARE_BRACKET } }); } + + public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { + CoreEditingCommands.Outdent.runEditorCommand(null, editor, null); + } } @editorAction @@ -351,20 +360,24 @@ export class InsertLineBeforeAction extends EditorAction { } @editorAction -class InsertLineAfterAction extends HandlerEditorAction { +export class InsertLineAfterAction extends EditorAction { constructor() { super({ id: 'editor.action.insertLineAfter', label: nls.localize('lines.insertAfter', "Insert Line Below"), alias: 'Insert Line Below', precondition: EditorContextKeys.writable, - handlerId: Handler.LineInsertAfter, kbOpts: { kbExpr: EditorContextKeys.textFocus, primary: KeyMod.CtrlCmd | KeyCode.Enter } }); } + + public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void { + editor.pushUndoStop(); + editor.executeCommands(this.id, TypeOperations.lineInsertAfter(editor._getCursorConfiguration(), editor.getModel(), editor.getSelections())); + } } export abstract class AbstractDeleteAllToBoundaryAction extends EditorAction { diff --git a/src/vs/editor/contrib/linesOperations/test/common/linesOperations.test.ts b/src/vs/editor/contrib/linesOperations/test/common/linesOperations.test.ts index f32dd7ee822..87930f8457f 100644 --- a/src/vs/editor/contrib/linesOperations/test/common/linesOperations.test.ts +++ b/src/vs/editor/contrib/linesOperations/test/common/linesOperations.test.ts @@ -7,10 +7,12 @@ import * as assert from 'assert'; import { Selection } from 'vs/editor/common/core/selection'; import { Position } from 'vs/editor/common/core/position'; -import { Handler, IModel } from 'vs/editor/common/editorCommon'; +import { Handler, IModel, DefaultEndOfLine } from 'vs/editor/common/editorCommon'; import { withMockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor'; -import { DeleteAllLeftAction, JoinLinesAction, TransposeAction, UpperCaseAction, LowerCaseAction, DeleteAllRightAction, InsertLineBeforeAction } from 'vs/editor/contrib/linesOperations/common/linesOperations'; +import { DeleteAllLeftAction, JoinLinesAction, TransposeAction, UpperCaseAction, LowerCaseAction, DeleteAllRightAction, InsertLineBeforeAction, InsertLineAfterAction, IndentLinesAction } from 'vs/editor/contrib/linesOperations/common/linesOperations'; import { Cursor } from "vs/editor/common/controller/cursor"; +import { Model } from "vs/editor/common/model/model"; +import { CoreEditingCommands } from "vs/editor/common/controller/coreCommands"; suite('Editor Contrib - Line Operations', () => { suite('DeleteAllLeftAction', () => { @@ -531,4 +533,75 @@ suite('Editor Contrib - Line Operations', () => { assert.equal(model.getLineContent(4), 'Third line'); }); }); -}); \ No newline at end of file + + test('InsertLineAfterAction', () => { + function testInsertLineAfter(lineNumber: number, column: number, callback: (model: IModel, cursor: Cursor) => void): void { + const TEXT = [ + 'First line', + 'Second line', + 'Third line' + ]; + withMockCodeEditor(TEXT, {}, (editor, cursor) => { + editor.setPosition(new Position(lineNumber, column)); + let insertLineAfterAction = new InsertLineAfterAction(); + + insertLineAfterAction.run(null, editor); + callback(editor.getModel(), cursor); + }); + } + + testInsertLineAfter(1, 3, (model, cursor) => { + assert.deepEqual(cursor.getSelection(), new Selection(2, 1, 2, 1)); + assert.equal(model.getLineContent(1), 'First line'); + assert.equal(model.getLineContent(2), ''); + assert.equal(model.getLineContent(3), 'Second line'); + assert.equal(model.getLineContent(4), 'Third line'); + }); + + testInsertLineAfter(2, 3, (model, cursor) => { + assert.deepEqual(cursor.getSelection(), new Selection(3, 1, 3, 1)); + assert.equal(model.getLineContent(1), 'First line'); + assert.equal(model.getLineContent(2), 'Second line'); + assert.equal(model.getLineContent(3), ''); + assert.equal(model.getLineContent(4), 'Third line'); + }); + + testInsertLineAfter(3, 3, (model, cursor) => { + assert.deepEqual(cursor.getSelection(), new Selection(4, 1, 4, 1)); + assert.equal(model.getLineContent(1), 'First line'); + assert.equal(model.getLineContent(2), 'Second line'); + assert.equal(model.getLineContent(3), 'Third line'); + assert.equal(model.getLineContent(4), ''); + }); + }); + + test('Bug 18276:[editor] Indentation broken when selection is empty', () => { + + let model = Model.createFromString( + [ + 'function baz() {' + ].join('\n'), + { + defaultEOL: DefaultEndOfLine.LF, + detectIndentation: false, + insertSpaces: false, + tabSize: 4, + trimAutoWhitespace: true + } + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { + let indentLinesAction = new IndentLinesAction(); + editor.setPosition(new Position(1, 2)); + + indentLinesAction.run(null, editor); + assert.equal(model.getLineContent(1), '\tfunction baz() {'); + assert.deepEqual(editor.getSelection(), new Selection(1, 3, 1, 3)); + + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); + assert.equal(model.getLineContent(1), '\tf\tunction baz() {'); + }); + + model.dispose(); + }); +}); diff --git a/src/vs/editor/test/common/controller/cursor.test.ts b/src/vs/editor/test/common/controller/cursor.test.ts index 8a505460120..f11a0c6775e 100644 --- a/src/vs/editor/test/common/controller/cursor.test.ts +++ b/src/vs/editor/test/common/controller/cursor.test.ts @@ -24,7 +24,9 @@ import { LanguageIdentifier } from 'vs/editor/common/modes'; import { viewModelHelper } from 'vs/editor/test/common/editorTestUtils'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; -import { CoreNavigationCommands } from 'vs/editor/common/controller/coreCommands'; +import { CoreNavigationCommands, CoreEditingCommands } from 'vs/editor/common/controller/coreCommands'; +import { withMockCodeEditor } from "vs/editor/test/common/mocks/mockCodeEditor"; +import { TextModel } from "vs/editor/common/model/textModel"; let H = Handler; @@ -1119,22 +1121,24 @@ class IndentRulesMode extends MockMode { suite('Editor Controller - Regression tests', () => { test('Bug 9121: Auto indent + undo + redo is funky', () => { - usingCursor({ - text: [ + let model = Model.createFromString( + [ '' - ], - modelOpts: { + ].join('\n'), + { defaultEOL: DefaultEndOfLine.LF, detectIndentation: false, insertSpaces: false, tabSize: 4, trimAutoWhitespace: false - } - }, (model, cursor) => { + }, + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { cursorCommand(cursor, H.Type, { text: '\n' }, 'keyboard'); assert.equal(model.getValue(EndOfLinePreference.LF), '\n', 'assert1'); - cursorCommand(cursor, H.Tab, {}); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getValue(EndOfLinePreference.LF), '\n\t', 'assert2'); cursorCommand(cursor, H.Type, { text: '\n' }, 'keyboard'); @@ -1146,16 +1150,16 @@ suite('Editor Controller - Regression tests', () => { CoreNavigationCommands.CursorLeft.runCoreEditorCommand(cursor, {}); assert.equal(model.getValue(EndOfLinePreference.LF), '\n\t\n\tx', 'assert5'); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getValue(EndOfLinePreference.LF), '\n\t\nx', 'assert6'); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getValue(EndOfLinePreference.LF), '\n\tx', 'assert7'); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getValue(EndOfLinePreference.LF), '\nx', 'assert8'); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getValue(EndOfLinePreference.LF), 'x', 'assert9'); cursorCommand(cursor, H.Undo, {}); @@ -1176,219 +1180,234 @@ suite('Editor Controller - Regression tests', () => { cursorCommand(cursor, H.Redo, {}); assert.equal(model.getValue(EndOfLinePreference.LF), 'x', 'assert15'); }); + + model.dispose(); }); - - test('bug #16543: Tab should indent to correct indentation spot immediately', () => { let mode = new OnEnterMode(IndentAction.Indent); - usingCursor({ - text: [ + let model = Model.createFromString( + [ 'function baz() {', '\tfunction hello() { // something here', '\t', '', '\t}', '}' - ], - modelOpts: { + ].join('\n'), + { defaultEOL: DefaultEndOfLine.LF, detectIndentation: false, insertSpaces: false, tabSize: 4, trimAutoWhitespace: true }, - languageIdentifier: mode.getLanguageIdentifier(), - }, (model, cursor) => { + mode.getLanguageIdentifier() + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { moveTo(cursor, 4, 1, false); assertCursor(cursor, new Selection(4, 1, 4, 1)); - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(4), '\t\t'); }); + + model.dispose(); mode.dispose(); }); test('bug #2938 (1): When pressing Tab on white-space only lines, indent straight to the right spot (similar to empty lines)', () => { let mode = new OnEnterMode(IndentAction.Indent); - usingCursor({ - text: [ + let model = Model.createFromString( + [ '\tfunction baz() {', '\t\tfunction hello() { // something here', '\t\t', '\t', '\t\t}', '\t}' - ], - modelOpts: { + ].join('\n'), + { defaultEOL: DefaultEndOfLine.LF, detectIndentation: false, insertSpaces: false, tabSize: 4, trimAutoWhitespace: true }, - languageIdentifier: mode.getLanguageIdentifier(), - }, (model, cursor) => { + mode.getLanguageIdentifier() + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { moveTo(cursor, 4, 2, false); assertCursor(cursor, new Selection(4, 2, 4, 2)); - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(4), '\t\t\t'); }); + + model.dispose(); mode.dispose(); }); test('bug #2938 (2): When pressing Tab on white-space only lines, indent straight to the right spot (similar to empty lines)', () => { let mode = new OnEnterMode(IndentAction.Indent); - usingCursor({ - text: [ + let model = Model.createFromString( + [ '\tfunction baz() {', '\t\tfunction hello() { // something here', '\t\t', ' ', '\t\t}', '\t}' - ], - modelOpts: { + ].join('\n'), + { defaultEOL: DefaultEndOfLine.LF, detectIndentation: false, insertSpaces: false, tabSize: 4, trimAutoWhitespace: true }, - languageIdentifier: mode.getLanguageIdentifier(), - }, (model, cursor) => { + mode.getLanguageIdentifier() + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { moveTo(cursor, 4, 1, false); assertCursor(cursor, new Selection(4, 1, 4, 1)); - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(4), '\t\t\t'); }); + + model.dispose(); mode.dispose(); }); test('bug #2938 (3): When pressing Tab on white-space only lines, indent straight to the right spot (similar to empty lines)', () => { let mode = new OnEnterMode(IndentAction.Indent); - usingCursor({ - text: [ + let model = Model.createFromString( + [ '\tfunction baz() {', '\t\tfunction hello() { // something here', '\t\t', '\t\t\t', '\t\t}', '\t}' - ], - modelOpts: { + ].join('\n'), + { defaultEOL: DefaultEndOfLine.LF, detectIndentation: false, insertSpaces: false, tabSize: 4, trimAutoWhitespace: true }, - languageIdentifier: mode.getLanguageIdentifier(), - }, (model, cursor) => { + mode.getLanguageIdentifier() + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { moveTo(cursor, 4, 3, false); assertCursor(cursor, new Selection(4, 3, 4, 3)); - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(4), '\t\t\t\t'); }); + + model.dispose(); mode.dispose(); }); test('bug #2938 (4): When pressing Tab on white-space only lines, indent straight to the right spot (similar to empty lines)', () => { let mode = new OnEnterMode(IndentAction.Indent); - usingCursor({ - text: [ + let model = Model.createFromString( + [ '\tfunction baz() {', '\t\tfunction hello() { // something here', '\t\t', '\t\t\t\t', '\t\t}', '\t}' - ], - modelOpts: { + ].join('\n'), + { defaultEOL: DefaultEndOfLine.LF, detectIndentation: false, insertSpaces: false, tabSize: 4, trimAutoWhitespace: true }, - languageIdentifier: mode.getLanguageIdentifier(), - }, (model, cursor) => { + mode.getLanguageIdentifier() + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { moveTo(cursor, 4, 4, false); assertCursor(cursor, new Selection(4, 4, 4, 4)); - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(4), '\t\t\t\t\t'); }); + + model.dispose(); mode.dispose(); }); - test('Bug 18276:[editor] Indentation broken when selection is empty', () => { - usingCursor({ - text: [ - 'function baz() {' - ], - modelOpts: { - defaultEOL: DefaultEndOfLine.LF, - detectIndentation: false, - insertSpaces: false, - tabSize: 4, - trimAutoWhitespace: true - }, - }, (model, cursor) => { - moveTo(cursor, 1, 2, false); - assertCursor(cursor, new Selection(1, 2, 1, 2)); - - cursorCommand(cursor, H.Indent, null, 'keyboard'); - assert.equal(model.getLineContent(1), '\tfunction baz() {'); - - assertCursor(cursor, new Selection(1, 3, 1, 3)); - cursorCommand(cursor, H.Tab, null, 'keyboard'); - assert.equal(model.getLineContent(1), '\tf\tunction baz() {'); - }); - }); - test('bug #16815:Shift+Tab doesn\'t go back to tabstop', () => { let mode = new OnEnterMode(IndentAction.IndentOutdent); - usingCursor({ - text: [ + let model = Model.createFromString( + [ ' function baz() {' - ], - languageIdentifier: mode.getLanguageIdentifier(), - modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true } - }, (model, cursor) => { + ].join('\n'), + { + insertSpaces: true, + tabSize: 4, + detectIndentation: false, + defaultEOL: DefaultEndOfLine.LF, + trimAutoWhitespace: true + }, + mode.getLanguageIdentifier() + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { moveTo(cursor, 1, 6, false); assertCursor(cursor, new Selection(1, 6, 1, 6)); - cursorCommand(cursor, H.Outdent, null, 'keyboard'); + CoreEditingCommands.Outdent.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(1), ' function baz() {'); assertCursor(cursor, new Selection(1, 5, 1, 5)); }); + + model.dispose(); mode.dispose(); }); test('Bug #18293:[regression][editor] Can\'t outdent whitespace line', () => { - usingCursor({ - text: [ + let model = Model.createFromString( + [ ' ' - ], - modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true } - }, (model, cursor) => { + ].join('\n'), + { + insertSpaces: true, + tabSize: 4, + detectIndentation: false, + defaultEOL: DefaultEndOfLine.LF, + trimAutoWhitespace: true + } + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { moveTo(cursor, 1, 7, false); assertCursor(cursor, new Selection(1, 7, 1, 7)); - cursorCommand(cursor, H.Outdent, null, 'keyboard'); + CoreEditingCommands.Outdent.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(1), ' '); assertCursor(cursor, new Selection(1, 5, 1, 5)); }); + + model.dispose(); }); test('Bug #16657: [editor] Tab on empty line of zero indentation moves cursor to position (1,1)', () => { - usingCursor({ - text: [ + let model = Model.createFromString( + [ 'function baz() {', '\tfunction hello() { // something here', '\t', @@ -1396,22 +1415,26 @@ suite('Editor Controller - Regression tests', () => { '\t}', '}', '' - ], - modelOpts: { + ].join('\n'), + { defaultEOL: DefaultEndOfLine.LF, detectIndentation: false, insertSpaces: false, tabSize: 4, trimAutoWhitespace: true }, - }, (model, cursor) => { + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { moveTo(cursor, 7, 1, false); assertCursor(cursor, new Selection(7, 1, 7, 1)); - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(7), '\t'); assertCursor(cursor, new Selection(7, 2, 7, 2)); }); + + model.dispose(); }); test('bug #16740: [editor] Cut line doesn\'t quite cut the last line', () => { @@ -1480,24 +1503,33 @@ suite('Editor Controller - Regression tests', () => { test('issue #1140: Backspace stops prematurely', () => { let mode = new SurroundingMode(); - usingCursor({ - text: [ + let model = Model.createFromString( + [ 'function baz() {', ' return 1;', '};' - ], - languageIdentifier: mode.getLanguageIdentifier(), - modelOpts: { tabSize: 4, insertSpaces: true, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true } - }, (model, cursor) => { + ].join('\n'), + { + tabSize: 4, + insertSpaces: true, + detectIndentation: false, + defaultEOL: DefaultEndOfLine.LF, + trimAutoWhitespace: true + }, + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { moveTo(cursor, 3, 2, false); moveTo(cursor, 1, 14, true); assertCursor(cursor, new Selection(3, 2, 1, 14)); - cursorCommand(cursor, H.DeleteLeft); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assertCursor(cursor, new Selection(1, 14, 1, 14)); assert.equal(model.getLineCount(), 1); assert.equal(model.getLineContent(1), 'function baz(;'); }); + + model.dispose(); mode.dispose(); }); @@ -1520,15 +1552,22 @@ suite('Editor Controller - Regression tests', () => { }); test('issue #3071: Investigate why undo stack gets corrupted', () => { - usingCursor({ - text: [ + let model = Model.createFromString( + [ 'some lines', 'and more lines', 'just some text', - ], - languageIdentifier: null, - modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true } - }, (model, cursor) => { + ].join('\n'), + { + insertSpaces: true, + tabSize: 4, + detectIndentation: false, + defaultEOL: DefaultEndOfLine.LF, + trimAutoWhitespace: true + } + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { moveTo(cursor, 1, 1, false); moveTo(cursor, 3, 4, true); @@ -1540,7 +1579,7 @@ suite('Editor Controller - Regression tests', () => { } }); - cursorCommand(cursor, H.Tab); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getValue(), [ '\t just some text' ].join('\n'), '001'); @@ -1559,6 +1598,8 @@ suite('Editor Controller - Regression tests', () => { 'just some text', ].join('\n'), '003'); }); + + model.dispose(); }); test('issue #12950: Cannot Double Click To Insert Emoji Using OSX Emoji Panel', () => { @@ -1584,35 +1625,55 @@ suite('Editor Controller - Regression tests', () => { }); test('issue #3463: pressing tab adds spaces, but not as many as for a tab', () => { - usingCursor({ - text: [ + let model = Model.createFromString( + [ 'function a() {', '\tvar a = {', '\t\tx: 3', '\t};', '}', - ], - modelOpts: { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true } - }, (model, cursor) => { + ].join('\n'), + { + insertSpaces: true, + tabSize: 4, + detectIndentation: false, + defaultEOL: DefaultEndOfLine.LF, + trimAutoWhitespace: true + } + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { moveTo(cursor, 3, 2, false); - cursorCommand(cursor, H.Tab); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(3), '\t \tx: 3'); }); + + model.dispose(); }); test('issue #4312: trying to type a tab character over a sequence of spaces results in unexpected behaviour', () => { - usingCursor({ - text: [ + let model = Model.createFromString( + [ 'var foo = 123; // this is a comment', 'var bar = 4; // another comment' - ], - modelOpts: { insertSpaces: false, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true } - }, (model, cursor) => { + ].join('\n'), + { + insertSpaces: false, + tabSize: 4, + detectIndentation: false, + defaultEOL: DefaultEndOfLine.LF, + trimAutoWhitespace: true + } + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { moveTo(cursor, 1, 15, false); moveTo(cursor, 1, 22, true); - cursorCommand(cursor, H.Tab); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(1), 'var foo = 123;\t// this is a comment'); }); + + model.dispose(); }); test('issue #832: word right', () => { @@ -1810,70 +1871,80 @@ suite('Editor Controller - Cursor Configuration', () => { }); test('Cursor honors insertSpaces configuration on tab', () => { - usingCursor({ - text: [ + let model = Model.createFromString( + [ ' \tMy First Line\t ', 'My Second Line123', ' Third Line', '', '1' - ], - modelOpts: { insertSpaces: true, tabSize: 13, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true } - }, (model, cursor) => { + ].join('\n'), + { + insertSpaces: true, + tabSize: 13, + detectIndentation: false, + defaultEOL: DefaultEndOfLine.LF, + trimAutoWhitespace: true + } + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { // Tab on column 1 cursorCommand(cursor, CoreNavigationCommands.MoveTo.id, { position: new Position(2, 1) }, 'keyboard'); - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(2), ' My Second Line123'); cursorCommand(cursor, H.Undo, null, 'keyboard'); // Tab on column 2 assert.equal(model.getLineContent(2), 'My Second Line123'); cursorCommand(cursor, CoreNavigationCommands.MoveTo.id, { position: new Position(2, 2) }, 'keyboard'); - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(2), 'M y Second Line123'); cursorCommand(cursor, H.Undo, null, 'keyboard'); // Tab on column 3 assert.equal(model.getLineContent(2), 'My Second Line123'); cursorCommand(cursor, CoreNavigationCommands.MoveTo.id, { position: new Position(2, 3) }, 'keyboard'); - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(2), 'My Second Line123'); cursorCommand(cursor, H.Undo, null, 'keyboard'); // Tab on column 4 assert.equal(model.getLineContent(2), 'My Second Line123'); cursorCommand(cursor, CoreNavigationCommands.MoveTo.id, { position: new Position(2, 4) }, 'keyboard'); - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(2), 'My Second Line123'); cursorCommand(cursor, H.Undo, null, 'keyboard'); // Tab on column 5 assert.equal(model.getLineContent(2), 'My Second Line123'); cursorCommand(cursor, CoreNavigationCommands.MoveTo.id, { position: new Position(2, 5) }, 'keyboard'); - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(2), 'My S econd Line123'); cursorCommand(cursor, H.Undo, null, 'keyboard'); // Tab on column 5 assert.equal(model.getLineContent(2), 'My Second Line123'); cursorCommand(cursor, CoreNavigationCommands.MoveTo.id, { position: new Position(2, 5) }, 'keyboard'); - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(2), 'My S econd Line123'); cursorCommand(cursor, H.Undo, null, 'keyboard'); // Tab on column 13 assert.equal(model.getLineContent(2), 'My Second Line123'); cursorCommand(cursor, CoreNavigationCommands.MoveTo.id, { position: new Position(2, 13) }, 'keyboard'); - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(2), 'My Second Li ne123'); cursorCommand(cursor, H.Undo, null, 'keyboard'); // Tab on column 14 assert.equal(model.getLineContent(2), 'My Second Line123'); cursorCommand(cursor, CoreNavigationCommands.MoveTo.id, { position: new Position(2, 14) }, 'keyboard'); - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(2), 'My Second Lin e123'); }); + + model.dispose(); }); test('Enter auto-indents with insertSpaces setting 1', () => { @@ -1930,48 +2001,6 @@ suite('Editor Controller - Cursor Configuration', () => { mode.dispose(); }); - test('Insert line after', () => { - let testInsertLineAfter = (lineNumber: number, column: number, callback: (model: Model, cursor: Cursor) => void) => { - usingCursor({ - text: [ - 'First line', - 'Second line', - 'Third line' - ], - }, (model, cursor) => { - moveTo(cursor, lineNumber, column, false); - assertCursor(cursor, new Position(lineNumber, column)); - - cursorCommand(cursor, H.LineInsertAfter, null, 'keyboard'); - callback(model, cursor); - }); - }; - - testInsertLineAfter(1, 3, (model, cursor) => { - assertCursor(cursor, new Selection(2, 1, 2, 1)); - assert.equal(model.getLineContent(1), 'First line'); - assert.equal(model.getLineContent(2), ''); - assert.equal(model.getLineContent(3), 'Second line'); - assert.equal(model.getLineContent(4), 'Third line'); - }); - - testInsertLineAfter(2, 3, (model, cursor) => { - assertCursor(cursor, new Selection(3, 1, 3, 1)); - assert.equal(model.getLineContent(1), 'First line'); - assert.equal(model.getLineContent(2), 'Second line'); - assert.equal(model.getLineContent(3), ''); - assert.equal(model.getLineContent(4), 'Third line'); - }); - - testInsertLineAfter(3, 3, (model, cursor) => { - assertCursor(cursor, new Selection(4, 1, 4, 1)); - assert.equal(model.getLineContent(1), 'First line'); - assert.equal(model.getLineContent(2), 'Second line'); - assert.equal(model.getLineContent(3), 'Third line'); - assert.equal(model.getLineContent(4), ''); - }); - }); - test('removeAutoWhitespace off', () => { usingCursor({ text: [ @@ -2071,25 +2100,27 @@ suite('Editor Controller - Cursor Configuration', () => { }); test('removeAutoWhitespace on: removes only whitespace the cursor added 2', () => { - usingCursor({ - text: [ + let model = Model.createFromString( + [ ' if (a) {', ' ', '', '', ' }' - ], - modelOpts: { + ].join('\n'), + { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true } - }, (model, cursor) => { + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { moveTo(cursor, 3, 1); - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(1), ' if (a) {'); assert.equal(model.getLineContent(2), ' '); assert.equal(model.getLineContent(3), ' '); @@ -2097,7 +2128,7 @@ suite('Editor Controller - Cursor Configuration', () => { assert.equal(model.getLineContent(5), ' }'); moveTo(cursor, 4, 1); - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(1), ' if (a) {'); assert.equal(model.getLineContent(2), ' '); assert.equal(model.getLineContent(3), ''); @@ -2112,21 +2143,25 @@ suite('Editor Controller - Cursor Configuration', () => { assert.equal(model.getLineContent(4), ''); assert.equal(model.getLineContent(5), ' }something'); }); + + model.dispose(); }); test('removeAutoWhitespace on: test 1', () => { - usingCursor({ - text: [ + let model = Model.createFromString( + [ ' some line abc ' - ], - modelOpts: { + ].join('\n'), + { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true } - }, (model, cursor) => { + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { // Move cursor to the end, verify that we do not trim whitespaces if line has values moveTo(cursor, 1, model.getLineContent(1).length + 1); @@ -2141,7 +2176,7 @@ suite('Editor Controller - Cursor Configuration', () => { assert.equal(model.getLineContent(3), ' '); // More whitespaces - cursorCommand(cursor, H.Tab, null, 'keyboard'); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(1), ' some line abc '); assert.equal(model.getLineContent(2), ''); assert.equal(model.getLineContent(3), ' '); @@ -2172,63 +2207,65 @@ suite('Editor Controller - Cursor Configuration', () => { assert.equal(model.getLineContent(4), ''); assert.equal(model.getLineContent(5), ''); }); + + model.dispose(); }); test('UseTabStops is off', () => { - usingCursor({ - text: [ + let model = Model.createFromString( + [ ' x', ' a ', ' ' - ], - modelOpts: { + ].join('\n'), + { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true - }, - editorOpts: { - useTabStops: false } - }, (model, cursor) => { + ); + + withMockCodeEditor(null, { model: model, useTabStops: false }, (editor, cursor) => { // DeleteLeft removes just one whitespace moveTo(cursor, 2, 9); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(2), ' a '); }); + + model.dispose(); }); test('Backspace removes whitespaces with tab size', () => { - usingCursor({ - text: [ + let model = Model.createFromString( + [ ' \t \t x', ' a ', ' ' - ], - modelOpts: { + ].join('\n'), + { insertSpaces: true, tabSize: 4, detectIndentation: false, defaultEOL: DefaultEndOfLine.LF, trimAutoWhitespace: true - }, - editorOpts: { - useTabStops: true } - }, (model, cursor) => { + ); + + withMockCodeEditor(null, { model: model, useTabStops: true }, (editor, cursor) => { // DeleteLeft does not remove tab size, because some text exists before moveTo(cursor, 2, model.getLineContent(2).length + 1); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(2), ' a '); // DeleteLeft removes tab size = 4 moveTo(cursor, 2, 9); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(2), ' a '); // DeleteLeft removes tab size = 4 - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(2), 'a '); // Undo DeleteLeft - get us back to original indentation @@ -2237,57 +2274,61 @@ suite('Editor Controller - Cursor Configuration', () => { // Nothing is broken when cursor is in (1,1) moveTo(cursor, 1, 1); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(1), ' \t \t x'); // DeleteLeft stops at tab stops even in mixed whitespace case moveTo(cursor, 1, 10); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(1), ' \t \t x'); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(1), ' \t \tx'); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(1), ' \tx'); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(1), 'x'); // DeleteLeft on last line moveTo(cursor, 3, model.getLineContent(3).length + 1); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(3), ''); // DeleteLeft with removing new line symbol - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getValue(EndOfLinePreference.LF), 'x\n a '); // In case of selection DeleteLeft only deletes selected text moveTo(cursor, 2, 3); moveTo(cursor, 2, 4, true); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getLineContent(2), ' a '); }); + + model.dispose(); }); test('PR #5423: Auto indent + undo + redo is funky', () => { - usingCursor({ - text: [ + let model = Model.createFromString( + [ '' - ], - modelOpts: { + ].join('\n'), + { defaultEOL: DefaultEndOfLine.LF, detectIndentation: false, insertSpaces: false, tabSize: 4, trimAutoWhitespace: true } - }, (model, cursor) => { + ); + + withMockCodeEditor(null, { model: model }, (editor, cursor) => { cursorCommand(cursor, H.Type, { text: '\n' }, 'keyboard'); assert.equal(model.getValue(EndOfLinePreference.LF), '\n', 'assert1'); - cursorCommand(cursor, H.Tab, {}); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); assert.equal(model.getValue(EndOfLinePreference.LF), '\n\t', 'assert2'); cursorCommand(cursor, H.Type, { text: 'y' }, 'keyboard'); @@ -2302,19 +2343,19 @@ suite('Editor Controller - Cursor Configuration', () => { CoreNavigationCommands.CursorLeft.runCoreEditorCommand(cursor, {}); assert.equal(model.getValue(EndOfLinePreference.LF), '\n\ty\n\tx', 'assert5'); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getValue(EndOfLinePreference.LF), '\n\ty\nx', 'assert6'); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getValue(EndOfLinePreference.LF), '\n\tyx', 'assert7'); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getValue(EndOfLinePreference.LF), '\n\tx', 'assert8'); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getValue(EndOfLinePreference.LF), '\nx', 'assert9'); - cursorCommand(cursor, H.DeleteLeft, {}); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getValue(EndOfLinePreference.LF), 'x', 'assert10'); cursorCommand(cursor, H.Undo, {}); @@ -2335,6 +2376,8 @@ suite('Editor Controller - Cursor Configuration', () => { cursorCommand(cursor, H.Redo, {}); assert.equal(model.getValue(EndOfLinePreference.LF), 'x', 'assert16'); }); + + model.dispose(); }); }); @@ -3247,23 +3290,26 @@ suite('autoClosingPairs', () => { test('All cursors should do the same thing when deleting left', () => { let mode = new AutoClosingMode(); - usingCursor({ - text: [ + let model = Model.createFromString( + [ 'var a = ()' - ], - languageIdentifier: mode.getLanguageIdentifier() - }, (model, cursor) => { + ].join('\n'), + TextModel.DEFAULT_CREATION_OPTIONS, + mode.getLanguageIdentifier() + ); + withMockCodeEditor(null, { model: model }, (editor, cursor) => { cursor.setSelections('test', [ new Selection(1, 4, 1, 4), new Selection(1, 10, 1, 10), ]); // delete left - cursorCommand(cursor, H.DeleteLeft, null, 'keyboard'); + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); assert.equal(model.getValue(), 'va a = )'); }); + model.dispose(); mode.dispose(); }); }); diff --git a/src/vs/workbench/parts/debug/electron-browser/debugEditorContribution.ts b/src/vs/workbench/parts/debug/electron-browser/debugEditorContribution.ts index 2b29b662fec..f0e0ed7a9bd 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugEditorContribution.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugEditorContribution.ts @@ -19,7 +19,7 @@ import { StandardTokenType } from 'vs/editor/common/modes'; import { DEFAULT_WORD_REGEXP } from 'vs/editor/common/model/wordHelper'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; -import { IDecorationOptions, IModelDecorationOptions, IModelDeltaDecoration, TrackedRangeStickiness, Handler } from 'vs/editor/common/editorCommon'; +import { IDecorationOptions, IModelDecorationOptions, IModelDeltaDecoration, TrackedRangeStickiness } from 'vs/editor/common/editorCommon'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; import { Range } from 'vs/editor/common/core/range'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -37,6 +37,7 @@ import { FloatingClickWidget } from 'vs/workbench/parts/preferences/browser/pref import { IListService } from 'vs/platform/list/browser/listService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Position } from 'vs/editor/common/core/position'; +import { CoreEditingCommands } from "vs/editor/common/controller/coreCommands"; const HOVER_DELAY = 300; const LAUNCH_JSON_REGEX = /launch\.json$/; @@ -434,7 +435,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { // Check if there are more characters on a line after a "configurations": [, if yes enter a newline if (this.editor.getModel().getLineLastNonWhitespaceColumn(position.lineNumber) > position.column) { this.editor.setPosition(position); - this.editor.trigger(this.getId(), Handler.LineBreakInsert, undefined); + CoreEditingCommands.LineBreakInsert.runEditorCommand(null, this.editor, null); } // Check if there is already an empty line to insert suggest, if yes just place the cursor if (this.editor.getModel().getLineLastNonWhitespaceColumn(position.lineNumber + 1) === 0) { diff --git a/src/vs/workbench/parts/emmet/electron-browser/actions/expandAbbreviation.ts b/src/vs/workbench/parts/emmet/electron-browser/actions/expandAbbreviation.ts index 85f464b2865..f1db99bf647 100644 --- a/src/vs/workbench/parts/emmet/electron-browser/actions/expandAbbreviation.ts +++ b/src/vs/workbench/parts/emmet/electron-browser/actions/expandAbbreviation.ts @@ -9,8 +9,9 @@ import nls = require('vs/nls'); import { BasicEmmetEditorAction } from 'vs/workbench/parts/emmet/electron-browser/emmetActions'; import { editorAction } from 'vs/editor/common/editorCommonExtensions'; -import { Handler, ICommonCodeEditor } from 'vs/editor/common/editorCommon'; +import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { CoreEditingCommands } from "vs/editor/common/controller/coreCommands"; import { KeyCode } from 'vs/base/common/keyCodes'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; @@ -40,6 +41,6 @@ class ExpandAbbreviationAction extends BasicEmmetEditorAction { protected noExpansionOccurred(editor: ICommonCodeEditor): void { // forward the tab key back to the editor - editor.trigger('emmet', Handler.Tab, {}); + CoreEditingCommands.Tab.runEditorCommand(null, editor, null); } } diff --git a/src/vs/workbench/parts/emmet/electron-browser/editorAccessor.ts b/src/vs/workbench/parts/emmet/electron-browser/editorAccessor.ts index 15079c88a2c..a55193df515 100644 --- a/src/vs/workbench/parts/emmet/electron-browser/editorAccessor.ts +++ b/src/vs/workbench/parts/emmet/electron-browser/editorAccessor.ts @@ -5,13 +5,14 @@ 'use strict'; -import { ICommonCodeEditor, Handler } from 'vs/editor/common/editorCommon'; +import { ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import strings = require('vs/base/common/strings'); import snippets = require('vs/editor/contrib/snippet/common/snippet'); import { Range } from 'vs/editor/common/core/range'; import { SnippetController2 } from 'vs/editor/contrib/snippet/browser/snippetController2'; import { LanguageId, LanguageIdentifier } from 'vs/editor/common/modes'; import { Position } from 'vs/editor/common/core/position'; +import { CoreEditingCommands } from "vs/editor/common/controller/coreCommands"; import emmet = require('emmet'); @@ -140,7 +141,7 @@ export class EditorAccessor implements emmet.Editor { // During Expand Abbreviation action, if the expanded abbr is the same as the text it intends to replace, // then treat it as a no-op and return TAB to the editor if (this._emmetActionName === 'expand_abbreviation' && (value === textToReplace || value === textToReplace + '${0}')) { - this._editor.trigger('emmet', Handler.Tab, {}); + CoreEditingCommands.Tab.runEditorCommand(null, this._editor, null); return null; }