mirror of
https://github.com/stablyai/orca.git
synced 2026-10-01 00:02:10 +00:00
`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.