//! 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<Option<Event>> {
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",
}
}