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 action::ActionParams;
pub use action::ActionSummary;Deprecated
pub use component::Component;
pub use features::DynamicFeatures;
pub use features::FeatureFlags;
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 effect::DispatchResult;
pub use effect::EffectReducer;
pub use effect::EffectStore;
pub use effect::EffectStoreWithMiddleware;
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
effect
Effect-based state management
event
Event types for the pub/sub system
features
Runtime feature flags for TUI applications
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