Phosphor::SearchMock
Inherits Phosphor::MockWidget < Reference < Object
A composite of InputMock + ListMock that filters rows in real time
— the common /-search pattern nearly every list-heavy TUI app
implements.
Generic and app-agnostic: no knowledge of AppState, Msg, or the
application theme. The Widget wrapper resolves theme → Style values
and sets them in Props before each render.
SearchMock never filters props.all_rows itself — the owning
Widget#sync filters all_rows by query and populates
filtered_rows in Props. render_content only ever draws from
props.filtered_rows; all_rows is carried through unread so the
Widget has somewhere to pull the unfiltered dataset from, never so
SearchMock can run a filter algorithm on it. See
.claude/rules/widgets.md § "Anti-patterns to flag".
Constructors
Initialises the search widget with props and an optional state.
Constructs the internal @input and @list widgets once, seeded
from props; render_content re-syncs their Props on every call
so their own WidgetState (cursor position, scroll offset) persists
across renders like any other MockWidget.
Instance methods
Routes cmd by type, delegating to whichever internal widget owns that concern:
Cmd::InsertChar,Cmd::DeleteChar,Cmd::MoveCursorLeft,Cmd::MoveCursorRight,Cmd::SelectAll— delegate to@input, returning itsCmdResultunchanged. Typing never moves the list cursor.Cmd::MoveUp,Cmd::MoveDown— delegate to@list, returning itsCmdResultunchanged. Navigation never affects the query.Cmd::Confirm— alwaysCmdResult::Bubble, so the owningWidgetcan read@list's cursor and emit a domainMsgfor the selected filtered row.SearchMockhas no idea what selecting a row means.Cmd::Cancel— alwaysCmdResult::Bubble, so the owningWidgetcan dismiss the search.- Any other command — returns
CmdResult::None.
The internal InputMock driving the query field. Read-only — exposed
so specs can inspect its props/state directly (e.g. to confirm
navigation commands never touch the query); nothing outside this
class should mutate it.
The internal ListMock driving the filtered results. Read-only — same
rationale as #input.
Renders the query field on the top row and the filtered results below it, into buf within frame.
@input and @list are re-synced from props first (so external
changes to query/filtered_rows/styles between renders show up
immediately), then @input renders into a one-row frame at
frame.y and @list renders into the remaining rows below —
computed with plain Frame arithmetic, not Layout (SearchMock is
a MockWidget, not a Screen).