diff --git a/src/shared/terminal-osc-link-retirement.ts b/src/shared/terminal-osc-link-retirement.ts index 8350620c006..5883d365dae 100644 --- a/src/shared/terminal-osc-link-retirement.ts +++ b/src/shared/terminal-osc-link-retirement.ts @@ -1,6 +1,6 @@ import type { IBuffer, Terminal } from '@xterm/headless' -type OscLinkMarker = { dispose(): void } +type OscLinkMarker = { dispose(): void; line?: number } type OscLinkEntry = { id: number; lines: OscLinkMarker[] } type TerminalBuffers = Pick @@ -34,9 +34,28 @@ export function createTerminalOscLinkRetirement(terminal: TerminalBuffers): () = } } - function collectBufferLinks(buffer: IBuffer, links: Set): void { + function collectBufferLinks( + buffer: IBuffer, + links: Set, + rows?: ReadonlySet + ): void { const cell = buffer.getNullCell() - for (let row = 0; row < buffer.length; row++) { + if (rows === undefined) { + for (let row = 0; row < buffer.length; row++) { + const line = buffer.getLine(row) + if (!line) { + continue + } + for (let column = 0; column < line.length; column++) { + addAttributeLink(line.getCell(column, cell), links) + } + } + return + } + for (const row of rows) { + if (row < 0 || row >= buffer.length) { + continue + } const line = buffer.getLine(row) if (!line) { continue @@ -47,6 +66,23 @@ export function createTerminalOscLinkRetirement(terminal: TerminalBuffers): () = } } + /** Marker lines identify the only rows that can still contain a registered link. */ + function collectMarkerRows(entries: Iterable): Set | undefined { + const rows = new Set() + for (const value of entries) { + if (!isLinkEntry(value)) { + return undefined + } + for (const marker of value.lines) { + if (typeof marker.line !== 'number' || marker.line < 0) { + return undefined + } + rows.add(marker.line) + } + } + return rows.size > 0 ? rows : undefined + } + return (): number => { if (!('_core' in terminal) || !isRecord(terminal._core)) { return 0 @@ -72,8 +108,9 @@ export function createTerminalOscLinkRetirement(terminal: TerminalBuffers): () = } const live = new Set() - collectBufferLinks(terminal.buffer.normal, live) - collectBufferLinks(terminal.buffer.alternate, live) + const markerRows = collectMarkerRows(entries.values()) + collectBufferLinks(terminal.buffer.normal, live, markerRows) + collectBufferLinks(terminal.buffer.alternate, live, markerRows) // An OSC 8 open can finish one write before its linked text arrives in the next. addAttributeLink(input.getAttrData(), live) const bufferService = core._bufferService