tui-pages 0.7.2

Core for TUI apps with multiple pages
Documentation
# 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)`:

```rust
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`:

```rust
let quit = tui.submit_command(&input, state)?.quit_requested;
```

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

```rust
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:

```rust
// 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:

```rust
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:

```rust
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`:

```rust
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.