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_or(0, |dv| dv.get_pinned_columns().len());
93                self.state_container().navigation_mut().scroll_offset.1 =
94                    viewport.start.saturating_sub(pinned_count);
95            }
96
97            self.buffer_mut().set_current_column(new_col);
98        }
99
100        // Set status message
101        self.buffer_mut().set_status_message(result.description);
102    }
103
104    // ========== Column Operation Methods ==========
105
106    /// Hide the currently selected column
107    fn hide_current_column(&mut self) {
108        if !self.is_in_results_mode() {
109            return;
110        }
111
112        let result = self.viewport_manager().borrow_mut().as_mut().map_or_else(
113            || ColumnOperationResult::failure("No viewport manager"),
114            crate::ui::viewport_manager::ViewportManager::hide_current_column_with_result,
115        );
116
117        self.apply_column_operation_result(result);
118    }
119
120    /// Unhide all columns
121    fn unhide_all_columns(&mut self) {
122        let result = self.viewport_manager().borrow_mut().as_mut().map_or_else(
123            || ColumnOperationResult::failure("No viewport manager"),
124            crate::ui::viewport_manager::ViewportManager::unhide_all_columns_with_result,
125        );
126
127        self.apply_column_operation_result(result);
128    }
129
130    /// Move the current column left in the view
131    fn move_current_column_left(&mut self) {
132        if !self.is_in_results_mode() {
133            return;
134        }
135
136        let result = self.viewport_manager().borrow_mut().as_mut().map_or_else(
137            || ColumnOperationResult::failure("No viewport manager"),
138            crate::ui::viewport_manager::ViewportManager::reorder_column_left_with_result,
139        );
140
141        self.apply_column_operation_result(result);
142    }
143
144    /// Move the current column right in the view
145    fn move_current_column_right(&mut self) {
146        if !self.is_in_results_mode() {
147            return;
148        }
149
150        let result = self.viewport_manager().borrow_mut().as_mut().map_or_else(
151            || ColumnOperationResult::failure("No viewport manager"),
152            crate::ui::viewport_manager::ViewportManager::reorder_column_right_with_result,
153        );
154
155        self.apply_column_operation_result(result);
156    }
157
158    /// Navigate to the column on the left
159    fn move_column_left(&mut self) {
160        // Get navigation result from ViewportManager
161        let nav_result = {
162            let mut viewport_borrow = self.viewport_manager().borrow_mut();
163            let vm = viewport_borrow
164                .as_mut()
165                .expect("ViewportManager must exist for navigation");
166            let current_visual = vm.get_crosshair_col();
167            vm.navigate_column_left(current_visual)
168        };
169
170        self.apply_column_navigation_result(nav_result, "left");
171    }
172
173    /// Navigate to the column on the right
174    fn move_column_right(&mut self) {
175        // Get navigation result from ViewportManager
176        let nav_result = {
177            let mut viewport_borrow = self.viewport_manager().borrow_mut();
178            let vm = viewport_borrow
179                .as_mut()
180                .expect("ViewportManager must exist for navigation");
181            let current_visual = vm.get_crosshair_col();
182            tracing::debug!(
183                "[COLUMN_OPS] move_column_right: current_visual from VM = {}",
184                current_visual
185            );
186            let result = vm.navigate_column_right(current_visual);
187            tracing::debug!(
188                "[COLUMN_OPS] move_column_right: navigation result column_position = {}",
189                result.column_position
190            );
191            result
192        };
193
194        tracing::debug!(
195            "[COLUMN_OPS] move_column_right: applying result with column_position = {}",
196            nav_result.column_position
197        );
198        self.apply_column_navigation_result(nav_result, "right");
199    }
200
201    /// Navigate to the first column
202    fn goto_first_column(&mut self) {
203        // Get navigation result from ViewportManager
204        let nav_result = {
205            let mut viewport_borrow = self.viewport_manager().borrow_mut();
206            viewport_borrow
207                .as_mut()
208                .expect("ViewportManager must exist for navigation")
209                .navigate_to_first_column()
210        };
211
212        // Note: goto_first/last_column don't need cursor_manager updates
213        self.apply_column_navigation_result(nav_result, "first");
214    }
215
216    /// Navigate to the last column
217    fn goto_last_column(&mut self) {
218        // Get navigation result from ViewportManager
219        let nav_result = {
220            let mut viewport_borrow = self.viewport_manager().borrow_mut();
221            viewport_borrow
222                .as_mut()
223                .expect("ViewportManager must exist for navigation")
224                .navigate_to_last_column()
225        };
226
227        // Note: goto_first/last_column don't need cursor_manager updates
228        self.apply_column_navigation_result(nav_result, "last");
229    }
230}