vtcode_commons/
styling.rs1use crate::ansi_codes::RESET;
4use crate::color_policy;
5use anstyle::{AnsiColor, Color, Effects, Style};
6
7#[derive(Debug, Clone, Copy)]
9pub struct ColorPalette {
10 pub success: Color, pub error: Color, pub warning: Color, pub info: Color, pub accent: Color, pub primary: Color, pub muted: Color, }
18
19impl Default for ColorPalette {
20 fn default() -> Self {
21 Self {
22 success: Color::Ansi(AnsiColor::Green),
23 error: Color::Ansi(AnsiColor::Red),
24 warning: Color::Ansi(AnsiColor::Red),
25 info: Color::Ansi(AnsiColor::Cyan),
26 accent: Color::Ansi(AnsiColor::Magenta),
27 primary: Color::Ansi(AnsiColor::Cyan),
28 muted: Color::Ansi(AnsiColor::BrightBlack),
29 }
30 }
31}
32
33pub fn render_styled(text: &str, color: Color, effects: Option<String>) -> String {
35 let mut style = Style::new();
36 if color_policy::color_output_enabled() {
37 style = style.fg_color(Some(color));
38 }
39
40 if let Some(effects_str) = effects {
41 let mut ansi_effects = Effects::new();
42
43 for effect in effects_str.split(',') {
44 let effect = effect.trim().to_lowercase();
45 match effect.as_str() {
46 "bold" => ansi_effects |= Effects::BOLD,
47 "dim" | "dimmed" => ansi_effects |= Effects::DIMMED,
48 "italic" => ansi_effects |= Effects::ITALIC,
49 "underline" => ansi_effects |= Effects::UNDERLINE,
50 "blink" => ansi_effects |= Effects::BLINK,
51 "invert" | "reversed" => ansi_effects |= Effects::INVERT,
52 "hidden" => ansi_effects |= Effects::HIDDEN,
53 "strikethrough" => ansi_effects |= Effects::STRIKETHROUGH,
54 _ => {}
55 }
56 }
57
58 style = style.effects(ansi_effects);
59 }
60
61 let prefix = style.to_string();
62 if prefix.is_empty() {
63 text.to_string()
64 } else {
65 format!("{prefix}{text}{RESET}")
66 }
67}
68
69pub fn style_from_color_name(name: &str) -> Style {
71 let (color_name, dimmed) = if let Some(idx) = name.find(':') {
72 let (color, modifier) = name.split_at(idx);
73 (color, modifier.strip_prefix(':').unwrap_or(""))
74 } else {
75 (name, "")
76 };
77
78 let color = match color_name.to_lowercase().as_str() {
79 "red" => Color::Ansi(AnsiColor::Red),
80 "green" => Color::Ansi(AnsiColor::Green),
81 "blue" => Color::Ansi(AnsiColor::Blue),
82 "yellow" => Color::Ansi(AnsiColor::Yellow),
83 "cyan" => Color::Ansi(AnsiColor::Cyan),
84 "magenta" | "purple" => Color::Ansi(AnsiColor::Magenta),
85 "white" => Color::Ansi(AnsiColor::White),
86 "black" => Color::Ansi(AnsiColor::Black),
87 _ => return Style::new(),
88 };
89
90 let mut style = Style::new().fg_color(Some(color));
91 if dimmed.eq_ignore_ascii_case("dimmed") {
92 style = style.dimmed();
93 }
94 style
95}
96
97pub fn bold_color(color: AnsiColor) -> Style {
99 Style::new().bold().fg_color(Some(Color::Ansi(color)))
100}
101
102pub fn dimmed_color(color: AnsiColor) -> Style {
104 Style::new().dimmed().fg_color(Some(Color::Ansi(color)))
105}
106
107#[derive(Debug, Clone, Copy)]
110pub struct DiffColorPalette {
111 pub added_fg: Color,
112 pub added_bg: Color,
113 pub removed_fg: Color,
114 pub removed_bg: Color,
115 pub header_fg: Color,
116 pub header_bg: Color,
117}
118
119impl Default for DiffColorPalette {
120 fn default() -> Self {
121 Self {
122 added_fg: Color::Ansi(AnsiColor::Green),
123 added_bg: Color::Ansi(AnsiColor::Green),
124 removed_fg: Color::Ansi(AnsiColor::Red),
125 removed_bg: Color::Ansi(AnsiColor::Red),
126 header_fg: Color::Ansi(AnsiColor::Cyan),
127 header_bg: Color::Ansi(AnsiColor::Cyan),
128 }
129 }
130}
131
132impl DiffColorPalette {
133 pub fn added_style(&self) -> Style {
134 Style::new().fg_color(Some(self.added_fg))
135 }
136
137 pub fn removed_style(&self) -> Style {
138 Style::new().fg_color(Some(self.removed_fg))
139 }
140
141 pub fn header_style(&self) -> Style {
142 Style::new().fg_color(Some(self.header_fg))
143 }
144}
145
146pub use crate::diff_theme::{
148 DiffColorLevel, DiffTheme, diff_add_bg, diff_del_bg, diff_gutter_bg_add_light,
149 diff_gutter_bg_del_light, diff_gutter_fg_light,
150};
151
152pub struct Styles;
157
158impl Styles {
159 pub fn error() -> Style {
161 Style::new().fg_color(Some(Color::Ansi(AnsiColor::Red)))
162 }
163
164 pub fn warning() -> Style {
166 Style::new().fg_color(Some(Color::Ansi(AnsiColor::Red)))
167 }
168
169 pub fn success() -> Style {
171 Style::new().fg_color(Some(Color::Ansi(AnsiColor::Green)))
172 }
173
174 pub fn info() -> Style {
176 Style::new().fg_color(Some(Color::Ansi(AnsiColor::Cyan)))
177 }
178
179 pub fn debug() -> Style {
181 Style::new()
182 .fg_color(Some(Color::Ansi(AnsiColor::Cyan)))
183 .dimmed()
184 }
185
186 pub fn bold() -> Style {
188 Style::new().effects(Effects::BOLD)
189 }
190
191 pub fn bold_error() -> Style {
193 Self::error().bold()
194 }
195
196 pub fn bold_success() -> Style {
198 Self::success().bold()
199 }
200
201 pub fn bold_warning() -> Style {
203 Self::warning().bold()
204 }
205
206 pub fn header() -> Style {
208 Style::new().effects(Effects::BOLD)
209 }
210
211 pub fn code() -> Style {
213 Style::new().fg_color(Some(Color::Ansi(AnsiColor::Magenta)))
214 }
215
216 pub fn render(style: &Style) -> String {
218 style.to_string()
219 }
220
221 pub fn render_reset() -> String {
223 anstyle::Reset.to_string()
224 }
225}