//! TUI event handling. use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyModifiers}; use std::time::Duration; use super::app::{Action, App, InputMode}; /// Poll for events with timeout pub fn poll_event(timeout: Duration) -> std::io::Result> { if event::poll(timeout)? { Ok(Some(event::read()?)) } else { Ok(None) } } /// Handle a key event and return the resulting action pub fn handle_key_event(app: &App, key: KeyEvent) -> Action { match app.input_mode { InputMode::Normal => handle_normal_mode(key), InputMode::Search => handle_search_mode(key), InputMode::Confirm => handle_confirm_mode(key), } } /// Handle key events in normal navigation mode fn handle_normal_mode(key: KeyEvent) -> Action { // Check for Ctrl+C first if key.modifiers.contains(KeyModifiers::CONTROL) { match key.code { KeyCode::Char('c') => return Action::Quit, _ => {} } } match key.code { // Navigation KeyCode::Up | KeyCode::Char('k') => Action::Up, KeyCode::Down | KeyCode::Char('j') => Action::Down, // Actions KeyCode::Enter => Action::Select, KeyCode::Char('e') => Action::Edit, KeyCode::Char('d') => Action::Delete, KeyCode::Char('c') => Action::Navigate, // cd to worktree // Search KeyCode::Char('/') => Action::EnterSearch, // Preview toggle (space to toggle preview visibility) KeyCode::Char(' ') => Action::Select, // Refresh KeyCode::Char('r') => Action::Refresh, // Quit KeyCode::Char('q') | KeyCode::Esc => Action::Quit, _ => Action::None, } } /// Handle key events in search mode fn handle_search_mode(key: KeyEvent) -> Action { // Check for Ctrl+C first if key.modifiers.contains(KeyModifiers::CONTROL) { match key.code { KeyCode::Char('c') => return Action::Quit, KeyCode::Char('u') => return Action::ClearSearch, _ => {} } } match key.code { // Exit search mode KeyCode::Esc => Action::ExitSearch, KeyCode::Enter => Action::ExitSearch, // Text input KeyCode::Char(c) => Action::SearchChar(c), KeyCode::Backspace => Action::SearchBackspace, // Navigation while searching KeyCode::Up => Action::Up, KeyCode::Down => Action::Down, _ => Action::None, } } /// Handle key events in confirmation mode fn handle_confirm_mode(key: KeyEvent) -> Action { // Check for Ctrl+C first if key.modifiers.contains(KeyModifiers::CONTROL) { if let KeyCode::Char('c') = key.code { return Action::Quit; } } match key.code { // Confirm KeyCode::Char('y') | KeyCode::Char('Y') => Action::ConfirmYes, // Cancel KeyCode::Char('n') | KeyCode::Char('N') | KeyCode::Esc => Action::ConfirmNo, _ => Action::None, } } /// Get help text for current mode pub fn get_help_text(mode: InputMode) -> &'static str { match mode { InputMode::Normal => "j/k: navigate | Enter: details | e: edit | d: delete | c: cd | /: search | q: quit", InputMode::Search => "Type to search | Enter/Esc: exit search | Up/Down: navigate", InputMode::Confirm => "y: confirm | n/Esc: cancel", } }