Skip to main content

oxicode_vtui_compat/
lib.rs

1#![allow(
2    missing_docs,
3    clippy::expect_used,
4    dead_code,
5    unused_imports,
6    unexpected_cfgs
7)]
8#![allow(
9    clippy::let_and_return,
10    clippy::borrow_interior_mutable_const,
11    clippy::derivable_impls
12)]
13// oxicode-vtui-compat — Compatibility stubs replacing vtcode-config + vtcode-commons
14// for the vendored vtcode-ui.
15//
16// MIT licensed — provides the minimum surface area needed for oxicode-vtui to compile.
17
18// ── Re-export ui_protocol from vtcode-commons ──────────────────────────────
19pub mod ui_protocol;
20// ui_protocol/ contains: InlineMessageKind, InlineSegment, InlineTextStyle,
21// InlineTheme, InlineHeaderContext, SlashCommandItem, ThinkingBlockState, etc.
22
23// ── constants (originally vtcode_config::constants) ────────────────────────
24pub mod constants {
25    pub mod ui {
26        pub const TOOL_OUTPUT_MODE_COMPACT: &str = "compact";
27        pub const TOOL_OUTPUT_MODE_FULL: &str = "full";
28        pub const DEFAULT_REASONING_VISIBLE: bool = false;
29        pub const INLINE_PTY_PLACEHOLDER: &str = "...";
30        pub const INLINE_PTY_STATUS_DONE: &str = "DONE";
31        pub const HEADER_UNKNOWN_PLACEHOLDER: &str = "\u{2014}";
32        pub const HEADER_GIT_DIRTY_SUFFIX: &str = "*";
33        pub const CHAT_INPUT_PLACEHOLDER_BOOTSTRAP: &str =
34            "Describe what you want to build\u{2026}";
35        pub const CHAT_INPUT_PLACEHOLDER_FOLLOW_UP: &str = "Follow-up\u{2026}";
36        pub const WELCOME_TEXT_WIDTH: usize = 72;
37        pub const WELCOME_SHORTCUT_SECTION_TITLE: &str = "Shortcuts";
38        pub const WELCOME_SHORTCUT_HINT_PREFIX: &str = "  ";
39        pub const WELCOME_SHORTCUT_SEPARATOR: &str = " \u{2022} ";
40        pub const WELCOME_SHORTCUT_INDENT: &str = "    ";
41        pub const WELCOME_SLASH_COMMAND_SECTION_TITLE: &str = "Commands";
42        pub const WELCOME_SLASH_COMMAND_LIMIT: usize = 20;
43        pub const WELCOME_SLASH_COMMAND_PREFIX: &str = "  /";
44        pub const WELCOME_SLASH_COMMAND_INTRO: &str = "Use / to open the command palette";
45        pub const WELCOME_SLASH_COMMAND_INDENT: &str = "      ";
46        pub const INLINE_USER_PREFIX: &str = " ";
47        pub const HEADER_SHORTCUT_HINT: &str = "";
48        pub const HEADER_META_SEPARATOR: &str = "   ";
49
50        pub const THEME_RELATIVE_LUMINANCE_CUTOFF: f32 = 0.03928;
51        pub const THEME_RELATIVE_LUMINANCE_LOW_FACTOR: f32 = 12.92;
52        pub const THEME_RELATIVE_LUMINANCE_OFFSET: f32 = 0.055;
53        pub const THEME_RELATIVE_LUMINANCE_EXPONENT: f32 = 2.4;
54        pub const THEME_RED_LUMINANCE_COEFFICIENT: f32 = 0.2126;
55        pub const THEME_GREEN_LUMINANCE_COEFFICIENT: f32 = 0.7152;
56        pub const THEME_BLUE_LUMINANCE_COEFFICIENT: f32 = 0.0722;
57        pub const THEME_CONTRAST_RATIO_OFFSET: f32 = 0.05;
58        pub const THEME_MIX_RATIO_MIN: f32 = 0.0;
59        pub const THEME_MIX_RATIO_MAX: f32 = 1.0;
60        pub const THEME_BLEND_CLAMP_MIN: f32 = 0.0;
61        pub const THEME_BLEND_CLAMP_MAX: f32 = 255.0;
62        pub const THEME_COLOR_WHITE_RED: f32 = 1.0;
63        pub const THEME_COLOR_WHITE_GREEN: f32 = 1.0;
64        pub const THEME_COLOR_WHITE_BLUE: f32 = 1.0;
65        pub const THEME_LOGO_ACCENT_BANNER_LIGHTEN_RATIO: f32 = 0.15;
66        pub const THEME_PRIMARY_STATUS_SECONDARY_LIGHTEN_RATIO: f32 = 0.7;
67        pub const THEME_LOGO_ACCENT_BANNER_SECONDARY_LIGHTEN_RATIO: f32 = 0.5;
68        pub const THEME_MIN_CONTRAST_RATIO: f32 = 3.0;
69        pub const THEME_FOREGROUND_LIGHTEN_RATIO: f32 = 0.2;
70        pub const THEME_SECONDARY_LIGHTEN_RATIO: f32 = 0.8;
71        pub const THEME_MIX_RATIO: f32 = 0.0;
72        pub const THEME_TOOL_BODY_LIGHTEN_RATIO: f32 = 0.1;
73        pub const THEME_TOOL_BODY_MIX_RATIO: f32 = 0.0;
74        pub const THEME_PTY_OUTPUT_MIX_RATIO: f32 = 0.0;
75        pub const THEME_RESPONSE_COLOR_LIGHTEN_RATIO: f32 = 0.1;
76        pub const THEME_USER_COLOR_LIGHTEN_RATIO: f32 = 0.1;
77        pub const THEME_SECONDARY_USER_COLOR_LIGHTEN_RATIO: f32 = 0.3;
78        pub const THEME_LUMINANCE_LIGHTEN_RATIO: f32 = 0.1;
79        pub const THEME_PRIMARY_STATUS_LIGHTEN_RATIO: f32 = 0.3;
80        pub const THEME_LOGO_ACCENT_BANNER_RATIO: f32 = 0.15;
81
82        pub const HEADER_STATUS_LABEL: &str = "Status";
83        pub const HEADER_STATUS_ACTIVE: &str = "Active";
84        pub const HEADER_STATUS_PAUSED: &str = "Paused";
85        pub const MODAL_LIST_HIGHLIGHT_SYMBOL: &str = "\u{2502}";
86        pub const MODAL_LIST_HIGHLIGHT_FULL: &str = "\u{2502} ";
87        pub const INLINE_FILE_PICKER_TREE_PREFIX: &str = "\u{25B8} ";
88        pub const NAVIGATION_BLOCK_TITLE: &str = "Timeline";
89        pub const NAVIGATION_BLOCK_SHORTCUT_NOTE: &str = "Ctrl+T";
90        pub const NAVIGATION_EMPTY_LABEL: &str = "Waiting for activity";
91        pub const SLASH_PALETTE_MIN_WIDTH: u16 = 40;
92        pub const SLASH_PALETTE_MIN_HEIGHT: u16 = 9;
93        pub const DEFAULT_INLINE_VIEWPORT_ROWS: u16 = 16;
94        // Agent mode hue resolution (oxicode has no concept of agent modes — return None)
95        pub fn agent_mode_hue(_token: &str) -> Option<&str> {
96            None
97        }
98        // Additional constants sometimes referenced
99        pub const AGENT_COLOR_AUTO: &str = "auto";
100        pub const AGENT_COLOR_BUILD: &str = "build";
101        pub const AGENT_COLOR_DUCK: &str = "duck";
102        pub const AGENT_COLOR_PLAN: &str = "plan";
103    }
104
105    pub mod defaults {
106        pub fn default_provider() -> String {
107            "openai".into()
108        }
109        pub fn default_model() -> String {
110            "gpt-4o".into()
111        }
112        pub const DEFAULT_THEME: &str = "oxi";
113    }
114
115    pub mod tools {
116        pub const GREP_FILE: &str = "grep_file";
117        pub const LIST_FILES: &str = "list_files";
118        pub const READ_FILE: &str = "read_file";
119        pub const EDIT_FILE: &str = "edit_file";
120        pub const WRITE_FILE: &str = "write_file";
121        pub const CREATE_FILE: &str = "create_file";
122        pub const APPLY_PATCH: &str = "apply_patch";
123        pub const SEARCH_REPLACE: &str = "search_replace";
124        pub const DELETE_FILE: &str = "delete_file";
125        pub const UNIFIED_FILE: &str = "unified_file";
126    }
127}
128
129// ── vtcode_config::core::tools ─────────────────────────────────────────────
130pub mod core {
131    pub mod tools {
132        /// Policy for whether a tool requires user approval.
133        #[derive(
134            Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize,
135        )]
136        pub enum ToolPolicy {
137            #[default]
138            Allow,
139            Ask,
140            Prompt,
141            Deny,
142        }
143    }
144}
145
146// ── vtcode_config::types ───────────────────────────────────────────────────
147pub mod types {
148    #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
149    #[serde(rename_all = "snake_case")]
150    pub enum SystemPromptMode {
151        Default,
152        Compact,
153    }
154
155    #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
156    pub enum ToolDocumentationMode {
157        #[default]
158        Full,
159        Compact,
160        Progressive,
161        None,
162    }
163
164    #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
165    pub enum VerbosityLevel {
166        #[default]
167        Quiet,
168        Normal,
169        Medium,
170        Verbose,
171    }
172}
173
174// ── Common utility stubs ───────────────────────────────────────────────────
175pub mod reasoning {
176    #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
177    pub enum ReasoningEffortLevel {
178        #[default]
179        Low,
180        Medium,
181        High,
182    }
183}
184
185pub mod stop_hints {
186    pub const STOP_HINT_COMPACT: &str = "\u{2026}";
187    pub const STOP_HINT_INLINE: &str = "\u{2026}";
188}
189
190pub mod terminal_detection {
191    pub fn is_ghostty_terminal(_term_program: Option<&str>, _term: Option<&str>) -> bool {
192        false
193    }
194}
195
196pub mod trace_flush {
197    pub fn flush_trace_log() {}
198}
199
200pub mod exclusions {
201    pub fn is_sensitive_file(_file_name: &str) -> bool {
202        false
203    }
204}
205
206pub mod color_policy {
207    pub fn no_color_env_active() -> bool {
208        false
209    }
210}
211
212pub mod formatting {
213    pub fn clean_reasoning_text(text: &str) -> String {
214        text.to_string()
215    }
216}
217
218pub mod ansi_codes {
219    pub const RESET: &str = "\x1b[0m";
220}
221
222pub mod editor {
223    pub fn normalize_editor_hash_fragment(_text: &str) -> String {
224        String::new()
225    }
226    pub fn parse_editor_target(_s: &str) -> Option<EditorTarget> {
227        None
228    }
229
230    #[derive(Debug, Clone)]
231    pub struct EditorTarget {
232        pub path: String,
233        pub line: Option<usize>,
234        pub col: Option<usize>,
235    }
236    impl EditorTarget {
237        pub fn path(&self) -> &std::path::Path {
238            std::path::Path::new(&self.path)
239        }
240        pub fn canonical_string(&self) -> String {
241            let mut s = self.path.clone();
242            if let Some(line) = self.line {
243                s.push_str(&format!(":{}", line));
244                if let Some(col) = self.col {
245                    s.push_str(&format!(":{}", col));
246                }
247            }
248            s
249        }
250    }
251
252    #[derive(Debug, Clone)]
253    pub struct EditorPoint {
254        pub path: String,
255        pub line: usize,
256        pub col: usize,
257    }
258}
259
260pub mod color256_theme {
261    use anstyle::RgbColor;
262    pub fn rgb_to_ansi256_for_theme(_rgb: RgbColor, _light: bool) -> Option<u8> {
263        None
264    }
265}
266
267pub mod errors {
268    pub type MultiErrors = Vec<anyhow::Error>;
269}
270pub use errors::MultiErrors;
271
272// ── ansi module ────────────────────────────────────────────────────────────
273pub mod ansi {
274    /// Strip all ANSI escape sequences from a string.
275    pub fn strip_ansi(s: &str) -> String {
276        let re = regex::Regex::new("\x1b\\[[0-9;]*[a-zA-Z]").unwrap();
277        re.replace_all(s, "").to_string()
278    }
279    pub fn strip_ansi_codes(s: &str) -> String {
280        strip_ansi(s)
281    }
282}
283
284// ── ansi_capabilities ──────────────────────────────────────────────────────
285pub mod ansi_capabilities {
286    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
287    pub enum ColorScheme {
288        Light,
289        Dark,
290        Unknown,
291    }
292    pub fn detect_color_scheme() -> ColorScheme {
293        ColorScheme::Dark
294    }
295}
296
297// ── colors ─────────────────────────────────────────────────────────────────
298pub mod colors {
299    use anstyle::{AnsiColor, Color, RgbColor};
300    pub fn blend_colors(a: Color, b: Color, _ratio: f32) -> Color {
301        // Minimal stub: blend by picking the second color when ratio > 0.5,
302        // otherwise the first. This avoids complex anstyle type gymnastics.
303        if _ratio > 0.5 { b } else { a }
304    }
305}
306
307// ── diff modules (minimal stubs) ───────────────────────────────────────────
308pub mod diff {
309    #[derive(Clone, Debug)]
310    pub struct DiffOptions {
311        pub context: usize,
312        pub old_label: Option<String>,
313        pub new_label: Option<String>,
314        pub missing_newline_hint: Option<String>,
315    }
316    impl Default for DiffOptions {
317        fn default() -> Self {
318            Self {
319                context: 3,
320                old_label: None,
321                new_label: None,
322                missing_newline_hint: None,
323            }
324        }
325    }
326    #[derive(Clone, Debug)]
327    pub enum DiffLineKind {
328        Context,
329        Addition,
330        Deletion,
331    }
332    #[derive(Clone, Debug)]
333    pub struct DiffLine {
334        pub kind: DiffLineKind,
335        pub text: String,
336        pub content: String,
337    }
338    #[derive(Clone, Debug)]
339    pub struct DiffHunk {
340        pub old_start: usize,
341        pub new_start: usize,
342        pub old_lines: Vec<DiffLine>,
343        pub new_lines: Vec<DiffLine>,
344        pub lines: Vec<DiffLine>,
345    }
346    #[derive(Clone, Debug)]
347    pub struct DiffBundle {
348        pub old_path: Option<String>,
349        pub new_path: Option<String>,
350        pub hunks: Vec<DiffHunk>,
351        pub formatted: String,
352    }
353    #[derive(Clone, Debug)]
354    pub struct Chunk {
355        pub lines: Vec<DiffLine>,
356    }
357    pub fn compute_diff(old: &[String], new: &[String], opts: &DiffOptions) -> DiffBundle {
358        let _ = (old, new, opts);
359        DiffBundle {
360            old_path: None,
361            new_path: None,
362            hunks: vec![],
363            formatted: String::new(),
364        }
365    }
366    pub fn compute_diff_chunks(
367        _old: &[String],
368        _new_lines: &[String],
369        _opts: &DiffOptions,
370    ) -> Vec<Chunk> {
371        vec![]
372    }
373}
374
375pub mod diff_paths {
376    pub fn is_diff_addition_line(_line: &str) -> bool {
377        false
378    }
379    pub fn is_diff_deletion_line(_line: &str) -> bool {
380        false
381    }
382    pub fn language_hint_from_path(_path: &str) -> Option<&'static str> {
383        None
384    }
385    pub fn is_diff_header_line(_line: &str) -> bool {
386        false
387    }
388    pub fn is_diff_new_file_marker_line(_line: &str) -> bool {
389        false
390    }
391    pub fn looks_like_diff_content(_text: &str) -> bool {
392        false
393    }
394    pub fn parse_diff_git_path(_line: &str) -> Option<String> {
395        None
396    }
397    pub fn parse_diff_marker_path(_line: &str) -> Option<String> {
398        None
399    }
400    pub fn format_start_only_hunk_header(_old: usize, _new: usize) -> String {
401        String::new()
402    }
403}
404
405pub mod diff_preview {
406    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
407    pub enum DiffDisplayKind {
408        Unified,
409        Split,
410    }
411    pub fn count_diff_changes(_lines: &[String]) -> (usize, usize) {
412        (0, 0)
413    }
414    pub fn display_lines_from_hunks(_hunks: &[()], _kind: DiffDisplayKind) -> Vec<String> {
415        vec![]
416    }
417}
418
419pub mod diff_theme {
420    use crate::styling::DiffColorPalette;
421    use anstyle::{AnsiColor, Color};
422
423    #[derive(Clone, Debug)]
424    pub struct DiffTheme {
425        pub add_fg: Color,
426        pub add_bg: Color,
427        pub del_fg: Color,
428        pub del_bg: Color,
429        pub hunk_fg: Color,
430        pub hunk_bg: Color,
431        pub gutter_add_bg_light: Color,
432        pub gutter_del_bg_light: Color,
433        pub gutter_fg_light: Color,
434    }
435    impl Default for DiffTheme {
436        fn default() -> Self {
437            Self {
438                add_fg: Color::Ansi(AnsiColor::Green),
439                add_bg: Color::Ansi(AnsiColor::Black),
440                del_fg: Color::Ansi(AnsiColor::Red),
441                del_bg: Color::Ansi(AnsiColor::Black),
442                hunk_fg: Color::Ansi(AnsiColor::Cyan),
443                hunk_bg: Color::Ansi(AnsiColor::Black),
444                gutter_add_bg_light: Color::Ansi(AnsiColor::Black),
445                gutter_del_bg_light: Color::Ansi(AnsiColor::Black),
446                gutter_fg_light: Color::Ansi(AnsiColor::Black),
447            }
448        }
449    }
450
451    #[derive(Clone, Copy, Debug)]
452    pub enum DiffColorLevel {
453        Full,
454        Ansi256,
455        Ansi16,
456        None,
457    }
458
459    pub fn diff_add_bg(_level: DiffColorLevel) -> Color {
460        DiffTheme::default().add_bg
461    }
462    pub fn diff_del_bg(_level: DiffColorLevel) -> Color {
463        DiffTheme::default().del_bg
464    }
465    pub fn diff_gutter_bg_add_light(_level: DiffColorLevel) -> Color {
466        DiffTheme::default().gutter_add_bg_light
467    }
468    pub fn diff_gutter_bg_del_light(_level: DiffColorLevel) -> Color {
469        DiffTheme::default().gutter_del_bg_light
470    }
471    pub fn diff_gutter_fg_light(_level: DiffColorLevel) -> Color {
472        DiffTheme::default().gutter_fg_light
473    }
474
475    pub fn default_diff_palette() -> DiffColorPalette {
476        DiffColorPalette::default()
477    }
478}
479
480// ── styling ────────────────────────────────────────────────────────────────
481pub mod styling {
482    use anstyle::{AnsiColor, Color, RgbColor};
483
484    #[derive(Debug, Clone)]
485    pub struct ColorPalette {
486        pub primary: Color,
487        pub secondary: Color,
488        pub background: Color,
489        pub foreground: Color,
490        pub error: Color,
491        pub warning: Color,
492        pub success: Color,
493    }
494
495    impl Default for ColorPalette {
496        fn default() -> Self {
497            Self {
498                primary: Color::Ansi(AnsiColor::Blue),
499                secondary: Color::Ansi(AnsiColor::Cyan),
500                background: Color::Rgb(RgbColor(30, 30, 30)),
501                foreground: Color::Ansi(AnsiColor::White),
502                error: Color::Ansi(AnsiColor::Red),
503                warning: Color::Ansi(AnsiColor::Yellow),
504                success: Color::Ansi(AnsiColor::Green),
505            }
506        }
507    }
508
509    /// Color palette for diff rendering.
510    #[derive(Debug, Clone)]
511    pub struct DiffColorPalette {
512        pub addition_fg: Color,
513        pub addition_bg: Color,
514        pub deletion_fg: Color,
515        pub deletion_bg: Color,
516        pub hunk_header: Color,
517        pub context: Color,
518    }
519
520    impl Default for DiffColorPalette {
521        fn default() -> Self {
522            Self {
523                addition_fg: Color::Rgb(RgbColor(0x50, 0xFA, 0x7B)),
524                addition_bg: Color::Rgb(RgbColor(0x1B, 0x3B, 0x20)),
525                deletion_fg: Color::Rgb(RgbColor(0xFF, 0x55, 0x55)),
526                deletion_bg: Color::Rgb(RgbColor(0x3B, 0x1B, 0x1B)),
527                hunk_header: Color::Ansi(AnsiColor::Cyan),
528                context: Color::Rgb(RgbColor(128, 128, 128)),
529            }
530        }
531    }
532}
533
534// ── fs utilities ───────────────────────────────────────────────────────────
535pub mod fs {
536    use std::path::Path;
537
538    pub fn read_file_with_context_sync(
539        path: &Path,
540        _context_lines: usize,
541    ) -> anyhow::Result<String> {
542        Ok(std::fs::read_to_string(path)?)
543    }
544
545    pub fn write_file_with_context_sync(path: &Path, _content: &str) -> anyhow::Result<()> {
546        if let Some(parent) = path.parent() {
547            std::fs::create_dir_all(parent)?;
548        }
549        std::fs::write(path, _content)?;
550        Ok(())
551    }
552
553    pub fn is_image_path(_path: &str) -> bool {
554        false
555    }
556
557    pub fn trim_trailing_image_path_str(_s: &str) -> String {
558        _s.to_string()
559    }
560
561    pub fn unescape_whitespace(s: &str) -> String {
562        s.replace("\\n", "\n").replace("\\t", "\t")
563    }
564}
565
566// ── lr_map ─────────────────────────────────────────────────────────────────
567pub mod lr_map {
568    /// Minimal Left-Right Map — a concurrent lock-free map with two copies
569    /// (one for writes, one for reads), swapped atomically.
570    pub struct LrMap<'a, K, V> {
571        _phantom: std::marker::PhantomData<&'a (K, V)>,
572    }
573
574    impl<'a, K, V> LrMap<'a, K, V> {
575        pub fn new() -> Self {
576            Self {
577                _phantom: std::marker::PhantomData,
578            }
579        }
580        pub fn insert(&self, _key: K, _value: V) {}
581        pub fn refresh(&self) {}
582    }
583    impl<'a, K, V> LrMap<'a, K, V> {
584        pub fn get(&self, _key: &K) -> Option<&V> {
585            None
586        }
587    }
588
589    impl<'a, K, V> Default for LrMap<'a, K, V> {
590        fn default() -> Self {
591            Self::new()
592        }
593    }
594
595    impl<'a, K, V> Clone for LrMap<'a, K, V> {
596        fn clone(&self) -> Self {
597            Self {
598                _phantom: std::marker::PhantomData,
599            }
600        }
601    }
602}
603
604// ── preview ────────────────────────────────────────────────────────────────
605pub mod preview;
606
607// ── Re-exports needed by vendored vtcode-ui ────────────────────────────────
608pub use colors::blend_colors;
609pub use editor::{EditorPoint, EditorTarget, normalize_editor_hash_fragment, parse_editor_target};
610pub use stop_hints::STOP_HINT_COMPACT;
611pub use styling::DiffColorPalette;