1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
6pub enum Color {
7 #[default]
8 Reset,
9 Black,
10 Red,
11 Green,
12 Yellow,
13 Blue,
14 Magenta,
15 Cyan,
16 Gray,
17 DarkGray,
18 LightRed,
19 LightGreen,
20 LightYellow,
21 LightBlue,
22 LightMagenta,
23 LightCyan,
24 White,
25 Indexed(u8),
27 Rgb(u8, u8, u8),
29}
30
31impl fmt::Display for Color {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 match self {
34 Self::Rgb(r, g, b) => write!(f, "#{r:02X}{g:02X}{b:02X}"),
35 Self::Indexed(i) => write!(f, "color({i})"),
36 other => write!(f, "{other:?}"),
37 }
38 }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
43pub struct Modifier(u16);
44
45impl Modifier {
46 pub const NONE: Self = Self(0);
47 pub const BOLD: Self = Self(1 << 0);
48 pub const DIM: Self = Self(1 << 1);
49 pub const ITALIC: Self = Self(1 << 2);
50 pub const UNDERLINED: Self = Self(1 << 3);
51 pub const SLOW_BLINK: Self = Self(1 << 4);
52 pub const RAPID_BLINK: Self = Self(1 << 5);
53 pub const REVERSED: Self = Self(1 << 6);
54 pub const HIDDEN: Self = Self(1 << 7);
55 pub const CROSSED_OUT: Self = Self(1 << 8);
56 pub const DOUBLE_UNDERLINED: Self = Self(1 << 9);
57 pub const UNDERCURLED: Self = Self(1 << 10);
58 pub const UNDERDOTTED: Self = Self(1 << 11);
59 pub const UNDERDASHED: Self = Self(1 << 12);
60 pub const OVERLINED: Self = Self(1 << 13);
61 pub const SUPERSCRIPT: Self = Self(1 << 14);
62 pub const SUBSCRIPT: Self = Self(1 << 15);
63
64 pub const fn empty() -> Self {
65 Self(0)
66 }
67
68 pub const fn contains(self, other: Self) -> bool {
69 self.0 & other.0 == other.0
70 }
71
72 pub const fn union(self, other: Self) -> Self {
73 Self(self.0 | other.0)
74 }
75
76 pub const fn difference(self, other: Self) -> Self {
77 Self(self.0 & !other.0)
78 }
79
80 pub const fn is_empty(self) -> bool {
81 self.0 == 0
82 }
83}
84
85impl std::ops::BitOr for Modifier {
86 type Output = Self;
87 fn bitor(self, rhs: Self) -> Self::Output {
88 Self(self.0 | rhs.0)
89 }
90}
91
92impl std::ops::BitAnd for Modifier {
93 type Output = Self;
94 fn bitand(self, rhs: Self) -> Self::Output {
95 Self(self.0 & rhs.0)
96 }
97}
98
99impl std::ops::Not for Modifier {
100 type Output = Self;
101 fn not(self) -> Self::Output {
102 Self(!self.0)
103 }
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
108pub struct Style {
109 pub fg: Option<Color>,
110 pub bg: Option<Color>,
111 pub underline_color: Option<Color>,
112 pub add_modifier: Modifier,
113 pub sub_modifier: Modifier,
114}
115
116impl Style {
117 pub const fn new() -> Self {
118 Self {
119 fg: None,
120 bg: None,
121 underline_color: None,
122 add_modifier: Modifier::NONE,
123 sub_modifier: Modifier::NONE,
124 }
125 }
126
127 pub const fn reset() -> Self {
129 Self {
130 fg: Some(Color::Reset),
131 bg: Some(Color::Reset),
132 underline_color: Some(Color::Reset),
133 add_modifier: Modifier::NONE,
134 sub_modifier: Modifier::NONE,
135 }
136 }
137
138 pub const fn fg(mut self, color: Color) -> Self {
139 self.fg = Some(color);
140 self
141 }
142
143 pub const fn bg(mut self, color: Color) -> Self {
144 self.bg = Some(color);
145 self
146 }
147
148 pub const fn underline_color(mut self, color: Color) -> Self {
149 self.underline_color = Some(color);
150 self
151 }
152
153 pub const fn bold(mut self) -> Self {
154 self.add_modifier = self.add_modifier.union(Modifier::BOLD);
155 self
156 }
157
158 pub const fn dim(mut self) -> Self {
159 self.add_modifier = self.add_modifier.union(Modifier::DIM);
160 self
161 }
162
163 pub const fn italic(mut self) -> Self {
164 self.add_modifier = self.add_modifier.union(Modifier::ITALIC);
165 self
166 }
167
168 pub const fn underlined(mut self) -> Self {
169 self.add_modifier = self.add_modifier.union(Modifier::UNDERLINED);
170 self
171 }
172
173 pub const fn reversed(mut self) -> Self {
174 self.add_modifier = self.add_modifier.union(Modifier::REVERSED);
175 self
176 }
177
178 pub const fn crossed_out(mut self) -> Self {
179 self.add_modifier = self.add_modifier.union(Modifier::CROSSED_OUT);
180 self
181 }
182
183 pub const fn hidden(mut self) -> Self {
184 self.add_modifier = self.add_modifier.union(Modifier::HIDDEN);
185 self
186 }
187
188 pub const fn slow_blink(mut self) -> Self {
189 self.add_modifier = self.add_modifier.union(Modifier::SLOW_BLINK);
190 self
191 }
192
193 pub const fn rapid_blink(mut self) -> Self {
194 self.add_modifier = self.add_modifier.union(Modifier::RAPID_BLINK);
195 self
196 }
197
198 pub const fn overlined(mut self) -> Self {
199 self.add_modifier = self.add_modifier.union(Modifier::OVERLINED);
200 self
201 }
202
203 pub const fn not_bold(mut self) -> Self {
204 self.sub_modifier = self.sub_modifier.union(Modifier::BOLD);
205 self
206 }
207
208 pub const fn not_italic(mut self) -> Self {
209 self.sub_modifier = self.sub_modifier.union(Modifier::ITALIC);
210 self
211 }
212
213 pub const fn not_underlined(mut self) -> Self {
214 self.sub_modifier = self.sub_modifier.union(Modifier::UNDERLINED);
215 self
216 }
217
218 pub fn patch(mut self, other: Style) -> Self {
221 if other.fg.is_some() {
222 self.fg = other.fg;
223 }
224 if other.bg.is_some() {
225 self.bg = other.bg;
226 }
227 if other.underline_color.is_some() {
228 self.underline_color = other.underline_color;
229 }
230 self.add_modifier = self
231 .add_modifier
232 .difference(other.sub_modifier)
233 .union(other.add_modifier);
234 self.sub_modifier = self
235 .sub_modifier
236 .difference(other.add_modifier)
237 .union(other.sub_modifier);
238 self
239 }
240}
241
242pub trait Stylize: Sized {
249 fn style(self, style: Style) -> Self;
250
251 fn red(self) -> Self {
252 self.style(Style::new().fg(Color::Red))
253 }
254 fn green(self) -> Self {
255 self.style(Style::new().fg(Color::Green))
256 }
257 fn yellow(self) -> Self {
258 self.style(Style::new().fg(Color::Yellow))
259 }
260 fn blue(self) -> Self {
261 self.style(Style::new().fg(Color::Blue))
262 }
263 fn magenta(self) -> Self {
264 self.style(Style::new().fg(Color::Magenta))
265 }
266 fn cyan(self) -> Self {
267 self.style(Style::new().fg(Color::Cyan))
268 }
269 fn white(self) -> Self {
270 self.style(Style::new().fg(Color::White))
271 }
272 fn gray(self) -> Self {
273 self.style(Style::new().fg(Color::Gray))
274 }
275
276 fn on_red(self) -> Self {
277 self.style(Style::new().bg(Color::Red))
278 }
279 fn on_green(self) -> Self {
280 self.style(Style::new().bg(Color::Green))
281 }
282 fn on_yellow(self) -> Self {
283 self.style(Style::new().bg(Color::Yellow))
284 }
285 fn on_blue(self) -> Self {
286 self.style(Style::new().bg(Color::Blue))
287 }
288 fn on_magenta(self) -> Self {
289 self.style(Style::new().bg(Color::Magenta))
290 }
291 fn on_cyan(self) -> Self {
292 self.style(Style::new().bg(Color::Cyan))
293 }
294 fn on_white(self) -> Self {
295 self.style(Style::new().bg(Color::White))
296 }
297
298 fn bold(self) -> Self {
299 self.style(Style::new().bold())
300 }
301 fn dim(self) -> Self {
302 self.style(Style::new().dim())
303 }
304 fn italic(self) -> Self {
305 self.style(Style::new().italic())
306 }
307 fn underlined(self) -> Self {
308 self.style(Style::new().underlined())
309 }
310 fn reversed(self) -> Self {
311 self.style(Style::new().reversed())
312 }
313 fn crossed_out(self) -> Self {
314 self.style(Style::new().crossed_out())
315 }
316}
317
318impl Stylize for Style {
319 fn style(self, other: Style) -> Self {
320 self.patch(other)
321 }
322}