sql_cli/
buffer_handler.rs

1use crate::buffer::{Buffer, BufferAPI, BufferManager};
2use crate::config::config::Config;
3use tracing::{debug, info};
4
5/// Handles all buffer-related operations
6pub struct BufferHandler {
7    /// Stack for tracking buffer history (for quick switching)
8    buffer_history: Vec<usize>,
9    /// Maximum number of buffers to keep in history
10    max_history: usize,
11}
12
13impl BufferHandler {
14    pub fn new() -> Self {
15        Self {
16            buffer_history: vec![0], // Start with buffer 0
17            max_history: 10,
18        }
19    }
20
21    /// Switch to next buffer
22    pub fn next_buffer(&mut self, manager: &mut BufferManager) -> String {
23        let prev_index = manager.current_index();
24        manager.next_buffer();
25        let index = manager.current_index();
26        let total = manager.all_buffers().len();
27
28        self.update_history(index);
29        debug!(target: "buffer", "Switched from buffer {} to {} (total: {})", prev_index + 1, index + 1, total);
30
31        format!("Switched to buffer {}/{}", index + 1, total)
32    }
33
34    /// Switch to previous buffer
35    pub fn previous_buffer(&mut self, manager: &mut BufferManager) -> String {
36        let prev_index = manager.current_index();
37        manager.prev_buffer();
38        let index = manager.current_index();
39        let total = manager.all_buffers().len();
40
41        self.update_history(index);
42        debug!(target: "buffer", "Switched from buffer {} to {} (total: {})", prev_index + 1, index + 1, total);
43
44        format!("Switched to buffer {}/{}", index + 1, total)
45    }
46
47    /// Quick switch between last two buffers (like vim's Ctrl+6)
48    pub fn quick_switch(&mut self, manager: &mut BufferManager) -> String {
49        if self.buffer_history.len() >= 2 {
50            // Get the previous buffer from history
51            let prev_buffer = self.buffer_history[self.buffer_history.len() - 2];
52            self.switch_to_buffer(manager, prev_buffer)
53        } else {
54            // If no history, just switch to next
55            self.next_buffer(manager)
56        }
57    }
58
59    /// Switch to specific buffer by index (0-based)
60    pub fn switch_to_buffer(&mut self, manager: &mut BufferManager, index: usize) -> String {
61        let total = manager.all_buffers().len();
62        if index >= total {
63            return format!(
64                "Buffer {} does not exist (have {} buffers)",
65                index + 1,
66                total
67            );
68        }
69
70        let prev_index = manager.current_index();
71        if prev_index == index {
72            return format!("Already on buffer {}/{}", index + 1, total);
73        }
74
75        // Set the buffer directly
76        if index == 0 {
77            while manager.current_index() != 0 {
78                manager.prev_buffer();
79            }
80        } else {
81            while manager.current_index() != index {
82                if manager.current_index() < index {
83                    manager.next_buffer();
84                } else {
85                    manager.prev_buffer();
86                }
87            }
88        }
89
90        self.update_history(index);
91        debug!(target: "buffer", "Switched from buffer {} to {} (total: {})", prev_index + 1, index + 1, total);
92
93        format!("Switched to buffer {}/{}", index + 1, total)
94    }
95
96    /// Create a new buffer
97    pub fn new_buffer(&mut self, manager: &mut BufferManager, config: &Config) -> String {
98        let buffer_id = manager.all_buffers().len() + 1;
99        let mut new_buffer = Buffer::new(buffer_id);
100
101        // Apply config settings to the new buffer
102        new_buffer.set_compact_mode(config.display.compact_mode);
103        new_buffer.set_case_insensitive(config.behavior.case_insensitive_default);
104        new_buffer.set_show_row_numbers(config.display.show_row_numbers);
105
106        info!(target: "buffer", "Creating new buffer with config: compact_mode={}, case_insensitive={}, show_row_numbers={}",
107              config.display.compact_mode,
108              config.behavior.case_insensitive_default,
109              config.display.show_row_numbers);
110
111        manager.add_buffer(new_buffer);
112        let index = manager.current_index();
113        let total = manager.all_buffers().len();
114
115        self.update_history(index);
116
117        format!("Created new buffer {}/{}", index + 1, total)
118    }
119
120    /// Close current buffer
121    pub fn close_buffer(&mut self, manager: &mut BufferManager) -> (bool, String) {
122        if manager.all_buffers().len() == 1 {
123            return (false, "Cannot close the last buffer".to_string());
124        }
125
126        if manager.close_current() {
127            let index = manager.current_index();
128            let total = manager.all_buffers().len();
129
130            // Remove closed buffer from history
131            self.buffer_history.retain(|&idx| idx < total);
132
133            // Update indices in history (shift down if needed)
134            for idx in &mut self.buffer_history {
135                if *idx > index {
136                    *idx -= 1;
137                }
138            }
139
140            self.update_history(index);
141
142            (
143                true,
144                format!("Buffer closed. Now at buffer {}/{}", index + 1, total),
145            )
146        } else {
147            (false, "Failed to close buffer".to_string())
148        }
149    }
150
151    /// List all buffers with their status
152    pub fn list_buffers(&self, manager: &BufferManager) -> Vec<String> {
153        let current_index = manager.current_index();
154        let mut buffer_list = Vec::new();
155
156        for (i, buffer) in manager.all_buffers().iter().enumerate() {
157            let marker = if i == current_index { "▶" } else { " " };
158
159            // Get buffer info
160            let has_results = buffer.has_datatable();
161            let query = buffer.get_query();
162            let query_preview = if !query.is_empty() {
163                if query.len() > 30 {
164                    format!("{}...", &query[..27])
165                } else {
166                    query.clone()
167                }
168            } else {
169                "Empty".to_string()
170            };
171
172            let status = if has_results { "●" } else { "○" };
173
174            buffer_list.push(format!(
175                "{} [{}] Buffer {}: {} {}",
176                marker,
177                status,
178                i + 1,
179                query_preview,
180                if i < 9 {
181                    format!("(Alt+{})", i + 1)
182                } else {
183                    String::new()
184                }
185            ));
186        }
187
188        // Add history at the bottom
189        if !self.buffer_history.is_empty() {
190            buffer_list.push(format!(
191                "  History: {}",
192                self.buffer_history
193                    .iter()
194                    .rev()
195                    .take(5)
196                    .map(|idx| format!("{}", idx + 1))
197                    .collect::<Vec<_>>()
198                    .join(" → ")
199            ));
200        }
201
202        buffer_list
203    }
204
205    /// Update buffer history
206    fn update_history(&mut self, index: usize) {
207        // Remove if already in history
208        self.buffer_history.retain(|&idx| idx != index);
209
210        // Add to end
211        self.buffer_history.push(index);
212
213        // Trim to max size
214        if self.buffer_history.len() > self.max_history {
215            self.buffer_history.remove(0);
216        }
217    }
218
219    /// Get buffer history
220    pub fn get_history(&self) -> &[usize] {
221        &self.buffer_history
222    }
223
224    /// Clear buffer history
225    pub fn clear_history(&mut self) {
226        self.buffer_history.clear();
227        self.buffer_history.push(0);
228    }
229}