Commands - tui-pages

## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

# Commands

Commands are the typed kind: `:quit`, `:n`, `go to notes`. You register a name with aliases, the user types a string, and the runtime resolves it (by prefix) to one of your actions.

The crate gives you the resolver. It does not give you a command palette — the text box, the cursor, the open/close state are ordinary app state you own and render. The `full` example builds a complete `:`-style palette this way in about 30 lines.

## Registering commands

On the builder, `.command(name, aliases, action)`:

    #![allow(unused)]
    fn main() {
    TuiPages::builder(View::Home)
        .command("Go to Home",  ["h", "home"],   Action::GotoHome)
        .command("Go to Notes", ["n", "notes"],  Action::GotoNotes)
        .command("Quit",        ["q", "quit"],   Action::Quit)
    }

The first argument is a display name (shown in hints); the rest are the aliases the user can type. Matching is by prefix, so `not` resolves to `notes`.

## Submitting input

When the user confirms their typed string, hand it to `submit_command`. It resolves and runs the action exactly like a key binding would — including applying any effects and setting `quit_requested`:

    #![allow(unused)]
    fn main() {
    let quit = tui.submit_command(&input, state)?.quit_requested;
    }

The returned `TuiPagesOutput::status` tells you what happened:

    #![allow(unused)]
    fn main() {
    pub enum TuiPagesStatus<A> {
        ActionHandled,                       // resolved and ran
        CommandIncomplete(Vec<CommandHint>), // a prefix of several commands
        CommandUnknown,                      // no match
        CommandEmpty,                        // empty input
        // ...
    }
    }

## A palette is just app state

The runtime owns no palette. You own a flag and a string, open it on a key, feed keystrokes to your string, and call `submit_command` on Enter. This is the whole palette loop from the `full` example:

    #![allow(unused)]
    fn main() {
    // State you own:
    //   palette_open: bool,
    //   palette_input: String,

    if state.palette_open {
        match key.code {
            KeyCode::Enter => {
                let input = state.palette_input.clone();
                let quit = tui.submit_command(&input, state)?.quit_requested;
                close_palette(tui, state);
                if quit { return Ok(()); }
            }
            KeyCode::Esc       => close_palette(tui, state),
            KeyCode::Backspace => { state.palette_input.pop(); }
            KeyCode::Char(c)   => state.palette_input.push(c),
            _ => {}
        }
        continue; // palette swallows the key; don't fall through to handle_key
    }
    }

Opening it is an action that sets the flag and (optionally) opens an overlay focus target so your renderer knows to draw the bar:

    #![allow(unused)]
    fn main() {
    Action::OpenPalette => {
        state.palette_open = true;
        state.palette_input.clear();
        ActionOutcome::effect(TuiEffect::Focus(FocusIntent::Open(
            FocusTarget::Overlay(Overlay::CommandBar),
        )))
    }
    }

Closing it clears your state and the overlay:

    #![allow(unused)]
    fn main() {
    fn close_palette(tui: &mut App, state: &mut State) {
        state.palette_open = false;
        state.palette_input.clear();
        tui.focus.clear_overlay();
    }
    }

## Live hints while typing

To show completions as the user types, query the resolver directly. `tui.commands` is the public `CommandResolver`:

    #![allow(unused)]
    fn main() {
    match tui.commands.process(&state.palette_input) {
        CommandResponse::Incomplete(hints) => show(hints), // Vec<CommandHint>
        CommandResponse::Execute(_)        => {}           // a full match exists
        CommandResponse::Unknown           => show_error(),
        CommandResponse::Empty             => {}
    }
    }

Each `CommandHint` is `{ alias: String, action_name: String }` — the alias to complete to, and its display name.

The resolution timeout (for multi-step command states) defaults to 1000ms and is configurable with `.command_timeout_ms(ms)` on the builder.