Move more editing operations out of cursor.ts

This commit is contained in:
Alex Dima
2017-05-19 00:19:54 +02:00
parent 5a40238c40
commit cc38e4eabb
13 changed files with 553 additions and 455 deletions
+20 -8
View File
@@ -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 {
+116 -78
View File
@@ -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;
+1 -37
View File
@@ -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<void>): EditOperationResult {
return TypeOperations.lineInsertAfter(this.context.config, this.context.model, this._getAllCursorsModelState());
}
private _lineBreakInsert(args: CursorOperationArgs<void>): 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<void>): EditOperationResult {
return TypeOperations.tab(this.context.config, this.context.model, this._getAllCursorsModelState());
}
private _indent(args: CursorOperationArgs<void>): EditOperationResult {
return TypeOperations.indent(this.context.config, this.context.model, this._getAllCursorsModelState());
}
private _outdent(args: CursorOperationArgs<void>): 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<void>): EditOperationResult {
return DeleteOperations.deleteLeft(this.context.config, this.context.model, this._getAllCursorsModelState());
}
private _deleteRight(args: CursorOperationArgs<void>): EditOperationResult {
return DeleteOperations.deleteRight(this.context.config, this.context.model, this._getAllCursorsModelState());
}
private _cut(args: CursorOperationArgs<void>): EditOperationResult {
return DeleteOperations.cut(this.context.config, this.context.model, this._getAllCursorsModelState());
}
@@ -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 {
@@ -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;
}
}
-10
View File
@@ -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',
};
@@ -74,22 +74,6 @@ export abstract class EditorAction extends ConfigEditorCommand {
public abstract run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void | TPromise<void>;
}
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 {
@@ -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 {
@@ -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');
});
});
});
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();
});
});
@@ -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();
});
});
@@ -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) {
@@ -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);
}
}
@@ -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;
}