Files
orca/config
Neil ed19fbc024 perf(terminal): bound the highlight pass over a long wrapped line
`SearchAddon._highlightAllMatches` calls `SearchEngine.find` once per match, up
to the addon's 1 000-decoration limit, and every call resumes deep inside the
logical line. Three things in that path were O(line) per call, so one
un-newlined line holding many matches stayed quadratic after the no-match scan
was bounded: the rewind to the line start, `stringLine.toLowerCase()`, and
`_bufferColsToStringOffset` summing the cells of every row before the resume
column.

Measured on the real Terminal + real SearchAddon through Orca's `safeFind`, one
line of 30 000 rows with 750 matches: 31.0 s plain, 36.2 s regex, 38.2 s whole
word of blocked renderer main thread — re-run on every find-bar keystroke and
200 ms after every write. Above the default scrollback that is a worse failure
than the RangeError the `terminal.workbench` boundary used to recover from, so
bounding the other scans was not enough on its own.

- `_bufferColsToStringOffset` takes the cached `lineOffsets` and reads whole
  rows out of it, walking cells only for the last, partial row.
- `SearchLineCache.lineStartRow` remembers the wrapped span it last resolved, so
  re-entering the same line costs O(1) instead of O(rows). It keeps the row-0
  bound the rewind loop had.
- `SearchLineCache.caseFoldLine` memoizes the folded line per row.

Both memos live in `SearchLineCache` beside `_linesCache` and are dropped by
`_destroyLinesCache`, so they inherit its invalidation exactly: line feed,
cursor move, resize, and the 15 s TTL.

Same three shapes now 222 ms / 310 ms / 180 ms of test time including the 2.4 MB
write, against a 5 000 ms budget the committed test asserts.

Reading whole rows out of `lineOffsets` also removes an upstream off-by-one: the
cell sum counted the trailing null placeholder of a wide character that wrapped
to the next row, which `translateBufferLineToStringWithWrap` had already dropped
from the joined string, so a match at that boundary was skipped. A 400-scenario
differential fuzz against the previous build diverges in 27 scenarios; in every
one the new match count equals an independent oracle counted over the same
translated lines, the old build under-counted in 8 of the 18 rechecked, and no
selection on either side pointed at text that was not the term.
2026-09-03 04:01:02 -07:00
..