sql_cli/ui/input/
input_handlers.rs

1// Input handlers extracted from EnhancedTuiApp
2// Start simple and build up gradually
3
4use crate::app_state_container::AppStateContainer;
5use crate::buffer::{AppMode, BufferAPI, BufferManager};
6use crate::ui::state::shadow_state::ShadowStateManager;
7use crate::widgets::help_widget::HelpAction;
8use crate::widgets::stats_widget::StatsAction;
9use anyhow::Result;
10use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
11use std::cell::RefCell;
12
13/// Minimal context for debug/pretty query input handlers
14/// We'll add more fields as we extract more handlers
15pub struct DebugInputContext<'a> {
16    pub buffer_manager: &'a mut BufferManager,
17    pub debug_widget: &'a mut crate::widgets::debug_widget::DebugWidget,
18    pub shadow_state: &'a RefCell<ShadowStateManager>,
19}
20
21/// Context for help input handler
22pub struct HelpInputContext<'a> {
23    pub buffer_manager: &'a mut BufferManager,
24    pub help_widget: &'a mut crate::widgets::help_widget::HelpWidget,
25    pub state_container: &'a AppStateContainer,
26    pub shadow_state: &'a RefCell<ShadowStateManager>,
27}
28
29/// Context for column stats input handler
30pub struct StatsInputContext<'a> {
31    pub buffer_manager: &'a mut BufferManager,
32    pub stats_widget: &'a mut crate::widgets::stats_widget::StatsWidget,
33    pub shadow_state: &'a RefCell<ShadowStateManager>,
34}
35
36/// Handle debug mode input
37pub fn handle_debug_input(ctx: &mut DebugInputContext, key: KeyEvent) -> Result<bool> {
38    // Handle special keys for test case generation
39    match key.code {
40        KeyCode::Char('c') if key.modifiers.contains(KeyModifiers::CONTROL) => {
41            // Ctrl+C to quit
42            return Ok(true);
43        }
44        KeyCode::Char('t') if key.modifiers.contains(KeyModifiers::CONTROL) => {
45            // Ctrl+T: "Yank as Test" - capture current session as test case
46            // Note: For now we can't do this as it needs yank_as_test_case
47            // We'll add this capability later
48            if let Some(buffer) = ctx.buffer_manager.current_mut() {
49                buffer.set_status_message(
50                    "Test case yank not yet implemented in extracted handler".to_string(),
51                );
52            }
53            return Ok(false);
54        }
55        KeyCode::Char('y') if key.modifiers.contains(KeyModifiers::SHIFT) => {
56            // Shift+Y: Yank debug dump with context
57            // Note: For now we can't do this as it needs yank_debug_with_context
58            // We'll add this capability later
59            if let Some(buffer) = ctx.buffer_manager.current_mut() {
60                buffer.set_status_message(
61                    "Debug yank not yet implemented in extracted handler".to_string(),
62                );
63            }
64            return Ok(false);
65        }
66        _ => {}
67    }
68
69    // Let the widget handle navigation and exit
70    if ctx.debug_widget.handle_key(key) {
71        // Widget returned true - exit debug mode
72        if let Some(buffer) = ctx.buffer_manager.current_mut() {
73            ctx.shadow_state
74                .borrow_mut()
75                .set_mode(AppMode::Command, buffer, "debug_exit");
76        }
77    }
78
79    Ok(false)
80}
81
82/// Handle pretty query mode input
83pub fn handle_pretty_query_input(ctx: &mut DebugInputContext, key: KeyEvent) -> Result<bool> {
84    if key.code == KeyCode::Char('c') && key.modifiers.contains(KeyModifiers::CONTROL) {
85        return Ok(true);
86    }
87
88    // Let debug widget handle the key (includes scrolling and exit)
89    if ctx.debug_widget.handle_key(key) {
90        // Widget returned true - exit pretty query mode
91        if let Some(buffer) = ctx.buffer_manager.current_mut() {
92            ctx.shadow_state
93                .borrow_mut()
94                .set_mode(AppMode::Command, buffer, "pretty_query_exit");
95        }
96    }
97
98    Ok(false)
99}
100
101/// Handle cache list mode input
102pub fn handle_cache_list_input(ctx: &mut DebugInputContext, key: KeyEvent) -> Result<bool> {
103    match key.code {
104        KeyCode::Char('c') if key.modifiers.contains(KeyModifiers::CONTROL) => return Ok(true),
105        KeyCode::Esc | KeyCode::Enter | KeyCode::Char('q') => {
106            if let Some(buffer) = ctx.buffer_manager.current_mut() {
107                ctx.shadow_state
108                    .borrow_mut()
109                    .set_mode(AppMode::Command, buffer, "cache_list_exit");
110            }
111        }
112        _ => {}
113    }
114    Ok(false)
115}
116
117/// Handle help mode input  
118pub fn handle_help_input(ctx: &mut HelpInputContext, key: KeyEvent) -> Result<bool> {
119    // Use the new HelpWidget
120    match ctx.help_widget.handle_key(key) {
121        HelpAction::Exit => {
122            exit_help(ctx);
123        }
124        HelpAction::ShowDebug => {
125            // F5 was pressed in help - this is handled by the widget itself
126        }
127        _ => {
128            // Other actions are handled internally by the widget
129        }
130    }
131    Ok(false)
132}
133
134/// Helper function for help mode exit
135fn exit_help(ctx: &mut HelpInputContext) {
136    ctx.help_widget.on_exit();
137    ctx.state_container.set_help_visible(false);
138    // Scroll is automatically reset when help is hidden in state_container
139    let mode = if let Some(buffer) = ctx.buffer_manager.current() {
140        if buffer.has_dataview() {
141            AppMode::Results
142        } else {
143            AppMode::Command
144        }
145    } else {
146        AppMode::Command
147    };
148    if let Some(buffer) = ctx.buffer_manager.current_mut() {
149        ctx.shadow_state
150            .borrow_mut()
151            .set_mode(mode, buffer, "help_exit");
152    }
153}
154
155/// Handle column stats mode input
156pub fn handle_column_stats_input(ctx: &mut StatsInputContext, key: KeyEvent) -> Result<bool> {
157    match ctx.stats_widget.handle_key(key) {
158        StatsAction::Quit => return Ok(true),
159        StatsAction::Close => {
160            if let Some(buffer) = ctx.buffer_manager.current_mut() {
161                buffer.set_column_stats(None);
162                ctx.shadow_state
163                    .borrow_mut()
164                    .set_mode(AppMode::Results, buffer, "stats_close");
165            }
166        }
167        StatsAction::Continue | StatsAction::PassThrough => {}
168    }
169    Ok(false)
170}