//! TUI module for interactive browsing. //! //! This module provides an interactive Terminal User Interface (TUI) for //! browsing and managing tasks, contracts, and files in the makima system. //! //! # Features //! //! - **Fuzzy Search**: Real-time filtering with the SkimMatcherV2 algorithm //! - **Keyboard Navigation**: Vim-style keybindings (j/k) and arrow keys //! - **Preview Pane**: Side-by-side view of item details //! - **Multiple Views**: Browse tasks, contracts, or files pub mod app; pub mod event; pub mod fuzzy; pub mod ui; pub mod ws_client; pub use app::{App, ListItem, ViewType, ViewState, InputMode, Action, OutputBuffer, OutputLine, OutputMessageType, WsConnectionState, CreateContractState, CreateFormField, RepositorySuggestion}; pub use ws_client::{TuiWsClient, WsCommand, WsEvent, TaskOutputEvent}; pub use fuzzy::FuzzyMatcher; use std::io; use crossterm::{ event::{DisableMouseCapture, EnableMouseCapture}, execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; use ratatui::backend::CrosstermBackend; pub type Terminal = ratatui::Terminal>; /// Run the TUI application pub fn run(mut app: App) -> Result, Box> { // Setup terminal enable_raw_mode()?; let mut stdout = io::stdout(); execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; let backend = CrosstermBackend::new(stdout); let mut terminal = ratatui::Terminal::new(backend)?; // Run the main loop let result = run_app(&mut terminal, &mut app); // Cleanup terminal disable_raw_mode()?; execute!( terminal.backend_mut(), LeaveAlternateScreen, DisableMouseCapture )?; terminal.show_cursor()?; result } fn run_app( terminal: &mut Terminal, app: &mut App, ) -> Result, Box> { use crossterm::event::Event; use std::time::Duration; loop { terminal.draw(|f| ui::render(f, app))?; // Poll for events with 100ms timeout if let Some(evt) = event::poll_event(Duration::from_millis(100))? { if let Event::Key(key) = evt { let action = event::handle_key_event(app, key); match action { Action::Quit => break, Action::OutputPath(path) => return Ok(Some(path)), Action::None => {} _ => { let result = app.handle_action(action); // Check if handle_action returned a special action if let Action::OutputPath(path) = result { return Ok(Some(path)); } } } } } if app.should_quit { break; } } Ok(None) } /// Print a path to stdout (for cd integration) pub fn print_path(path: &str) { println!("{}", path); }