sql_cli/ui/traits/
column_ops.rs

1use crate::app_state_container::AppStateContainer;
2use crate::buffer::{AppMode, BufferAPI};
3use crate::ui::viewport_manager::{ColumnOperationResult, NavigationResult, ViewportManager};
4use std::cell::RefCell;
5// Arc import removed - no longer needed
6
7/// Trait that provides column operation behavior for TUI components
8/// This extracts column operation methods from EnhancedTui to reduce coupling
9pub trait ColumnBehavior {
10    // Required methods - these provide access to TUI internals
11    fn viewport_manager(&self) -> &RefCell<Option<ViewportManager>>;
12    fn buffer_mut(&mut self) -> &mut dyn BufferAPI;
13    fn buffer(&self) -> &dyn BufferAPI;
14    fn state_container(&self) -> &AppStateContainer;
15
16    // Mode checking - will be implemented by TUI to use shadow state
17    fn is_in_results_mode(&self) -> bool {
18        // Default implementation for compatibility
19        self.buffer().get_mode() == AppMode::Results
20    }
21
22    // Helper method to apply column navigation results
23    fn apply_column_navigation_result(&mut self, result: NavigationResult, direction: &str) {
24        // Use the column position from the navigation result - this is the visual/display index
25        // IMPORTANT: Don't re-query ViewportManager as that may have stale state
26        let visual_position = result.column_position;
27
28        tracing::debug!(
29            "[COLUMN_OPS] apply_column_navigation_result: direction={}, visual_position={}",
30            direction,
31            visual_position
32        );
33
34        // Update Buffer's current column
35        self.buffer_mut().set_current_column(visual_position);
36        tracing::debug!(
37            "[COLUMN_OPS] apply_column_navigation_result: set buffer column to {}",
38            visual_position
39        );
40
41        // Update navigation state
42        self.state_container().navigation_mut().selected_column = visual_position;
43        tracing::debug!(
44            "[COLUMN_OPS] apply_column_navigation_result: set navigation column to {}",
45            visual_position
46        );
47
48        // Update scroll offset if viewport changed
49        if result.viewport_changed {
50            let mut offset = self.buffer().get_scroll_offset();
51            offset.1 = result.scroll_offset;
52            self.buffer_mut().set_scroll_offset(offset);
53
54            // Also update the navigation state scroll offset
55            self.state_container().navigation_mut().scroll_offset.1 = result.scroll_offset;
56        }
57
58        // Set status message based on direction
59        let message = match direction {
60            "first" => "Moved to first column".to_string(),
61            "last" => "Moved to last column".to_string(),
62            _ => format!("Moved to column {}", visual_position),
63        };
64        self.buffer_mut().set_status_message(message);
65    }
66
67    // Helper method that stays in the trait
68    fn apply_column_operation_result(&mut self, result: ColumnOperationResult) {
69        if !result.success {
70            if !result.description.is_empty() {
71                self.buffer_mut().set_status_message(result.description);
72            }
73            return;
74        }
75
76        // Sync DataView if updated
77        if let Some(dataview) = result.updated_dataview {
78            self.buffer_mut().set_dataview(Some(dataview));
79        }
80
81        // Update navigation state if column position changed
82        if let Some(new_col) = result.new_column_position {
83            // Update navigation state
84            self.state_container().navigation_mut().selected_column = new_col;
85
86            // Update scroll offset if viewport changed
87            if let Some(viewport) = result.new_viewport {
88                let pinned_count = self
89                    .buffer()
90                    .get_dataview()
91                    .as_ref()
92                    .map(|dv| dv.get_pinned_columns().len())
93                    .unwrap_or(0);
94                self.state_container().navigation_mut().scroll_offset.1 =
95                    viewport.start.saturating_sub(pinned_count);
96            }
97
98            self.buffer_mut().set_current_column(new_col);
99        }
100
101        // Set status message
102        self.buffer_mut().set_status_message(result.description);
103    }
104
105    // ========== Column Operation Methods ==========
106
107    /// Hide the currently selected column
108    fn hide_current_column(&mut self) {
109        if !self.is_in_results_mode() {
110            return;
111        }
112
113        let result = self
114            .viewport_manager()
115            .borrow_mut()
116            .as_mut()
117            .map(|vm| vm.hide_current_column_with_result())
118            .unwrap_or_else(|| ColumnOperationResult::failure("No viewport manager"));
119
120        self.apply_column_operation_result(result);
121    }
122
123    /// Unhide all columns
124    fn unhide_all_columns(&mut self) {
125        let result = self
126            .viewport_manager()
127            .borrow_mut()
128            .as_mut()
129            .map(|vm| vm.unhide_all_columns_with_result())
130            .unwrap_or_else(|| ColumnOperationResult::failure("No viewport manager"));
131
132        self.apply_column_operation_result(result);
133    }
134
135    /// Move the current column left in the view
136    fn move_current_column_left(&mut self) {
137        if !self.is_in_results_mode() {
138            return;
139        }
140
141        let result = self
142            .viewport_manager()
143            .borrow_mut()
144            .as_mut()
145            .map(|vm| vm.reorder_column_left_with_result())
146            .unwrap_or_else(|| ColumnOperationResult::failure("No viewport manager"));
147
148        self.apply_column_operation_result(result);
149    }
150
151    /// Move the current column right in the view
152    fn move_current_column_right(&mut self) {
153        if !self.is_in_results_mode() {
154            return;
155        }
156
157        let result = self
158            .viewport_manager()
159            .borrow_mut()
160            .as_mut()
161            .map(|vm| vm.reorder_column_right_with_result())
162            .unwrap_or_else(|| ColumnOperationResult::failure("No viewport manager"));
163
164        self.apply_column_operation_result(result);
165    }
166
167    /// Navigate to the column on the left
168    fn move_column_left(&mut self) {
169        // Get navigation result from ViewportManager
170        let nav_result = {
171            let mut viewport_borrow = self.viewport_manager().borrow_mut();
172            let vm = viewport_borrow
173                .as_mut()
174                .expect("ViewportManager must exist for navigation");
175            let current_visual = vm.get_crosshair_col();
176            vm.navigate_column_left(current_visual)
177        };
178
179        self.apply_column_navigation_result(nav_result, "left");
180    }
181
182    /// Navigate to the column on the right
183    fn move_column_right(&mut self) {
184        // Get navigation result from ViewportManager
185        let nav_result = {
186            let mut viewport_borrow = self.viewport_manager().borrow_mut();
187            let vm = viewport_borrow
188                .as_mut()
189                .expect("ViewportManager must exist for navigation");
190            let current_visual = vm.get_crosshair_col();
191            tracing::debug!(
192                "[COLUMN_OPS] move_column_right: current_visual from VM = {}",
193                current_visual
194            );
195            let result = vm.navigate_column_right(current_visual);
196            tracing::debug!(
197                "[COLUMN_OPS] move_column_right: navigation result column_position = {}",
198                result.column_position
199            );
200            result
201        };
202
203        tracing::debug!(
204            "[COLUMN_OPS] move_column_right: applying result with column_position = {}",
205            nav_result.column_position
206        );
207        self.apply_column_navigation_result(nav_result, "right");
208    }
209
210    /// Navigate to the first column
211    fn goto_first_column(&mut self) {
212        // Get navigation result from ViewportManager
213        let nav_result = {
214            let mut viewport_borrow = self.viewport_manager().borrow_mut();
215            viewport_borrow
216                .as_mut()
217                .expect("ViewportManager must exist for navigation")
218                .navigate_to_first_column()
219        };
220
221        // Note: goto_first/last_column don't need cursor_manager updates
222        self.apply_column_navigation_result(nav_result, "first");
223    }
224
225    /// Navigate to the last column
226    fn goto_last_column(&mut self) {
227        // Get navigation result from ViewportManager
228        let nav_result = {
229            let mut viewport_borrow = self.viewport_manager().borrow_mut();
230            viewport_borrow
231                .as_mut()
232                .expect("ViewportManager must exist for navigation")
233                .navigate_to_last_column()
234        };
235
236        // Note: goto_first/last_column don't need cursor_manager updates
237        self.apply_column_navigation_result(nav_result, "last");
238    }
239}