Skip to main content

Crate lattice_picker

Crate lattice_picker 

Source
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

  • Picker owns 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.
  • PickerSource tags how the raw candidate list was built so refresh paths know which generator to re-run.
  • PickerAction tags 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-picker next to the PickerSourceGenerator trait and the PickerRegistry they register against. Symmetric with how feature crates already organise their sources (lattice_snippet::picker_sources, future lattice_lsp::picker_sources).
source
Picker source registry (metadata layer).
transient
Transient mode — grouped action menus within the picker.

Structs§

AiSessionRow
One row of the AI-session source. The picker host (App) snapshots this from the AiLogger service’s known_sessions() (no async lock — the logger’s ring map is a sync Mutex), then hands the vec to the picker. Mirrors LspInstanceRow, one level simpler: a session has no workspace / buffer-count / capability marginalia, only its (provider, index) key.
ErrorLocation
A place in a file the error list can navigate to: (path, line, col), line and column 0-based to match lattice_protocol::error_list::ErrorEntry.
LspInstanceRow
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 async Mutex.
LspLocationRow
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.picker while active; the input and render layers route to / from it via the Action::Picker* family.

Enums§

OpenTarget
Issue #32 (2026-05-22): where a picker’s file-opening outcome should land. <CR> uses Default; <C-s> / <C-v> / <C-t> override to a split / vsplit / new tab.
PickerAction
What <CR> does to the selected candidate. Variants stay dumb data; the App’s App::accept_picker dispatcher pattern-matches and calls the right method.
PickerSource
Where a picker pulls its raw candidates from. The App resolves this on populate / refresh and 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 separate Plugin(GeneratorId) variant once the WASM host is online.
RoutingPayload
Typed payload the picker accept dispatch reads to figure out which side effect to run. Replaces the tab-encoded string payloads stuffed into RawCandidate.text in 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 a u32 LE index into the picker’s routing_meta sidecar vec; the sidecar holds the typed RoutingPayload enum the accept dispatch matches on.

Traits§

BufferPathResolver
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.