ratatui_command_palette/lib.rs
1#![warn(missing_docs)]
2#![warn(rustdoc::broken_intra_doc_links)]
3
4//! Command palette state, view data, events, and renderers for Ratatui apps.
5//!
6//! `ratatui-command-palette` is the UI-state half of the command palette
7//! experiment in `ratatui-labs`. It consumes semantic action descriptions from
8//! [`ratatui_action`], tracks palette interaction state, prepares renderable
9//! view data, and emits events for the application to handle.
10//!
11//! The palette owns interaction state such as the current query, selected row,
12//! argument collection mode, and collected argument values. Applications own the
13//! action list, keybinding policy, dispatch, side effects, and any preview
14//! rollback. Accepting a row returns a [`PaletteEvent`](event::PaletteEvent)
15//! rather than executing application code directly.
16//!
17//! The API is experimental. Callers can rely on the documented behavior while
18//! evaluating the crate, but names, module boundaries, renderer options, and
19//! storage choices may change before any release with compatibility
20//! commitments.
21//!
22//! # Crate Model
23//!
24//! The crate separates palette work into four boundaries:
25//!
26//! - [`state::PaletteState`] owns search text, selection, input collection, and event emission.
27//! - [`view::PaletteView`] and [`view::PaletteRow`] are snapshots prepared for rendering.
28//! - [`render`] contains built-in renderers and the [`render::PaletteRenderer`] trait for alternate
29//! layouts.
30//! - [`key::PaletteKey`] is a small normalized input command type, including a crossterm adapter
31//! for applications that use crossterm events.
32//!
33//! Matching, selection, input collection, preview events, and rendering are
34//! intentionally separate so applications can keep one action model while
35//! changing presentation.
36//!
37//! # Lifecycle
38//!
39//! A typical application:
40//!
41//! 1. Builds or refreshes a list of [`ratatui_action::spec::ActionSpec`] values.
42//! 1. Calls [`PaletteState::open`](state::PaletteState::open).
43//! 1. Sends key-derived edits, movement, cancellation, and accept actions to the state machine.
44//! 1. Renders [`PaletteState::view`](state::PaletteState::view) with a [`render::PaletteRenderer`].
45//! 1. Handles emitted [`PaletteEvent`](event::PaletteEvent) values at the application's dispatch
46//! boundary.
47//!
48//! # Basic Invocation
49//!
50//! ```
51//! use ratatui_action::spec::ActionSpec;
52//! use ratatui_command_palette::event::PaletteEvent;
53//! use ratatui_command_palette::state::PaletteState;
54//!
55//! let actions = vec![ActionSpec::new("document.open", "Open document")];
56//! let mut palette = PaletteState::new();
57//! palette.open(&actions);
58//!
59//! if let Some(PaletteEvent::Invoke(invocation)) = palette.accept(&actions) {
60//! assert_eq!(invocation.id().as_str(), "document.open");
61//! // The application decides how to handle the invocation.
62//! }
63//! ```
64//!
65//! # Choice Input And Preview Events
66//!
67//! Actions with a choice input move the palette into
68//! [`PaletteMode::CollectingInput`](event::PaletteMode::CollectingInput).
69//! Moving the selected choice emits
70//! [`PaletteEvent::PreviewChanged`](event::PaletteEvent::PreviewChanged), and
71//! accepting the choice emits [`PaletteEvent::Invoke`](event::PaletteEvent::Invoke)
72//! with resolved arguments.
73//!
74//! ```
75//! use ratatui_action::id::InputId;
76//! use ratatui_action::input::{ActionChoice, ActionInput};
77//! use ratatui_action::spec::ActionSpec;
78//! use ratatui_command_palette::event::{MoveSelection, PaletteEvent};
79//! use ratatui_command_palette::state::PaletteState;
80//!
81//! let actions =
82//! vec![
83//! ActionSpec::new("theme.switch", "Switch theme").with_input(ActionInput::Choice {
84//! id: InputId::new("theme"),
85//! label: "Theme".into(),
86//! choices: vec![
87//! ActionChoice::new("catppuccin", "Catppuccin"),
88//! ActionChoice::new("github-dark", "GitHub Dark"),
89//! ],
90//! }),
91//! ];
92//!
93//! let mut palette = PaletteState::new();
94//! palette.open(&actions);
95//! palette.accept(&actions);
96//!
97//! let Some(PaletteEvent::PreviewChanged(Some(preview))) =
98//! palette.move_selection(MoveSelection::Next, &actions)
99//! else {
100//! panic!("expected preview event");
101//! };
102//!
103//! assert_eq!(
104//! preview.args().get(&InputId::new("theme")),
105//! Some("github-dark")
106//! );
107//! ```
108//!
109//! Text inputs use the query line as the input field and invoke with the typed
110//! value when accepted. Choice and boolean inputs emit preview events as
111//! selection changes. When an application applies transient preview state, use
112//! [`PaletteState::cancel_events`](state::PaletteState::cancel_events) to get an
113//! explicit rollback event before closing the palette.
114//!
115//! # Keyboard Input
116//!
117//! The palette does not decide which application key opens or closes it. It only
118//! provides [`key::PaletteKey`] as a small command type for operations the state
119//! machine understands. Applications can convert crossterm key events with
120//! [`PaletteKey::from_crossterm`](key::PaletteKey::from_crossterm) and keep
121//! policy decisions, such as whether `Esc` cancels the palette or exits the
122//! application, outside the crate.
123//!
124//! # Rendering
125//!
126//! Renderers consume [`view::PaletteView`] values produced by
127//! [`state::PaletteState::view`]. The built-in renderers include
128//! [`render::ModalRenderer`], [`render::FlatOverlayRenderer`],
129//! [`render::SplitPreviewRenderer`], [`render::FullscreenRenderer`], and
130//! [`render::InlineDropdownRenderer`].
131//!
132//! Renderers are pure drawing code. They should not filter actions, move
133//! selection, collect input, dispatch invocations, or mutate application state.
134//! See the `command-palette` and `renderer-gallery` examples for complete
135//! terminal integrations and the repository Betamax tapes for rendered
136//! validation.
137
138pub mod event;
139pub mod key;
140pub mod matching;
141pub mod render;
142mod selection;
143pub mod shortcut;
144pub mod state;
145pub mod view;