Skip to main content

chronicle/show/
keymap.rs

1use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
2
3use super::tui::AppState;
4
5/// Map a key event to an app state mutation.
6pub fn handle_key(app: &mut AppState, key: KeyEvent) {
7    match key.code {
8        // Scroll source
9        KeyCode::Char('j') | KeyCode::Down => {
10            if app.scroll_offset + 1 < app.total_lines() {
11                app.scroll_offset += 1;
12                update_selected_region_from_scroll(app);
13            }
14        }
15        KeyCode::Char('k') | KeyCode::Up => {
16            app.scroll_offset = app.scroll_offset.saturating_sub(1);
17            update_selected_region_from_scroll(app);
18        }
19        KeyCode::Char('d') if key.modifiers.contains(KeyModifiers::CONTROL) => {
20            let half = 20; // approximate half screen
21            app.scroll_offset = (app.scroll_offset + half).min(app.total_lines().saturating_sub(1));
22            update_selected_region_from_scroll(app);
23        }
24        KeyCode::PageDown => {
25            let half = 20;
26            app.scroll_offset = (app.scroll_offset + half).min(app.total_lines().saturating_sub(1));
27            update_selected_region_from_scroll(app);
28        }
29        KeyCode::Char('u') if key.modifiers.contains(KeyModifiers::CONTROL) => {
30            app.scroll_offset = app.scroll_offset.saturating_sub(20);
31            update_selected_region_from_scroll(app);
32        }
33        KeyCode::PageUp => {
34            app.scroll_offset = app.scroll_offset.saturating_sub(20);
35            update_selected_region_from_scroll(app);
36        }
37        KeyCode::Char('g') | KeyCode::Home => {
38            app.scroll_offset = 0;
39            update_selected_region_from_scroll(app);
40        }
41        KeyCode::Char('G') | KeyCode::End => {
42            app.scroll_offset = app.total_lines().saturating_sub(1);
43            update_selected_region_from_scroll(app);
44        }
45
46        // Region navigation
47        KeyCode::Char('n') => app.next_region(),
48        KeyCode::Char('N') => app.prev_region(),
49
50        // Panel
51        KeyCode::Enter => app.panel_expanded = !app.panel_expanded,
52        KeyCode::Char('J') => app.panel_scroll += 1,
53        KeyCode::Char('K') => app.panel_scroll = app.panel_scroll.saturating_sub(1),
54
55        // Help
56        KeyCode::Char('?') => app.show_help = !app.show_help,
57
58        _ => {}
59    }
60}
61
62/// When scrolling, auto-select the region at the current scroll position.
63fn update_selected_region_from_scroll(app: &mut AppState) {
64    let current_line = (app.scroll_offset + 1) as u32;
65    let regions = app.data.annotation_map.regions_at_line(current_line);
66    if let Some(&idx) = regions.first() {
67        if app.selected_region != Some(idx) {
68            app.selected_region = Some(idx);
69            app.panel_scroll = 0;
70        }
71    }
72}