Expand description
Interactive terminal components for rs-rich (#451): the layer between printing and a full TUI framework.
A Component is a state machine: it handles one Event and renders
one View. Two drivers run it:
- blocking:
runtakes the terminal, drives the component to anOutcomeand gives the terminal back, likePrompt.ask; - event loop: an
EventLoopruns one or more components at once, with ticks and timers, and repaints only when something changed.
Views are painted through rich_ext::frame::Frame::diff, cell by cell,
so an idle loop writes nothing. Around them:
session: raw mode, the alternate screen, mouse and paste, restored on every way out, including a panic, Ctrl+C and a hand-off to another program (#489), driven by crossterm, or by termion or termwiz behind the features of those names (BackendKind), and each frame written as one synchronized update where the terminal has it;event: keys, mouse, resizes and pastes, from whichever drives the terminal;viewport: a scrollable window over rendered lines (#495);item: one item model behind every picker (#452);policy: with no terminal, under CI or withTERM=dumb, a component asks line by line, returns its default, or fails, as the caller chooses, and never blocks on a pipe (#492);headless: scripted events in, frames out, for tests;components:Select,MultiSelect,TableSelect,TreeSelect,Input,TextArea,Confirm,Form,Pager,Paginator,FilePicker,ColorPicker,AssetPicker,ThemePicker,Reorder(#720), andDatePicker,TimePickerandDateTimePicker(#719, on thedatetimetypes),LogView(#724, a live view of log records), built on the above with afuzzymatcher,ApprovalQueue(#471, a review of pending items) andJump(#484, one fuzzy box over several sources), and with thedatafeatureDataExplorer, for JSON, YAML, TOML and the other formatsrich_ext::datareads;clipboard: copy to the terminal’s clipboard with OSC 52, when it takes it.
Components compose (0.0.14): compose has containers that are
components themselves (Column, Row, Stack, Split,
Tabs, Layers), with focus, routing and bubbling
(Flow::Ignored); kit has the line helpers and state types the
built-ins are made of; and keymap declares, rebinds and lists every
component’s keys. On top of those, overlay has a command palette, a
help overlay, a shortcut sheet and an action menu read from the keymap,
and chrome a status bar and breadcrumbs; Overlays wires them all
into any component.
Mouse support (#476) is opt-in per component (Component::mouse):
clicks, drags and the wheel arrive in the component’s own coordinates, a
click on a hyperlink arrives as Event::Link, and the border beside a
preview drags. Actions (#491) attach to list items, table rows, tree
nodes and file entries through Actions and an ActionTarget, and
open in a modal menu (Ctrl+K); a region takes actions too, through
Overlays::actions; plugins register them through
rs-rich-plugin-api. Plugins register whole components too, and
PluginView mounts one by name beside the built-ins (plugin).
use rich_interact::{headless, Component, Context, Event, Flow, KeyCode, Outcome, View};
/// Counts Up presses; Enter returns the count.
struct Counter(u32);
impl Component for Counter {
type Output = u32;
fn handle(&mut self, event: &Event, _: &Context<'_>) -> Flow<u32> {
match event.key().map(|key| key.code) {
Some(KeyCode::Up) => self.0 += 1,
Some(KeyCode::Enter) => return Flow::Done(self.0),
_ => {}
}
Flow::Continue
}
fn render(&self, context: &Context<'_>) -> View {
View::new(context.markup(&format!("count: [bold]{}[/]", self.0)))
}
}
let script = headless::Script::new().keys("up up enter");
let (outcome, record) = headless::run(Counter(0), script, 40, 5);
assert_eq!(outcome.unwrap(), Outcome::Done(2));
assert_eq!(record.last_frame(), "count: 2");Re-exports§
pub use chrome::Breadcrumbs;pub use chrome::StatusBar;pub use chrome::StatusItem;pub use component::Component;pub use component::Context;pub use component::Flow;pub use component::View;pub use components::Answers;pub use components::ApprovalQueue;pub use components::ApprovalReport;pub use components::AssetKind;pub use components::AssetPicker;pub use components::Choice;pub use components::ColorFormat;pub use components::ColorPicker;pub use components::Confirm;pub use components::DatePicker;pub use components::DateTimePicker;pub use components::Decision;pub use components::FileMode;pub use components::FilePicker;pub use components::Form;pub use components::Input;pub use components::Jump;pub use components::JumpIndex;pub use components::JumpSource;pub use components::Jumped;pub use components::LogEvent;pub use components::LogView;pub use components::MultiSelect;pub use components::Pager;pub use components::PreviewLayout;pub use components::Reorder;pub use components::Select;pub use components::Suggestion;pub use components::TableSelect;pub use components::TextArea;pub use components::Theme;pub use components::ThemePicker;pub use components::TimePicker;pub use components::TreeSelect;pub use components::Value;pub use components::Verdict;pub use components::Paginator;pub use components::PaginatorStyle;pub use compose::Axis;pub use compose::Column;pub use compose::ComponentExt;pub use compose::Label;pub use compose::Layer;pub use compose::LayerHandle;pub use compose::Layers;pub use compose::Rect;pub use compose::Row;pub use compose::Size;pub use compose::Split;pub use compose::Stack;pub use compose::Tabs;pub use event::Button;pub use event::Event;pub use event::HeldButton;pub use event::Key;pub use event::KeyCode;pub use event::ModifierKey;pub use event::Modifiers;pub use event::Mouse;pub use event::MouseKind;pub use event::Releases;pub use event::Subcell;pub use event_loop::Error;pub use event_loop::EventLoop;pub use event_loop::Handle;pub use event_loop::LoopOptions;pub use event_loop::Outcome;pub use event_loop::RunOptions;pub use event_loop::degrade;pub use event_loop::run;pub use event_loop::run_with_graphics;pub use item::Action;pub use item::ActionFilter;pub use item::ActionTarget;pub use item::Actions;pub use item::Item;pub use item::Preview;pub use item::TargetKind;pub use keymap::Binding;pub use keymap::Keymap;pub use overlay::Command;pub use overlay::Help;pub use overlay::Menu;pub use overlay::Overlays;pub use overlay::Palette;pub use overlay::Shortcuts;pub use plugin::PluginView;pub use policy::Fallback;pub use policy::LineIo;pub use policy::NotInteractive;pub use policy::Policy;pub use policy::Reason;pub use push::PushBackend;pub use push::PushPort;pub use session::Backend;pub use session::BackendKind;pub use session::Output;pub use session::Session;pub use session::SessionOptions;pub use session::Waker;pub use session::synchronized_update;pub use viewport::Viewport;
Modules§
- caret
- The text caret’s shape: a block, a bar or an underline, set on the
terminal’s own cursor with DECSCUSR (
CSI n SP q), which xterm, the kitty, WezTerm, iTerm2, Windows Terminal, foot, Alacritty and the VTE terminals follow. A terminal that does not know it ignores it. - chrome
- Chrome: a status bar (#481) and breadcrumbs (#482), the lines round a view that say where you are and what you can do (0.0.14 workstream 2).
- clipboard
- Copy from a component to the terminal’s clipboard (#488).
- component
- The component contract: one event in, one view out.
- components
- Ready-made components (0.0.13 workstream 3), built from the crate’s
primitives:
Item,Viewportand the fuzzy matcher. Each works under both drivers, degrades to a line-based prompt without a terminal, and is styled by oneTheme. - compose
- Composition: containers that are themselves components (0.0.14 workstream 1, #478, #479, #480).
- dates
- Dates as people type them:
tomorrow,eow,monday,3d,2026-11-01, read relative to a given now. Generic: a todo list’s due dates, a log viewer’ssince, a calendar’s jump; the names are Taskwarrior’s, which most such tools share. - datetime
- Dates and times of day (#719), without a time zone: what the date and
time pickers (
DatePicker,TimePicker,DateTimePicker) and intuiTUIve’s calendar choose. Hand-rolled, with no dependency: aDateis a day of the proleptic Gregorian calendar, aTimea time of day to the second, and aDateTimethe two together. Each parses the ISO 8601 form it prints (2026-10-17,14:30,2026-10-17 14:30), and a time also parses a 12-hour clock (2:30 pm). - edit
- A text buffer for editors: lines of text, a caret on a grapheme boundary, a selection, a character limit, and undo and redo.
- edit_
keys - Editor keys: what a text editor’s keys do, as actions in a
Keymap, so they can be rebound, listed and swapped for a preset. - event
- Input events: keys, mouse, resizes, pastes and ticks.
- event_
loop - The event loop, and the blocking
runbuilt on it. - fuzzy
- Fuzzy matching for pickers: a pattern’s characters in order, anywhere in the candidate, scored so that the matches people mean rank first.
- headless
- The headless driver: scripted events in, painted frames out.
- item
- The universal item model (#452): one type behind every picker.
- keymap
- The keymap registry: what each key does, declared rather than matched inline, so it can be rebound and listed (0.0.14 workstream 1).
- kit
- The building-block kit: the pieces the built-in components are made of, public so your own components can use them too (0.0.14 workstream 1).
- overlay
- Overlays: a command palette, a help overlay, a shortcut sheet and an action menu, all read from the keymap, and a wrapper that puts them over any component (0.0.14 workstream 2: #453, #473, #474, #475).
- paint
- Painting views into a region of the terminal, cell by cell.
- plugin
- Components from plugins (0.0.14 workstream 4): a
PluginComponentthat a plugin registered by name withPluginRegistrar::component, mounted as aComponentbeside the built-ins. - policy
- When the terminal is not interactive (#492): detect it, and degrade without control sequences and without blocking.
- push
- A backend for push driving: the host owns the clock and the screen.
- session
- The terminal session: raw mode, the alternate screen, mouse and paste modes, the kitty keyboard protocol, synchronized output, and their restoration on every way out (#489).
- viewport
- A scrollable window over rendered lines (#495).