1pub use vtcode_commons::ui_protocol::{
12 EditingMode, InlineHeaderContext, InlineHeaderHighlight, InlineHeaderStatusBadge,
13 InlineHeaderStatusTone, InlineLinkRange, InlineLinkTarget, InlineListItem,
14 InlineListSearchConfig, InlineListSelection, InlineMessageKind, InlineSegment, InlineTextStyle,
15 InlineTheme, LayoutModeOverride, PlanContent, PlanPhase, PlanStep, ReasoningDisplayMode,
16 RewindAction, SecurePromptConfig, SessionSurface, SlashCommandItem, UiMode, WizardModalMode,
17 WizardStep, convert_style, theme_from_color_fields,
18};
19
20pub use vtcode_commons::ui_protocol::KeyboardProtocolSettings;
21
22#[cfg(feature = "tui")]
25pub use vtcode_tui::app::*;
26
27#[cfg(not(feature = "tui"))]
30mod headless {
31 use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
32
33 use super::{
34 InlineListItem, InlineListSearchConfig, InlineListSelection, InlineMessageKind,
35 InlineSegment, SecurePromptConfig,
36 };
37
38 use crate::ui::theme::ThemeStyles;
39
40 #[derive(Clone, Debug, PartialEq, Eq)]
42 pub enum InlineEvent {
43 Submit(String),
44 QueueSubmit(String),
45 Steer(String),
46 ProcessLatestQueued,
47 EditQueue,
48 Cancel,
49 Exit,
50 Interrupt,
51 Pause,
52 Resume,
53 BackgroundOperation,
54 ScrollLineUp,
55 ScrollLineDown,
56 ScrollPageUp,
57 ScrollPageDown,
58 OpenFileInEditor(String),
59 OpenUrl(String),
60 LaunchEditor,
61 ForceCancelPtySession,
62 RequestInlinePromptSuggestion(String),
63 ToggleMode,
64 HistoryPrevious,
65 HistoryNext,
66 }
67
68 #[derive(Clone, Debug)]
70 pub enum InlineCommand {
71 AppendLine {
72 kind: InlineMessageKind,
73 segments: Vec<InlineSegment>,
74 },
75 AppendPastedMessage {
76 kind: InlineMessageKind,
77 text: String,
78 line_count: usize,
79 },
80 Inline {
81 kind: InlineMessageKind,
82 segment: InlineSegment,
83 },
84 ReplaceLast {
85 count: usize,
86 kind: InlineMessageKind,
87 lines: Vec<Vec<InlineSegment>>,
88 },
89 ForceRedraw,
90 Shutdown,
91 ClearScreen,
92 CloseModal,
93 SetReasoningStage(Option<String>),
94 }
95
96 #[derive(Clone, Debug)]
98 pub struct InlineHandle {
99 sender: Option<UnboundedSender<InlineCommand>>,
100 }
101
102 impl InlineHandle {
103 pub fn new_for_tests(sender: UnboundedSender<InlineCommand>) -> Self {
104 Self {
105 sender: Some(sender),
106 }
107 }
108
109 fn send_command(&self, command: InlineCommand) {
110 if let Some(sender) = &self.sender {
111 let _ = sender.send(command);
112 }
113 }
114
115 pub fn append_line(&self, kind: InlineMessageKind, segments: Vec<InlineSegment>) {
116 self.send_command(InlineCommand::AppendLine { kind, segments });
117 }
118 pub fn append_pasted_message(
119 &self,
120 kind: InlineMessageKind,
121 text: String,
122 line_count: usize,
123 ) {
124 self.send_command(InlineCommand::AppendPastedMessage {
125 kind,
126 text,
127 line_count,
128 });
129 }
130 pub fn inline(&self, kind: InlineMessageKind, segment: InlineSegment) {
131 self.send_command(InlineCommand::Inline { kind, segment });
132 }
133 pub fn replace_last(
134 &self,
135 count: usize,
136 kind: InlineMessageKind,
137 lines: Vec<Vec<InlineSegment>>,
138 ) {
139 self.send_command(InlineCommand::ReplaceLast { count, kind, lines });
140 }
141 pub fn force_redraw(&self) {
142 self.send_command(InlineCommand::ForceRedraw);
143 }
144 pub fn shutdown(&self) {
145 self.send_command(InlineCommand::Shutdown);
146 }
147 pub fn clear_screen(&self) {
148 self.send_command(InlineCommand::ClearScreen);
149 }
150 pub fn show_modal(
151 &self,
152 _title: String,
153 _lines: Vec<String>,
154 _secure_prompt: Option<SecurePromptConfig>,
155 ) {
156 }
157 pub fn show_list_modal(
158 &self,
159 _title: String,
160 _lines: Vec<String>,
161 _items: Vec<InlineListItem>,
162 _selected: Option<InlineListSelection>,
163 _search: Option<InlineListSearchConfig>,
164 ) {
165 }
166 pub fn close_modal(&self) {
167 self.send_command(InlineCommand::CloseModal);
168 }
169 pub fn set_reasoning_stage(&self, stage: Option<String>) {
170 self.send_command(InlineCommand::SetReasoningStage(stage));
171 }
172 }
173
174 pub struct InlineSession {
176 pub handle: InlineHandle,
177 pub events: UnboundedReceiver<InlineEvent>,
178 }
179
180 impl InlineSession {
181 pub async fn next_event(&mut self) -> Option<InlineEvent> {
182 self.events.recv().await
183 }
184
185 pub fn clone_inline_handle(&self) -> InlineHandle {
186 self.handle.clone()
187 }
188 }
189
190 #[derive(Debug, Clone, Default)]
192 pub struct SessionAppearanceConfig {
193 pub theme: String,
194 pub ui_mode: super::UiMode,
195 pub show_sidebar: bool,
196 pub min_content_width: u16,
197 pub min_navigation_width: u16,
198 pub navigation_width_percent: u8,
199 pub transcript_bottom_padding: u16,
200 pub dim_completed_todos: bool,
201 pub message_block_spacing: u8,
202 pub layout_mode: super::LayoutModeOverride,
203 pub reasoning_display_mode: super::ReasoningDisplayMode,
204 pub reasoning_visible_default: bool,
205 pub vim_mode: bool,
206 pub screen_reader_mode: bool,
207 pub reduce_motion_mode: bool,
208 pub reduce_motion_keep_progress_animation: bool,
209 pub customization: (),
210 }
211
212 pub fn theme_from_styles(styles: &ThemeStyles) -> super::InlineTheme {
214 super::theme_from_color_fields(
215 styles.foreground,
216 styles.background,
217 styles.primary,
218 styles.secondary,
219 styles.tool,
220 styles.tool_detail,
221 styles.pty_output,
222 )
223 }
224}
225
226#[cfg(not(feature = "tui"))]
227pub use headless::*;