/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as strings from '../../../base/common/strings.js'; import { SingleCursorState } from '../cursorCommon.js'; import { DeleteOperations } from './cursorDeleteOperations.js'; import { getMapForWordSeparators } from '../core/wordCharacterClassifier.js'; import { Position } from '../core/position.js'; import { Range } from '../core/range.js'; export class WordOperations { static _createWord(lineContent, wordType, nextCharClass, start, end) { // console.log('WORD ==> ' + start + ' => ' + end + ':::: <<<' + lineContent.substring(start, end) + '>>>'); return { start: start, end: end, wordType: wordType, nextCharClass: nextCharClass }; } static _findPreviousWordOnLine(wordSeparators, model, position) { const lineContent = model.getLineContent(position.lineNumber); return this._doFindPreviousWordOnLine(lineContent, wordSeparators, position); } static _doFindPreviousWordOnLine(lineContent, wordSeparators, position) { let wordType = 0 /* WordType.None */; for (let chIndex = position.column - 2; chIndex >= 0; chIndex--) { const chCode = lineContent.charCodeAt(chIndex); const chClass = wordSeparators.get(chCode); if (chClass === 0 /* WordCharacterClass.Regular */) { if (wordType === 2 /* WordType.Separator */) { return this._createWord(lineContent, wordType, chClass, chIndex + 1, this._findEndOfWord(lineContent, wordSeparators, wordType, chIndex + 1)); } wordType = 1 /* WordType.Regular */; } else if (chClass === 2 /* WordCharacterClass.WordSeparator */) { if (wordType === 1 /* WordType.Regular */) { return this._createWord(lineContent, wordType, chClass, chIndex + 1, this._findEndOfWord(lineContent, wordSeparators, wordType, chIndex + 1)); } wordType = 2 /* WordType.Separator */; } else if (chClass === 1 /* WordCharacterClass.Whitespace */) { if (wordType !== 0 /* WordType.None */) { return this._createWord(lineContent, wordType, chClass, chIndex + 1, this._findEndOfWord(lineContent, wordSeparators, wordType, chIndex + 1)); } } } if (wordType !== 0 /* WordType.None */) { return this._createWord(lineContent, wordType, 1 /* WordCharacterClass.Whitespace */, 0, this._findEndOfWord(lineContent, wordSeparators, wordType, 0)); } return null; } static _findEndOfWord(lineContent, wordSeparators, wordType, startIndex) { const len = lineContent.length; for (let chIndex = startIndex; chIndex < len; chIndex++) { const chCode = lineContent.charCodeAt(chIndex); const chClass = wordSeparators.get(chCode); if (chClass === 1 /* WordCharacterClass.Whitespace */) { return chIndex; } if (wordType === 1 /* WordType.Regular */ && chClass === 2 /* WordCharacterClass.WordSeparator */) { return chIndex; } if (wordType === 2 /* WordType.Separator */ && chClass === 0 /* WordCharacterClass.Regular */) { return chIndex; } } return len; } static _findNextWordOnLine(wordSeparators, model, position) { const lineContent = model.getLineContent(position.lineNumber); return this._doFindNextWordOnLine(lineContent, wordSeparators, position); } static _doFindNextWordOnLine(lineContent, wordSeparators, position) { let wordType = 0 /* WordType.None */; const len = lineContent.length; for (let chIndex = position.column - 1; chIndex < len; chIndex++) { const chCode = lineContent.charCodeAt(chIndex); const chClass = wordSeparators.get(chCode); if (chClass === 0 /* WordCharacterClass.Regular */) { if (wordType === 2 /* WordType.Separator */) { return this._createWord(lineContent, wordType, chClass, this._findStartOfWord(lineContent, wordSeparators, wordType, chIndex - 1), chIndex); } wordType = 1 /* WordType.Regular */; } else if (chClass === 2 /* WordCharacterClass.WordSeparator */) { if (wordType === 1 /* WordType.Regular */) { return this._createWord(lineContent, wordType, chClass, this._findStartOfWord(lineContent, wordSeparators, wordType, chIndex - 1), chIndex); } wordType = 2 /* WordType.Separator */; } else if (chClass === 1 /* WordCharacterClass.Whitespace */) { if (wordType !== 0 /* WordType.None */) { return this._createWord(lineContent, wordType, chClass, this._findStartOfWord(lineContent, wordSeparators, wordType, chIndex - 1), chIndex); } } } if (wordType !== 0 /* WordType.None */) { return this._createWord(lineContent, wordType, 1 /* WordCharacterClass.Whitespace */, this._findStartOfWord(lineContent, wordSeparators, wordType, len - 1), len); } return null; } static _findStartOfWord(lineContent, wordSeparators, wordType, startIndex) { for (let chIndex = startIndex; chIndex >= 0; chIndex--) { const chCode = lineContent.charCodeAt(chIndex); const chClass = wordSeparators.get(chCode); if (chClass === 1 /* WordCharacterClass.Whitespace */) { return chIndex + 1; } if (wordType === 1 /* WordType.Regular */ && chClass === 2 /* WordCharacterClass.WordSeparator */) { return chIndex + 1; } if (wordType === 2 /* WordType.Separator */ && chClass === 0 /* WordCharacterClass.Regular */) { return chIndex + 1; } } return 0; } static moveWordLeft(wordSeparators, model, position, wordNavigationType) { let lineNumber = position.lineNumber; let column = position.column; if (column === 1) { if (lineNumber > 1) { lineNumber = lineNumber - 1; column = model.getLineMaxColumn(lineNumber); } } let prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, column)); if (wordNavigationType === 0 /* WordNavigationType.WordStart */) { return new Position(lineNumber, prevWordOnLine ? prevWordOnLine.start + 1 : 1); } if (wordNavigationType === 1 /* WordNavigationType.WordStartFast */) { if (prevWordOnLine && prevWordOnLine.wordType === 2 /* WordType.Separator */ && prevWordOnLine.end - prevWordOnLine.start === 1 && prevWordOnLine.nextCharClass === 0 /* WordCharacterClass.Regular */) { // Skip over a word made up of one single separator and followed by a regular character prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, prevWordOnLine.start + 1)); } return new Position(lineNumber, prevWordOnLine ? prevWordOnLine.start + 1 : 1); } if (wordNavigationType === 3 /* WordNavigationType.WordAccessibility */) { while (prevWordOnLine && prevWordOnLine.wordType === 2 /* WordType.Separator */) { // Skip over words made up of only separators prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, prevWordOnLine.start + 1)); } return new Position(lineNumber, prevWordOnLine ? prevWordOnLine.start + 1 : 1); } // We are stopping at the ending of words if (prevWordOnLine && column <= prevWordOnLine.end + 1) { prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, prevWordOnLine.start + 1)); } return new Position(lineNumber, prevWordOnLine ? prevWordOnLine.end + 1 : 1); } static _moveWordPartLeft(model, position) { const lineNumber = position.lineNumber; const maxColumn = model.getLineMaxColumn(lineNumber); if (position.column === 1) { return (lineNumber > 1 ? new Position(lineNumber - 1, model.getLineMaxColumn(lineNumber - 1)) : position); } const lineContent = model.getLineContent(lineNumber); for (let column = position.column - 1; column > 1; column--) { const left = lineContent.charCodeAt(column - 2); const right = lineContent.charCodeAt(column - 1); if (left === 95 /* CharCode.Underline */ && right !== 95 /* CharCode.Underline */) { // snake_case_variables return new Position(lineNumber, column); } if ((strings.isLowerAsciiLetter(left) || strings.isAsciiDigit(left)) && strings.isUpperAsciiLetter(right)) { // camelCaseVariables return new Position(lineNumber, column); } if (strings.isUpperAsciiLetter(left) && strings.isUpperAsciiLetter(right)) { // thisIsACamelCaseWithOneLetterWords if (column + 1 < maxColumn) { const rightRight = lineContent.charCodeAt(column); if (strings.isLowerAsciiLetter(rightRight) || strings.isAsciiDigit(rightRight)) { return new Position(lineNumber, column); } } } } return new Position(lineNumber, 1); } static moveWordRight(wordSeparators, model, position, wordNavigationType) { let lineNumber = position.lineNumber; let column = position.column; let movedDown = false; if (column === model.getLineMaxColumn(lineNumber)) { if (lineNumber < model.getLineCount()) { movedDown = true; lineNumber = lineNumber + 1; column = 1; } } let nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, column)); if (wordNavigationType === 2 /* WordNavigationType.WordEnd */) { if (nextWordOnLine && nextWordOnLine.wordType === 2 /* WordType.Separator */) { if (nextWordOnLine.end - nextWordOnLine.start === 1 && nextWordOnLine.nextCharClass === 0 /* WordCharacterClass.Regular */) { // Skip over a word made up of one single separator and followed by a regular character nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, nextWordOnLine.end + 1)); } } if (nextWordOnLine) { column = nextWordOnLine.end + 1; } else { column = model.getLineMaxColumn(lineNumber); } } else if (wordNavigationType === 3 /* WordNavigationType.WordAccessibility */) { if (movedDown) { // If we move to the next line, pretend that the cursor is right before the first character. // This is needed when the first word starts right at the first character - and in order not to miss it, // we need to start before. column = 0; } while (nextWordOnLine && (nextWordOnLine.wordType === 2 /* WordType.Separator */ || nextWordOnLine.start + 1 <= column)) { // Skip over a word made up of one single separator // Also skip over word if it begins before current cursor position to ascertain we're moving forward at least 1 character. nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, nextWordOnLine.end + 1)); } if (nextWordOnLine) { column = nextWordOnLine.start + 1; } else { column = model.getLineMaxColumn(lineNumber); } } else { if (nextWordOnLine && !movedDown && column >= nextWordOnLine.start + 1) { nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, nextWordOnLine.end + 1)); } if (nextWordOnLine) { column = nextWordOnLine.start + 1; } else { column = model.getLineMaxColumn(lineNumber); } } return new Position(lineNumber, column); } static _moveWordPartRight(model, position) { const lineNumber = position.lineNumber; const maxColumn = model.getLineMaxColumn(lineNumber); if (position.column === maxColumn) { return (lineNumber < model.getLineCount() ? new Position(lineNumber + 1, 1) : position); } const lineContent = model.getLineContent(lineNumber); for (let column = position.column + 1; column < maxColumn; column++) { const left = lineContent.charCodeAt(column - 2); const right = lineContent.charCodeAt(column - 1); if (left !== 95 /* CharCode.Underline */ && right === 95 /* CharCode.Underline */) { // snake_case_variables return new Position(lineNumber, column); } if ((strings.isLowerAsciiLetter(left) || strings.isAsciiDigit(left)) && strings.isUpperAsciiLetter(right)) { // camelCaseVariables return new Position(lineNumber, column); } if (strings.isUpperAsciiLetter(left) && strings.isUpperAsciiLetter(right)) { // thisIsACamelCaseWithOneLetterWords if (column + 1 < maxColumn) { const rightRight = lineContent.charCodeAt(column); if (strings.isLowerAsciiLetter(rightRight) || strings.isAsciiDigit(rightRight)) { return new Position(lineNumber, column); } } } } return new Position(lineNumber, maxColumn); } static _deleteWordLeftWhitespace(model, position) { const lineContent = model.getLineContent(position.lineNumber); const startIndex = position.column - 2; const lastNonWhitespace = strings.lastNonWhitespaceIndex(lineContent, startIndex); if (lastNonWhitespace + 1 < startIndex) { return new Range(position.lineNumber, lastNonWhitespace + 2, position.lineNumber, position.column); } return null; } static deleteWordLeft(ctx, wordNavigationType) { const wordSeparators = ctx.wordSeparators; const model = ctx.model; const selection = ctx.selection; const whitespaceHeuristics = ctx.whitespaceHeuristics; if (!selection.isEmpty()) { return selection; } if (DeleteOperations.isAutoClosingPairDelete(ctx.autoClosingDelete, ctx.autoClosingBrackets, ctx.autoClosingQuotes, ctx.autoClosingPairs.autoClosingPairsOpenByEnd, ctx.model, [ctx.selection], ctx.autoClosedCharacters)) { const position = ctx.selection.getPosition(); return new Range(position.lineNumber, position.column - 1, position.lineNumber, position.column + 1); } const position = new Position(selection.positionLineNumber, selection.positionColumn); let lineNumber = position.lineNumber; let column = position.column; if (lineNumber === 1 && column === 1) { // Ignore deleting at beginning of file return null; } if (whitespaceHeuristics) { const r = this._deleteWordLeftWhitespace(model, position); if (r) { return r; } } let prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, position); if (wordNavigationType === 0 /* WordNavigationType.WordStart */) { if (prevWordOnLine) { column = prevWordOnLine.start + 1; } else { if (column > 1) { column = 1; } else { lineNumber--; column = model.getLineMaxColumn(lineNumber); } } } else { if (prevWordOnLine && column <= prevWordOnLine.end + 1) { prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, prevWordOnLine.start + 1)); } if (prevWordOnLine) { column = prevWordOnLine.end + 1; } else { if (column > 1) { column = 1; } else { lineNumber--; column = model.getLineMaxColumn(lineNumber); } } } return new Range(lineNumber, column, position.lineNumber, position.column); } static deleteInsideWord(wordSeparators, model, selection) { if (!selection.isEmpty()) { return selection; } const position = new Position(selection.positionLineNumber, selection.positionColumn); const r = this._deleteInsideWordWhitespace(model, position); if (r) { return r; } return this._deleteInsideWordDetermineDeleteRange(wordSeparators, model, position); } static _charAtIsWhitespace(str, index) { const charCode = str.charCodeAt(index); return (charCode === 32 /* CharCode.Space */ || charCode === 9 /* CharCode.Tab */); } static _deleteInsideWordWhitespace(model, position) { const lineContent = model.getLineContent(position.lineNumber); const lineContentLength = lineContent.length; if (lineContentLength === 0) { // empty line return null; } let leftIndex = Math.max(position.column - 2, 0); if (!this._charAtIsWhitespace(lineContent, leftIndex)) { // touches a non-whitespace character to the left return null; } let rightIndex = Math.min(position.column - 1, lineContentLength - 1); if (!this._charAtIsWhitespace(lineContent, rightIndex)) { // touches a non-whitespace character to the right return null; } // walk over whitespace to the left while (leftIndex > 0 && this._charAtIsWhitespace(lineContent, leftIndex - 1)) { leftIndex--; } // walk over whitespace to the right while (rightIndex + 1 < lineContentLength && this._charAtIsWhitespace(lineContent, rightIndex + 1)) { rightIndex++; } return new Range(position.lineNumber, leftIndex + 1, position.lineNumber, rightIndex + 2); } static _deleteInsideWordDetermineDeleteRange(wordSeparators, model, position) { const lineContent = model.getLineContent(position.lineNumber); const lineLength = lineContent.length; if (lineLength === 0) { // empty line if (position.lineNumber > 1) { return new Range(position.lineNumber - 1, model.getLineMaxColumn(position.lineNumber - 1), position.lineNumber, 1); } else { if (position.lineNumber < model.getLineCount()) { return new Range(position.lineNumber, 1, position.lineNumber + 1, 1); } else { // empty model return new Range(position.lineNumber, 1, position.lineNumber, 1); } } } const touchesWord = (word) => { return (word.start + 1 <= position.column && position.column <= word.end + 1); }; const createRangeWithPosition = (startColumn, endColumn) => { startColumn = Math.min(startColumn, position.column); endColumn = Math.max(endColumn, position.column); return new Range(position.lineNumber, startColumn, position.lineNumber, endColumn); }; const deleteWordAndAdjacentWhitespace = (word) => { let startColumn = word.start + 1; let endColumn = word.end + 1; let expandedToTheRight = false; while (endColumn - 1 < lineLength && this._charAtIsWhitespace(lineContent, endColumn - 1)) { expandedToTheRight = true; endColumn++; } if (!expandedToTheRight) { while (startColumn > 1 && this._charAtIsWhitespace(lineContent, startColumn - 2)) { startColumn--; } } return createRangeWithPosition(startColumn, endColumn); }; const prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, position); if (prevWordOnLine && touchesWord(prevWordOnLine)) { return deleteWordAndAdjacentWhitespace(prevWordOnLine); } const nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, position); if (nextWordOnLine && touchesWord(nextWordOnLine)) { return deleteWordAndAdjacentWhitespace(nextWordOnLine); } if (prevWordOnLine && nextWordOnLine) { return createRangeWithPosition(prevWordOnLine.end + 1, nextWordOnLine.start + 1); } if (prevWordOnLine) { return createRangeWithPosition(prevWordOnLine.start + 1, prevWordOnLine.end + 1); } if (nextWordOnLine) { return createRangeWithPosition(nextWordOnLine.start + 1, nextWordOnLine.end + 1); } return createRangeWithPosition(1, lineLength + 1); } static _deleteWordPartLeft(model, selection) { if (!selection.isEmpty()) { return selection; } const pos = selection.getPosition(); const toPosition = WordOperations._moveWordPartLeft(model, pos); return new Range(pos.lineNumber, pos.column, toPosition.lineNumber, toPosition.column); } static _findFirstNonWhitespaceChar(str, startIndex) { const len = str.length; for (let chIndex = startIndex; chIndex < len; chIndex++) { const ch = str.charAt(chIndex); if (ch !== ' ' && ch !== '\t') { return chIndex; } } return len; } static _deleteWordRightWhitespace(model, position) { const lineContent = model.getLineContent(position.lineNumber); const startIndex = position.column - 1; const firstNonWhitespace = this._findFirstNonWhitespaceChar(lineContent, startIndex); if (startIndex + 1 < firstNonWhitespace) { // bingo return new Range(position.lineNumber, position.column, position.lineNumber, firstNonWhitespace + 1); } return null; } static deleteWordRight(ctx, wordNavigationType) { const wordSeparators = ctx.wordSeparators; const model = ctx.model; const selection = ctx.selection; const whitespaceHeuristics = ctx.whitespaceHeuristics; if (!selection.isEmpty()) { return selection; } const position = new Position(selection.positionLineNumber, selection.positionColumn); let lineNumber = position.lineNumber; let 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) { const r = this._deleteWordRightWhitespace(model, position); if (r) { return r; } } let nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, position); if (wordNavigationType === 2 /* WordNavigationType.WordEnd */) { if (nextWordOnLine) { column = nextWordOnLine.end + 1; } else { if (column < maxColumn || lineNumber === lineCount) { column = maxColumn; } else { lineNumber++; nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, 1)); if (nextWordOnLine) { column = nextWordOnLine.start + 1; } else { column = model.getLineMaxColumn(lineNumber); } } } } else { if (nextWordOnLine && column >= nextWordOnLine.start + 1) { nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, nextWordOnLine.end + 1)); } if (nextWordOnLine) { column = nextWordOnLine.start + 1; } else { if (column < maxColumn || lineNumber === lineCount) { column = maxColumn; } else { lineNumber++; nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, 1)); if (nextWordOnLine) { column = nextWordOnLine.start + 1; } else { column = model.getLineMaxColumn(lineNumber); } } } } return new Range(lineNumber, column, position.lineNumber, position.column); } static _deleteWordPartRight(model, selection) { if (!selection.isEmpty()) { return selection; } const pos = selection.getPosition(); const toPosition = WordOperations._moveWordPartRight(model, pos); return new Range(pos.lineNumber, pos.column, toPosition.lineNumber, toPosition.column); } static _createWordAtPosition(model, lineNumber, word) { const range = new Range(lineNumber, word.start + 1, lineNumber, word.end + 1); return { word: model.getValueInRange(range), startColumn: range.startColumn, endColumn: range.endColumn }; } static getWordAtPosition(model, _wordSeparators, position) { const wordSeparators = getMapForWordSeparators(_wordSeparators); const prevWord = WordOperations._findPreviousWordOnLine(wordSeparators, model, position); if (prevWord && prevWord.wordType === 1 /* WordType.Regular */ && prevWord.start <= position.column - 1 && position.column - 1 <= prevWord.end) { return WordOperations._createWordAtPosition(model, position.lineNumber, prevWord); } const nextWord = WordOperations._findNextWordOnLine(wordSeparators, model, position); if (nextWord && nextWord.wordType === 1 /* WordType.Regular */ && nextWord.start <= position.column - 1 && position.column - 1 <= nextWord.end) { return WordOperations._createWordAtPosition(model, position.lineNumber, nextWord); } return null; } static word(config, model, cursor, inSelectionMode, position) { const wordSeparators = getMapForWordSeparators(config.wordSeparators); const prevWord = WordOperations._findPreviousWordOnLine(wordSeparators, model, position); const nextWord = WordOperations._findNextWordOnLine(wordSeparators, model, position); if (!inSelectionMode) { // Entering word selection for the first time let startColumn; let endColumn; if (prevWord && prevWord.wordType === 1 /* WordType.Regular */ && prevWord.start <= position.column - 1 && position.column - 1 <= prevWord.end) { // isTouchingPrevWord startColumn = prevWord.start + 1; endColumn = prevWord.end + 1; } else if (nextWord && nextWord.wordType === 1 /* WordType.Regular */ && nextWord.start <= position.column - 1 && position.column - 1 <= nextWord.end) { // isTouchingNextWord startColumn = nextWord.start + 1; endColumn = nextWord.end + 1; } else { if (prevWord) { startColumn = prevWord.end + 1; } else { startColumn = 1; } if (nextWord) { endColumn = nextWord.start + 1; } else { endColumn = model.getLineMaxColumn(position.lineNumber); } } return new SingleCursorState(new Range(position.lineNumber, startColumn, position.lineNumber, endColumn), 0, new Position(position.lineNumber, endColumn), 0); } let startColumn; let endColumn; if (prevWord && prevWord.wordType === 1 /* WordType.Regular */ && prevWord.start < position.column - 1 && position.column - 1 < prevWord.end) { // isInsidePrevWord startColumn = prevWord.start + 1; endColumn = prevWord.end + 1; } else if (nextWord && nextWord.wordType === 1 /* WordType.Regular */ && nextWord.start < position.column - 1 && position.column - 1 < nextWord.end) { // isInsideNextWord startColumn = nextWord.start + 1; endColumn = nextWord.end + 1; } else { startColumn = position.column; endColumn = position.column; } const lineNumber = position.lineNumber; let column; if (cursor.selectionStart.containsPosition(position)) { column = cursor.selectionStart.endColumn; } else if (position.isBeforeOrEqual(cursor.selectionStart.getStartPosition())) { column = startColumn; const possiblePosition = new Position(lineNumber, column); if (cursor.selectionStart.containsPosition(possiblePosition)) { column = cursor.selectionStart.endColumn; } } else { column = endColumn; const possiblePosition = new Position(lineNumber, column); if (cursor.selectionStart.containsPosition(possiblePosition)) { column = cursor.selectionStart.startColumn; } } return cursor.move(true, lineNumber, column, 0); } } export class WordPartOperations extends WordOperations { static deleteWordPartLeft(ctx) { const candidates = enforceDefined([ WordOperations.deleteWordLeft(ctx, 0 /* WordNavigationType.WordStart */), WordOperations.deleteWordLeft(ctx, 2 /* WordNavigationType.WordEnd */), WordOperations._deleteWordPartLeft(ctx.model, ctx.selection) ]); candidates.sort(Range.compareRangesUsingEnds); return candidates[2]; } static deleteWordPartRight(ctx) { const candidates = enforceDefined([ WordOperations.deleteWordRight(ctx, 0 /* WordNavigationType.WordStart */), WordOperations.deleteWordRight(ctx, 2 /* WordNavigationType.WordEnd */), WordOperations._deleteWordPartRight(ctx.model, ctx.selection) ]); candidates.sort(Range.compareRangesUsingStarts); return candidates[0]; } static moveWordPartLeft(wordSeparators, model, position) { const candidates = enforceDefined([ WordOperations.moveWordLeft(wordSeparators, model, position, 0 /* WordNavigationType.WordStart */), WordOperations.moveWordLeft(wordSeparators, model, position, 2 /* WordNavigationType.WordEnd */), WordOperations._moveWordPartLeft(model, position) ]); candidates.sort(Position.compare); return candidates[2]; } static moveWordPartRight(wordSeparators, model, position) { const candidates = enforceDefined([ WordOperations.moveWordRight(wordSeparators, model, position, 0 /* WordNavigationType.WordStart */), WordOperations.moveWordRight(wordSeparators, model, position, 2 /* WordNavigationType.WordEnd */), WordOperations._moveWordPartRight(model, position) ]); candidates.sort(Position.compare); return candidates[0]; } } function enforceDefined(arr) { return arr.filter(el => Boolean(el)); }