Skip to main content

tui_dispatch/
lib.rs

1//! tui-dispatch: Centralized state management for Rust TUI apps
2//!
3//! Like Redux/Elm, but for terminals. Components are pure functions of state,
4//! and all state mutations happen through dispatched actions.
5//!
6//! # Quick Start
7//!
8//! ```
9//! use tui_dispatch::prelude::*;
10//!
11//! // Define your actions
12//! #[derive(Action, Clone, Debug)]
13//! enum MyAction {
14//!     Increment,
15//!     Decrement,
16//!     Quit,
17//! }
18//!
19//! // Define your state
20//! #[derive(Default)]
21//! struct MyState {
22//!     count: i32,
23//! }
24//!
25//! // Write a reducer
26//! fn reducer(state: &mut MyState, action: MyAction) -> bool {
27//!     match action {
28//!         MyAction::Increment => { state.count += 1; true }
29//!         MyAction::Decrement => { state.count -= 1; true }
30//!         MyAction::Quit => false,
31//!     }
32//! }
33//!
34//! // Create a store
35//! let mut store = Store::new(MyState::default(), reducer);
36//! store.dispatch(MyAction::Increment);
37//! assert_eq!(store.state().count, 1);
38//! ```
39//!
40//! # With Effects
41//!
42//! For async operations, use `EffectStore` with `ReducerResult`:
43//!
44//! ```
45//! use tui_dispatch::prelude::*;
46//!
47//! #[derive(Action, Clone, Debug)]
48//! enum Action {
49//!     Fetch,
50//!     DidLoad(String),
51//! }
52//!
53//! enum Effect {
54//!     FetchData,
55//! }
56//!
57//! #[derive(Default)]
58//! struct State {
59//!     data: Option<String>,
60//!     loading: bool,
61//! }
62//!
63//! fn reducer(state: &mut State, action: Action) -> ReducerResult<Effect> {
64//!     match action {
65//!         Action::Fetch => {
66//!             state.loading = true;
67//!             ReducerResult::changed_with(Effect::FetchData)
68//!         }
69//!         Action::DidLoad(data) => {
70//!             state.data = Some(data);
71//!             state.loading = false;
72//!             ReducerResult::changed()
73//!         }
74//!     }
75//! }
76//!
77//! let mut store = EffectStore::new(State::default(), reducer);
78//! let result = store.dispatch(Action::Fetch);
79//! assert!(result.changed);
80//! assert_eq!(result.effects.len(), 1);
81//! ```
82//!
83//! See the [documentation](https://docs.rs/tui-dispatch) for full guides.
84
85// Re-export everything from core
86pub use tui_dispatch_core::reducer_compose;
87pub use tui_dispatch_core::*;
88
89// Debug utilities
90#[cfg(feature = "debug")]
91pub use tui_dispatch_debug::debug;
92#[cfg(not(feature = "debug"))]
93pub mod debug {
94    use std::fmt::Debug;
95
96    #[derive(Clone, Debug, Default)]
97    pub struct DebugEntry {
98        pub key: String,
99        pub value: String,
100    }
101
102    impl DebugEntry {
103        pub fn new(key: impl Into<String>, value: impl Into<String>) -> Self {
104            Self {
105                key: key.into(),
106                value: value.into(),
107            }
108        }
109    }
110
111    #[derive(Clone, Debug, Default)]
112    pub struct DebugSection {
113        pub title: String,
114        pub entries: Vec<DebugEntry>,
115    }
116
117    impl DebugSection {
118        pub fn new(title: impl Into<String>) -> Self {
119            Self {
120                title: title.into(),
121                entries: Vec::new(),
122            }
123        }
124
125        pub fn entry(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
126            self.entries.push(DebugEntry::new(key, value));
127            self
128        }
129    }
130
131    pub trait DebugState {
132        fn debug_sections(&self) -> Vec<DebugSection>;
133    }
134
135    pub fn debug_string<T: Debug>(value: &T) -> String {
136        format!("{value:?}")
137    }
138
139    pub fn debug_string_pretty<T: Debug>(value: &T) -> String {
140        format!("{value:#?}")
141    }
142}
143
144// Re-export derive macros
145pub use tui_dispatch_macros::{Action, BindingContext, ComponentId, DebugState, FeatureFlags};
146
147/// Prelude for convenient imports
148pub mod prelude {
149    // Traits
150    pub use tui_dispatch_core::{
151        Action, ActionCategory, ActionParams, BindingContext, Component, ComponentId,
152    };
153
154    // Event system
155    pub use tui_dispatch_core::{
156        process_raw_event, spawn_event_poller, DefaultBindingContext, Event, EventBus,
157        EventContext, EventHandler, EventKind, EventRoutingState, EventType, GlobalKeyPolicy,
158        HandlerResponse, NumericComponentId, RawEvent, RouteTarget, RoutedEvent, SimpleEventBus,
159    };
160
161    // Keybindings
162    pub use tui_dispatch_core::{format_key_for_display, parse_key_string, Keybindings};
163
164    // Store
165    pub use tui_dispatch_core::reducer_compose;
166    #[cfg(feature = "tracing")]
167    pub use tui_dispatch_core::LoggingMiddleware;
168    pub use tui_dispatch_core::{
169        ComposedMiddleware, DispatchError, DispatchLimits, Middleware, NoopMiddleware, Reducer,
170        Store, StoreWithMiddleware,
171    };
172
173    // Effects and state types
174    pub use tui_dispatch_core::{
175        DataResource, EffectReducer, EffectStore, EffectStoreWithMiddleware, ReducerResult,
176    };
177
178    // Runtime helpers
179    pub use tui_dispatch_core::{
180        DispatchErrorPolicy, DispatchRuntime, DispatchStore, EffectContext, EffectRuntime,
181        EffectStoreLike, EventOutcome, PollerConfig, RenderContext,
182    };
183
184    // Tasks (requires "tasks" feature)
185    #[cfg(feature = "tasks")]
186    pub use tui_dispatch_core::{TaskKey, TaskManager, TaskPauseHandle};
187
188    // Subscriptions (requires "subscriptions" feature)
189    #[cfg(feature = "subscriptions")]
190    pub use tui_dispatch_core::{SubKey, SubPauseHandle, Subscriptions};
191
192    // Debug
193    #[cfg(feature = "debug")]
194    pub use crate::debug::{
195        ActionLoggerConfig, ActionLoggerMiddleware, DebugFreeze, DebugOverlay, DebugTableBuilder,
196    };
197    pub use crate::debug::{DebugSection, DebugState};
198
199    // Derive macros
200    pub use tui_dispatch_macros::{Action, BindingContext, ComponentId, DebugState, FeatureFlags};
201
202    // Ratatui re-exports
203    pub use tui_dispatch_core::{Color, Frame, Line, Modifier, Rect, Span, Style, Text};
204}