summaryrefslogblamecommitdiff
path: root/makima/src/daemon/tui/mod.rs
blob: e52b12aa3d7c69b30fed6476a73f25415fe45286 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16















                                                                            
                  
 
                                                                                                                                                                                                 
                                                                      







                                                                                              
                        




































































                                                                                
//! 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::prelude::*;
use ratatui::backend::CrosstermBackend;

pub type Terminal = ratatui::Terminal<CrosstermBackend<io::Stdout>>;

/// Run the TUI application
pub fn run(mut app: App) -> Result<Option<String>, Box<dyn std::error::Error>> {
    // 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<Option<String>, Box<dyn std::error::Error>> {
    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);
}