Skip to main content

vtcode_tui/core_tui/session/
impl_input.rs

1use 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        match command {
25            InlineCommand::AppendLine { kind, segments } => {
26                self.clear_thinking_spinner_if_active(kind);
27                self.push_line(kind, segments);
28                self.transcript_content_changed = true;
29            }
30            InlineCommand::AppendPastedMessage {
31                kind,
32                text,
33                line_count,
34            } => {
35                self.clear_thinking_spinner_if_active(kind);
36                self.append_pasted_message(kind, text, line_count);
37                self.transcript_content_changed = true;
38            }
39            InlineCommand::Inline { kind, segment } => {
40                self.clear_thinking_spinner_if_active(kind);
41                self.append_inline(kind, segment);
42                self.transcript_content_changed = true;
43            }
44            InlineCommand::ReplaceLast { count, kind, lines } => {
45                self.clear_thinking_spinner_if_active(kind);
46                self.replace_last(count, kind, lines);
47                self.transcript_content_changed = true;
48            }
49            InlineCommand::SetPrompt { prefix, style } => {
50                self.prompt_prefix = prefix;
51                self.prompt_style = style;
52                self.ensure_prompt_style_color();
53            }
54            InlineCommand::SetPlaceholder { hint, style } => {
55                self.placeholder = hint;
56                self.placeholder_style = style;
57            }
58            InlineCommand::SetMessageLabels { agent, user } => {
59                self.labels.agent = agent.filter(|label| !label.is_empty());
60                self.labels.user = user.filter(|label| !label.is_empty());
61                self.invalidate_scroll_metrics();
62            }
63            InlineCommand::SetHeaderContext { context } => {
64                self.header_context = context;
65                self.needs_redraw = true;
66            }
67            InlineCommand::SetInputStatus { left, right } => {
68                self.input_status_left = left;
69                self.input_status_right = right;
70                if self.thinking_spinner.is_active {
71                    self.thinking_spinner.stop();
72                }
73                self.needs_redraw = true;
74            }
75            InlineCommand::SetTheme { theme } => {
76                let previous_theme = self.theme.clone();
77                self.theme = theme.clone();
78                self.styles.set_theme(theme);
79                self.retint_lines_for_theme_change(&previous_theme);
80                self.ensure_prompt_style_color();
81                self.invalidate_transcript_cache();
82            }
83            InlineCommand::SetAppearance { appearance } => {
84                self.appearance = appearance;
85                self.invalidate_transcript_cache();
86                self.invalidate_scroll_metrics();
87            }
88            InlineCommand::SetQueuedInputs { entries } => {
89                self.set_queued_inputs_entries(entries);
90                self.mark_dirty();
91            }
92            InlineCommand::SetCursorVisible(value) => {
93                self.cursor_visible = value;
94            }
95            InlineCommand::SetInputEnabled(value) => {
96                self.input_enabled = value;
97                slash::update_slash_suggestions(self);
98            }
99            InlineCommand::SetInput(content) => {
100                // Check if the content appears to be an error message
101                // If it looks like an error, redirect to transcript instead
102                if Self::is_error_content(&content) {
103                    // Add error to transcript instead of input field
104                    crate::utils::transcript::display_error(&content);
105                } else {
106                    self.input_manager.set_content(content);
107                    self.input_compact_mode = self.input_compact_placeholder().is_some();
108                    self.scroll_manager.set_offset(0);
109                    slash::update_slash_suggestions(self);
110                }
111            }
112            InlineCommand::ClearInput => {
113                command::clear_input(self);
114            }
115            InlineCommand::ForceRedraw => {
116                self.mark_dirty();
117            }
118            InlineCommand::ShowModal {
119                title,
120                lines,
121                secure_prompt,
122            } => {
123                self.show_modal(title, lines, secure_prompt);
124            }
125            InlineCommand::ShowListModal {
126                title,
127                lines,
128                items,
129                selected,
130                search,
131            } => {
132                self.show_list_modal(title, lines, items, selected, search);
133            }
134            InlineCommand::ShowWizardModal {
135                title,
136                steps,
137                current_step,
138                search,
139                mode,
140            } => {
141                self.show_wizard_modal(title, steps, current_step, search, mode);
142            }
143            InlineCommand::CloseModal => {
144                self.close_modal();
145            }
146            InlineCommand::LoadFilePalette { files, workspace } => {
147                self.load_file_palette(files, workspace);
148            }
149            InlineCommand::ClearScreen => {
150                self.clear_screen();
151            }
152            InlineCommand::SuspendEventLoop
153            | InlineCommand::ResumeEventLoop
154            | InlineCommand::ClearInputQueue => {
155                // Handled by drive_terminal
156            }
157            InlineCommand::SetEditingMode(mode) => {
158                self.header_context.editing_mode = mode;
159                self.needs_redraw = true;
160            }
161            InlineCommand::SetAutonomousMode(enabled) => {
162                self.header_context.autonomous_mode = enabled;
163                self.needs_redraw = true;
164            }
165            InlineCommand::ShowPlanConfirmation { plan } => {
166                command::show_plan_confirmation_modal(self, *plan);
167            }
168            InlineCommand::ShowDiffPreview {
169                file_path,
170                before,
171                after,
172                hunks,
173                current_hunk,
174            } => {
175                command::show_diff_preview(self, file_path, before, after, hunks, current_hunk);
176            }
177            InlineCommand::SetSkipConfirmations(skip) => {
178                self.skip_confirmations = skip;
179                if skip {
180                    self.close_modal();
181                }
182            }
183            InlineCommand::Shutdown => {
184                self.request_exit();
185            }
186            InlineCommand::SetReasoningStage(stage) => {
187                self.header_context.reasoning_stage = stage;
188                self.invalidate_header_cache();
189            }
190        }
191        self.needs_redraw = true;
192    }
193}