Skip to content

Fix GUI search rescans on every frame - #3384

Merged
breznknecht merged 5 commits into
mainfrom
codex/gui-search-index-3280
Sep 16, 2026
Merged

breznknecht merged 5 commits into
mainfrom
codex/gui-search-index-3280

Conversation

@jsmestad

@jsmestad jsmestad commented Sep 16, 2026

Copy link
Copy Markdown
Owner

TL;DR

GUI Find now builds and maintains a versioned search index outside Editor and render callbacks. Unchanged frames do not fetch or scan document text, while edits, undo and redo, query changes, option changes, and buffer switches keep exact counts and navigation current.

Closes #3280

Context

The Find toolbar previously fetched the full buffer and ran the complete search during render-state construction. Cursor-only frames and unrelated UI updates therefore repeated document-scale work. The render path also hid failures behind a zero-result fallback and encoded result counts as 16-bit values.

Changes

  • Add a persistent line-keyed search index with subtree match counts, exact ordinal lookup, and lazy suffix shifts.
  • Apply line-local literal and regex updates from sequence-qualified buffer deltas, and rebuild from the latest full snapshot when history is missing or bulk replacement invalidates incremental work.
  • Run full index builds through the existing latest-wins scheduler, outside the Editor process and render callbacks. Reject stale results by buffer, search revision, version, and monotonic sequence.
  • Model loading, rebuilding, ready, and failed search states explicitly. Keep the previous accepted index visible during a rebuild.
  • Preserve a correlated ready index when the active toolbar changes between Find and Replace, so that presentation-only mode changes do not race an unnecessary rebuild.
  • Reduce render work to a bounded search projection and cursor lookup. Remove document fetching and match scanning from the render path.
  • Advance the frontend protocol to version 21, encode counts and the current ordinal as 32-bit values, and add explicit native search status.
  • Add focused Elixir, Go, Swift, protocol, and render-path tests.
  • Retain optimized BEAM and native benchmark scripts plus raw JSON evidence for the 100,000-line case.

Compatibility

This changes the frontend protocol from version 20 to version 21. The BEAM encoder, generated Go decoder, and Swift decoder are updated together. Older payloads remain rejected by the existing protocol version check.

Verification

  • make lint
  • mix test.llm: 58 doctests, 98 properties, 10,361 tests, 0 failures, 1 skipped
  • Focused Elixir search and render tests: 225 tests, 0 failures
  • mix conformance: 162 tests, 0 failures
  • go test ./internal/protocol ./internal/generated
  • Focused macOS SearchToolbarTests and ProtocolSchemaTests with xcodebuild
  • Optimized BEAM benchmark: 100,000 lines, 200,000 matches, edit and undo p95 212 microseconds, two lines and 32 bytes scanned, 1,000 unchanged frames with zero matching work
  • Optimized dense single-line benchmark: 70,000 matches, exact ordinals 65,536 and 70,000, 1,000 cursor projection and encode frames p50 1,203 microseconds and p95 1,755 microseconds total, with zero matching-work delta
  • Optimized native benchmark: fixed 27-byte wire payload with exact 100,000-line result counts
  • Find-to-Replace immediate replacement scenario repeated 100 times without failure

Acceptance Criteria Addressed

  1. ✅ The first search builds the index; cursor movement and unrelated frames perform no full-buffer fetch or match scan.
  2. ✅ Edits, undo and redo, query and option changes, and buffer switches produce fresh navigation and exact counts beyond 65,535.
  3. ✅ Full builds run outside the Editor and render path; stale results are rejected with version and sequence correlation; loading, rebuilding, and failure states are visible.
  4. ✅ Literal and regex updates rescan only affected lines and shift the unchanged suffix lazily; missing history and bulk changes rebuild from the latest snapshot.
  5. ✅ Release-oriented benchmark evidence separates matching work from render, encode, and native decode/model-update work.

@jsmestad
jsmestad force-pushed the codex/gui-search-index-3280 branch from d7874cc to c85c7b0 Compare September 16, 2026 13:47
@breznknecht
breznknecht merged commit 85bcfc2 into main Sep 16, 2026
11 checks passed
@breznknecht
breznknecht deleted the codex/gui-search-index-3280 branch September 16, 2026 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Keeping Find open does not rescan the document on every frame

2 participants