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;
16
17impl AppSession {
18 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 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)) = extract_file_reference(
31 self.core.input_manager.content(),
32 self.core.input_manager.cursor(),
33 ) {
34 palette.set_filter(query);
35 if !self.file_palette_active {
36 self.ensure_inline_lists_visible_for_trigger();
37 self.file_palette_active = true;
38 self.core.needs_full_clear = true;
39 self.mark_dirty();
40 }
41 } else if self.file_palette_active {
42 self.close_file_palette();
43 }
44 }
45 }
46
47 pub(super) fn close_file_palette(&mut self) {
49 self.file_palette_active = false;
50 self.core.needs_full_clear = true;
51
52 if let Some(palette) = self.file_palette.as_mut() {
54 palette.set_filter(String::new());
55 }
56 }
57
58 pub(super) fn handle_file_palette_key(&mut self, key: &KeyEvent) -> bool {
62 if !self.file_palette_active {
63 return false;
64 }
65
66 let Some(palette) = self.file_palette.as_mut() else {
67 return false;
68 };
69
70 match key.code {
71 KeyCode::Up => {
72 palette.move_selection_up();
73 self.mark_dirty();
74 true
75 }
76 KeyCode::Down => {
77 palette.move_selection_down();
78 self.mark_dirty();
79 true
80 }
81 KeyCode::Tab => {
82 palette.select_best_match();
83 self.mark_dirty();
84 true
85 }
86 KeyCode::Enter => {
87 let selected_path = palette.get_selected().map(|e| e.relative_path.clone());
88 if let Some(path) = selected_path {
89 self.insert_file_reference(&path);
90 self.close_file_palette();
91 self.mark_dirty();
92 true } else {
94 self.close_file_palette();
96 self.mark_dirty();
97 false }
99 }
100 KeyCode::Esc => {
101 self.close_file_palette();
102 self.mark_dirty();
103 true
104 }
105 KeyCode::Char('n') if key.modifiers.contains(KeyModifiers::CONTROL) => {
106 palette.move_selection_down();
107 self.mark_dirty();
108 true
109 }
110 KeyCode::Char('p') if key.modifiers.contains(KeyModifiers::CONTROL) => {
111 palette.move_selection_up();
112 self.mark_dirty();
113 true
114 }
115 _ => false,
116 }
117 }
118
119 pub(crate) fn insert_file_reference(&mut self, file_path: &str) {
121 if let Some((start, end, _)) = extract_file_reference(
122 self.core.input_manager.content(),
123 self.core.input_manager.cursor(),
124 ) {
125 let before = &self.core.input_manager.content()[..start];
126 let after = &self.core.input_manager.content()[end..];
127 let reference_alias = format!("@{}", file_path);
128 let new_content = format!("{}{} {}", before, reference_alias, after);
129 let new_cursor = start + reference_alias.len() + 1;
130
131 self.core.input_manager.set_content(new_content);
132 self.core.input_manager.set_cursor(new_cursor);
133 slash::update_slash_suggestions(self);
134 }
135 }
136}