API Reference
A map of the public surface, with the signatures you'll actually call. Full generated docs live on docs.rs. Signatures here are abbreviated (bounds elided) for readability.
Prelude
#![allow(unused)] fn main() { use tui_pages::prelude::*; }
Pulls in the runtime types, the focus types, modes::*, parse_binding, and —
importantly — the traits TuiActionHandler, FocusController, and
PageProvider. With the dialog feature it also brings in DialogData,
DialogResult, DialogTheme, render_dialog, and the dialog::* helpers.
Building the app
#![allow(unused)] fn main() { TuiPages::builder(initial_view: V) -> TuiPagesBuilder<...> impl TuiPagesBuilder { // pages + handler (both required) fn page_fn(self, f: PageFn<V, S, O>) -> Self; // page provider as a fn fn pages(self, provider: P) -> Self; // or a custom PageProvider fn handler(self, h: Handler) -> Self; // bindings & commands fn bind(self, mode: impl Into<ModeId>, binding: &str, action: A) -> Self; fn keymap(self, mode: impl Into<ModeId>, f: impl FnOnce(&mut KeyMap<A>)) -> Self; fn command(self, name: impl Into<String>, aliases, action: A) -> Self; // tuning (all optional) fn fallback_view(self, view: V) -> Self; // view to fall back to on close fn focus_wrap(self, wrap: FocusWrap) -> Self; // Clamp (default) or Wrap fn input_timeout_ms(self, ms: u64) -> Self; // chord-sequence timeout fn command_timeout_ms(self, ms: u64) -> Self; fn build(self) -> TuiPages<...>; } }
PageFn<V, S, O> is fn(&V, &S, Option<&FocusTarget<O>>) -> PageSpec<O>.
The runtime: TuiPages
Public fields (you read these to render; you don't drive them):
#![allow(unused)] fn main() { pub input: InputPipeline<A> pub commands: CommandResolver<A> // resolve typed commands pub focus: FocusManager<O, M> // focus.current(), focus.has_overlay(), ... pub buffer: BufferState<V> // buffer.panes(), buffer.is_split(), ... }
Methods you call:
#![allow(unused)] fn main() { fn handle_key(&mut self, key: KeyEvent, state: &mut S) -> Result<TuiPagesOutput<A>, TuiPagesError<E>>; fn submit_command(&mut self, input: &str, state: &mut S) -> Result<TuiPagesOutput<A>, TuiPagesError<E>>; fn refresh_page(&mut self, state: &S); // re-read the current page spec fn current_view(&self) -> &V; // active buffer's view fn apply_effect(&mut self, effect: TuiEffect<V, O, M>, state: &S) -> bool; }
#![allow(unused)] fn main() { pub struct TuiPagesOutput<A> { pub status: TuiPagesStatus<A>, pub quit_requested: bool, } pub enum TuiPagesStatus<A> { ActionHandled, TextHandled, Waiting(Vec<InputHint<A>>), Cancelled, CommandIncomplete(Vec<CommandHint>), CommandUnknown, CommandEmpty, } }
Your handler
#![allow(unused)] fn main() { pub trait TuiActionHandler<V, A, S, O = (), M = ()> { type Error; fn handle_action(&mut self, action: A, ctx: ActionContext<V, O>, state: &mut S) -> Result<ActionOutcome<V, O, M>, Self::Error>; // default returns ActionOutcome::none(); override for text-input pages fn handle_text(&mut self, chord: KeyChord, ctx: ActionContext<V, O>, state: &mut S) -> Result<ActionOutcome<V, O, M>, Self::Error>; } pub struct ActionContext<V, O = ()> { pub current_view: V, pub focus: Option<FocusTarget<O>>, pub has_overlay: bool, } }
Effects & outcomes
#![allow(unused)] fn main() { pub enum TuiEffect<V, O = (), M = ()> { None, Focus(FocusIntent<O, M>), Navigate(V), NextBuffer, PreviousBuffer, CloseBuffer, SplitPane(PaneSplit), ClosePane, NextPane, PreviousPane, RefreshPage, Quit, } impl ActionOutcome<V, O, M> { fn none() -> Self; fn effect(e: TuiEffect<V, O, M>) -> Self; fn effects(iter: impl IntoIterator<Item = TuiEffect<V, O, M>>) -> Self; } }
Pages & focus
#![allow(unused)] fn main() { pub struct PageSpec<O = ()> { /* see Core Concepts */ } impl PageSpec<O> { fn new() -> Self; fn focus(self, builder: PageFocusBuilder<O>) -> Self; // prefer this fn focus_targets(self, targets: Vec<FocusTarget<O>>) -> Self; fn modes(self, modes: impl IntoIterator<Item = ModeId>) -> Self; fn accepts_text_input(self, yes: bool) -> Self; } impl PageFocusBuilder<O> { fn new() -> Self; fn button(self, index: usize) -> Self; fn buttons(self, indices: &[usize]) -> Self; fn section(self, id: usize) -> Self; fn section_with_items(self, id: usize, item_count: usize) -> Self; fn canvas_field(self, index: usize) -> Self; fn canvas_fields(self, count: usize) -> Self; fn internal_canvas_field(self, index: usize) -> Self; fn target(self, t: FocusTarget<O>) -> Self; fn build(self) -> Vec<FocusTarget<O>>; } pub enum FocusTarget<O = ()> { Button(usize), Section(usize), SectionItem { section: usize, item: usize }, CanvasField(usize), InternalCanvasField(usize), Overlay(O), ModalItem(usize), Custom(String), } pub enum FocusIntent<O = (), M = ()> { Next, Prev, Activate, LeaveSection, Set(FocusTarget<O>), Open(FocusTarget<O>), Close(FocusTarget<O>), Toggle(FocusTarget<O>), ClearOverlay, EnterSection { item_count: usize }, ExitCanvasForward, ExitCanvasBackward, ShowModal { data: M, count: usize }, UpdateModal { data: M, count: usize }, RegisterPage(Vec<FocusTarget<O>>), RegisterPageAndEnterSection { targets: Vec<FocusTarget<O>>, section: usize, item_count: usize, item: usize }, } pub enum FocusWrap { Clamp, Wrap } }
FocusManager — read-only from your side:
#![allow(unused)] fn main() { fn current(&self) -> Option<FocusTarget<O>>; fn is_focused(&self, target: &FocusTarget<O>) -> bool; fn has_overlay(&self) -> bool; fn focus_wrap(&self) -> FocusWrap; fn clear_overlay(&mut self); // used when closing an app-owned palette }
Input
#![allow(unused)] fn main() { fn parse_binding(s: &str) -> Vec<KeyChord>; // lenient, drops bad tokens fn parse_key(s: &str) -> Option<KeyChord>; fn try_parse_binding(s: &str) -> Result<Vec<KeyChord>, ParseKeyError>; // strict fn try_parse_key(s: &str) -> Result<KeyChord, ParseKeyError>; impl KeyChord { fn from_event(event: &KeyEvent) -> Self; fn display_string(&self) -> String; pub code: KeyCode, pub modifiers: KeyModifiers, } }
There is no FromStr/parse() on KeyChord — use the functions above.
Commands
#![allow(unused)] fn main() { pub enum CommandResponse<A> { Execute(A), Incomplete(Vec<CommandHint>), Unknown, Empty } pub struct CommandHint { pub alias: String, pub action_name: String } impl CommandResolver<A> { // available as tui.commands fn process(&self, input: &str) -> CommandResponse<A>; fn get_feedback(&self, input: &str) -> Option<String>; } }
Navigation
#![allow(unused)] fn main() { pub enum PaneSplit { Horizontal, Vertical } impl BufferState<V> { // available as tui.buffer (read-only use) fn get_active_view(&self) -> Option<&V>; fn is_split(&self) -> bool; fn split_direction(&self) -> Option<PaneSplit>; fn panes(&self) -> &[PaneSession<V>]; fn active_pane_index(&self) -> usize; } }
You drive buffers and panes through TuiEffect, not through these mutators.
Dialog (feature dialog)
#![allow(unused)] fn main() { pub struct DialogData<D = ()> { pub title: String, pub message: String, pub buttons: Vec<String>, pub purpose: Option<D>, pub is_loading: bool, } impl DialogData<D> { fn new(title, message, buttons, purpose: D) -> Self; fn loading(title, message) -> Self; fn show_intent<O>(self) -> FocusIntent<O, DialogData<D>>; } pub enum DialogResult<D> { Selected { purpose: Option<D>, index: usize }, Dismissed } pub enum DialogKey<D> { Ignored, Consumed, Resolved(DialogResult<D>) } // helpers fn dialog::handle_key<O, D>(focus: &mut FocusManager<O, DialogData<D>>, key: KeyEvent) -> DialogKey<D>; fn dialog::current_dialog<O, D>(focus: &FocusManager<O, DialogData<D>>) -> Option<&DialogData<D>>; fn dialog::active_button<O, D>(focus: &FocusManager<O, DialogData<D>>) -> Option<usize>; fn render_dialog<D>(f: &mut Frame, area: Rect, data: &DialogData<D>, active_button: usize, theme: &DialogTheme); }
Terminal
#![allow(unused)] fn main() { fn tui_pages::terminal::enter() -> io::Result<TerminalGuard>; }
Enables raw mode + the alternate screen and returns a guard that restores the terminal when it drops — including on a panic.