diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index ba293981009..31dff819977 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -333,11 +333,11 @@ export function compareIgnoreCase(a: string, b: string): number { } } -function isLowerAsciiLetter(code: number): boolean { +export function isLowerAsciiLetter(code: number): boolean { return code >= CharCode.a && code <= CharCode.z; } -function isUpperAsciiLetter(code: number): boolean { +export function isUpperAsciiLetter(code: number): boolean { return code >= CharCode.A && code <= CharCode.Z; } diff --git a/src/vs/editor/common/controller/cursorWordOperations.ts b/src/vs/editor/common/controller/cursorWordOperations.ts index 8bd73b791f0..b69d9799b53 100644 --- a/src/vs/editor/common/controller/cursorWordOperations.ts +++ b/src/vs/editor/common/controller/cursorWordOperations.ts @@ -10,6 +10,7 @@ import { WordCharacterClassifier, WordCharacterClass, getMapForWordSeparators } import * as strings from 'vs/base/common/strings'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; +import { CharCode } from 'vs/base/common/charCode'; interface IFindWordResult { /** @@ -235,7 +236,7 @@ export class WordOperations { return new Position(lineNumber, column); } - private static _deleteWordLeftWhitespace(model: ICursorSimpleModel, position: Position): Range { + protected static _deleteWordLeftWhitespace(model: ICursorSimpleModel, position: Position): Range { const lineContent = model.getLineContent(position.lineNumber); const startIndex = position.column - 2; const lastNonWhitespace = strings.lastNonWhitespaceIndex(lineContent, startIndex); @@ -310,7 +311,7 @@ export class WordOperations { return len; } - private static _deleteWordRightWhitespace(model: ICursorSimpleModel, position: Position): Range { + protected static _deleteWordRightWhitespace(model: ICursorSimpleModel, position: Position): Range { const lineContent = model.getLineContent(position.lineNumber); const startIndex = position.column - 1; const firstNonWhitespace = this._findFirstNonWhitespaceChar(lineContent, startIndex); @@ -463,3 +464,128 @@ export class WordOperations { return cursor.move(true, lineNumber, column, 0); } } + +export function _lastWordPartEnd(str: string, startIndex: number = str.length - 1): number { + for (let i = startIndex; i >= 0; i--) { + let chCode = str.charCodeAt(i); + if (chCode === CharCode.Space || chCode === CharCode.Tab || strings.isUpperAsciiLetter(chCode) || chCode === CharCode.Underline) { + return i - 1; + } + } + return -1; +} + +export function _nextWordPartBegin(str: string, startIndex: number = str.length - 1): number { + const checkLowerCase = str.charCodeAt(startIndex - 1) === CharCode.Space; // does a lc char count as a part start? + for (let i = startIndex; i < str.length; ++i) { + let chCode = str.charCodeAt(i); + if (chCode === CharCode.Space || chCode === CharCode.Tab || strings.isUpperAsciiLetter(chCode) || (checkLowerCase && strings.isLowerAsciiLetter(chCode))) { + return i + 1; + } + if (chCode === CharCode.Underline) { + return i + 2; + } + } + return str.length + 1; +} + +export class WordPartOperations extends WordOperations { + public static deleteWordPartLeft(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, selection: Selection, whitespaceHeuristics: boolean, wordNavigationType: WordNavigationType): Range { + if (!selection.isEmpty()) { + return selection; + } + + const position = new Position(selection.positionLineNumber, selection.positionColumn); + const lineNumber = position.lineNumber; + const column = position.column; + + if (lineNumber === 1 && column === 1) { + // Ignore deleting at beginning of file + return null; + } + + if (whitespaceHeuristics) { + let r = WordOperations._deleteWordLeftWhitespace(model, position); + if (r) { + return r; + } + } + + const wordRange = WordOperations.deleteWordLeft(wordSeparators, model, selection, whitespaceHeuristics, wordNavigationType); + const lastWordPartEnd = _lastWordPartEnd(model.getLineContent(position.lineNumber), position.column - 2); + const wordPartRange = new Range(lineNumber, column, lineNumber, lastWordPartEnd + 2); + + if (wordPartRange.getStartPosition().isBeforeOrEqual(wordRange.getStartPosition())) { + return wordRange; + } + return wordPartRange; + } + + public static deleteWordPartRight(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, selection: Selection, whitespaceHeuristics: boolean, wordNavigationType: WordNavigationType): Range { + if (!selection.isEmpty()) { + return selection; + } + + const position = new Position(selection.positionLineNumber, selection.positionColumn); + const lineNumber = position.lineNumber; + const column = position.column; + + const lineCount = model.getLineCount(); + const maxColumn = model.getLineMaxColumn(lineNumber); + if (lineNumber === lineCount && column === maxColumn) { + // Ignore deleting at end of file + return null; + } + + if (whitespaceHeuristics) { + let r = WordOperations._deleteWordRightWhitespace(model, position); + if (r) { + return r; + } + } + + const wordRange = WordOperations.deleteWordRight(wordSeparators, model, selection, whitespaceHeuristics, wordNavigationType); + const nextWordPartBegin = _nextWordPartBegin(model.getLineContent(position.lineNumber), position.column); + const wordPartRange = new Range(lineNumber, column, lineNumber, nextWordPartBegin); + + if (wordRange.getEndPosition().isBeforeOrEqual(wordPartRange.getEndPosition())) { + return wordRange; + } + return wordPartRange; + } + + public static moveWordPartLeft(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position, wordNavigationType: WordNavigationType): Position { + const lineNumber = position.lineNumber; + const column = position.column; + if (column === 1) { + return (lineNumber > 1 ? new Position(lineNumber - 1, model.getLineMaxColumn(lineNumber - 1)) : position); + } + + const wordPos = WordOperations.moveWordLeft(wordSeparators, model, position, wordNavigationType); + const lastWordPartEnd = _lastWordPartEnd(model.getLineContent(lineNumber), column - 2); + const wordPartPos = new Position(lineNumber, lastWordPartEnd + 2); + + if (wordPartPos.isBeforeOrEqual(wordPos)) { + return wordPos; + } + return wordPartPos; + } + + public static moveWordPartRight(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position, wordNavigationType: WordNavigationType): Position { + const lineNumber = position.lineNumber; + const column = position.column; + const maxColumn = model.getLineMaxColumn(lineNumber); + if (column === maxColumn) { + return (lineNumber < model.getLineCount() ? new Position(lineNumber + 1, 1) : position); + } + + const wordPos = WordOperations.moveWordRight(wordSeparators, model, position, wordNavigationType); + const nextWordPartBegin = _nextWordPartBegin(model.getLineContent(lineNumber), column); + const wordPartPos = new Position(lineNumber, nextWordPartBegin); + + if (wordPos.isBeforeOrEqual(wordPartPos)) { + return wordPos; + } + return wordPartPos; + } +} diff --git a/src/vs/editor/contrib/wordPartOperations/test/wordPartOperations.test.ts b/src/vs/editor/contrib/wordPartOperations/test/wordPartOperations.test.ts new file mode 100644 index 00000000000..2074dd9cfc6 --- /dev/null +++ b/src/vs/editor/contrib/wordPartOperations/test/wordPartOperations.test.ts @@ -0,0 +1,209 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import * as assert from 'assert'; +import { Position } from 'vs/editor/common/core/position'; +import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor'; +import { + DeleteWordPartLeft, DeleteWordPartRight, + CursorWordPartLeft, CursorWordPartRight +} from 'vs/editor/contrib/wordPartOperations/wordPartOperations'; +import { EditorCommand } from 'vs/editor/browser/editorExtensions'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; + +suite('WordPartOperations', () => { + const _deleteWordPartLeft = new DeleteWordPartLeft(); + const _deleteWordPartRight = new DeleteWordPartRight(); + const _cursorWordPartLeft = new CursorWordPartLeft(); + const _cursorWordPartRight = new CursorWordPartRight(); + + function runEditorCommand(editor: ICodeEditor, command: EditorCommand): void { + command.runEditorCommand(null, editor, null); + } + function moveWordPartLeft(editor: ICodeEditor, inSelectionmode: boolean = false): void { + runEditorCommand(editor, inSelectionmode ? _cursorWordPartLeft : _cursorWordPartLeft); + } + function moveWordPartRight(editor: ICodeEditor, inSelectionmode: boolean = false): void { + runEditorCommand(editor, inSelectionmode ? _cursorWordPartLeft : _cursorWordPartRight); + } + function deleteWordPartLeft(editor: ICodeEditor): void { + runEditorCommand(editor, _deleteWordPartLeft); + } + function deleteWordPartRight(editor: ICodeEditor): void { + runEditorCommand(editor, _deleteWordPartRight); + } + + test('move word part left basic', () => { + withTestCodeEditor([ + 'start line', + 'thisIsACamelCaseVar this_is_a_snake_case_var', + 'end line' + ], {}, (editor, _) => { + editor.setPosition(new Position(3, 8)); + const expectedStops = [ + [3, 5], + [3, 4], + [3, 1], + [2, 46], + [2, 42], + [2, 37], + [2, 31], + [2, 29], + [2, 26], + [2, 22], + [2, 21], + [2, 20], + [2, 17], + [2, 13], + [2, 8], + [2, 7], + [2, 5], + [2, 1], + [1, 11], + [1, 7], + [1, 6], + [1, 1] + ]; + + let actualStops: number[][] = []; + for (let i = 0; i < expectedStops.length; i++) { + moveWordPartLeft(editor); + const pos = editor.getPosition(); + actualStops.push([pos.lineNumber, pos.column]); + } + + assert.deepEqual(actualStops, expectedStops); + }); + }); + + test('move word part right basic', () => { + withTestCodeEditor([ + 'start line', + 'thisIsACamelCaseVar this_is_a_snake_case_var', + 'end line' + ], {}, (editor, _) => { + editor.setPosition(new Position(1, 1)); + const expectedStops = [ + [1, 6], + [1, 7], + [1, 11], + [2, 1], + [2, 5], + [2, 7], + [2, 8], + [2, 13], + [2, 17], + [2, 20], + [2, 21], + [2, 22], + [2, 27], + [2, 30], + [2, 32], + [2, 38], + [2, 43], + [2, 46], + [3, 1], + [3, 4], + [3, 5], + [3, 9] + ]; + + let actualStops: number[][] = []; + for (let i = 0; i < expectedStops.length; i++) { + moveWordPartRight(editor); + const pos = editor.getPosition(); + actualStops.push([pos.lineNumber, pos.column]); + } + + assert.deepEqual(actualStops, expectedStops); + }); + }); + + test('delete word part left basic', () => { + withTestCodeEditor([ + ' /* Just some text a+= 3 +5-3 */ thisIsACamelCaseVar this_is_a_snake_case_var' + ], {}, (editor, _) => { + const model = editor.getModel(); + editor.setPosition(new Position(1, 84)); + + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-3 */ thisIsACamelCaseVar this_is_a_snake_case', '001'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-3 */ thisIsACamelCaseVar this_is_a_snake', '002'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-3 */ thisIsACamelCaseVar this_is_a', '003'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-3 */ thisIsACamelCaseVar this_is', '004'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-3 */ thisIsACamelCaseVar this', '005'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-3 */ thisIsACamelCaseVar ', '006'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-3 */ thisIsACamelCaseVar', '007'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-3 */ thisIsACamelCase', '008'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-3 */ thisIsACamel', '009'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-3 */ thisIsA', '010'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-3 */ thisIs', '011'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-3 */ this', '012'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-3 */ ', '013'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-3 */', '014'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-3 ', '015'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-3', '015bis'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5-', '016'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +5', '017'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 +', '018'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3 ', '019'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= 3', '019bis'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+= ', '020'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a+=', '021'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text a', '022'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text ', '023'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some text', '024'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some ', '025'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just some', '026'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just ', '027'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* Just', '028'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /* ', '029'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' /*', '030'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), ' ', '031'); + deleteWordPartLeft(editor); assert.equal(model.getLineContent(1), '', '032'); + }); + }); + + test('delete word part right basic', () => { + withTestCodeEditor([ + ' /* Just some text a+= 3 +5-3 */ thisIsACamelCaseVar this_is_a_snake_case_var' + ], {}, (editor, _) => { + const model = editor.getModel(); + editor.setPosition(new Position(1, 1)); + + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), '/* Just some text a+= 3 +5-3 */ thisIsACamelCaseVar this_is_a_snake_case_var', '001'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), ' Just some text a+= 3 +5-3 */ thisIsACamelCaseVar this_is_a_snake_case_var', '002'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), 'Just some text a+= 3 +5-3 */ thisIsACamelCaseVar this_is_a_snake_case_var', '003'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), ' some text a+= 3 +5-3 */ thisIsACamelCaseVar this_is_a_snake_case_var', '004'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), 'some text a+= 3 +5-3 */ thisIsACamelCaseVar this_is_a_snake_case_var', '005'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), ' text a+= 3 +5-3 */ thisIsACamelCaseVar this_is_a_snake_case_var', '006'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), 'text a+= 3 +5-3 */ thisIsACamelCaseVar this_is_a_snake_case_var', '007'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), ' a+= 3 +5-3 */ thisIsACamelCaseVar this_is_a_snake_case_var', '008'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), 'a+= 3 +5-3 */ thisIsACamelCaseVar this_is_a_snake_case_var', '009'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), '+= 3 +5-3 */ thisIsACamelCaseVar this_is_a_snake_case_var', '010'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), ' 3 +5-3 */ thisIsACamelCaseVar this_is_a_snake_case_var', '011'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), ' +5-3 */ thisIsACamelCaseVar this_is_a_snake_case_var', '012'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), '5-3 */ thisIsACamelCaseVar this_is_a_snake_case_var', '013'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), '-3 */ thisIsACamelCaseVar this_is_a_snake_case_var', '014'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), '3 */ thisIsACamelCaseVar this_is_a_snake_case_var', '015'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), ' */ thisIsACamelCaseVar this_is_a_snake_case_var', '016'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), ' thisIsACamelCaseVar this_is_a_snake_case_var', '017'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), 'thisIsACamelCaseVar this_is_a_snake_case_var', '018'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), 'IsACamelCaseVar this_is_a_snake_case_var', '019'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), 'ACamelCaseVar this_is_a_snake_case_var', '020'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), 'CamelCaseVar this_is_a_snake_case_var', '021'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), 'CaseVar this_is_a_snake_case_var', '022'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), 'Var this_is_a_snake_case_var', '023'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), ' this_is_a_snake_case_var', '024'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), 'this_is_a_snake_case_var', '025'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), 'is_a_snake_case_var', '026'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), 'a_snake_case_var', '027'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), 'snake_case_var', '028'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), 'case_var', '029'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), 'var', '030'); + deleteWordPartRight(editor); assert.equal(model.getLineContent(1), '', '031'); + }); + }); +}); diff --git a/src/vs/editor/contrib/wordPartOperations/wordPartOperations.ts b/src/vs/editor/contrib/wordPartOperations/wordPartOperations.ts new file mode 100644 index 00000000000..28829ba7b31 --- /dev/null +++ b/src/vs/editor/contrib/wordPartOperations/wordPartOperations.ts @@ -0,0 +1,147 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { ITextModel } from 'vs/editor/common/model'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { Selection } from 'vs/editor/common/core/selection'; +import { registerEditorCommand } from 'vs/editor/browser/editorExtensions'; +import { Range } from 'vs/editor/common/core/range'; +import { WordNavigationType, WordPartOperations } from 'vs/editor/common/controller/cursorWordOperations'; +import { WordCharacterClassifier } from 'vs/editor/common/controller/wordCharacterClassifier'; +import { DeleteWordCommand, MoveWordCommand } from '../wordOperations/wordOperations'; +import { Position } from 'vs/editor/common/core/position'; + +export class DeleteWordPartLeft extends DeleteWordCommand { + constructor() { + super({ + whitespaceHeuristics: true, + wordNavigationType: WordNavigationType.WordStart, + id: 'deleteWordPartLeft', + precondition: EditorContextKeys.writable, + kbOpts: { + kbExpr: EditorContextKeys.textInputFocus, + primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Backspace, + mac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.Backspace } + } + }); + } + + protected _delete(wordSeparators: WordCharacterClassifier, model: ITextModel, selection: Selection, whitespaceHeuristics: boolean, wordNavigationType: WordNavigationType): Range { + let r = WordPartOperations.deleteWordPartLeft(wordSeparators, model, selection, whitespaceHeuristics, wordNavigationType); + if (r) { + return r; + } + return new Range(1, 1, 1, 1); + } +} + +export class DeleteWordPartRight extends DeleteWordCommand { + constructor() { + super({ + whitespaceHeuristics: true, + wordNavigationType: WordNavigationType.WordEnd, + id: 'deleteWordPartRight', + precondition: EditorContextKeys.writable, + kbOpts: { + kbExpr: EditorContextKeys.textInputFocus, + primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Delete, + mac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.Delete } + } + }); + } + + protected _delete(wordSeparators: WordCharacterClassifier, model: ITextModel, selection: Selection, whitespaceHeuristics: boolean, wordNavigationType: WordNavigationType): Range { + let r = WordPartOperations.deleteWordPartRight(wordSeparators, model, selection, whitespaceHeuristics, wordNavigationType); + if (r) { + return r; + } + const lineCount = model.getLineCount(); + const maxColumn = model.getLineMaxColumn(lineCount); + return new Range(lineCount, maxColumn, lineCount, maxColumn); + } +} + +export class WordPartLeftCommand extends MoveWordCommand { + protected _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position { + return WordPartOperations.moveWordPartLeft(wordSeparators, model, position, wordNavigationType); + } +} +export class CursorWordPartLeft extends WordPartLeftCommand { + constructor() { + super({ + inSelectionMode: false, + wordNavigationType: WordNavigationType.WordStart, + id: 'cursorWordPartStartLeft', + precondition: null, + kbOpts: { + kbExpr: EditorContextKeys.textInputFocus, + primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.LeftArrow, + mac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.LeftArrow } + } + }); + } +} +export class CursorWordPartLeftSelect extends WordPartLeftCommand { + constructor() { + super({ + inSelectionMode: true, + wordNavigationType: WordNavigationType.WordStart, + id: 'cursorWordPartStartLeftSelect', + precondition: null, + kbOpts: { + kbExpr: EditorContextKeys.textInputFocus, + primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyMod.Shift | KeyCode.LeftArrow, + mac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyMod.Shift | KeyCode.LeftArrow } + } + }); + } +} + +export class WordPartRightCommand extends MoveWordCommand { + protected _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position { + return WordPartOperations.moveWordPartRight(wordSeparators, model, position, wordNavigationType); + } +} +export class CursorWordPartRight extends WordPartRightCommand { + constructor() { + super({ + inSelectionMode: false, + wordNavigationType: WordNavigationType.WordEnd, + id: 'cursorWordPartRight', + precondition: null, + kbOpts: { + kbExpr: EditorContextKeys.textInputFocus, + primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.RightArrow, + mac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.RightArrow } + } + }); + } +} +export class CursorWordPartRightSelect extends WordPartRightCommand { + constructor() { + super({ + inSelectionMode: true, + wordNavigationType: WordNavigationType.WordEnd, + id: 'cursorWordPartRightSelect', + precondition: null, + kbOpts: { + kbExpr: EditorContextKeys.textInputFocus, + primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyMod.Shift | KeyCode.RightArrow, + mac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyMod.Shift | KeyCode.RightArrow } + } + }); + } +} + + +registerEditorCommand(new DeleteWordPartLeft()); +registerEditorCommand(new DeleteWordPartRight()); +registerEditorCommand(new CursorWordPartLeft()); +registerEditorCommand(new CursorWordPartLeftSelect()); +registerEditorCommand(new CursorWordPartRight()); +registerEditorCommand(new CursorWordPartRightSelect()); diff --git a/src/vs/editor/editor.all.ts b/src/vs/editor/editor.all.ts index e23a365cca7..cc32769c6a6 100644 --- a/src/vs/editor/editor.all.ts +++ b/src/vs/editor/editor.all.ts @@ -42,3 +42,4 @@ import 'vs/editor/contrib/suggest/suggestController'; import 'vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode'; import 'vs/editor/contrib/wordHighlighter/wordHighlighter'; import 'vs/editor/contrib/wordOperations/wordOperations'; +import 'vs/editor/contrib/wordPartOperations/wordPartOperations';