vtcode_commons/
styling.rs1use crate::color_policy;
4use anstyle::{AnsiColor, Color, Effects, RgbColor, Style};
5
6#[derive(Debug, Clone, Copy)]
8pub struct ColorPalette {
9 pub success: Color, pub error: Color, pub warning: Color, pub info: Color, pub accent: Color, pub primary: Color, pub muted: Color, }
17
18impl Default for ColorPalette {
19 fn default() -> Self {
20 Self {
21 success: Color::Ansi(AnsiColor::Green),
22 error: Color::Ansi(AnsiColor::Red),
23 warning: Color::Ansi(AnsiColor::Red),
24 info: Color::Ansi(AnsiColor::Cyan),
25 accent: Color::Ansi(AnsiColor::Magenta),
26 primary: Color::Ansi(AnsiColor::Cyan),
27 muted: Color::Ansi(AnsiColor::BrightBlack),
28 }
29 }
30}
31
32pub fn render_styled(text: &str, color: Color, effects: Option<String>) -> String {
34 let mut style = Style::new();
35 if color_policy::color_output_enabled() {
36 style = style.fg_color(Some(color));
37 }
38
39 if let Some(effects_str) = effects {
40 let mut ansi_effects = Effects::new();
41
42 for effect in effects_str.split(',') {
43 let effect = effect.trim().to_lowercase();
44 match effect.as_str() {
45 "bold" => ansi_effects |= Effects::BOLD,
46 "dim" | "dimmed" => ansi_effects |= Effects::DIMMED,
47 "italic" => ansi_effects |= Effects::ITALIC,
48 "underline" => ansi_effects |= Effects::UNDERLINE,
49 "blink" => ansi_effects |= Effects::BLINK,
50 "invert" | "reversed" => ansi_effects |= Effects::INVERT,
51 "hidden" => ansi_effects |= Effects::HIDDEN,
52 "strikethrough" => ansi_effects |= Effects::STRIKETHROUGH,
53 _ => {}
54 }
55 }
56
57 style = style.effects(ansi_effects);
58 }
59
60 let prefix = style.to_string();
61 if prefix.is_empty() {
62 text.to_string()
63 } else {
64 format!("{}{}{}", prefix, text, "\x1b[0m")
65 }
66}
67
68pub fn style_from_color_name(name: &str) -> Style {
70 let (color_name, dimmed) = if let Some(idx) = name.find(':') {
71 let (color, modifier) = name.split_at(idx);
72 (color, modifier.strip_prefix(':').unwrap_or(""))
73 } else {
74 (name, "")
75 };
76
77 let color = match color_name.to_lowercase().as_str() {
78 "red" => Color::Ansi(AnsiColor::Red),
79 "green" => Color::Ansi(AnsiColor::Green),
80 "blue" => Color::Ansi(AnsiColor::Blue),
81 "yellow" => Color::Ansi(AnsiColor::Yellow),
82 "cyan" => Color::Ansi(AnsiColor::Cyan),
83 "magenta" | "purple" => Color::Ansi(AnsiColor::Magenta),
84 "white" => Color::Ansi(AnsiColor::White),
85 "black" => Color::Ansi(AnsiColor::Black),
86 _ => return Style::new(),
87 };
88
89 let mut style = Style::new().fg_color(Some(color));
90 if dimmed.eq_ignore_ascii_case("dimmed") {
91 style = style.dimmed();
92 }
93 style
94}
95
96pub fn bold_color(color: AnsiColor) -> Style {
98 Style::new().bold().fg_color(Some(Color::Ansi(color)))
99}
100
101pub fn dimmed_color(color: AnsiColor) -> Style {
103 Style::new().dimmed().fg_color(Some(Color::Ansi(color)))
104}
105
106#[derive(Debug, Clone, Copy)]
109pub struct DiffColorPalette {
110 pub added_fg: Color,
111 pub added_bg: Color,
112 pub removed_fg: Color,
113 pub removed_bg: Color,
114 pub header_fg: Color,
115 pub header_bg: Color,
116}
117
118impl Default for DiffColorPalette {
119 fn default() -> Self {
120 Self {
121 added_fg: Color::Ansi(AnsiColor::Green),
122 added_bg: Color::Rgb(RgbColor(10, 24, 10)),
123 removed_fg: Color::Ansi(AnsiColor::Red),
124 removed_bg: Color::Rgb(RgbColor(24, 10, 10)),
125 header_fg: Color::Ansi(AnsiColor::Cyan),
126 header_bg: Color::Rgb(RgbColor(10, 16, 20)),
127 }
128 }
129}
130
131impl DiffColorPalette {
132 pub fn added_style(&self) -> Style {
133 Style::new().fg_color(Some(self.added_fg))
134 }
135
136 pub fn removed_style(&self) -> Style {
137 Style::new().fg_color(Some(self.removed_fg))
138 }
139
140 pub fn header_style(&self) -> Style {
141 Style::new().fg_color(Some(self.header_fg))
142 }
143}
144
145pub use crate::diff_theme::{
147 DiffColorLevel, DiffTheme, diff_add_bg, diff_del_bg, diff_gutter_bg_add_light,
148 diff_gutter_bg_del_light, diff_gutter_fg_light,
149};