Files
pages-tui/PROGRESS.md

11 KiB

TUI Orchestrator - Progress Summary

Current Status

Completed Features

Phase 1: Core Foundation

  • Input handling (src/input/)

    • Key types (KeyCode, KeyModifiers, Key)
    • Bindings (key → action mappings)
    • SequenceHandler (multi-key sequences, feature-gated)
    • MatchResult (action/pending/no-match)
  • Focus management (src/focus/)

    • FocusId trait (generic focus identifiers)
    • FocusManager (focus tracking, navigation, overlays)
    • FocusQuery (read-only focus state for rendering)
    • Focusable trait (components declare focusable elements)
    • FocusError (error types)

Documentation

  • PLAN.md - Complete implementation plan for framework approach
  • REDESIGN.md - Deep dive into framework architecture
  • INTEGRATION_GUIDE.md - User guide for building TUI apps
  • README.md - Project overview and quick start

Tests

  • Input tests: 12 tests passing
  • Focus tests: 18 tests passing
  • Total: 30 tests covering all core functionality

Next Steps

Phase 2: Component System

The foundation for the entire framework. This is the highest priority.

Files to create:

  • src/component/mod.rs - Module routing
  • src/component/trait.rs - Component trait definition
  • src/component/action.rs - Standard component actions
  • src/component/error.rs - Component-specific errors

Component trait design:

pub trait Component {
    type Focus: FocusId + Clone;
    type Action: Action + Clone;
    type Event: Clone + core::fmt::Debug;
    
    // REQUIRED
    fn targets(&self) -> &[Self::Focus];
    fn handle(&mut self, focus: &Self::Focus, action: Self::Action) -> Result<Option<Self::Event>>;
    
    // OPTIONAL (all with defaults)
    fn on_enter(&mut self) -> Result<()>;
    fn on_exit(&mut self) -> Result<()>;
    fn on_focus(&mut self, focus: &Self::Focus) -> Result<()>;
    fn on_blur(&mut self, focus: &Self::Focus) -> Result<()>;
    fn handle_text(&mut self, focus: &Self::Focus, ch: char) -> Result<Option<Self::Event>>;
    fn can_navigate_forward(&self, focus: &Self::Focus) -> bool;
    fn can_navigate_backward(&self, focus: &Self::Focus) -> bool;
}

ComponentAction enum:

pub enum ComponentAction {
    Next,           // Tab → move focus forward
    Prev,            // Shift+Tab → move focus backward
    First,           // Home → move to first
    Last,            // End → move to last
    Select,          // Enter → activate current focus
    Cancel,          // Esc → cancel/close
    TypeChar(char),  // Character → type text
    Backspace,       // Backspace → delete before cursor
    Delete,          // Delete → delete at cursor
    Custom(usize),   // User-defined action
}

Priority: HIGHEST - This enables all other functionality


Phase 3: Router & Lifecycle

Page navigation with automatic lifecycle hook invocation.

Files to create:

  • src/router/mod.rs - Module routing
  • src/router/router.rs - Router implementation
  • src/router/history.rs - Navigation history

Router API:

pub struct Router<C: Component> {
    pages: alloc::collections::HashMap<String, C>,
    current: Option<String>,
    history: alloc::vec::Vec<String>,
    future: alloc::vec::Vec<String>,  // For forward navigation
}

impl<C: Component> Router<C> {
    pub fn new() -> Self;
    pub fn navigate(&mut self, id: &str) -> Result<()>;
    pub fn back(&mut self) -> Result<Option<()>>;
    pub fn forward(&mut self) -> Result<Option<()>>;
    pub fn current(&self) -> Option<&C>;
}

Automatic behavior:

  • navigate() calls old_page.on_exit() → swaps → calls new_page.on_enter()
  • back()/forward() manage history stack

Priority: HIGH - Essential for multi-page apps


Phase 4: Orchestrator Core

The complete runtime that wires everything together.

