vtcode_tui/core_tui/
style.rs1use anstyle::{AnsiColor, Color as AnsiColorEnum, Effects, RgbColor, Style as AnsiStyle};
2use ratatui::style::{Color, Modifier, Style};
3use unicode_width::UnicodeWidthStr;
4
5use crate::ui::theme;
6
7use super::types::{InlineTextStyle, InlineTheme};
8
9fn convert_ansi_color(color: AnsiColorEnum) -> Option<AnsiColorEnum> {
10 Some(match color {
11 AnsiColorEnum::Ansi(ansi) => AnsiColorEnum::Ansi(ansi),
12 AnsiColorEnum::Ansi256(value) => AnsiColorEnum::Ansi256(value),
13 AnsiColorEnum::Rgb(rgb) => AnsiColorEnum::Rgb(rgb),
14 })
15}
16
17fn convert_style_color(style: &AnsiStyle) -> Option<AnsiColorEnum> {
18 style.get_fg_color().and_then(convert_ansi_color)
19}
20
21fn convert_style_bg_color(style: &AnsiStyle) -> Option<AnsiColorEnum> {
22 style.get_bg_color().and_then(convert_ansi_color)
23}
24
25pub fn convert_style(style: AnsiStyle) -> InlineTextStyle {
26 InlineTextStyle {
27 color: convert_style_color(&style),
28 bg_color: convert_style_bg_color(&style),
29 effects: style.get_effects(),
30 }
31}
32
33pub fn theme_from_styles(styles: &theme::ThemeStyles) -> InlineTheme {
34 InlineTheme {
35 foreground: convert_ansi_color(styles.foreground),
36 background: convert_ansi_color(styles.background),
37 primary: convert_style_color(&styles.primary),
38 secondary: convert_style_color(&styles.secondary),
39 tool_accent: convert_style_color(&styles.tool),
40 tool_body: convert_style_color(&styles.tool_detail),
41 pty_body: convert_style_color(&styles.pty_output),
42 }
43}
44
45pub fn measure_text_width(text: &str) -> u16 {
46 UnicodeWidthStr::width(text) as u16
47}
48
49pub fn ratatui_color_from_ansi(color: AnsiColorEnum) -> Color {
50 match color {
51 AnsiColorEnum::Ansi(base) => match base {
52 AnsiColor::Black => Color::Black,
53 AnsiColor::Red => Color::Red,
54 AnsiColor::Green => Color::Green,
55 AnsiColor::Yellow => Color::Yellow,
56 AnsiColor::Blue => Color::Blue,
57 AnsiColor::Magenta => Color::DarkGray,
58 AnsiColor::Cyan => Color::Cyan,
59 AnsiColor::White => Color::White,
60 AnsiColor::BrightBlack => Color::DarkGray,
61 AnsiColor::BrightRed => Color::Red,
62 AnsiColor::BrightGreen => Color::Green,
63 AnsiColor::BrightYellow => Color::Yellow,
64 AnsiColor::BrightBlue => Color::Blue,
65 AnsiColor::BrightMagenta => Color::DarkGray,
66 AnsiColor::BrightCyan => Color::Cyan,
67 AnsiColor::BrightWhite => Color::Gray,
68 },
69 AnsiColorEnum::Ansi256(value) => Color::Indexed(value.index()),
70 AnsiColorEnum::Rgb(RgbColor(red, green, blue)) => Color::Rgb(red, green, blue),
71 }
72}
73
74pub fn ratatui_style_from_inline(
75 style: &InlineTextStyle,
76 fallback: Option<AnsiColorEnum>,
77) -> Style {
78 let mut resolved = Style::default();
79
80 if let Some(color) = style.color.or(fallback) {
82 resolved = resolved.fg(ratatui_color_from_ansi(color));
83 }
84
85 if let Some(color) = style.bg_color {
87 resolved = resolved.bg(ratatui_color_from_ansi(color));
88 }
89
90 if style.effects.contains(Effects::BOLD) {
92 resolved = resolved.add_modifier(Modifier::BOLD);
93 }
94 if style.effects.contains(Effects::ITALIC) {
95 resolved = resolved.add_modifier(Modifier::ITALIC);
96 }
97 if style.effects.contains(Effects::UNDERLINE) {
98 resolved = resolved.add_modifier(Modifier::UNDERLINED);
99 }
100 if style.effects.contains(Effects::DIMMED) {
101 resolved = resolved.add_modifier(Modifier::DIM);
102 }
103
104 resolved
105}
106
107pub fn ratatui_style_from_ansi(style: AnsiStyle) -> Style {
112 let inline = convert_style(style);
113 ratatui_style_from_inline(&inline, None)
114}