1use crate::buffer::{AppMode, BufferAPI};
2use serde_json::Value;
3use std::collections::HashMap;
4use std::time::Instant;
5
6#[derive(Debug, Clone)]
7pub struct ModeState {
8 pub mode: AppMode,
9 pub context: StateContext,
10 pub timestamp: Instant,
11}
12
13#[derive(Debug, Clone, Default)]
14pub struct StateContext {
15 pub input_text: String,
16 pub cursor_position: usize,
17 pub scroll_offset: (usize, usize),
18
19 pub selected_row: Option<usize>,
20 pub selected_column: usize,
21
22 pub search_pattern: Option<String>,
23 pub filter_pattern: Option<String>,
24 pub fuzzy_filter_pattern: Option<String>,
25 pub column_search_pattern: Option<String>,
26
27 pub table_scroll: (usize, usize),
28 pub column_widths: Vec<u16>,
29
30 pub custom_data: HashMap<String, Value>,
31}
32
33pub struct StateManager {
34 mode_stack: Vec<ModeState>,
35 current_context: StateContext,
36 max_stack_size: usize,
37}
38
39impl StateManager {
40 pub fn new() -> Self {
41 Self {
42 mode_stack: Vec::new(),
43 current_context: StateContext::default(),
44 max_stack_size: 10,
45 }
46 }
47
48 pub fn push_mode(&mut self, new_mode: AppMode, buffer: &mut dyn BufferAPI) {
49 let current_state = ModeState {
50 mode: buffer.get_mode(),
51 context: self.capture_context(buffer),
52 timestamp: Instant::now(),
53 };
54
55 self.mode_stack.push(current_state);
56 if self.mode_stack.len() > self.max_stack_size {
57 self.mode_stack.remove(0);
58 }
59
60 self.transition_to_mode(new_mode, buffer);
61 }
62
63 pub fn pop_mode(&mut self, buffer: &mut dyn BufferAPI) -> bool {
64 if let Some(previous_state) = self.mode_stack.pop() {
65 self.restore_context(&previous_state.context, buffer);
66 buffer.set_mode(previous_state.mode);
67 true
68 } else {
69 buffer.set_mode(AppMode::Command);
70 false
71 }
72 }
73
74 pub fn peek_previous_mode(&self) -> Option<AppMode> {
75 self.mode_stack.last().map(|state| state.mode.clone())
76 }
77
78 pub fn save_current_state(&mut self, buffer: &dyn BufferAPI) {
79 self.current_context = self.capture_context(buffer);
80 }
81
82 pub fn restore_current_state(&self, buffer: &mut dyn BufferAPI) {
83 self.restore_context(&self.current_context, buffer);
84 }
85
86 pub fn get_stack_depth(&self) -> usize {
87 self.mode_stack.len()
88 }
89
90 pub fn clear_stack(&mut self) {
91 self.mode_stack.clear();
92 }
93
94 fn capture_context(&self, buffer: &dyn BufferAPI) -> StateContext {
95 StateContext {
96 input_text: buffer.get_input_text(),
97 cursor_position: buffer.get_input_cursor_position(),
98 scroll_offset: buffer.get_scroll_offset(),
99 selected_row: buffer.get_selected_row(),
100 selected_column: buffer.get_current_column(),
101 search_pattern: if !buffer.get_search_pattern().is_empty() {
102 Some(buffer.get_search_pattern())
103 } else {
104 None
105 },
106 filter_pattern: if !buffer.get_filter_pattern().is_empty() {
107 Some(buffer.get_filter_pattern())
108 } else {
109 None
110 },
111 fuzzy_filter_pattern: if !buffer.get_fuzzy_filter_pattern().is_empty() {
112 Some(buffer.get_fuzzy_filter_pattern())
113 } else {
114 None
115 },
116 column_search_pattern: {
117 None
119 },
120 table_scroll: buffer.get_scroll_offset(),
121 column_widths: Vec::new(), custom_data: HashMap::new(),
123 }
124 }
125
126 fn restore_context(&self, context: &StateContext, buffer: &mut dyn BufferAPI) {
127 buffer.set_input_text(context.input_text.clone());
128 buffer.set_input_cursor_position(context.cursor_position);
129 buffer.set_scroll_offset(context.scroll_offset);
130
131 if let Some(row) = context.selected_row {
132 buffer.set_selected_row(Some(row));
133 }
134 buffer.set_current_column(context.selected_column);
135
136 if let Some(pattern) = &context.search_pattern {
137 buffer.set_search_pattern(pattern.clone());
138 }
139 if let Some(pattern) = &context.filter_pattern {
140 buffer.set_filter_pattern(pattern.clone());
141 }
142 if let Some(pattern) = &context.fuzzy_filter_pattern {
143 buffer.set_fuzzy_filter_pattern(pattern.clone());
144 }
145 if let Some(pattern) = &context.column_search_pattern {
146 }
149 }
150
151 fn transition_to_mode(&self, mode: AppMode, buffer: &mut dyn BufferAPI) {
152 buffer.set_mode(mode.clone());
153
154 match mode {
155 AppMode::Search => {
156 buffer.set_search_pattern(String::new());
157 }
158 AppMode::Filter => {
159 buffer.set_filter_pattern(String::new());
160 }
161 AppMode::FuzzyFilter => {
162 buffer.set_fuzzy_filter_pattern(String::new());
163 buffer.set_fuzzy_filter_active(false);
164 }
165 AppMode::ColumnSearch => {
166 }
169 _ => {}
170 }
171 }
172
173 pub fn format_debug_info(&self) -> String {
174 let mut info = String::from("========== STATE MANAGER ==========\n");
175 info.push_str(&format!("Stack Depth: {}\n", self.mode_stack.len()));
176
177 if !self.mode_stack.is_empty() {
178 info.push_str("\nMode Stack (oldest to newest):\n");
179 for (i, state) in self.mode_stack.iter().enumerate() {
180 info.push_str(&format!(" [{}] {:?}\n", i, state.mode));
181 }
182 }
183
184 info.push_str(&format!("\nCurrent Mode Context:\n"));
185 info.push_str(&format!(
186 " Input Length: {}\n",
187 self.current_context.input_text.len()
188 ));
189 info.push_str(&format!(
190 " Cursor: {}\n",
191 self.current_context.cursor_position
192 ));
193 info.push_str(&format!(
194 " Selected Row: {:?}\n",
195 self.current_context.selected_row
196 ));
197 info.push_str(&format!(
198 " Selected Column: {}\n",
199 self.current_context.selected_column
200 ));
201
202 info
203 }
204}