Search: stop at the first match from the cursor; capped count

run_search() replaces collecting every match in the buffer (and building
the full list again for every next/previous):

- Plain search finds forward from the search origin (then the current
  match) in the materialized text, or backwards through 1 MiB blocks
  searched forward (string_view::rfind scans a byte at a time: 511 ms
  per previous-match on 105 MB, now 6 ms). Regex search walks lines
  from the position with early exit.
- The i/N count stops at 1,000 matches, and for regex after 4 MiB; the
  status says 'N+' when capped.
- The first match is the first at or after the cursor (it was the first
  in the buffer). Extending the query keeps the current match while it
  still matches. Left/Right also step through matches in the regex
  replace prompt; Up/Down in a regex prompt use the regex.

On a 26 MB file: plain keystroke 30 ms -> 0.1 ms, next 24 -> 3 ms, regex
keystroke 434 -> 1.6 ms, regex next 420 -> 66 ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015rcVQiiWyTzoNrsvLSaAfB
This commit is contained in:
Claude
2026-09-24 09:16:04 -07:00
committed by Kyle Isom
parent 404b983009
commit fc15a58a2b
4 changed files with 510 additions and 319 deletions
+13
View File
@@ -700,6 +700,19 @@ public:
return content_.Size();
}
// Byte offset of (row, col) in the content (clamped), and back.
[[nodiscard]] std::size_t RowColToOffset(std::size_t row, std::size_t col) const
{
return content_.LineColToByteOffset(row, col);
}
[[nodiscard]] std::pair<std::size_t, std::size_t> OffsetToRowCol(std::size_t off) const
{
return content_.ByteOffsetToLineCol(off);
}
// Undo system accessors (created per-buffer)
[[nodiscard]] UndoSystem *Undo();