Files to create:

  • src/orchestrator/mod.rs - Module routing
  • src/orchestrator/core.rs - Main Orchestrator struct
  • src/orchestrator/bindings.rs - Default + custom bindings
  • src/orchestrator/modes.rs - Mode stack and resolution
  • src/orchestrator/overlays.rs - Overlay stack
  • src/orchestrator/events.rs - Event bus

Orchestrator API:

pub struct Orchestrator<C: Component> {
    registry: ComponentRegistry<C>,
    focus: FocusManager<C::Focus>,
    bindings: Bindings<ComponentAction>,
    router: Router<C>,
    modes: ModeStack<ModeName>,
    overlays: OverlayStack<C::Event>,
    events: EventBus<C::Event>,
}

impl<C: Component> Orchestrator<C> {
    pub fn new() -> Self;
    
    pub fn register_page(&mut self, id: &str, page: C) -> Result<()>;
    pub fn navigate_to(&mut self, id: &str) -> Result<()>;
    
    pub fn process_frame(&mut self, key: Key) -> Result<alloc::vec::Vec<C::Event>>;
    
    pub fn run<I: InputSource>(&mut self, input: I) -> Result<()>;
    
    // Extension points
    pub fn set_mode_resolver<R: ModeResolver + 'static>(&mut self, resolver: R);
    pub fn set_overlay_manager<O: OverlayManager + 'static>(&mut self, manager: O);
    pub fn set_event_handler<H: EventHandler<C::Event> + 'static>(&mut self, handler: H);
}

Process flow:

  1. Check overlay active → route to overlay
  2. Get current mode + focus
  3. Lookup binding → get action
  4. Get current component
  5. Call component.handle(action, focus)
  6. Collect events
  7. Handle internal events (focus changes, page nav)
  8. Return external events

Priority: HIGH - This makes the framework "ready to use"


Phase 5: Extension Traits

Extension points for komp_ac and other complex apps.

Files to create:

  • src/extension/mod.rs - Module routing
  • src/extension/mode.rs - ModeResolver trait
  • src/extension/overlay.rs - OverlayManager trait
  • src/extension/event.rs - EventHandler trait

ModeResolver trait:

pub trait ModeResolver {
    fn resolve(&self, focus: &dyn core::any::Any) -> alloc::vec::Vec<ModeName>;
}

pub struct DefaultModeResolver;
impl ModeResolver for DefaultModeResolver { ... }

OverlayManager trait:

pub trait OverlayManager {
    fn is_active(&self) -> bool;
    fn handle_input(&mut self, key: Key) -> Option<OverlayResult>;
}

pub enum OverlayResult {
    Dismissed,
    Selected(OverlayData),
    Continue,
}

EventHandler trait:

pub trait EventHandler<E> {
    fn handle(&mut self, event: E) -> Result<HandleResult>;
}

pub enum HandleResult {
    Consumed,
    Forward,
    Navigate(String),
}

Priority: MEDIUM - Defaults work for most apps, komp_ac needs these


Phase 6: Builder & Defaults

Easy setup pattern with sensible defaults.

Files to create:

  • src/builder/mod.rs - Module routing
  • src/builder/builder.rs - Builder pattern
  • src/builder/defaults.rs - Preset keybindings

Builder API:

pub struct Builder<C: Component> {
    orchestrator: Orchestrator<C>,
}

impl<C: Component> Builder<C> {
    pub fn new() -> Self;
    pub fn with_page(mut self, id: &str, page: C) -> Result<Self>;
    pub fn with_default_bindings(mut self) -> Self;
    pub fn with_mode_resolver<R: ModeResolver + 'static>(mut self, resolver: R) -> Self;
    pub fn with_overlay_manager<O: OverlayManager + 'static>(mut self, manager: O) -> Self;
    pub fn build(self) -> Result<Orchestrator<C>>;
}

Default bindings:

