Skip to main content

vtcode_tui/core_tui/session/
palette.rs

1/// Palette management operations for Session
2///
3/// This module handles file palette interactions including:
4/// - Loading and closing palettes
5/// - Checking and handling triggers
6/// - Key event handling for palette navigation
7/// - Reference insertion
8use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
9use std::path::PathBuf;
10
11use super::{
12    Session,
13    file_palette::{FilePalette, extract_file_reference},
14};
15use crate::ui::tui::session::slash;
16
17impl Session {
18    /// Load the file palette with files from the workspace
19    pub(super) fn load_file_palette(&mut self, files: Vec<String>, workspace: PathBuf) {
20        let mut palette = FilePalette::new(workspace);
21        palette.load_files(files);
22        self.file_palette = Some(palette);
23        self.file_palette_active = false;
24        self.check_file_reference_trigger();
25    }
26
27    /// Check if the current input should trigger the file palette
28    pub fn check_file_reference_trigger(&mut self) {
29        if let Some(palette) = self.file_palette.as_mut() {
30            if let Some((_start, _end, query)) =
31                extract_file_reference(self.input_manager.content(), self.input_manager.cursor())
32            {
33                palette.set_filter(query);
34                if !self.file_palette_active {
35                    self.file_palette_active = true;
36                }
37            } else if self.file_palette_active {
38                self.close_file_palette();
39            }
40        }
41    }
42
43    /// Close the file palette and clean up resources
44    pub(super) fn close_file_palette(&mut self) {
45        self.file_palette_active = false;
46
47        // Clean up resources when closing to free memory
48        if let Some(palette) = self.file_palette.as_mut() {
49            palette.set_filter(String::new());
50        }
51    }
52
53    /// Handle key events for the file palette
54    ///
55    /// Returns true if the key was handled by the palette
56    pub(super) fn handle_file_palette_key(&mut self, key: &KeyEvent) -> bool {
57        if !self.file_palette_active {
58            return false;
59        }
60
61        let Some(palette) = self.file_palette.as_mut() else {
62            return false;
63        };
64
65        match key.code {
66            KeyCode::Up => {
67                palette.move_selection_up();
68                self.mark_dirty();
69                true
70            }
71            KeyCode::Down => {
72                palette.move_selection_down();
73                self.mark_dirty();
74                true
75            }
76            KeyCode::Tab => {
77                palette.select_best_match();
78                self.mark_dirty();
79                true
80            }
81            KeyCode::Enter => {
82                let selected_path = palette.get_selected().map(|e| e.relative_path.clone());
83                if let Some(path) = selected_path {
84                    self.insert_file_reference(&path);
85                    self.close_file_palette();
86                    self.mark_dirty();
87                }
88                true
89            }
90            KeyCode::Esc => {
91                self.close_file_palette();
92                self.mark_dirty();
93                true
94            }
95            KeyCode::Char('n') if key.modifiers.contains(KeyModifiers::CONTROL) => {
96                palette.move_selection_down();
97                self.mark_dirty();
98                true
99            }
100            KeyCode::Char('p') if key.modifiers.contains(KeyModifiers::CONTROL) => {
101                palette.move_selection_up();
102                self.mark_dirty();
103                true
104            }
105            _ => false,
106        }
107    }
108
109    /// Insert a file reference into the input at the current position
110    pub(super) fn insert_file_reference(&mut self, file_path: &str) {
111        if let Some((start, end, _)) =
112            extract_file_reference(self.input_manager.content(), self.input_manager.cursor())
113        {
114            let before = &self.input_manager.content()[..start];
115            let after = &self.input_manager.content()[end..];
116            let reference_alias = format!("@{}", file_path);
117            let new_content = format!("{}{} {}", before, reference_alias, after);
118            let new_cursor = start + reference_alias.len() + 1;
119
120            self.input_manager.set_content(new_content);
121            self.input_manager.set_cursor(new_cursor);
122            slash::update_slash_suggestions(self);
123        }
124    }
125}