Skip to main content

cove_cli/sidebar/
event.rs

1// ── Event loop for sidebar ──
2
3use std::time::Duration;
4
5use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyModifiers};
6
7// ── Types ──
8
9pub enum Action {
10    Up,
11    Down,
12    Select,
13    Quit,
14    Tick,
15}
16
17// ── Public API ──
18
19/// Poll for input events with a 100ms timeout. Returns accumulated actions.
20/// Batches rapid arrow presses into single moves (key draining).
21pub fn poll() -> Vec<Action> {
22    let mut actions = Vec::new();
23
24    if event::poll(Duration::from_millis(100)).unwrap_or(false) {
25        // Process first event
26        if let Ok(Event::Key(key)) = event::read()
27            && let Some(action) = key_to_action(key)
28        {
29            actions.push(action);
30        }
31
32        // Drain queued keys (batch rapid arrow presses)
33        while event::poll(Duration::from_millis(0)).unwrap_or(false) {
34            if let Ok(Event::Key(key)) = event::read()
35                && let Some(action) = key_to_action(key)
36            {
37                actions.push(action);
38            }
39        }
40    }
41
42    if actions.is_empty() {
43        actions.push(Action::Tick);
44    }
45
46    actions
47}
48
49// ── Helpers ──
50
51fn key_to_action(key: KeyEvent) -> Option<Action> {
52    // Only handle key press events (ignore release/repeat)
53    if key.kind != crossterm::event::KeyEventKind::Press {
54        return None;
55    }
56
57    match key.code {
58        KeyCode::Up | KeyCode::Char('k') => Some(Action::Up),
59        KeyCode::Down | KeyCode::Char('j') => Some(Action::Down),
60        KeyCode::Enter => Some(Action::Select),
61        KeyCode::Char('q') => Some(Action::Quit),
62        KeyCode::Char('c') if key.modifiers.contains(KeyModifiers::CONTROL) => Some(Action::Quit),
63        _ => None,
64    }
65}