diff --git a/packages/diffs/src/editor/editor.ts b/packages/diffs/src/editor/editor.ts index 3f1901a58..d2f0b9f49 100644 --- a/packages/diffs/src/editor/editor.ts +++ b/packages/diffs/src/editor/editor.ts @@ -3881,7 +3881,14 @@ export class Editor implements DiffsEditor { } const { start, end } = range; - for (let line = start.line; line <= end.line; line++) { + let firstLine = start.line; + let endLine = end.line + 1; + if (this.#renderRange !== undefined) { + const { startingLine, totalLines } = this.#renderRange; + firstLine = Math.max(firstLine, startingLine); + endLine = Math.min(endLine, startingLine + totalLines); + } + for (let line = firstLine; line < endLine; line++) { if (!this.#isLineVisible(line)) { continue; } diff --git a/packages/diffs/test/editorVirtualizedEdit.test.ts b/packages/diffs/test/editorVirtualizedEdit.test.ts index a19169866..a2d086d86 100644 --- a/packages/diffs/test/editorVirtualizedEdit.test.ts +++ b/packages/diffs/test/editorVirtualizedEdit.test.ts @@ -4,6 +4,7 @@ import { File } from '../src/components/File'; import { DEFAULT_THEMES } from '../src/constants'; import { Editor } from '../src/editor/editor'; import { PieceTable } from '../src/editor/pieceTable'; +import { DirectionForward } from '../src/editor/selection'; import { disposeHighlighter } from '../src/highlighter/shared_highlighter'; import type { FileContents, RenderRange } from '../src/types'; import { installDom, wait } from './domHarness'; @@ -306,6 +307,36 @@ describe('Editor edits at the bottom of a virtualized window', () => { }); }); +describe('Editor selections in a virtualized window', () => { + test('limits a document-spanning selection to the rendered lines', async () => { + const range = makeRange(4900, 7); + const { cleanup, editor, fileContainer } = await createWindowedEditor( + 10_000, + range + ); + editor.setOptions({ roundedSelection: false }); + + try { + editor.setState({ + selections: [ + { + start: { line: 0, character: 0 }, + end: { line: 9999, character: 10 }, + direction: DirectionForward, + }, + ], + view: { scrollLeft: 0, scrollTop: 0 }, + }); + + expect( + fileContainer.shadowRoot?.querySelectorAll('[data-selection-range]') + ).toHaveLength(range.totalLines); + } finally { + cleanup(); + } + }); +}); + describe('Editor search matches in a virtualized window', () => { test('resolves positions only for matches in the rendered window', async () => { const range = makeRange(900, 7);