perf(terminal): scan OSC links only on marker rows

This commit is contained in:
Neil
2026-09-18 01:35:57 -07:00
parent 5e984fd093
commit 7e990eda24
+42 -5
View File
@@ -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<Terminal, 'buffer'>
@@ -34,9 +34,28 @@ export function createTerminalOscLinkRetirement(terminal: TerminalBuffers): () =
}
}
function collectBufferLinks(buffer: IBuffer, links: Set<number>): void {
function collectBufferLinks(
buffer: IBuffer,
links: Set<number>,
rows?: ReadonlySet<number>
): 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<unknown>): Set<number> | undefined {
const rows = new Set<number>()
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<number>()
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