Expand description
Vertico-style picker (DESIGN.md §5.9.7, §5.9.10).
Generalises the completion popup’s three-stage shape (raw candidates -> filter -> render) into a reusable host for any “type to drill down, Enter to act” UI: buffer switcher, LSP instance picker, future fuzzy-finder, command palette, diagnostics list, register / mark history.
§Architecture
Pickerowns the live state: a query buffer, a cursor on that query, the unfiltered raw candidate list, the filtered rendered list, and a selection cursor on the rendered list.PickerSourcetags how the raw candidate list was built so refresh paths know which generator to re-run.PickerActiontags what to do when the user accepts a row. The dispatch happens on the host side; Picker is dumb about side effects.
Filtering today is case-insensitive substring (cheap, easy
to reason about). The pipeline-driven path (lattice-completion
crate’s full vertico stack: matcher / ranker / annotators) takes
over once we lift CommandLineSlot out of the slot detector –
same data shape, richer scoring. Substring is enough to ship a
useful buffer switcher and stays cheap when the candidate set is
small (typical: <50 buffers, <10 LSP instances).
§Renderer-agnostic by design
This crate is the data model for pickers; it owns no
rendering code and no host-specific imports beyond
lattice-completion’s candidate shape. Hosts (the TUI
renderer today; the GPUI / web renderers later) read picker
state and paint it however they like.
The buffer-source candidate builder lives in the TUI host
(lattice-ui-tui::app::raw_buffer_candidates) because it
walks the host’s BufferRegistry. LSP-instance candidates
arrive via Picker::set_lsp_instances which takes a
Vec<LspInstanceRow> of pure-data rows the host snapshots
from the supervisor. Both paths feed Picker::set_raw_candidates
(the only entry point that mutates raw).
See docs/dev/architecture/picker.md for the trait-surface
design that the registry, source generators, and MRU
pipeline will land on top of this data model.
Re-exports§
pub use context::ActiveBufferSnapshot;pub use context::BufferEntry;pub use context::PaneHistoryRow;pub use context::PickerContext;pub use context::PositionEntry;pub use context::PositionSource;pub use mru::DEFAULT_CAP_PER_NAMESPACE;pub use mru::DEFAULT_HALF_LIFE;pub use mru::MruEntry;pub use mru::MruKey;pub use mru::MruPersistError;pub use mru::PickerMruIndex;pub use mru::bonus_of;pub use mru::default_persist_path;pub use mru::routing_identity;pub use outcome::FillTarget;pub use outcome::PickerAcceptOutcome;pub use outcome::PickerPreviewOutcome;pub use picker_sources::DIR_PICK_SOURCE;pub use picker_sources::FILE_PICK_SOURCE;pub use picker_sources::YANK_RING_SOURCE;pub use source::AcceptFuture;pub use source::CandidateBatch;pub use source::CandidateFuture;pub use source::CandidateStream;pub use source::PickerInitResult;pub use source::PickerRegistry;pub use source::PickerRegistryHandle;pub use source::PickerSourceGenerator;pub use source::PickerSourceSpec;pub use source::SourceResult;pub use transient::KeyResolution;pub use transient::TransientArgSource;pub use transient::TransientBuild;pub use transient::TransientBuildFuture;pub use transient::TransientContext;pub use transient::TransientGroup;pub use transient::TransientItem;pub use transient::TransientItemKind;pub use transient::TransientSourceRegistry;pub use transient::TransientSourceRegistryHandle;pub use transient::TransientSpec;pub use transient::TransientState;pub use transient::TransientValue;pub use transient::confirm_transient_spec;pub use transient::transient_initial_state;
Modules§
- context
- Host-built snapshot the picker primitive hands to source
generators on every
:picker <source>open. - events
- Picker-owned editor-bus events (§5.10).
- mru
- MRU (frecency) index for picker candidates.
- outcome
- Picker accept outcomes – typed effects the source
generator emits on
<CR>for the host to apply. - picker_
sources - First-party picker source generators – renderer-neutral; live
in
lattice-pickernext to thePickerSourceGeneratortrait and thePickerRegistrythey register against. Symmetric with how feature crates already organise their sources (lattice_snippet::picker_sources, futurelattice_lsp::picker_sources). - source
- Picker source registry (metadata layer).
- transient
- Transient mode — grouped action menus within the picker.
Structs§
- AiSession
Row - One row of the AI-session source. The picker host (App)
snapshots this from the
AiLoggerservice’sknown_sessions()(no async lock — the logger’s ring map is a syncMutex), then hands the vec to the picker. MirrorsLspInstanceRow, one level simpler: a session has no workspace / buffer-count / capability marginalia, only its(provider, index)key. - Error
Location - A place in a file the error list can navigate to:
(path, line, col), line and column 0-based to matchlattice_protocol::error_list::ErrorEntry. - LspInstance
Row - One row of the LSP-instance source. The picker host (App)
snapshots this from
LspSupervisor::running_actors()under the supervisor lock, then drops the lock before handing the vec to the picker. Decouples the picker module from the supervisor’s asyncMutex. - LspLocation
Row - One row of an LSP-location source – multi-result navigation,
references, diagnostics. Carries the canonical
(path, line, col)triple the host needs to jump (LSP 0-based line, utf-8 byte column already converted host-side) plus the presentation pieces. - Picker
- One open vertico-style picker. Lives on
App.pickerwhile active; the input and render layers route to / from it via theAction::Picker*family.
Enums§
- Open
Target - Issue #32 (2026-05-22): where a picker’s file-opening outcome should
land.
<CR>usesDefault;<C-s>/<C-v>/<C-t>override to a split / vsplit / new tab. - Picker
Action - What
<CR>does to the selected candidate. Variants stay dumb data; the App’sApp::accept_pickerdispatcher pattern-matches and calls the right method. - Picker
Source - Where a picker pulls its raw candidates from. The App resolves
this on
populate/refreshand walks the appropriate source. One enum variant per first-party source so the App stays decoupled from generator implementations; plugin-provided pickers will arrive as a separatePlugin(GeneratorId)variant once the WASM host is online. - Routing
Payload - Typed payload the picker accept dispatch reads to figure out
which side effect to run. Replaces the tab-encoded string
payloads stuffed into
RawCandidate.textin earlier phases (Phase 4.2.g.7 polish).
Constants§
- PICKER_
CREATE_ KIND_ ID - OR.5:
CandidateData::Extension { kind_id }the picker stamps on its synthetic create row. - PICKER_
ROUTING_ KIND_ ID CandidateData::Extension { kind_id }value the picker stamps on every candidate it builds. Each candidate’s payload bytes are au32LE index into the picker’srouting_metasidecar vec; the sidecar holds the typedRoutingPayloadenum the accept dispatch matches on.
Traits§
- Buffer
Path Resolver - Resolves a picker-relative buffer id to its on-disk path, for the one
routing variant (
RoutingPayload::JumpInBuffer) whose location is buffer-relative rather than a filesystem path.