pub fn default_bindings() -> Bindings<ComponentAction> {
    let mut bindings = Bindings::new();
    bindings.bind(Key::tab(), ComponentAction::Next);
    bindings.bind(Key::shift_tab(), ComponentAction::Prev);
    bindings.bind(Key::enter(), ComponentAction::Select);
    bindings.bind(Key::esc(), ComponentAction::Cancel);
    bindings.bind(Key::ctrl('c'), ComponentAction::Custom(0)); // Common quit
}

Priority: MEDIUM - Improves developer experience


Phase 7: Integration with komp_ac

Adapters and integration helpers for seamless komp_ac migration.

Files to create:

  • src/integration/mod.rs - Module routing
  • src/integration/komp_ac.rs - komp_ac-specific adapters

Integration pattern:

impl Component for komp_ac::LoginPage {
    type Focus = komp_ac::FocusTarget;
    type Action = komp_ac::ResolvedAction;
    type Event = komp_ac::AppEvent;
    
    fn targets(&self) -> &[Self::Focus] { ... }
    fn handle(&mut self, focus: &Self::Focus, action: Self::Action) -> Result<Option<Self::Event>> { ... }
}

komp_ac setup:

let mut orch = Orchestrator::new()
    .with_mode_resolver(CanvasModeResolver::new(app_state))
    .with_overlay_manager(KompAcOverlayManager::new())
    .with_event_handler(KompAcEventHandler::new(router, focus));

Priority: LOW - Not needed for general library users, but essential for komp_ac


File Structure After All Phases

src/
├── lib.rs                    # Routing
├── prelude.rs                # Common imports
│
├── input/                    # Phase 1 ✅
│   ├── mod.rs
│   ├── key.rs
│   ├── bindings.rs
│   ├── handler.rs
│   ├── result.rs
│   └── action.rs
│
├── focus/                    # Phase 1 ✅
│   ├── mod.rs
│   ├── id.rs
│   ├── manager.rs
│   ├── query.rs
│   ├── error.rs
│   └── traits.rs
│
├── component/                 # Phase 2 (NEXT)
│   ├── mod.rs
│   ├── trait.rs
│   ├── action.rs
│   └── error.rs
│
├── router/                    # Phase 3
│   ├── mod.rs
│   ├── router.rs
│   └── history.rs
│
├── orchestrator/              # Phase 4
│   ├── mod.rs
│   ├── core.rs
│   ├── bindings.rs
│   ├── modes.rs
│   ├── overlays.rs
│   └── events.rs
│
├── extension/                 # Phase 5
│   ├── mod.rs
│   ├── mode.rs
│   ├── overlay.rs
│   └── event.rs
│
├── builder/                   # Phase 6
│   ├── mod.rs
│   ├── builder.rs
│   └── defaults.rs
│
└── integration/               # Phase 7
    ├── mod.rs
    └── komp_ac.rs

tests/
├── input/
├── focus/
├── component/
├── router/
├── orchestrator/
└── integration/

Testing Strategy

For each phase:

  1. Write tests first - Define expected behavior
  2. Implement to pass - Code should make tests pass
  3. Run cargo test - Verify all pass
  4. Run cargo clippy - Ensure code quality
  5. Run cargo fmt - Ensure formatting

Target: 100% test coverage for all public APIs


Dependencies Update

Cargo.toml (after Phase 4)

[package]
name = "tui_orchestrator"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"

[features]
default = ["std"]
std = []
alloc = ["hashbrown"]
sequences = ["alloc"]

[dependencies]
hashbrown = { version = "0.15", optional = true }

[dev-dependencies]

Next Action

Implement Phase 2: Component System

This is the foundation that enables:

  • Page/component registration
  • Button logic definition
  • Lifecycle hooks
  • Everything the framework needs

Tasks:

  1. Create src/component/mod.rs
  2. Create src/component/trait.rs with Component trait
  3. Create src/component/action.rs with ComponentAction enum
  4. Create src/component/error.rs with ComponentError enum
  5. Write tests in tests/component/
  6. Update src/lib.rs to export component module
  7. Update src/prelude.rs to include Component types
  8. Run cargo test --all-features
  9. Run cargo clippy --all-features
  10. Update documentation if needed

Ready to implement?