Rio
adr/0052-search-panel.mdRaw Markdown · GitHub ↗

ADR-0052: One search panel: two engines, three scopes

  • Status: Accepted
  • Date: 2026-08-19
  • Deciders: jka
  • Decision: D52

Context

With both an inline find bar (ADR-0036) and a find-in-files panel (ADR-0051), the question was whether to merge them into one "all things search" dialog, as Notepad++ does.

Decision

The two remain separate surfaces, connected by a handoff. The find bar stays the quick in-buffer tool. The find-in-files panel becomes a general Search panel with three scopes:

ScopeOperationReads
Projectproject.searchfiles on disk
Open docsbuffers.searchevery open buffer's text
Current docbuffers.search with onlythe focused buffer

The buffer scopes read live text, so they include unsaved edits. Both engines share one line matcher (rio::doc::grep_lines). Pressing Ctrl+Shift+F in the find bar carries its needle and options into the panel and widens the scope to Project. The panel's default scope is Current doc.

Replace works in every scope. Buffer scopes use buffer.replace_all and leave changes unsaved. Project scope uses project.replace, after a confirmation, and routes each file by whether it is open: open files are changed through their buffer (undoable, unsaved), closed files are rewritten on disk with their encoding and line endings preserved. Disk is never rewritten under an open buffer.

Regular expressions are available on every search and replace operation and on both surfaces. Patterns are Tcl ARE, matched line by line (^ and $ anchor at line boundaries). Whole word is disabled while regex is on, since a pattern states its own boundaries. Replacement text may use back-references. An invalid pattern matches nothing rather than raising an error, so a half-typed pattern shows no hits. Because regex matches vary in length, each match row carries a lens array beside cols.

Consequences

  • The quick bar and the panel cannot disagree, because they use the same engine.
  • The panel lives in the bottom dock site as an ordinary tool window (ADR-0035).
  • project.replace must call model functions directly instead of nested dispatch, so its events are not duplicated.