feat: complete TUI Phase 0 — Toolchain Gate
Implements the full lore-tui crate scaffold with 6 Phase 0 modules: - message.rs: Msg (~40 variants), Screen (12), EntityKey, AppError, InputMode - clock.rs: Clock trait with SystemClock + FakeClock for deterministic testing - safety.rs: Terminal sanitizer (ANSI filter), URL policy, PII/secret redaction - db.rs: DbManager with 3 reader pool (round-robin) + dedicated writer (WAL mode) - theme.rs: Flexoki adaptive theme (19 slots), state/event colors, label styling - app.rs: Minimal LoreApp Model trait impl proving FrankenTUI integration 68 tests, clippy clean, fmt clean. Closes bd-3ddw, bd-c9gk, bd-2lg6, bd-3ir1, bd-2kop, bd-5ofk, bd-2emv, bd-1cj0.
This commit is contained in:
101
crates/lore-tui/src/app.rs
Normal file
101
crates/lore-tui/src/app.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
#![allow(dead_code)] // Phase 0: minimal scaffold, fleshed out in bd-6pmy
|
||||
|
||||
//! Minimal FrankenTUI Model implementation for the lore TUI.
|
||||
//!
|
||||
//! This is the Phase 0 integration proof — validates that the ftui Model trait
|
||||
//! compiles with our Msg type and produces basic output. The full LoreApp with
|
||||
//! screen routing, navigation stack, and action dispatch comes in bd-6pmy.
|
||||
|
||||
use ftui::{Cmd, Frame, Model};
|
||||
|
||||
use crate::message::Msg;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// LoreApp
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Root model for the lore TUI.
|
||||
///
|
||||
/// Phase 0: minimal scaffold that renders a placeholder and handles Quit.
|
||||
/// Phase 1 (bd-6pmy) will add screen routing, DbManager, theme, and subscriptions.
|
||||
pub struct LoreApp;
|
||||
|
||||
impl Model for LoreApp {
|
||||
type Message = Msg;
|
||||
|
||||
fn init(&mut self) -> Cmd<Self::Message> {
|
||||
Cmd::none()
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> Cmd<Self::Message> {
|
||||
match msg {
|
||||
Msg::Quit => Cmd::quit(),
|
||||
_ => Cmd::none(),
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self, _frame: &mut Frame) {
|
||||
// Phase 0: no-op view. Phase 1 will render screens via the frame.
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify that `App::fullscreen(LoreApp).run()` compiles.
|
||||
///
|
||||
/// This is a compile-time check — we don't actually run it because that
|
||||
/// would require a real TTY. The function exists solely to prove the wiring.
|
||||
#[cfg(test)]
|
||||
fn _assert_app_fullscreen_compiles() {
|
||||
// This function is never called — it only needs to compile.
|
||||
fn _inner() {
|
||||
use ftui::App;
|
||||
let _app_builder = App::fullscreen(LoreApp);
|
||||
// _app_builder.run() would need a TTY, so we don't call it.
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify that `App::inline(LoreApp, 12).run()` compiles.
|
||||
#[cfg(test)]
|
||||
fn _assert_app_inline_compiles() {
|
||||
fn _inner() {
|
||||
use ftui::App;
|
||||
let _app_builder = App::inline(LoreApp, 12);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Tests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_lore_app_init_returns_none() {
|
||||
let mut app = LoreApp;
|
||||
let cmd = app.init();
|
||||
assert!(matches!(cmd, Cmd::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lore_app_quit_returns_quit_cmd() {
|
||||
let mut app = LoreApp;
|
||||
let cmd = app.update(Msg::Quit);
|
||||
assert!(matches!(cmd, Cmd::Quit));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lore_app_tick_returns_none() {
|
||||
let mut app = LoreApp;
|
||||
let cmd = app.update(Msg::Tick);
|
||||
assert!(matches!(cmd, Cmd::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lore_app_navigate_returns_none() {
|
||||
use crate::message::Screen;
|
||||
let mut app = LoreApp;
|
||||
let cmd = app.update(Msg::NavigateTo(Screen::Dashboard));
|
||||
assert!(matches!(cmd, Cmd::None));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user