Repository navigation
Search the dez rail by workspace, session, kind, or directory - #22
Conversation
The rail lists every workspace group and every live session under it, which stops being scannable well before dez's own multi-project, multi-session workflow does. v0.6 had a filter here and the port dropped it; this brings it back. A single-line editor under the rail header narrows the rail to the groups and rows whose text matches, and highlights the matched characters where they sit. A session is searched by what its row shows plus the two things it does not: the agent kind behind the row's actor label, and the directory it was started in. A group whose own name matched keeps all of its rows, so asking for a workspace answers with that workspace rather than with only its sessions that happen to match. Matching is a synchronous subsequence scan, ported from v0.6's `fuzzy_match_positions` and widened from contiguous substring to subsequence. It is deliberately not the async `fuzzy` crate: the rail rebuilds every row on each render, so a background pass would race its own keystrokes and can land out of order, and the rail holds tens of rows rather than thousands. The scan prefers a continued run, then a word start, so `fps` highlights a readable span in "Fix bug in panel sidebar" instead of scattered characters. Attention-first ordering and the header's rollup are computed over the filtered rows, so the count beside "Workspaces" always describes what is on screen. `cmd-f` / `ctrl-f` focuses the field through a new `MultiWorkspace` route that opens a closed rail first. It is bound in the `Workspace` key context rather than globally so an open editor keeps its own `cmd-f`. Reopening a rail that already holds a query returns focus to the field, so closing it mid-search does not throw the query away. Ports behavior, not the old file: no `agent_threads` API changes, and the state machine is untouched.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 3 advisory finding(s) below merit a look before merge.
Graphify review — findings
Adds a search field under the rail header that filters workspaces and sessions by name, title, agent kind, or working directory, highlighting matched characters in place while keeping attention-first ordering. Matching is a synchronous subsequence scan that prefers continuing a run, then a word start. A whitespace-only query counts as no filter, and a group whose own name matches keeps all its rows. cmd-f / ctrl-f in the Workspace context focuses the field via MultiWorkspace::focus_sidebar_search, opening a closed rail first, without stealing find from an open editor.
Worth a look
- Caller passes
Option<&mut Window>(already moved) toDezSidebar::new, which now requires&mut Window—crates/dez/src/dez.rs:410· Escalate · high- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- Greedy word-start preference makes match_positions reject candidates that contain the query —
crates/dez_sidebar/src/filter.rs:55· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- Group hidden when only a multi-root workspace label matches the search —
crates/dez_sidebar/src/sidebar.rs· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Review partial — this diff was larger than one review pass covers, so later files were not reviewed; some findings may be missing.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1307 functions depend on the 748 functions this change touches.
Health — grade A; 10 existing hotspot(s) in the area this change touches (pre-existing, not introduced here):
init()— 52 callers, 3 callees (high)init_test()— 38 callers, 4 callees (high)spawn_live_codex_thread()— 20 callers, 6 callees (high)init_test_with_editor()— 40 callers, 3 callees (high)init_test()— 18 callers, 6 callees (high)init_test()— 27 callers, 3 callees (high)init()— 10 callers, 8 callees (high)init_test()— 10 callers, 7 callees (high)- …and 2 more
Verification — 1307 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 1303 function(s) in the blast radius were not formally verified this run
Docs that may be stale (advisory)
.factory/commands/opsx-propose.md§ (document) (lines 1-105): references changed symbolsnewcrates/agent_control_skill/skills/dezctl/SKILL.md§ dez control (lines 8-51): references changed symbolsnewcrates/gpui/README.md§ Getting Started (lines 6-18): references changed symbolsnewcrates/inspector_ui/README.md§ Cleaner lifecycle for inspector state viewers / editors (lines 101-112): references changed symbolsnewcrates/terminal_view/README.md§ Design Notes (lines 3-12): references changed symbolsnewcrates/vim/README.md§ Testing against Neovim (lines 7-33): references changed symbolsnewdocs/src/command-palette.md§ Command Palette (lines 6-14): references changed symbolsnewdocs/src/debugger.md§ Configuration (lines 85-111): references changed symbolsnewdocs/src/development/glossary.md§ State management (lines 31-52): references changed symbolsnewdocs/src/development/windows.md§ Setting RUSTFLAGS env var breaks builds (lines 126-173): references changed symbolsnew
…and 10 more.
`Option<Vec<usize>>` on the row structs was carrying no information: `session_title` drew a plain label for `None` and a `HighlightedLabel` with no highlights for `Some(vec![])` -- the same pixels. The fields are plain `Vec<usize>>` now and there is one label shape, which also removes the possibility of the two drifting apart. Also drops an `aria_label` that `IconButton` does not have in this fork (the tooltip already names the button), and gives the two empty-state arms the same tuple type.
observe_new hands the closure an Option<&mut Window> and the existing early return bound it as _window, so the call site passed the Option itself into a constructor that needs the window.
Neither was a bug in the matcher; both were my expectations being wrong about it, and both are worth stating correctly because the precedence they describe is the whole point of the scan. "at" on "atlas data" cannot demonstrate the word-start preference: "at" is the front of "atlas", so continuing the run resolves it at [0, 1] before the word-start preference is ever consulted. Replaced with "ab" on "axb b", which does isolate it -- the `b` inside "axb" comes first but is mid-word, so the preference skips it for the one that opens a word, giving [0, 4] where a plain first-match scan gives [0, 2]. Added the run wins case and a separator case alongside, so all three rungs of the preference are pinned. `match_positions` returns one offset per query character, not per byte, so "café" is four offsets; the assertion was summing `len_utf8()`.
Summary
The rail is dez's only supervision surface, and it lists every workspace group plus every live session under it. That stops being scannable well before dez's own multi-project, multi-session workflow does. v0.6 had a filter here and the port dropped it; this restores it.
Why not the
fuzzycrateMatching is a synchronous subsequence scan, ported from v0.6's
fuzzy_match_positionsand widened from contiguous substring to subsequence. It is deliberately notfuzzy::match_strings, which isasync: the rail rebuilds every row on each render, so a background pass would race its own keystrokes and can land out of order, and the rail holds tens of rows rather than thousands. One forward scan per field is cheaper than the machinery to cancel and reorder one.The scan prefers a continued run, then a word start, so
fpshighlights a readable span in "Fix bug in panel sidebar" instead of scattered characters. Offsets are always UTF-8 character boundaries, which is what keeps a multi-byte title from trippingHighlightedLabel's debug assertion.Keyboard
cmd-f/ctrl-ffocuses the field via a newMultiWorkspace::focus_sidebar_search, which opens a closed rail first. It is bound in theWorkspacekey context rather than globally, so an open editor keeps its owncmd-f— the same scoping v0.6 used.Sidebargains afocus_searchwith a default that delegates toprepare_for_focus, so a sidebar without a search field is unaffected.Rules
agent_threadsAPI additions, no state-machine change (MERGE.md §2.2).docs/dez-workspace-shell.md, oneSYNC-LEDGER.mdline, twoFORK.mdrows.crates/dez_sidebar/src/filter.rscover the matcher: substring, subsequence, case in both directions, run-vs-loose preference, out-of-order rejection, repeated characters, non-ASCII boundaries, hidden-field admission, and blank-query normalization.Verification
Not built locally by request — CI is the build.
cargo fmtwas run withrustfmtdirectly on the touched files (parse-clean). Expectclippyand thetestsjob to be the real gate.Suggested .rules additions
render, so anything the rail filters on must match synchronously.fuzzy::match_stringsisasyncand will race its own keystrokes there; a scan incrates/dez_sidebar/src/filter.rsis the pattern.DezSidebar::newtakes a&mut WindowbecauseEditor::single_lineneeds one. Constructors in this repo that build anEditorcannot be called from a plain&mut App— check before assuming a signature can stay windowless.Release Notes:
cmd-f/ctrl-f.