monaco-editor
Version:
A browser based code editor
687 lines (686 loc) • 33.7 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* 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 (left === 45 /* CharCode.Dash */ && right !== 45 /* CharCode.Dash */) {
// kebab-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 (left !== 45 /* CharCode.Dash */ && right === 45 /* CharCode.Dash */) {
// kebab-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), 1 /* SelectionStartKind.Word */, 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));
}