Crate tui_dispatch_core

Crate tui_dispatch_core 

Source
Expand description

Core traits and types for tui-dispatch

This crate provides the foundational abstractions for building TUI applications with centralized state management, following a Redux/Elm-inspired architecture.

§Core Concepts

  • Action: Events that describe state changes
  • Store: Centralized state container with reducer pattern
  • Component: Pure UI elements that render based on props
  • EventBus: Pub/sub system for event routing
  • Keybindings: Context-aware key mapping

§Basic Example

use tui_dispatch_core::prelude::*;

#[derive(Action, Clone, Debug)]
enum MyAction {
    Increment,
    Decrement,
}

#[derive(Default)]
struct AppState {
    counter: i32,
}

fn reducer(state: &mut AppState, action: MyAction) -> bool {
    match action {
        MyAction::Increment => { state.counter += 1; true }
        MyAction::Decrement => { state.counter -= 1; true }
    }
}

let mut store = Store::new(AppState::default(), reducer);
store.dispatch(MyAction::Increment);

§Async Handler Pattern

For applications with async operations (API calls, file I/O, etc.), use a two-phase action pattern:

  1. Intent actions trigger async work (e.g., FetchData)
  2. Result actions carry the outcome back (e.g., DidFetchData, DidFetchError)
use tokio::sync::mpsc;

#[derive(Action, Clone, Debug)]
#[action(infer_categories)]
enum Action {
    // Intent: triggers async fetch
    DataFetch { id: String },
    // Result: async operation completed
    DataDidLoad { id: String, payload: Vec<u8> },
    DataDidError { id: String, error: String },
}

// Async handler spawns a task and sends result back via channel
fn handle_async(action: &Action, tx: mpsc::UnboundedSender<Action>) {
    match action {
        Action::DataFetch { id } => {
            let id = id.clone();
            let tx = tx.clone();
            tokio::spawn(async move {
                match fetch_from_api(&id).await {
                    Ok(payload) => tx.send(Action::DataDidLoad { id, payload }),
                    Err(e) => tx.send(Action::DataDidError { id, error: e.to_string() }),
                }
            });
        }
        _ => {}
    }
}

// Main loop receives actions from both events and async completions
loop {
    tokio::select! {
        Some(action) = action_rx.recv() => {
            handle_async(&action, action_tx.clone());
            store.dispatch(action);
        }
        // ... event handling
    }
}

The Did* naming convention clearly identifies result actions. With #[action(infer_categories)], these are automatically grouped (e.g., DataFetch and DataDidLoad both get category "data").

Re-exports§

pub use action::Action;
pub use action::ActionCategory;
pub use component::Component;
pub use bus::process_raw_event;
pub use bus::spawn_event_poller;
pub use bus::EventBus;
pub use bus::RawEvent;
pub use event::ComponentId;
pub use event::Event;
pub use event::EventContext;
pub use event::EventKind;
pub use event::EventType;
pub use event::NumericComponentId;
pub use keybindings::format_key_for_display;
pub use keybindings::parse_key_string;
pub use keybindings::BindingContext;
pub use keybindings::Keybindings;
pub use store::ComposedMiddleware;
pub use store::LoggingMiddleware;
pub use store::Middleware;
pub use store::NoopMiddleware;
pub use store::Reducer;
pub use store::Store;
pub use store::StoreWithMiddleware;
pub use testing::alt_key;
pub use testing::buffer_rect_to_string_plain;
pub use testing::buffer_to_string;
pub use testing::buffer_to_string_plain;
pub use testing::char_key;
pub use testing::ctrl_key;
pub use testing::into_event;
pub use testing::key;
pub use testing::key_event;
pub use testing::key_events;
pub use testing::keys;
pub use testing::ActionAssertions;
pub use testing::ActionAssertionsEq;
pub use testing::RenderHarness;
pub use testing::TestHarness;

Modules§

action
Action trait for type-safe state mutations
bus
Event bus for dispatching events to subscribed components
component
Component trait for pure UI elements
debug
Debug and inspection utilities for TUI applications
event
Event types for the pub/sub system
keybindings
Keybindings system with context-aware key parsing and lookup
prelude
Prelude module for convenient imports
store
Centralized state store with reducer pattern
testing
Test utilities for tui-dispatch applications

Macros§

assert_category_emitted
Assert that an action of a specific category was emitted.
assert_category_not_emitted
Assert that NO action of a specific category was emitted.
assert_emitted
Assert that a specific action was emitted.
assert_not_emitted
Assert that a specific action was NOT emitted.
assert_state
Assert that a field of the harness state has an expected value.
assert_state_matches
Assert that a field of the harness state matches a pattern.
count_category
Count how many actions belong to a specific category.
count_emitted
Count how many actions match a pattern.
find_emitted
Find and return the first action matching a pattern.

Structs§

Frame
A consistent view into the terminal state for rendering a single frame.
Line
A line of text, consisting of one or more Spans.
Modifier
Modifier changes the way a piece of text is displayed.
Rect
A Rectangular area.
Span
Represents a part of a line that is contiguous and where all characters share the same style.
Style
Style lets you control the main characteristics of the displayed elements.
Text
A string split over one or more lines.

Enums§

Color
ANSI Color