vtcode_commons/
styling.rs1use crate::ansi_codes::RESET;
4use crate::color_policy;
5use anstyle::{AnsiColor, Color, Effects, RgbColor, 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::Rgb(RgbColor(10, 24, 10)),
124 removed_fg: Color::Ansi(AnsiColor::Red),
125 removed_bg: Color::Rgb(RgbColor(24, 10, 10)),
126 header_fg: Color::Ansi(AnsiColor::Cyan),
127 header_bg: Color::Rgb(RgbColor(10, 16, 20)),
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};