Path: blob/main/extensions/copilot/src/platform/notebook/common/alternativeNotebookDocument.ts
13401 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import type { NotebookCell, NotebookDocument, TextLine } from 'vscode';6import { DEFAULT_WORD_REGEXP, getWordAtText } from '../../../util/vs/editor/common/core/wordHelper';7import { Position, Range } from '../../../vscodeTypes';8import { PositionOffsetTransformer } from '../../editing/common/positionOffsetTransformer';9import { SnapshotDocumentLine } from '../../editing/common/textDocumentSnapshot';101112export abstract class AlternativeNotebookDocument {13private _transformer: PositionOffsetTransformer | null = null;14private get transformer(): PositionOffsetTransformer {15if (!this._transformer) {16this._transformer = new PositionOffsetTransformer(this._text);17}18return this._transformer;19}2021getText(range?: Range): string {22return range ? this._getTextInRange(range) : this._text;23}2425private _getTextInRange(_range: Range): string {26const range = this.validateRange(_range);2728if (range.isEmpty) {29return '';30}3132const offsetRange = this.transformer.toOffsetRange(range);33return this._text.substring(offsetRange.start, offsetRange.endExclusive);34}3536constructor(protected readonly _text: string, protected readonly notebook: NotebookDocument) {3738}3940protected positionToOffset(position: Position): number {41position = this.validatePosition(position);42return this.transformer.getOffset(position);43}4445/**46* Translates a position in the notebook document to the corresponding alternative position.47*/48abstract fromCellPosition(cell: NotebookCell, position: Position): Position;4950/**51* Translates a position in the alternative document to the corresponding cell index and position in the notebook document.52*/53abstract toCellPosition(position: Position): { cell: NotebookCell; position: Position } | undefined;5455getWordRangeAtPosition(_position: Position): Range | undefined {56const position = this.validatePosition(_position);5758const wordAtText = getWordAtText(59position.character + 1,60DEFAULT_WORD_REGEXP,61this.lines[position.line],62063);6465if (wordAtText) {66return new Range(position.line, wordAtText.startColumn - 1, position.line, wordAtText.endColumn - 1);67}68return undefined;69}707172private _lines: string[] | null = null;7374get lines(): string[] {75if (!this._lines) {76this._lines = this._text.split(/\r\n|\r|\n/g);77}78return this._lines;79}8081get lineCount(): number {82return this.lines.length;83}8485lineAt(line: number): TextLine;86lineAt(position: Position): TextLine;87lineAt(lineOrPosition: number | Position): TextLine {88let line: number | undefined;89if (lineOrPosition instanceof Position) {90line = lineOrPosition.line;91} else if (typeof lineOrPosition === 'number') {92line = lineOrPosition;93} else {94throw new Error(`Invalid argument`);95}96if (line < 0 || line >= this.lines.length) {97throw new Error('Illegal value for `line`');98}99100return new SnapshotDocumentLine(line, this.lines[line], line === this.lines.length - 1);101}102offsetAt(position: Position): number {103return this.transformer.getOffset(position);104}105106positionAt(offset: number): Position {107offset = Math.floor(offset);108offset = Math.max(0, offset);109110return this.transformer.getPosition(offset);111}112validateRange(range: Range): Range {113const start = this.validatePosition(range.start);114const end = this.validatePosition(range.end);115116if (start === range.start && end === range.end) {117return range;118}119return new Range(start.line, start.character, end.line, end.character);120}121122validatePosition(position: Position): Position {123if (this._text.length === 0) {124return position.with(0, 0);125}126127let { line, character } = position;128let hasChanged = false;129130if (line < 0) {131line = 0;132character = 0;133hasChanged = true;134} else if (line >= this.lines.length) {135line = this.lines.length - 1;136character = this.lines[line].length;137hasChanged = true;138} else {139const maxCharacter = this.lines[line].length;140if (character < 0) {141character = 0;142hasChanged = true;143} else if (character > maxCharacter) {144character = maxCharacter;145hasChanged = true;146}147}148149if (!hasChanged) {150return position;151}152return new Position(line, character);153}154}155156157