sql_cli/
action_handler.rs1use crate::buffer::{AppMode, EditMode};
2use anyhow::Result;
3use tracing::debug;
4
5pub struct ActionHandler;
7
8impl ActionHandler {
9 pub fn handle_navigation(action: &str, app: &mut impl AppContext) -> Result<bool> {
11 match action {
12 "next_row" => {
13 app.next_row();
14 Ok(false)
15 }
16 "previous_row" => {
17 app.previous_row();
18 Ok(false)
19 }
20 "next_column" | "move_column_right" => {
21 app.move_column_right();
22 Ok(false)
23 }
24 "previous_column" | "move_column_left" => {
25 app.move_column_left();
26 Ok(false)
27 }
28 "page_down" => {
29 app.page_down();
30 Ok(false)
31 }
32 "page_up" => {
33 app.page_up();
34 Ok(false)
35 }
36 "goto_first_row" => {
37 app.goto_first_row();
38 Ok(false)
39 }
40 "goto_last_row" => {
41 app.goto_last_row();
42 Ok(false)
43 }
44 "goto_first_column" => {
45 app.goto_first_column();
46 Ok(false)
47 }
48 "goto_last_column" => {
49 app.goto_last_column();
50 Ok(false)
51 }
52 _ => Ok(false),
53 }
54 }
55
56 pub fn handle_mode_change(action: &str, app: &mut impl AppContext) -> Result<bool> {
58 match action {
59 "enter_edit_mode" => {
60 app.set_mode(AppMode::Command);
61 app.set_edit_mode(EditMode::SingleLine);
62 Ok(false)
63 }
64 "enter_results_mode" => {
65 app.set_mode(AppMode::Results);
66 Ok(false)
67 }
68 "exit_results_mode" => {
69 app.set_mode(AppMode::Command);
70 Ok(false)
71 }
72 "toggle_help" => {
73 if app.get_mode() == AppMode::Help {
74 app.set_mode(AppMode::Command);
75 } else {
76 app.set_mode(AppMode::Help);
77 }
78 Ok(false)
79 }
80 "toggle_debug" => {
81 if app.get_mode() == AppMode::Debug {
82 app.set_mode(AppMode::Command);
83 } else {
84 app.set_mode(AppMode::Debug);
85 app.generate_debug_context();
86 }
87 Ok(false)
88 }
89 "show_pretty_query" => {
90 app.set_mode(AppMode::PrettyQuery);
91 app.generate_pretty_query();
92 Ok(false)
93 }
94 "show_history" => {
95 app.set_mode(AppMode::History);
96 Ok(false)
97 }
98 "show_cache" => {
99 app.set_mode(AppMode::Command);
100 Ok(false)
101 }
102 _ => Ok(false),
103 }
104 }
105
106 pub fn handle_yank(action: &str, app: &mut impl AppContext) -> Result<bool> {
108 match action {
109 "yank_cell" => {
110 app.yank_cell();
111 Ok(false)
112 }
113 "yank_row" => {
114 app.yank_row();
115 Ok(false)
116 }
117 "yank_column" => {
118 app.yank_column();
119 Ok(false)
120 }
121 "yank_all" => {
122 app.yank_all();
123 Ok(false)
124 }
125 "paste" => {
126 app.paste_from_clipboard();
127 Ok(false)
128 }
129 _ => Ok(false),
130 }
131 }
132
133 pub fn handle_export(action: &str, app: &mut impl AppContext) -> Result<bool> {
135 match action {
136 "export_csv" => {
137 app.export_to_csv();
138 Ok(false)
139 }
140 "export_json" => {
141 app.export_to_json();
142 Ok(false)
143 }
144 _ => Ok(false),
145 }
146 }
147
148 pub fn handle_buffer(action: &str, app: &mut impl AppContext) -> Result<bool> {
150 match action {
151 "next_buffer" => {
152 app.next_buffer();
153 Ok(false)
154 }
155 "previous_buffer" => {
156 app.previous_buffer();
157 Ok(false)
158 }
159 "close_buffer" => app.close_buffer(),
160 "new_buffer" => {
161 app.new_buffer();
162 Ok(false)
163 }
164 "list_buffers" => {
165 app.list_buffers();
166 Ok(false)
167 }
168 _ => Ok(false),
169 }
170 }
171
172 pub fn handle_query(action: &str, app: &mut impl AppContext) -> Result<bool> {
174 match action {
175 "execute_query" => {
176 let query = app.get_input_text();
177 if !query.trim().is_empty() {
178 app.execute_query(&query)?;
179 }
180 Ok(false)
181 }
182 "handle_completion" => {
183 app.handle_completion();
184 Ok(false)
185 }
186 _ => Ok(false),
187 }
188 }
189
190 pub fn handle_filter(action: &str, app: &mut impl AppContext) -> Result<bool> {
192 match action {
193 "start_filter" => {
194 app.set_mode(AppMode::Filter);
195 Ok(false)
196 }
197 "start_fuzzy_filter" => {
198 app.set_mode(AppMode::FuzzyFilter);
199 Ok(false)
200 }
201 "start_search" => {
202 app.set_mode(AppMode::Search);
203 Ok(false)
204 }
205 "clear_filter" => {
206 app.clear_filter();
207 Ok(false)
208 }
209 "next_match" => {
210 app.next_search_match();
211 Ok(false)
212 }
213 "previous_match" => {
214 app.previous_search_match();
215 Ok(false)
216 }
217 _ => Ok(false),
218 }
219 }
220
221 pub fn handle_sort(action: &str, app: &mut impl AppContext) -> Result<bool> {
223 match action {
224 "sort_column" | "sort_column_asc" => {
225 let column = app.get_current_column();
226 app.sort_by_column(column);
227 Ok(false)
228 }
229 "sort_column_desc" => {
230 let column = app.get_current_column();
231 app.sort_by_column_desc(column);
232 Ok(false)
233 }
234 _ => Ok(false),
235 }
236 }
237
238 pub fn handle_column(action: &str, app: &mut impl AppContext) -> Result<bool> {
240 match action {
241 "pin_column" | "toggle_column_pin" => {
242 app.toggle_column_pin();
243 Ok(false)
244 }
245 "clear_pins" | "clear_all_pinned_columns" => {
246 app.clear_all_pinned_columns();
247 Ok(false)
248 }
249 "calculate_statistics" => {
250 app.calculate_column_statistics();
251 Ok(false)
252 }
253 _ => Ok(false),
254 }
255 }
256
257 pub fn execute(action: &str, app: &mut impl AppContext) -> Result<bool> {
259 debug!("Executing action: {}", action);
260
261 if action == "quit" {
263 return Ok(true);
264 }
265
266 if Self::handle_navigation(action, app)? {
268 return Ok(true);
269 }
270 if Self::handle_mode_change(action, app)? {
271 return Ok(true);
272 }
273 if Self::handle_yank(action, app)? {
274 return Ok(true);
275 }
276 if Self::handle_export(action, app)? {
277 return Ok(true);
278 }
279 if Self::handle_buffer(action, app)? {
280 return Ok(true);
281 }
282 if Self::handle_query(action, app)? {
283 return Ok(true);
284 }
285 if Self::handle_filter(action, app)? {
286 return Ok(true);
287 }
288 if Self::handle_sort(action, app)? {
289 return Ok(true);
290 }
291 if Self::handle_column(action, app)? {
292 return Ok(true);
293 }
294
295 debug!("Unknown action: {}", action);
297 Ok(false)
298 }
299}
300
301pub trait AppContext {
303 fn next_row(&mut self);
305 fn previous_row(&mut self);
306 fn move_column_left(&mut self);
307 fn move_column_right(&mut self);
308 fn page_down(&mut self);
309 fn page_up(&mut self);
310 fn goto_first_row(&mut self);
311 fn goto_last_row(&mut self);
312 fn goto_first_column(&mut self);
313 fn goto_last_column(&mut self);
314 fn get_current_column(&self) -> usize;
315
316 fn get_mode(&self) -> AppMode;
318 fn set_mode(&mut self, mode: AppMode);
319 fn set_edit_mode(&mut self, mode: EditMode);
320
321 fn get_input_text(&self) -> String;
323 fn execute_query(&mut self, query: &str) -> Result<()>;
324 fn handle_completion(&mut self);
325
326 fn yank_cell(&mut self);
328 fn yank_row(&mut self);
329 fn yank_column(&mut self);
330 fn yank_all(&mut self);
331 fn paste_from_clipboard(&mut self);
332
333 fn export_to_csv(&mut self);
335 fn export_to_json(&mut self);
336
337 fn next_buffer(&mut self);
339 fn previous_buffer(&mut self);
340 fn close_buffer(&mut self) -> Result<bool>;
341 fn new_buffer(&mut self);
342 fn list_buffers(&mut self);
343
344 fn clear_filter(&mut self);
346 fn next_search_match(&mut self);
347 fn previous_search_match(&mut self);
348
349 fn sort_by_column(&mut self, column: usize);
351 fn sort_by_column_desc(&mut self, column: usize);
352
353 fn toggle_column_pin(&mut self);
355 fn clear_all_pinned_columns(&mut self);
356 fn calculate_column_statistics(&mut self);
357
358 fn generate_debug_context(&mut self);
360 fn generate_pretty_query(&mut self);
361}