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.mark_dirty();
12 }
13
14 pub fn set_cursor(&mut self, pos: usize) {
15 self.input_manager.set_cursor(pos);
16 self.mark_dirty();
17 }
18
19 pub fn process_key(&mut self, key: KeyEvent) -> Option<InlineEvent> {
20 events::process_key(self, key)
21 }
22
23 pub fn handle_command(&mut self, command: InlineCommand) {
24 if matches!(
26 &command,
27 InlineCommand::AppendLine { kind: InlineMessageKind::Agent, segments }
28 if !segments.is_empty()
29 ) || matches!(
30 &command,
31 InlineCommand::AppendPastedMessage { kind: InlineMessageKind::Agent, text, .. }
32 if !text.is_empty()
33 ) || matches!(
34 &command,
35 InlineCommand::Inline { kind: InlineMessageKind::Agent, segment }
36 if !segment.text.is_empty()
37 ) {
38 self.is_streaming_final_answer = true;
39 }
40
41 if let InlineCommand::SetInputStatus { left, right } = &command
43 && self.is_streaming_final_answer
44 && left.is_none()
45 && right.is_none()
46 {
47 self.is_streaming_final_answer = false;
48 }
49
50 match command {
51 InlineCommand::AppendLine { kind, segments } => {
52 self.clear_thinking_spinner_if_active(kind);
53 self.push_line(kind, segments);
54 self.request_transcript_clear();
55 }
56 InlineCommand::AppendPastedMessage {
57 kind,
58 text,
59 line_count,
60 } => {
61 self.clear_thinking_spinner_if_active(kind);
62 self.append_pasted_message(kind, text, line_count);
63 self.request_transcript_clear();
64 }
65 InlineCommand::Inline { kind, segment } => {
66 self.clear_thinking_spinner_if_active(kind);
67 self.append_inline(kind, segment);
68 self.request_transcript_clear();
69 }
70 InlineCommand::ReplaceLast {
71 count,
72 kind,
73 lines,
74 link_ranges,
75 } => {
76 self.clear_thinking_spinner_if_active(kind);
77 self.replace_last(count, kind, lines, link_ranges);
78 self.request_transcript_clear();
79 }
80 InlineCommand::SetPrompt { prefix, style } => {
81 self.prompt_prefix = prefix;
82 self.prompt_style = style;
83 self.ensure_prompt_style_color();
84 }
85 InlineCommand::SetPlaceholder { hint, style } => {
86 self.placeholder = hint;
87 self.placeholder_style = style;
88 }
89 InlineCommand::SetMessageLabels { agent, user } => {
90 self.labels.agent = agent.filter(|label| !label.is_empty());
91 self.labels.user = user.filter(|label| !label.is_empty());
92 self.invalidate_transcript_cache();
93 self.invalidate_scroll_metrics();
94 }
95 InlineCommand::SetHeaderContext { context } => {
96 let mut next_context = *context;
97 next_context.editing_mode = self.header_context.editing_mode;
98 next_context.autonomous_mode = self.header_context.autonomous_mode;
99 next_context.reasoning_stage = self.header_context.reasoning_stage.clone();
100 next_context.primary_agent = self.header_context.primary_agent.clone();
101 self.header_context = next_context;
102 self.invalidate_header_cache();
103 }
104 InlineCommand::SetInputStatus { left, right } => {
105 self.input_status_left = left;
106 self.input_status_right = right;
107 if self.thinking_spinner.is_active {
108 self.thinking_spinner.stop();
109 }
110 self.needs_redraw = true;
111 }
112 InlineCommand::SetTerminalTitleItems { items } => {
113 self.terminal_title_items = items;
114 self.needs_redraw = true;
115 }
116 InlineCommand::SetTerminalTitleThreadLabel { label } => {
117 self.terminal_title_thread_label = label.filter(|value| !value.trim().is_empty());
118 self.needs_redraw = true;
119 }
120 InlineCommand::SetTerminalTitleGitBranch { branch } => {
121 self.terminal_title_git_branch = branch.filter(|value| !value.trim().is_empty());
122 self.needs_redraw = true;
123 }
124 InlineCommand::SetTheme { theme } => {
125 let previous_theme = self.theme.clone();
126 self.theme = theme.clone();
127 self.styles.set_theme(theme);
128 self.retint_lines_for_theme_change(&previous_theme);
129 self.ensure_prompt_style_color();
130 self.invalidate_transcript_cache();
131 }
132 InlineCommand::SetAppearance { appearance } => {
133 self.appearance = appearance;
134 self.invalidate_header_cache();
135 self.invalidate_transcript_cache();
136 self.invalidate_scroll_metrics();
137 }
138 InlineCommand::SetVimModeEnabled(enabled) => {
139 self.vim_state.set_enabled(enabled);
140 self.needs_redraw = true;
141 }
142 InlineCommand::SetQueuedInputs { entries } => {
143 self.set_queued_inputs_entries(entries);
144 self.mark_dirty();
145 }
146 InlineCommand::SetSubprocessEntries { entries } => {
147 self.subprocess_entries = entries;
148 self.invalidate_sidebar_cache();
149 }
150 InlineCommand::SetSubagentPreview { text } => {
151 self.subagent_preview = text.filter(|value| !value.trim().is_empty());
152 self.invalidate_sidebar_cache();
153 }
154 InlineCommand::SetPrimaryAgent { name } => {
155 self.header_context.primary_agent = name.filter(|value| !value.trim().is_empty());
156 self.invalidate_header_cache();
157 }
158 InlineCommand::SetCursorVisible(value) => {
159 self.cursor_visible = value;
160 }
161 InlineCommand::SetInputEnabled(value) => {
162 self.input_enabled = value;
163 }
164 InlineCommand::SetInput(content) => {
165 if Self::is_error_content(&content) {
168 crate::utils::transcript::display_error(&content);
170 } else {
171 self.clear_suggested_prompt_state();
172 self.clear_inline_prompt_suggestion();
173 self.input_manager.set_content(content);
174 self.input_compact_mode = self.input_compact_placeholder().is_some();
175 self.scroll_manager.set_offset(0);
176 }
177 }
178 InlineCommand::ApplySuggestedPrompt(content) => {
179 self.apply_suggested_prompt(content);
180 self.scroll_manager.set_offset(0);
181 }
182 InlineCommand::SetInlinePromptSuggestion {
183 suggestion,
184 llm_generated,
185 } => {
186 self.set_inline_prompt_suggestion(suggestion, llm_generated);
187 }
188 InlineCommand::ClearInlinePromptSuggestion => {
189 self.clear_inline_prompt_suggestion();
190 }
191 InlineCommand::ClearInput => {
192 command::clear_input(self);
193 }
194 InlineCommand::ForceRedraw => {
195 self.mark_dirty();
196 }
197 InlineCommand::ShowOverlay { request } => {
198 self.clear_inline_prompt_suggestion();
199 self.show_overlay(*request);
200 }
201 InlineCommand::CloseOverlay => {
202 self.close_overlay();
203 }
204 InlineCommand::ClearScreen => {
205 self.clear_screen();
206 }
207 InlineCommand::SuspendEventLoop
208 | InlineCommand::ResumeEventLoop
209 | InlineCommand::ClearInputQueue
210 | InlineCommand::StopEventStream
211 | InlineCommand::StartEventStream => {
212 }
214 InlineCommand::SetEditingMode(mode) => {
215 self.clear_inline_prompt_suggestion();
216 self.header_context.editing_mode = mode;
217 self.invalidate_header_cache();
218 }
219 InlineCommand::SetAutonomousMode(enabled) => {
220 self.header_context.autonomous_mode = enabled;
221 self.invalidate_header_cache();
222 }
223 InlineCommand::SetSkipConfirmations(skip) => {
224 self.skip_confirmations = skip;
225 if skip {
226 self.close_overlay();
227 }
228 }
229 InlineCommand::Shutdown => {
230 self.request_exit();
231 }
232 InlineCommand::SetReasoningStage(stage) => {
233 self.header_context.reasoning_stage = stage;
234 self.invalidate_header_cache();
235 }
236 }
237 self.needs_redraw = true;
238 }
239}