summaryrefslogtreecommitdiff
path: root/makima/src/daemon/tui/event.rs
blob: 12a6890412adb37b275c6953e1f6578ab17042d0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! 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",
    }
}