# TUI Orchestrator A complete, **ready-to-use TUI framework** that handles input routing, focus management, page navigation, and lifecycle hooks—so you can define your pages, buttons, and logic, and it just works. ## Features - **Zero boilerplate** - Define components, library handles everything else - **Ready to use** - Register pages and run, no manual wiring needed - **Sensible defaults** - Works without configuration - **Fully extendable** - Customize via traits when needed - **no_std compatible** - Works on embedded systems and WebAssembly - **Backend-agnostic** - No crossterm/ratatui dependencies - **Zero unsafe** - Pure Rust, no unsafe code ## Quick Start ### Define Your Component ```rust extern crate alloc; use tui_orchestrator::prelude::*; #[derive(Debug, Clone, PartialEq, Eq, Hash)] enum LoginFocus { Username, Password, LoginButton, CancelButton, } #[derive(Debug, Clone)] enum LoginEvent { AttemptLogin { username: String, password: String }, Cancel, } struct LoginPage { username: alloc::string::String, password: alloc::string::String, } impl Component for LoginPage { type Focus = LoginFocus; type Action = ComponentAction; type Event = LoginEvent; fn targets(&self) -> &[Self::Focus] { &[ LoginFocus::Username, LoginFocus::Password, LoginFocus::LoginButton, LoginFocus::CancelButton, ] } fn handle(&mut self, focus: &Self::Focus, action: Self::Action) -> Result> { match (focus, action) { (LoginFocus::LoginButton, ComponentAction::Select) => { Ok(Some(LoginEvent::AttemptLogin { username: self.username.clone(), password: self.password.clone(), })) } (LoginFocus::CancelButton, ComponentAction::Select) => { Ok(Some(LoginEvent::Cancel)) } _ => Ok(None), } } fn handle_text(&mut self, focus: &Self::Focus, ch: char) -> Result> { match focus { LoginFocus::Username => { self.username.push(ch); Ok(None) } LoginFocus::Password => { self.password.push(ch); Ok(None) } _ => Ok(None), } } } ``` ### Register and Run ```rust use tui_orchestrator::prelude::*; fn main() -> Result<()> { let mut orch = Orchestrator::builder() .with_page("login", LoginPage::new()) .with_default_bindings() .build()?; orch.navigate_to("login")?; orch.run(&mut MyInputSource)?; } ``` **That's it.** The library handles: - Input processing (read keys, route to actions) - Focus management (next/prev navigation) - Page navigation (on_exit, swap, on_enter) - Default keybindings (Tab=Next, Enter=Select) - Event collection and routing --- ## Core Concepts ### Component The main abstraction in tui_orchestrator. A component represents a page or UI section with focusable elements. ```rust pub trait Component { type Focus: FocusId; // What can receive focus type Action: Action; // What actions this handles type Event: Clone + Debug; // Events this component emits fn targets(&self) -> &[Self::Focus]; fn handle(&mut self, focus: &Self::Focus, action: Self::Action) -> Result>; } ``` **Optional methods** (all have defaults): - `on_enter()` - Called when component becomes active - `on_exit()` - Called when component becomes inactive - `on_focus()` - Called when a focus target gains focus - `on_blur()` - Called when a focus target loses focus - `handle_text()` - Called when character is typed - `can_navigate_forward/backward()` - Control focus movement ### Component Actions Standard actions the library provides: ```rust pub enum ComponentAction { Next, // Tab Prev, // Shift+Tab First, // Home Last, // End Select, // Enter Cancel, // Esc TypeChar(char), // Any character Backspace, // Backspace Delete, // Delete Custom(usize), // User-defined } ``` ### Focus Management Focus tracks which element is currently active. The library provides: - `FocusManager` - Generic focus tracking - `FocusQuery` - Read-only focus state for rendering - Automatic navigation (next, prev, first, last) ### Orchestrator The complete TUI runtime that wires everything together: - `Orchestrator` - Main framework struct - `process_frame()` - Process one input frame - `run()` - Complete main loop - Extension points for custom behavior --- ## Extension Points For complex applications (like komp_ac), the library provides extension points to customize behavior: ### ModeResolver Customize how modes are resolved (dynamic vs static). ```rust impl ModeResolver for CustomResolver { fn resolve(&self, focus: &dyn Any) -> Vec { ... } } ``` ### OverlayManager Customize overlay types (dialogs, command palettes, search). ```rust impl OverlayManager for CustomOverlayManager { fn is_active(&self) -> bool { ... } fn handle_input(&mut self, key: Key) -> Option { ... } } ``` ### EventHandler Customize how events are routed to handlers. ```rust impl EventHandler for CustomHandler { fn handle(&mut self, event: AppEvent) -> Result { ... } } ``` --- ## Example: Multi-Page App ```rust #[derive(Debug, Clone)] enum MyPage { Login(LoginPage), Home(HomePage), Settings(SettingsPage), } fn main() -> Result<()> { let mut orch = Orchestrator::builder() .with_page("login", LoginPage::new()) .with_page("home", HomePage::new()) .with_page("settings", SettingsPage::new()) .with_default_bindings() .build()?; orch.navigate_to("login")?; orch.run()?; } ``` Navigation with history: ```rust orch.navigate_to("home")?; orch.navigate_to("settings")?; orch.back()? // Return to home ``` --- ## Feature Flags ```toml [dependencies] tui_orchestrator = { version = "0.1", features = ["std"] } # Optional features sequences = ["alloc"] # Enable multi-key sequences ``` - `default` - No features (pure no_std) - `std` - Enable std library support - `alloc` - Enable alloc support (needed for collections) --- ## Design Philosophy 1. **Plugin-play model** - Library is runtime, components are plugins 2. **Sensible defaults** - Zero configuration works 3. **Optional everything** - Define only what you need 4. **Extension points** - Override defaults when needed 5. **User-focused** - "register page" not "bind chord to registry" 6. **no_std first** - Works on embedded, opt-in std --- ## For komp_ac Integration komp_ac can: 1. Implement `Component` trait for all pages 2. Use library's `Orchestrator` as runtime 3. Extend with custom `ModeResolver` for dynamic Canvas-style modes 4. Extend with custom `OverlayManager` for command palette, find file, search 5. Extend with custom `EventHandler` for page/global/canvas routing **Result:** komp_ac uses library's core while keeping all custom behavior. See [INTEGRATION_GUIDE.md](INTEGRATION_GUIDE.md) for details. --- ## Migration Guide If you're migrating from a TUI built with manual wiring: 1. **Identify components** - What are your pages/sections? 2. **Implement Component trait** - `targets()`, `handle()`, optional hooks 3. **Remove manual orchestration** - Delete manual focus/binding/router setup 4. **Use Orchestrator** - Register pages and run 5. **Add extensions if needed** - ModeResolver, OverlayManager, EventHandler The library handles everything else. --- ## Examples See `examples/` directory for complete working applications: - `simple_app.rs` - Basic multi-page TUI - `form_app.rs` - Form with text input - `extended_app.rs` - Using extension points --- ## Documentation - [PLAN.md](PLAN.md) - Complete implementation plan - [REDESIGN.md](REDESIGN.md) - Framework architecture deep dive - [INTEGRATION_GUIDE.md](INTEGRATION_GUIDE.md) - Integration examples and patterns --- ## License MIT OR Apache-2.0