Files
pikl/crates/pikl-core/src/model/traits.rs
J. Champagne 8bf3366740 feat: Expand hook system to handle simple exec and plugin extensibility.
Item Model Expansion - Item now caches sublabel, icon, group with accessors. Added resolve_field_path() for dotted path traversal and field_value() on Item.
Output Struct - New OutputItem with OutputAction (select/cancel) and index. Object values flatten, strings get a value field. MenuResult::Selected now carries { value, index }.
Hook Types - Replaced the old Hook trait with HookEvent (serializable, 6 variants), HookResponse (deserializable, 5 commands), HookHandler trait (sync for dyn-compatibility), and parse_hook_response() with tracing warnings.
New Actions & Menu Methods - Added ReplaceItems, RemoveItems, ProcessHookResponse, CloseMenu actions. Menu trait gained original_index(), replace_all(), remove_by_indices(), formatted_label(). Pipeline got rebuild() and rebuild_with_values(). Smart cursor preservation on replace.
Lifecycle Events - MenuRunner emits Open, Close, Hover, Select, Cancel, Filter events through the dispatcher. Cursor tracking for Hover detection.
Debounce - DebouncedDispatcher with 4 modes: None, Debounce, CancelStale, DebounceAndCancelStale. Defaults: hover=DebounceAndCancelStale(200ms), filter=Debounce(200ms).
Exec Hooks - ShellExecHandler maps --on-{open,close,hover,select,cancel,filter}-exec flags to fire-and-forget subprocesses. Event JSON piped to stdin.
Handler Hooks - ShellHandlerHook launches persistent processes per --on-{event} flag. Bidirectional JSON lines: events on stdin, responses on stdout flowing back through Action::ProcessHookResponse. CompositeHookHandler dispatches to both.
--filter-fields - --filter-fields label,sublabel,meta.tags searches multiple fields. Combined text for fuzzy, individual for exact/regex.
--format - FormatTemplate parses {field.path} placeholders. --format '{label} - {sublabel}' controls display. TUI renders formatted_text when available.
Field Filters - meta.res:3840 in query syntax matches specific fields. !meta.res:3840 for inverse. Pipeline stores item Values for field resolution. Requires dotted path (single word colons stay fuzzy).
2026-03-14 01:42:11 -04:00

63 lines
2.4 KiB
Rust

//! Trait abstractions for the menu data layer. [`Menu`]
//! is what the event loop drives. [`MenuItem`] is the display
//! contract for a single entry. Different backends (JSON,
//! CSV, Postgres, etc.) implement these.
/// Display contract for a single entry in a menu.
/// Provides a label for display and serialization for output.
pub trait MenuItem: Send + Sync + 'static {
/// Human-readable display text for this entry.
fn label(&self) -> &str;
/// Serialize this entry for structured output (stdout, hooks).
fn serialize(&self) -> serde_json::Value;
}
/// A filterable collection that the menu event loop drives.
/// Each implementation owns its data and handles filtering
/// internally. The event loop only needs labels (strings)
/// and serialized output (JSON values).
pub trait Menu: Send + 'static {
/// Total number of items before filtering.
fn total(&self) -> usize;
/// Apply a filter query. Implementations decide how to
/// match (fuzzy, regex, exact, SQL WHERE, etc.).
fn apply_filter(&mut self, query: &str);
/// Number of items that passed the current filter.
fn filtered_count(&self) -> usize;
/// Get the display label for a filtered item by its
/// position in the filtered results.
fn filtered_label(&self, filtered_index: usize) -> Option<&str>;
/// Add raw values from streaming input or AddItems actions.
fn add_raw(&mut self, values: Vec<serde_json::Value>);
/// Get the JSON value of a filtered item for output.
/// Returns a reference to the stored value.
fn serialize_filtered(&self, filtered_index: usize) -> Option<&serde_json::Value>;
/// Get the original index of a filtered item. Used to
/// provide the item's position in the unfiltered list
/// for output and hook events.
fn original_index(&self, filtered_index: usize) -> Option<usize>;
/// Replace all items with a new set of values. Used by
/// handler hook `replace_items` responses.
fn replace_all(&mut self, values: Vec<serde_json::Value>);
/// Remove items at the given original indices. Used by
/// handler hook `remove_items` responses.
fn remove_by_indices(&mut self, indices: Vec<usize>);
/// Get the formatted display text for a filtered item,
/// if a format template is configured. Returns None if
/// no template is set, in which case the raw label is
/// used.
fn formatted_label(&self, _filtered_index: usize) -> Option<String> {
None
}
}