/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { SelectionRangeProvider, SelectionRange, } from '../../../../vs/editor/common/modes'; import { ITextModel } from '../../../../vs/editor/common/model'; import { Position } from '../../../../vs/editor/common/core/position'; import { Range } from '../../../../vs/editor/common/core/range'; import { CharCode } from '../../../../vs/base/common/charCode'; import { isUpperAsciiLetter, isLowerAsciiLetter, } from '../../../../vs/base/common/strings'; export class WordSelectionRangeProvider implements SelectionRangeProvider { provideSelectionRanges( model: ITextModel, positions: Position[] ): SelectionRange[][] { const result: SelectionRange[][] = []; for (const position of positions) { const bucket: SelectionRange[] = []; result.push(bucket); this._addInWordRanges(bucket, model, position); this._addWordRanges(bucket, model, position); this._addWhitespaceLine(bucket, model, position); bucket.push({ range: model.getFullModelRange() }); } return result; } private _addInWordRanges( bucket: SelectionRange[], model: ITextModel, pos: Position ): void { const obj = model.getWordAtPosition(pos); if (!obj) { return; } let { word, startColumn } = obj; let offset = pos.column - startColumn; let start = offset; let end = offset; let lastCh: number = 0; // LEFT anchor (start) for (; start >= 0; start--) { let ch = word.charCodeAt(start); if ( start !== offset && (ch === CharCode.Underline || ch === CharCode.Dash) ) { // foo-bar OR foo_bar break; } else if (isLowerAsciiLetter(ch) && isUpperAsciiLetter(lastCh)) { // fooBar break; } lastCh = ch; } start += 1; // RIGHT anchor (end) for (; end < word.length; end++) { let ch = word.charCodeAt(end); if (isUpperAsciiLetter(ch) && isLowerAsciiLetter(lastCh)) { // fooBar break; } else if (ch === CharCode.Underline || ch === CharCode.Dash) { // foo-bar OR foo_bar break; } lastCh = ch; } if (start < end) { bucket.push({ range: new Range( pos.lineNumber, startColumn + start, pos.lineNumber, startColumn + end ), }); } } private _addWordRanges( bucket: SelectionRange[], model: ITextModel, pos: Position ): void { const word = model.getWordAtPosition(pos); if (word) { bucket.push({ range: new Range( pos.lineNumber, word.startColumn, pos.lineNumber, word.endColumn ), }); } } private _addWhitespaceLine( bucket: SelectionRange[], model: ITextModel, pos: Position ): void { if ( model.getLineLength(pos.lineNumber) > 0 && model.getLineFirstNonWhitespaceColumn(pos.lineNumber) === 0 && model.getLineLastNonWhitespaceColumn(pos.lineNumber) === 0 ) { bucket.push({ range: new Range( pos.lineNumber, 1, pos.lineNumber, model.getLineMaxColumn(pos.lineNumber) ), }); } } }