vtcode_tui/core_tui/app/session/
palette.rs1use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
9use std::path::PathBuf;
10
11use super::{
12 AppSession,
13 file_palette::{FilePalette, extract_file_reference},
14};
15use crate::core_tui::app::session::slash;
16use crate::core_tui::app::session::transient::TransientSurface;
17
18impl AppSession {
19 pub(super) fn load_file_palette(&mut self, files: Vec<String>, workspace: PathBuf) {
21 let mut palette = FilePalette::new(workspace);
22 palette.load_files(files);
23 self.file_palette = Some(palette);
24 self.file_palette_active = false;
25 self.check_file_reference_trigger();
26 }
27
28 pub fn check_file_reference_trigger(&mut self) {
30 if let Some(palette) = self.file_palette.as_mut() {
31 if let Some((_start, _end, query)) = extract_file_reference(
32 self.core.input_manager.content(),
33 self.core.input_manager.cursor(),
34 ) {
35 palette.set_filter(query);
36 if !self.file_palette_active {
37 self.ensure_inline_lists_visible_for_trigger();
38 self.file_palette_active = true;
39 self.show_transient_surface(TransientSurface::FilePalette);
40 self.mark_dirty();
41 }
42 } else if self.file_palette_active {
43 self.close_file_palette();
44 }
45 }
46 }
47
48 pub(super) fn close_file_palette(&mut self) {
50 self.file_palette_active = false;
51 self.close_transient_surface(TransientSurface::FilePalette);
52
53 if let Some(palette) = self.file_palette.as_mut() {
55 palette.set_filter(String::new());
56 }
57 }
58
59 pub(super) fn handle_file_palette_key(&mut self, key: &KeyEvent) -> bool {
63 if !self.file_palette_visible() {
64 return false;
65 }
66
67 let Some(palette) = self.file_palette.as_mut() else {
68 return false;
69 };
70
71 match key.code {
72 KeyCode::Up => {
73 palette.move_selection_up();
74 self.mark_dirty();
75 true
76 }
77 KeyCode::Down => {
78 palette.move_selection_down();
79 self.mark_dirty();
80 true
81 }
82 KeyCode::Tab => {
83 palette.select_best_match();
84 self.mark_dirty();
85 true
86 }
87 KeyCode::Enter => {
88 let selected_path = palette.get_selected().map(|e| e.relative_path.clone());
89 if let Some(path) = selected_path {
90 self.insert_file_reference(&path);
91 self.close_file_palette();
92 self.mark_dirty();
93 true } else {
95 self.close_file_palette();
97 self.mark_dirty();
98 false }
100 }
101 KeyCode::Esc => {
102 self.close_file_palette();
103 self.mark_dirty();
104 true
105 }
106 KeyCode::Char('n') if key.modifiers.contains(KeyModifiers::CONTROL) => {
107 palette.move_selection_down();
108 self.mark_dirty();
109 true
110 }
111 KeyCode::Char('p') if key.modifiers.contains(KeyModifiers::CONTROL) => {
112 palette.move_selection_up();
113 self.mark_dirty();
114 true
115 }
116 _ => false,
117 }
118 }
119
120 pub(crate) fn insert_file_reference(&mut self, file_path: &str) {
122 if let Some((start, end, _)) = extract_file_reference(
123 self.core.input_manager.content(),
124 self.core.input_manager.cursor(),
125 ) {
126 let before = &self.core.input_manager.content()[..start];
127 let after = &self.core.input_manager.content()[end..];
128 let reference_alias = format!("@{}", file_path);
129 let new_content = format!("{}{} {}", before, reference_alias, after);
130 let new_cursor = start + reference_alias.len() + 1;
131
132 self.core.input_manager.set_content(new_content);
133 self.core.input_manager.set_cursor(new_cursor);
134 slash::update_slash_suggestions(self);
135 }
136 }
137}