vtcode_tui/core_tui/session/
impl_input.rs1use super::*;
2
3impl Session {
4 pub fn cursor(&self) -> usize {
5 self.input_manager.cursor()
6 }
7
8 pub fn set_input(&mut self, text: impl Into<String>) {
9 self.input_manager.set_content(text.into());
10 self.input_compact_mode = self.input_compact_placeholder().is_some();
11 self.check_file_reference_trigger();
12 self.mark_dirty();
13 }
14
15 pub fn set_cursor(&mut self, pos: usize) {
16 self.input_manager.set_cursor(pos);
17 self.mark_dirty();
18 }
19
20 pub fn process_key(&mut self, key: KeyEvent) -> Option<InlineEvent> {
21 events::process_key(self, key)
22 }
23
24 pub fn handle_command(&mut self, command: InlineCommand) {
25 if matches!(
27 &command,
28 InlineCommand::AppendLine { kind: InlineMessageKind::Agent, segments }
29 if !segments.is_empty()
30 ) || matches!(
31 &command,
32 InlineCommand::AppendPastedMessage { kind: InlineMessageKind::Agent, text, .. }
33 if !text.is_empty()
34 ) || matches!(
35 &command,
36 InlineCommand::Inline { kind: InlineMessageKind::Agent, segment }
37 if !segment.text.is_empty()
38 ) {
39 self.is_streaming_final_answer = true;
40 }
41
42 if let InlineCommand::SetInputStatus { left, right } = &command
44 && self.is_streaming_final_answer
45 && left.is_none()
46 && right.is_none()
47 {
48 self.is_streaming_final_answer = false;
49 }
50
51 match command {
52 InlineCommand::AppendLine { kind, segments } => {
53 self.clear_thinking_spinner_if_active(kind);
54 self.push_line(kind, segments);
55 self.transcript_content_changed = true;
56 }
57 InlineCommand::AppendPastedMessage {
58 kind,
59 text,
60 line_count,
61 } => {
62 self.clear_thinking_spinner_if_active(kind);
63 self.append_pasted_message(kind, text, line_count);
64 self.transcript_content_changed = true;
65 }
66 InlineCommand::Inline { kind, segment } => {
67 self.clear_thinking_spinner_if_active(kind);
68 self.append_inline(kind, segment);
69 self.transcript_content_changed = true;
70 }
71 InlineCommand::ReplaceLast { count, kind, lines } => {
72 self.clear_thinking_spinner_if_active(kind);
73 self.replace_last(count, kind, lines);
74 self.transcript_content_changed = true;
75 }
76 InlineCommand::SetPrompt { prefix, style } => {
77 self.prompt_prefix = prefix;
78 self.prompt_style = style;
79 self.ensure_prompt_style_color();
80 }
81 InlineCommand::SetPlaceholder { hint, style } => {
82 self.placeholder = hint;
83 self.placeholder_style = style;
84 }
85 InlineCommand::SetMessageLabels { agent, user } => {
86 self.labels.agent = agent.filter(|label| !label.is_empty());
87 self.labels.user = user.filter(|label| !label.is_empty());
88 self.invalidate_scroll_metrics();
89 }
90 InlineCommand::SetHeaderContext { context } => {
91 self.header_context = context;
92 self.needs_redraw = true;
93 }
94 InlineCommand::SetInputStatus { left, right } => {
95 self.input_status_left = left;
96 self.input_status_right = right;
97 if self.thinking_spinner.is_active {
98 self.thinking_spinner.stop();
99 }
100 self.needs_redraw = true;
101 }
102 InlineCommand::SetTheme { theme } => {
103 let previous_theme = self.theme.clone();
104 self.theme = theme.clone();
105 self.styles.set_theme(theme);
106 self.retint_lines_for_theme_change(&previous_theme);
107 self.ensure_prompt_style_color();
108 self.invalidate_transcript_cache();
109 }
110 InlineCommand::SetAppearance { appearance } => {
111 self.appearance = appearance;
112 self.invalidate_transcript_cache();
113 self.invalidate_scroll_metrics();
114 }
115 InlineCommand::SetQueuedInputs { entries } => {
116 self.set_queued_inputs_entries(entries);
117 self.mark_dirty();
118 }
119 InlineCommand::SetCursorVisible(value) => {
120 self.cursor_visible = value;
121 }
122 InlineCommand::SetInputEnabled(value) => {
123 self.input_enabled = value;
124 slash::update_slash_suggestions(self);
125 }
126 InlineCommand::SetInput(content) => {
127 if Self::is_error_content(&content) {
130 crate::utils::transcript::display_error(&content);
132 } else {
133 self.input_manager.set_content(content);
134 self.input_compact_mode = self.input_compact_placeholder().is_some();
135 self.scroll_manager.set_offset(0);
136 slash::update_slash_suggestions(self);
137 self.check_file_reference_trigger();
138 }
139 }
140 InlineCommand::ClearInput => {
141 command::clear_input(self);
142 }
143 InlineCommand::ForceRedraw => {
144 self.mark_dirty();
145 }
146 InlineCommand::ShowModal {
147 title,
148 lines,
149 secure_prompt,
150 } => {
151 self.show_modal(title, lines, secure_prompt);
152 }
153 InlineCommand::ShowListModal {
154 title,
155 lines,
156 items,
157 selected,
158 search,
159 } => {
160 self.show_list_modal(title, lines, items, selected, search);
161 }
162 InlineCommand::ShowWizardModal {
163 title,
164 steps,
165 current_step,
166 search,
167 mode,
168 } => {
169 self.show_wizard_modal(title, steps, current_step, search, mode);
170 }
171 InlineCommand::CloseModal => {
172 self.close_modal();
173 }
174 InlineCommand::LoadFilePalette { files, workspace } => {
175 self.load_file_palette(files, workspace);
176 }
177 InlineCommand::OpenHistoryPicker => {
178 events::open_history_picker(self);
179 }
180 InlineCommand::ClearScreen => {
181 self.clear_screen();
182 }
183 InlineCommand::SuspendEventLoop
184 | InlineCommand::ResumeEventLoop
185 | InlineCommand::ClearInputQueue => {
186 }
188 InlineCommand::SetEditingMode(mode) => {
189 self.header_context.editing_mode = mode;
190 self.needs_redraw = true;
191 }
192 InlineCommand::SetAutonomousMode(enabled) => {
193 self.header_context.autonomous_mode = enabled;
194 self.needs_redraw = true;
195 }
196 InlineCommand::ShowPlanConfirmation { plan } => {
197 command::show_plan_confirmation_modal(self, *plan);
198 }
199 InlineCommand::ShowDiffPreview {
200 file_path,
201 before,
202 after,
203 hunks,
204 current_hunk,
205 } => {
206 command::show_diff_preview(self, file_path, before, after, hunks, current_hunk);
207 }
208 InlineCommand::SetSkipConfirmations(skip) => {
209 self.skip_confirmations = skip;
210 if skip {
211 self.close_modal();
212 }
213 }
214 InlineCommand::Shutdown => {
215 self.request_exit();
216 }
217 InlineCommand::SetReasoningStage(stage) => {
218 self.header_context.reasoning_stage = stage;
219 self.invalidate_header_cache();
220 }
221 }
222 self.needs_redraw = true;
223 }
224}