1use crate::app_state_container::SelectionMode;
5use crate::buffer::AppMode;
6use anyhow::Result;
7
8#[derive(Debug, Clone, PartialEq)]
10pub enum CursorPosition {
11 Current,
13 End,
15 AfterClause(SqlClause),
17}
18
19#[derive(Debug, Clone, PartialEq)]
21pub enum SqlClause {
22 Select,
23 From,
24 Where,
25 OrderBy,
26 GroupBy,
27 Having,
28 Limit,
29}
30
31#[derive(Debug, Clone, PartialEq)]
33pub enum Action {
34 Navigate(NavigateAction),
36
37 SwitchMode(AppMode),
39 SwitchModeWithCursor(AppMode, CursorPosition),
40 ToggleSelectionMode,
41 ExitCurrentMode,
42
43 InsertChar(char),
45 Backspace,
46 Delete,
47 ClearLine,
48 Undo,
49 Redo,
50
51 MoveCursorLeft,
53 MoveCursorRight,
54 MoveCursorHome,
55 MoveCursorEnd,
56 MoveCursorWordLeft,
57 MoveCursorWordRight,
58 JumpToPrevToken,
59 JumpToNextToken,
60
61 DeleteWordBackward,
63 DeleteWordForward,
64 DeleteToLineStart,
65 DeleteToLineEnd,
66
67 Yank(YankTarget),
69 Paste,
70
71 ToggleColumnPin,
73 HideColumn,
74 UnhideAllColumns,
75 HideEmptyColumns,
76 MoveColumnLeft,
77 MoveColumnRight,
78 ClearAllPins,
79 NextColumn,
80 PreviousColumn,
81 ToggleCompactMode,
82 ToggleRowNumbers,
83
84 Sort(Option<usize>), StartFilter,
87 StartFuzzyFilter,
88 ApplyFilter(String),
89 ClearFilter,
90 ExportToCsv,
91 ExportToJson,
92
93 StartSearch,
95 StartColumnSearch,
96 NextMatch,
97 PreviousMatch,
98 NextSearchMatch, PreviousSearchMatch, ExecuteQuery,
103 LoadFromHistory(usize),
104 StartHistorySearch,
105 PreviousHistoryCommand, NextHistoryCommand, RefreshView,
110 ShowHelp,
111 ShowDebugInfo,
112 ShowPrettyQuery,
113 StartJumpToRow,
114 NavigateToViewportTop,
115 NavigateToViewportMiddle,
116 NavigateToViewportBottom,
117 ToggleCursorLock,
118 ToggleViewportLock,
119 ToggleCaseInsensitive,
120 ToggleKeyIndicator,
121 ShowColumnStatistics, CycleColumnPacking, KillLine, KillLineBackward, ExpandAsterisk, ExpandAsteriskVisible, Quit,
132 ForceQuit,
133}
134
135#[derive(Debug, Clone, PartialEq)]
137pub enum NavigateAction {
138 Up(usize),
139 Down(usize),
140 Left(usize),
141 Right(usize),
142 PageUp,
143 PageDown,
144 Home,
145 End,
146 FirstColumn,
147 LastColumn,
148 JumpToRow(usize),
149 JumpToColumn(usize),
150}
151
152#[derive(Debug, Clone, PartialEq)]
154pub enum YankTarget {
155 Cell,
156 Row,
157 Column,
158 All,
159 Query,
160}
161
162#[derive(Debug, Clone)]
164pub struct ActionContext {
165 pub mode: AppMode,
166 pub selection_mode: SelectionMode,
167 pub has_results: bool,
168 pub has_filter: bool,
169 pub has_search: bool,
170 pub row_count: usize,
171 pub column_count: usize,
172 pub current_row: usize,
173 pub current_column: usize,
174}
175
176#[derive(Debug, Clone, PartialEq)]
178pub enum ActionResult {
179 Handled,
181 NotHandled,
183 Exit,
185 SwitchMode(AppMode),
187 Error(String),
189}
190
191pub trait ActionHandler {
193 fn can_handle(&self, action: &Action, context: &ActionContext) -> bool;
195
196 fn handle(&mut self, action: Action, context: &ActionContext) -> Result<ActionResult>;
198}
199
200#[must_use]
202pub fn can_perform_action(action: &Action, context: &ActionContext) -> bool {
203 match action {
204 Action::Navigate(_) => context.mode == AppMode::Results && context.has_results,
206
207 Action::ToggleSelectionMode => context.mode == AppMode::Results,
209 Action::ExitCurrentMode => context.mode != AppMode::Command,
210
211 Action::Yank(_) => context.has_results,
213
214 Action::StartFilter | Action::StartFuzzyFilter => {
216 context.mode == AppMode::Results || context.mode == AppMode::Command
217 }
218 Action::ClearFilter => context.has_filter,
219
220 Action::NextMatch | Action::PreviousMatch => context.has_search,
222
223 _ => true,
225 }
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231
232 #[test]
233 fn test_navigation_action_creation() {
234 let action = Action::Navigate(NavigateAction::Down(5));
235 assert_eq!(action, Action::Navigate(NavigateAction::Down(5)));
236 }
237
238 #[test]
239 fn test_action_context() {
240 let context = ActionContext {
241 mode: AppMode::Results,
242 selection_mode: SelectionMode::Row,
243 has_results: true,
244 has_filter: false,
245 has_search: false,
246 row_count: 100,
247 column_count: 10,
248 current_row: 0,
249 current_column: 0,
250 };
251
252 assert!(can_perform_action(
254 &Action::Navigate(NavigateAction::Down(1)),
255 &context
256 ));
257
258 assert!(!can_perform_action(&Action::ClearFilter, &context));
260 }
261}