Recreate repository due to Git object corruption (all files preserved)
This commit is contained in:
431
PROGRESS.md
Normal file
431
PROGRESS.md
Normal file
@@ -0,0 +1,431 @@
|
||||
# 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:**
|
||||
```rust
|
||||
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:**
|
||||
```rust
|
||||
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:**
|
||||
```rust
|
||||
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:**
|
||||
```rust
|
||||
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:**
|
||||
```rust
|
||||
pub trait ModeResolver {
|
||||
fn resolve(&self, focus: &dyn core::any::Any) -> alloc::vec::Vec<ModeName>;
|
||||
}
|
||||
|
||||
pub struct DefaultModeResolver;
|
||||
impl ModeResolver for DefaultModeResolver { ... }
|
||||
```
|
||||
|
||||
**OverlayManager trait:**
|
||||
```rust
|
||||
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:**
|
||||
```rust
|
||||
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:**
|
||||
```rust
|
||||
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:**
|
||||
```rust
|
||||
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:**
|
||||
```rust
|
||||
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:**
|
||||
```rust
|
||||
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)
|
||||
|
||||
```toml
|
||||
[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?
|
||||
Reference in New Issue
Block a user