From fd4c439e0737c3c00b11d2c1bf03275e60b3e37d Mon Sep 17 00:00:00 2001 From: Je Xia Date: Wed, 10 Jun 2026 19:51:46 +0800 Subject: [PATCH 1/6] [diffs/edtior] Fix cursor move --- packages/diffs/src/editor/selection.ts | 6 ++- packages/diffs/test/editorSelection.test.ts | 45 +++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/packages/diffs/src/editor/selection.ts b/packages/diffs/src/editor/selection.ts index f2f0328a8..d1e4a8bbc 100644 --- a/packages/diffs/src/editor/selection.ts +++ b/packages/diffs/src/editor/selection.ts @@ -144,9 +144,13 @@ export function mapCursorMove( } } else if (shortcut === 'up') { line = Math.max(0, line - 1); + character = Math.min(character, textDocument.getLineText(line).length); } else if (shortcut === 'down') { line = Math.min(Math.max(lineCount - 1, 0), line + 1); + character = Math.min(character, textDocument.getLineText(line).length); } else if (isCollapsedSelection(selection)) { + const lineLength = textDocument.getLineText(line).length; + character = Math.min(character, lineLength); if (shortcut === 'left') { character--; @@ -160,7 +164,7 @@ export function mapCursorMove( } } else { character++; - if (character > textDocument.getLineText(line).length) { + if (character > lineLength) { if (line === lineCount - 1) { character--; } else { diff --git a/packages/diffs/test/editorSelection.test.ts b/packages/diffs/test/editorSelection.test.ts index 6fab3abc8..329d971ed 100644 --- a/packages/diffs/test/editorSelection.test.ts +++ b/packages/diffs/test/editorSelection.test.ts @@ -1157,6 +1157,51 @@ describe('mapSelectionMove', () => { createSelection(0, 4, 0, 4), ]); }); + + test('moves left from a goal column past a shorter line end', () => { + const textDocument = new TextDocument( + 'inmemory://1', + 'this is a much longer line\nshort\n' + ); + const onShortLine = mapCursorMove( + textDocument, + [createSelection(0, 20, 0, 20)], + 'down' + ); + + expect(onShortLine).toEqual([createSelection(1, 5, 1, 5)]); + + expect(mapCursorMove(textDocument, onShortLine, 'left')).toEqual([ + createSelection(1, 4, 1, 4), + ]); + }); + + test('inserts at the clamped caret after moving onto a shorter line', () => { + const textDocument = new TextDocument( + 'inmemory://1', + 'this is a much longer line\nshort\nnext\n' + ); + const onShortLine = mapCursorMove( + textDocument, + [createSelection(0, 20, 0, 20)], + 'down' + ); + const { nextSelections, change } = applyTextChangeToSelections( + textDocument, + onShortLine, + { + start: textDocument.offsetAt(onShortLine[0].start), + end: textDocument.offsetAt(onShortLine[0].end), + text: 'X', + } + ); + + expect(textDocument.getText()).toBe( + 'this is a much longer line\nshortX\nnext\n' + ); + expect(nextSelections).toEqual([createSelection(1, 6, 1, 6)]); + expect(change).toBeDefined(); + }); }); describe('mapSelectionRangeMove', () => { From 1138d44005419a8cdb3a1e819a6629f3baad52df Mon Sep 17 00:00:00 2001 From: Je Xia Date: Wed, 10 Jun 2026 20:08:49 +0800 Subject: [PATCH 2/6] Remain cursor x position --- packages/diffs/src/editor/editor.ts | 20 ++++++++++++----- packages/diffs/src/editor/selection.ts | 12 ++++++---- packages/diffs/test/editorSelection.test.ts | 25 ++++++++++++++++++--- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/packages/diffs/src/editor/editor.ts b/packages/diffs/src/editor/editor.ts index 8ef0c3bca..5d05d7d2d 100644 --- a/packages/diffs/src/editor/editor.ts +++ b/packages/diffs/src/editor/editor.ts @@ -2167,8 +2167,12 @@ export class Editor implements DiffsEditor { textDocument, selections, { - start: textDocument.offsetAt(primarySelection.start), - end: textDocument.offsetAt(primarySelection.end), + start: textDocument.offsetAt( + textDocument.normalizePosition(primarySelection.start) + ), + end: textDocument.offsetAt( + textDocument.normalizePosition(primarySelection.end) + ), text: Array.isArray(text) ? text.join('\n') : text, }, this.#lineAnnotations @@ -2197,7 +2201,9 @@ export class Editor implements DiffsEditor { const edit = isCollapsedSelection(primarySelection) ? (() => { - const offset = textDocument.offsetAt(primarySelection.start); + const offset = textDocument.offsetAt( + textDocument.normalizePosition(primarySelection.start) + ); const nextOffset = forward ? Math.min(textDocument.getText().length, offset + 1) : Math.max(0, offset - 1); @@ -2208,8 +2214,12 @@ export class Editor implements DiffsEditor { }; })() : { - start: textDocument.offsetAt(primarySelection.start), - end: textDocument.offsetAt(primarySelection.end), + start: textDocument.offsetAt( + textDocument.normalizePosition(primarySelection.start) + ), + end: textDocument.offsetAt( + textDocument.normalizePosition(primarySelection.end) + ), text: '', }; diff --git a/packages/diffs/src/editor/selection.ts b/packages/diffs/src/editor/selection.ts index d1e4a8bbc..49742ab4a 100644 --- a/packages/diffs/src/editor/selection.ts +++ b/packages/diffs/src/editor/selection.ts @@ -144,10 +144,8 @@ export function mapCursorMove( } } else if (shortcut === 'up') { line = Math.max(0, line - 1); - character = Math.min(character, textDocument.getLineText(line).length); } else if (shortcut === 'down') { line = Math.min(Math.max(lineCount - 1, 0), line + 1); - character = Math.min(character, textDocument.getLineText(line).length); } else if (isCollapsedSelection(selection)) { const lineLength = textDocument.getLineText(line).length; character = Math.min(character, lineLength); @@ -236,7 +234,10 @@ export function applyTextChangeToSelections( } const selectionPositions: Position[] = []; for (const selection of selections) { - selectionPositions.push(selection.start, selection.end); + selectionPositions.push( + textDocument.normalizePosition(selection.start), + textDocument.normalizePosition(selection.end) + ); } const selectionOffsets = textDocument.offsetsAt(selectionPositions); const primaryStartOffset = selectionOffsets[(selections.length - 1) * 2]; @@ -395,7 +396,10 @@ export function applyTextReplaceToSelections( } const selectionPositions: Position[] = []; for (const selection of selections) { - selectionPositions.push(selection.start, selection.end); + selectionPositions.push( + textDocument.normalizePosition(selection.start), + textDocument.normalizePosition(selection.end) + ); } const selectionOffsets = textDocument.offsetsAt(selectionPositions); const ordered: Array<{ diff --git a/packages/diffs/test/editorSelection.test.ts b/packages/diffs/test/editorSelection.test.ts index 329d971ed..02ab6b1e6 100644 --- a/packages/diffs/test/editorSelection.test.ts +++ b/packages/diffs/test/editorSelection.test.ts @@ -1169,13 +1169,31 @@ describe('mapSelectionMove', () => { 'down' ); - expect(onShortLine).toEqual([createSelection(1, 5, 1, 5)]); + expect(onShortLine).toEqual([createSelection(1, 20, 1, 20)]); expect(mapCursorMove(textDocument, onShortLine, 'left')).toEqual([ createSelection(1, 4, 1, 4), ]); }); + test('preserves goal column across short and empty lines', () => { + const textDocument = new TextDocument( + 'inmemory://1', + 'this is a much longer line here\nshort\n\nanother much longer line here\n' + ); + const onShortLine = mapCursorMove( + textDocument, + [createSelection(0, 20, 0, 20)], + 'down' + ); + const onEmptyLine = mapCursorMove(textDocument, onShortLine, 'down'); + const onLongLine = mapCursorMove(textDocument, onEmptyLine, 'down'); + + expect(onShortLine).toEqual([createSelection(1, 20, 1, 20)]); + expect(onEmptyLine).toEqual([createSelection(2, 20, 2, 20)]); + expect(onLongLine).toEqual([createSelection(3, 20, 3, 20)]); + }); + test('inserts at the clamped caret after moving onto a shorter line', () => { const textDocument = new TextDocument( 'inmemory://1', @@ -1186,12 +1204,13 @@ describe('mapSelectionMove', () => { [createSelection(0, 20, 0, 20)], 'down' ); + const caret = textDocument.normalizePosition(onShortLine[0].start); const { nextSelections, change } = applyTextChangeToSelections( textDocument, onShortLine, { - start: textDocument.offsetAt(onShortLine[0].start), - end: textDocument.offsetAt(onShortLine[0].end), + start: textDocument.offsetAt(caret), + end: textDocument.offsetAt(caret), text: 'X', } ); From db28172d46c411d2e55ed3ee87ed41b56295842c Mon Sep 17 00:00:00 2001 From: Je Xia Date: Wed, 10 Jun 2026 21:29:44 +0800 Subject: [PATCH 3/6] Add `getLineLength` method for piece table --- packages/diffs/src/editor/pieceTable.ts | 46 +++++++++++++++++-- packages/diffs/src/editor/selection.ts | 19 ++++---- packages/diffs/src/editor/textDocument.ts | 6 ++- packages/diffs/test/editorPieceTable.test.ts | 13 ++++++ .../diffs/test/editorTextDocument.test.ts | 3 ++ 5 files changed, 73 insertions(+), 14 deletions(-) diff --git a/packages/diffs/src/editor/pieceTable.ts b/packages/diffs/src/editor/pieceTable.ts index a5d2892e7..6da15854f 100644 --- a/packages/diffs/src/editor/pieceTable.ts +++ b/packages/diffs/src/editor/pieceTable.ts @@ -82,9 +82,8 @@ export class PieceTable { #piecesCache: Piece[] = []; #length = 0; #lineCount = 0; - #lastVisitedLine: - | [line: number, includeLineBreak: boolean, text: string] - | null = null; + #lastVisitedLine: [number, boolean, string] | null = null; + #lastVisitedLineLength: [number, boolean, number] | null = null; constructor(originalText: string) { this.#original = new TextBuffer(originalText); @@ -120,9 +119,47 @@ export class PieceTable { } const text = this.getTextSlice(offset[0], offset[1], !includeLineBreak); this.#lastVisitedLine = [line, includeLineBreak, text]; + this.#lastVisitedLineLength = [line, includeLineBreak, text.length]; return text; } + getLineLength(line: number, includeLineBreak = false): number { + const lastVisitedLineLength = this.#lastVisitedLineLength; + const lastVisitedLine = this.#lastVisitedLine; + if ( + lastVisitedLineLength !== null && + lastVisitedLineLength[0] === line && + lastVisitedLineLength[1] === includeLineBreak + ) { + return lastVisitedLineLength[2]; + } + if ( + lastVisitedLine !== null && + lastVisitedLine[0] === line && + lastVisitedLine[1] === includeLineBreak + ) { + const length = lastVisitedLine[2].length; + this.#lastVisitedLineLength = [line, includeLineBreak, length]; + return length; + } + const offset = this.#getLineOffset(line); + if (offset === undefined) { + throw new Error(`Line index out of range: ${line}`); + } + const [start, end] = offset; + let length = end - start; + if (!includeLineBreak) { + while ( + length > 0 && + isEOL(this.charAt(start + length - 1).charCodeAt(0)) + ) { + length--; + } + } + this.#lastVisitedLineLength = [line, includeLineBreak, length]; + return length; + } + getTextSlice(start: number, end: number, trimEOF = false): string { if (start >= end) { return ''; @@ -367,6 +404,7 @@ export class PieceTable { this.#setPieces(nextPieces); this.#lastVisitedLine = null; + this.#lastVisitedLineLength = null; } delete(offset: number, length: number): void { @@ -407,6 +445,7 @@ export class PieceTable { this.#setPieces(nextPieces); this.#lastVisitedLine = null; + this.#lastVisitedLineLength = null; } applyEdits(edits: readonly ResolvedTextEdit[]): void { @@ -487,6 +526,7 @@ export class PieceTable { this.#setPieces(nextPieces); this.#lastVisitedLine = null; + this.#lastVisitedLineLength = null; } positionAt(offset: number): Position { diff --git a/packages/diffs/src/editor/selection.ts b/packages/diffs/src/editor/selection.ts index 49742ab4a..a63c5de6f 100644 --- a/packages/diffs/src/editor/selection.ts +++ b/packages/diffs/src/editor/selection.ts @@ -134,8 +134,7 @@ export function mapCursorMove( const indent = getLeadingSpaces(textDocument.getLineText(line)); character = character === indent ? 0 : indent; } else { - character = - shortcut === 'start' ? 0 : textDocument.getLineText(line).length; + character = shortcut === 'start' ? 0 : textDocument.getLineLength(line); } if (selection.direction === DirectionBackward) { line = selection.start.line; @@ -147,7 +146,7 @@ export function mapCursorMove( } else if (shortcut === 'down') { line = Math.min(Math.max(lineCount - 1, 0), line + 1); } else if (isCollapsedSelection(selection)) { - const lineLength = textDocument.getLineText(line).length; + const lineLength = textDocument.getLineLength(line); character = Math.min(character, lineLength); if (shortcut === 'left') { character--; @@ -157,7 +156,7 @@ export function mapCursorMove( character = 0; } else { line = Math.max(0, line - 1); - character = textDocument.getLineText(line).length; + character = textDocument.getLineLength(line); } } } else { @@ -562,7 +561,7 @@ export function applyTransposeToSelections( const { line, character } = selection.start; const offset = anchor; - const lineLength = textDocument.getLineText(line).length; + const lineLength = textDocument.getLineLength(line); let edit: ResolvedTextEdit | undefined; if (character > 0 && character < lineLength) { @@ -581,7 +580,7 @@ export function applyTransposeToSelections( nextOffsetPairs.push([offset, offset]); } else if (character === 0 && line > 0 && lineLength > 0) { const prevLine = line - 1; - const prevLength = textDocument.getLineText(prevLine).length; + const prevLength = textDocument.getLineLength(prevLine); const prevEnd = textDocument.offsetAt({ line: prevLine, character: prevLength, @@ -704,7 +703,7 @@ export function applyDeleteSoftLineBackwardToSelections( direction: DirectionNone, }; } - const prevLineLength = textDocument.getLineText(line - 1).length; + const prevLineLength = textDocument.getLineLength(line - 1); return { start: { line: line - 1, character: prevLineLength }, end: { line, character: 0 }, @@ -1048,7 +1047,7 @@ export function getDocumentFullSelection( textDocument: TextDocument ): EditorSelection { const lastLine = textDocument.lineCount - 1; - const lastCharacter = textDocument.getLineText(lastLine)?.length ?? 0; + const lastCharacter = textDocument.getLineLength(lastLine); return { start: { line: 0, character: 0 }, end: { line: lastLine, character: lastCharacter }, @@ -1064,7 +1063,7 @@ export function getDocumentBoundarySelection( atEnd: boolean ): EditorSelection { const line = atEnd ? textDocument.lineCount - 1 : 0; - const character = atEnd ? (textDocument.getLineText(line)?.length ?? 0) : 0; + const character = atEnd ? textDocument.getLineLength(line) : 0; const start = { line, character }; return { start: start, @@ -1220,7 +1219,7 @@ function resolveDeleteWordBackwardRange( if (line === 0) { return [caret, caret]; } - const prevLineLength = textDocument.getLineText(line - 1).length; + const prevLineLength = textDocument.getLineLength(line - 1); return [ { line: line - 1, character: prevLineLength }, { line, character: 0 }, diff --git a/packages/diffs/src/editor/textDocument.ts b/packages/diffs/src/editor/textDocument.ts index 10a6edad9..c7f4059fe 100644 --- a/packages/diffs/src/editor/textDocument.ts +++ b/packages/diffs/src/editor/textDocument.ts @@ -184,6 +184,10 @@ export class TextDocument { return this.#pieceTable.getLineText(line, includeLineBreak); } + getLineLength(line: number, includeLineBreak?: boolean): number { + return this.#pieceTable.getLineLength(line, includeLineBreak); + } + charAt(offset: number): string; charAt(position: Position): string; charAt(positionOrOffset: Position | number): string { @@ -330,7 +334,7 @@ export class TextDocument { line, character: Math.max( 0, - Math.min(position.character, this.getLineText(line).length) + Math.min(position.character, this.getLineLength(line)) ), }; } diff --git a/packages/diffs/test/editorPieceTable.test.ts b/packages/diffs/test/editorPieceTable.test.ts index 9725a074b..c32b0bb54 100644 --- a/packages/diffs/test/editorPieceTable.test.ts +++ b/packages/diffs/test/editorPieceTable.test.ts @@ -138,6 +138,19 @@ describe('PieceTable', () => { expect(() => table.getLineText(99)).toThrow('Line index out of range: 99'); }); + test('getLineLength matches getLineText without slicing', () => { + const table = new PieceTable('first\r\nsecond\n'); + + expect(table.getLineLength(0)).toBe(table.getLineText(0).length); + expect(table.getLineLength(1)).toBe(table.getLineText(1).length); + expect(table.getLineLength(2)).toBe(0); + expect(table.getLineLength(0, true)).toBe(7); + expect(table.getLineLength(1, true)).toBe(7); + expect(() => table.getLineLength(99)).toThrow( + 'Line index out of range: 99' + ); + }); + test('maps between offsets and positions', () => { const table = new PieceTable('ab\nc'); diff --git a/packages/diffs/test/editorTextDocument.test.ts b/packages/diffs/test/editorTextDocument.test.ts index c113ae6ac..1909d8cbc 100644 --- a/packages/diffs/test/editorTextDocument.test.ts +++ b/packages/diffs/test/editorTextDocument.test.ts @@ -84,6 +84,9 @@ describe('TextDocument', () => { expect(d.getLineText(0)).toBe('first'); expect(d.getLineText(1)).toBe('second'); expect(d.getLineText(2)).toBe(''); + expect(d.getLineLength(0)).toBe(5); + expect(d.getLineLength(1)).toBe(6); + expect(d.getLineLength(2)).toBe(0); expect( d.getText({ start: { line: 0, character: 0 }, From 6d2f68e8e29d56d3c6104d7c9c731905dc546e1d Mon Sep 17 00:00:00 2001 From: Je Xia Date: Wed, 10 Jun 2026 21:59:32 +0800 Subject: [PATCH 4/6] refactor --- packages/diffs/src/editor/editor.ts | 47 +++++++++++++++-------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/packages/diffs/src/editor/editor.ts b/packages/diffs/src/editor/editor.ts index 64c754bcb..102a3ea57 100644 --- a/packages/diffs/src/editor/editor.ts +++ b/packages/diffs/src/editor/editor.ts @@ -2280,29 +2280,30 @@ export class Editor implements DiffsEditor { return; } - const edit = isCollapsedSelection(primarySelection) - ? (() => { - const offset = textDocument.offsetAt( - textDocument.normalizePosition(primarySelection.start) - ); - const nextOffset = forward - ? Math.min(textDocument.getText().length, offset + 1) - : Math.max(0, offset - 1); - return { - start: Math.min(offset, nextOffset), - end: Math.max(offset, nextOffset), - text: '', - }; - })() - : { - start: textDocument.offsetAt( - textDocument.normalizePosition(primarySelection.start) - ), - end: textDocument.offsetAt( - textDocument.normalizePosition(primarySelection.end) - ), - text: '', - }; + let edit: ResolvedTextEdit; + if (isCollapsedSelection(primarySelection)) { + const offset = textDocument.offsetAt( + textDocument.normalizePosition(primarySelection.start) + ); + const nextOffset = forward + ? Math.min(textDocument.getText().length, offset + 1) + : Math.max(0, offset - 1); + edit = { + start: Math.min(offset, nextOffset), + end: Math.max(offset, nextOffset), + text: '', + }; + } else { + edit = { + start: textDocument.offsetAt( + textDocument.normalizePosition(primarySelection.start) + ), + end: textDocument.offsetAt( + textDocument.normalizePosition(primarySelection.end) + ), + text: '', + }; + } this.#applyResolvedTextEdit(edit); } From aec17d09baf686851ed0c5fbc07adeadee356c9b Mon Sep 17 00:00:00 2001 From: Je Xia Date: Wed, 10 Jun 2026 23:02:24 +0800 Subject: [PATCH 5/6] clean up --- packages/diffs/src/editor/pieceTable.ts | 16 ---------------- packages/diffs/src/editor/selection.ts | 8 ++++++-- packages/diffs/src/editor/textDocument.ts | 4 ---- 3 files changed, 6 insertions(+), 22 deletions(-) diff --git a/packages/diffs/src/editor/pieceTable.ts b/packages/diffs/src/editor/pieceTable.ts index 6da15854f..b93138ac5 100644 --- a/packages/diffs/src/editor/pieceTable.ts +++ b/packages/diffs/src/editor/pieceTable.ts @@ -573,22 +573,6 @@ export class PieceTable { return offset[0] + character; } - offsetsAt(positions: readonly Position[]): number[] { - const offsets: number[] = Array.from({ length: positions.length }); - if (positions.length === 0) { - return offsets; - } - if (this.#length === 0) { - return offsets.fill(0); - } - - for (let i = 0; i < positions.length; i++) { - offsets[i] = this.offsetAt(positions[i]); - } - - return offsets; - } - #findPieceAtOffset( offset: number ): [node: PieceNode, offsetInPiece: number] | undefined { diff --git a/packages/diffs/src/editor/selection.ts b/packages/diffs/src/editor/selection.ts index cb7db3a3b..c60f0cba7 100644 --- a/packages/diffs/src/editor/selection.ts +++ b/packages/diffs/src/editor/selection.ts @@ -238,7 +238,9 @@ export function applyTextChangeToSelections( textDocument.normalizePosition(selection.end) ); } - const selectionOffsets = textDocument.offsetsAt(selectionPositions); + const selectionOffsets = selectionPositions.map((position) => + textDocument.offsetAt(position) + ); const primaryStartOffset = selectionOffsets[(selections.length - 1) * 2]; const primaryEndOffset = selectionOffsets[(selections.length - 1) * 2 + 1]; const ordered: Array<{ @@ -400,7 +402,9 @@ export function applyTextReplaceToSelections( textDocument.normalizePosition(selection.end) ); } - const selectionOffsets = textDocument.offsetsAt(selectionPositions); + const selectionOffsets = selectionPositions.map((position) => + textDocument.offsetAt(position) + ); const ordered: Array<{ index: number; start: number; diff --git a/packages/diffs/src/editor/textDocument.ts b/packages/diffs/src/editor/textDocument.ts index c7f4059fe..1b890a416 100644 --- a/packages/diffs/src/editor/textDocument.ts +++ b/packages/diffs/src/editor/textDocument.ts @@ -172,10 +172,6 @@ export class TextDocument { return this.#pieceTable.offsetAt(position); } - offsetsAt(positions: readonly Position[]): number[] { - return this.#pieceTable.offsetsAt(positions); - } - getText(range?: Range): string { return this.#pieceTable.getText(range); } From d6138cb0d6fbab1ae9389de755acc54806c4b01a Mon Sep 17 00:00:00 2001 From: Je Xia Date: Wed, 10 Jun 2026 23:08:22 +0800 Subject: [PATCH 6/6] refactor --- packages/diffs/src/editor/editor.ts | 20 +++++--------------- packages/diffs/src/editor/selection.ts | 10 ++-------- packages/diffs/src/editor/textDocument.ts | 2 +- packages/diffs/test/editorSelection.test.ts | 5 ++--- 4 files changed, 10 insertions(+), 27 deletions(-) diff --git a/packages/diffs/src/editor/editor.ts b/packages/diffs/src/editor/editor.ts index 102a3ea57..3f7568b8a 100644 --- a/packages/diffs/src/editor/editor.ts +++ b/packages/diffs/src/editor/editor.ts @@ -2248,12 +2248,8 @@ export class Editor implements DiffsEditor { textDocument, selections, { - start: textDocument.offsetAt( - textDocument.normalizePosition(primarySelection.start) - ), - end: textDocument.offsetAt( - textDocument.normalizePosition(primarySelection.end) - ), + start: textDocument.offsetAt(primarySelection.start), + end: textDocument.offsetAt(primarySelection.end), text: Array.isArray(text) ? text.join('\n') : text, }, this.#lineAnnotations @@ -2282,9 +2278,7 @@ export class Editor implements DiffsEditor { let edit: ResolvedTextEdit; if (isCollapsedSelection(primarySelection)) { - const offset = textDocument.offsetAt( - textDocument.normalizePosition(primarySelection.start) - ); + const offset = textDocument.offsetAt(primarySelection.start); const nextOffset = forward ? Math.min(textDocument.getText().length, offset + 1) : Math.max(0, offset - 1); @@ -2295,12 +2289,8 @@ export class Editor implements DiffsEditor { }; } else { edit = { - start: textDocument.offsetAt( - textDocument.normalizePosition(primarySelection.start) - ), - end: textDocument.offsetAt( - textDocument.normalizePosition(primarySelection.end) - ), + start: textDocument.offsetAt(primarySelection.start), + end: textDocument.offsetAt(primarySelection.end), text: '', }; } diff --git a/packages/diffs/src/editor/selection.ts b/packages/diffs/src/editor/selection.ts index c60f0cba7..00729328d 100644 --- a/packages/diffs/src/editor/selection.ts +++ b/packages/diffs/src/editor/selection.ts @@ -233,10 +233,7 @@ export function applyTextChangeToSelections( } const selectionPositions: Position[] = []; for (const selection of selections) { - selectionPositions.push( - textDocument.normalizePosition(selection.start), - textDocument.normalizePosition(selection.end) - ); + selectionPositions.push(selection.start, selection.end); } const selectionOffsets = selectionPositions.map((position) => textDocument.offsetAt(position) @@ -397,10 +394,7 @@ export function applyTextReplaceToSelections( } const selectionPositions: Position[] = []; for (const selection of selections) { - selectionPositions.push( - textDocument.normalizePosition(selection.start), - textDocument.normalizePosition(selection.end) - ); + selectionPositions.push(selection.start, selection.end); } const selectionOffsets = selectionPositions.map((position) => textDocument.offsetAt(position) diff --git a/packages/diffs/src/editor/textDocument.ts b/packages/diffs/src/editor/textDocument.ts index 1b890a416..369c074bb 100644 --- a/packages/diffs/src/editor/textDocument.ts +++ b/packages/diffs/src/editor/textDocument.ts @@ -169,7 +169,7 @@ export class TextDocument { } offsetAt(position: Position): number { - return this.#pieceTable.offsetAt(position); + return this.#pieceTable.offsetAt(this.normalizePosition(position)); } getText(range?: Range): string { diff --git a/packages/diffs/test/editorSelection.test.ts b/packages/diffs/test/editorSelection.test.ts index 02ab6b1e6..06cf2c695 100644 --- a/packages/diffs/test/editorSelection.test.ts +++ b/packages/diffs/test/editorSelection.test.ts @@ -1204,13 +1204,12 @@ describe('mapSelectionMove', () => { [createSelection(0, 20, 0, 20)], 'down' ); - const caret = textDocument.normalizePosition(onShortLine[0].start); const { nextSelections, change } = applyTextChangeToSelections( textDocument, onShortLine, { - start: textDocument.offsetAt(caret), - end: textDocument.offsetAt(caret), + start: textDocument.offsetAt(onShortLine[0].start), + end: textDocument.offsetAt(onShortLine[0].end), text: 'X', } );