1use std::{fmt::Display, io};
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11pub struct Styled<T: ?Sized> {
12 fg: Option<Color>,
13 bg: Option<Color>,
14 attributes: Attributes,
15 content: T,
16}
17
18impl<T: Display> Styled<T> {
19 pub fn new(content: T) -> Self {
21 Self {
22 fg: None,
23 bg: None,
24 attributes: Attributes::empty(),
25 content,
26 }
27 }
28}
29
30impl<T: Display + ?Sized> Styled<T> {
31 pub(super) fn write<B: crate::backend::DisplayBackend + ?Sized>(
32 &self,
33 backend: &mut B,
34 ) -> io::Result<()> {
35 if let Some(fg) = self.fg {
36 backend.set_fg(fg)?;
37 }
38 if let Some(bg) = self.bg {
39 backend.set_bg(bg)?;
40 }
41 if !self.attributes.is_empty() {
42 backend.set_attributes(self.attributes)?;
43 }
44
45 write!(backend, "{}", &self.content)?;
46
47 if self.fg.is_some() {
48 backend.set_fg(Color::Reset)?;
49 }
50 if self.bg.is_some() {
51 backend.set_bg(Color::Reset)?;
52 }
53 if !self.attributes.is_empty() {
54 backend.set_attributes(Attributes::empty())?;
55 }
56 Ok(())
57 }
58}
59
60impl<T: Display> From<T> for Styled<T> {
61 fn from(content: T) -> Self {
62 Self::new(content)
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
69#[allow(missing_docs)]
70pub enum Color {
71 Reset,
72 Black,
73 Red,
74 Green,
75 Yellow,
76 Blue,
77 Magenta,
78 Cyan,
79 Grey,
80 DarkGrey,
81 LightRed,
82 LightGreen,
83 LightYellow,
84 LightBlue,
85 LightMagenta,
86 LightCyan,
87 White,
88 Rgb(u8, u8, u8),
89 Ansi(u8),
90}
91
92bitflags::bitflags! {
93 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
95 pub struct Attributes: u16 {
96 const BOLD = 0b0000_0000_0001;
98 const DIM = 0b0000_0000_0010;
100 const ITALIC = 0b0000_0000_0100;
102 const UNDERLINED = 0b0000_0000_1000;
104 const SLOW_BLINK = 0b0000_0001_0000;
106 const RAPID_BLINK = 0b0000_0010_0000;
108 const REVERSED = 0b0000_0100_0000;
110 const HIDDEN = 0b0000_1000_0000;
112 const CROSSED_OUT = 0b0001_0000_0000;
114 }
115}
116
117impl Attributes {
118 pub fn diff(self, to: Attributes) -> AttributeDiff {
121 let diff = self ^ to;
122 AttributeDiff {
123 to_remove: diff & self,
124 to_add: diff & to,
125 }
126 }
127}
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
131#[allow(missing_docs)]
132pub struct AttributeDiff {
133 pub to_add: Attributes,
134 pub to_remove: Attributes,
135}
136
137#[allow(missing_docs)]
148pub trait Stylize<T> {
149 fn black(self) -> Styled<T>;
150 fn dark_grey(self) -> Styled<T>;
151 fn light_red(self) -> Styled<T>;
152 fn red(self) -> Styled<T>;
153 fn light_green(self) -> Styled<T>;
154 fn green(self) -> Styled<T>;
155 fn light_yellow(self) -> Styled<T>;
156 fn yellow(self) -> Styled<T>;
157 fn light_blue(self) -> Styled<T>;
158 fn blue(self) -> Styled<T>;
159 fn light_magenta(self) -> Styled<T>;
160 fn magenta(self) -> Styled<T>;
161 fn light_cyan(self) -> Styled<T>;
162 fn cyan(self) -> Styled<T>;
163 fn white(self) -> Styled<T>;
164 fn grey(self) -> Styled<T>;
165 fn rgb(self, r: u8, g: u8, b: u8) -> Styled<T>;
166 fn ansi(self, ansi: u8) -> Styled<T>;
167
168 fn on_black(self) -> Styled<T>;
169 fn on_dark_grey(self) -> Styled<T>;
170 fn on_light_red(self) -> Styled<T>;
171 fn on_red(self) -> Styled<T>;
172 fn on_light_green(self) -> Styled<T>;
173 fn on_green(self) -> Styled<T>;
174 fn on_light_yellow(self) -> Styled<T>;
175 fn on_yellow(self) -> Styled<T>;
176 fn on_light_blue(self) -> Styled<T>;
177 fn on_blue(self) -> Styled<T>;
178 fn on_light_magenta(self) -> Styled<T>;
179 fn on_magenta(self) -> Styled<T>;
180 fn on_light_cyan(self) -> Styled<T>;
181 fn on_cyan(self) -> Styled<T>;
182 fn on_white(self) -> Styled<T>;
183 fn on_grey(self) -> Styled<T>;
184 fn on_rgb(self, r: u8, g: u8, b: u8) -> Styled<T>;
185 fn on_ansi(self, ansi: u8) -> Styled<T>;
186
187 fn bold(self) -> Styled<T>;
188 fn underlined(self) -> Styled<T>;
189 fn reverse(self) -> Styled<T>;
190 fn dim(self) -> Styled<T>;
191 fn italic(self) -> Styled<T>;
192 fn slow_blink(self) -> Styled<T>;
193 fn rapid_blink(self) -> Styled<T>;
194 fn hidden(self) -> Styled<T>;
195 fn crossed_out(self) -> Styled<T>;
196}
197
198impl<T, I: Into<Styled<T>>> Stylize<T> for I {
199 fn black(self) -> Styled<T> {
200 let mut styled = self.into();
201 styled.fg = Some(Color::Black);
202 styled
203 }
204 fn dark_grey(self) -> Styled<T> {
205 let mut styled = self.into();
206 styled.fg = Some(Color::DarkGrey);
207 styled
208 }
209 fn light_red(self) -> Styled<T> {
210 let mut styled = self.into();
211 styled.fg = Some(Color::LightRed);
212 styled
213 }
214 fn red(self) -> Styled<T> {
215 let mut styled = self.into();
216 styled.fg = Some(Color::Red);
217 styled
218 }
219 fn light_green(self) -> Styled<T> {
220 let mut styled = self.into();
221 styled.fg = Some(Color::LightGreen);
222 styled
223 }
224 fn green(self) -> Styled<T> {
225 let mut styled = self.into();
226 styled.fg = Some(Color::Green);
227 styled
228 }
229 fn light_yellow(self) -> Styled<T> {
230 let mut styled = self.into();
231 styled.fg = Some(Color::LightYellow);
232 styled
233 }
234 fn yellow(self) -> Styled<T> {
235 let mut styled = self.into();
236 styled.fg = Some(Color::Yellow);
237 styled
238 }
239 fn light_blue(self) -> Styled<T> {
240 let mut styled = self.into();
241 styled.fg = Some(Color::LightBlue);
242 styled
243 }
244 fn blue(self) -> Styled<T> {
245 let mut styled = self.into();
246 styled.fg = Some(Color::Blue);
247 styled
248 }
249 fn light_magenta(self) -> Styled<T> {
250 let mut styled = self.into();
251 styled.fg = Some(Color::LightMagenta);
252 styled
253 }
254 fn magenta(self) -> Styled<T> {
255 let mut styled = self.into();
256 styled.fg = Some(Color::Magenta);
257 styled
258 }
259 fn light_cyan(self) -> Styled<T> {
260 let mut styled = self.into();
261 styled.fg = Some(Color::LightCyan);
262 styled
263 }
264 fn cyan(self) -> Styled<T> {
265 let mut styled = self.into();
266 styled.fg = Some(Color::Cyan);
267 styled
268 }
269 fn white(self) -> Styled<T> {
270 let mut styled = self.into();
271 styled.fg = Some(Color::White);
272 styled
273 }
274 fn grey(self) -> Styled<T> {
275 let mut styled = self.into();
276 styled.fg = Some(Color::Grey);
277 styled
278 }
279 fn rgb(self, r: u8, g: u8, b: u8) -> Styled<T> {
280 let mut styled = self.into();
281 styled.fg = Some(Color::Rgb(r, g, b));
282 styled
283 }
284 fn ansi(self, ansi: u8) -> Styled<T> {
285 let mut styled = self.into();
286 styled.fg = Some(Color::Ansi(ansi));
287 styled
288 }
289
290 fn on_black(self) -> Styled<T> {
291 let mut styled = self.into();
292 styled.bg = Some(Color::Black);
293 styled
294 }
295 fn on_dark_grey(self) -> Styled<T> {
296 let mut styled = self.into();
297 styled.bg = Some(Color::DarkGrey);
298 styled
299 }
300 fn on_light_red(self) -> Styled<T> {
301 let mut styled = self.into();
302 styled.bg = Some(Color::LightRed);
303 styled
304 }
305 fn on_red(self) -> Styled<T> {
306 let mut styled = self.into();
307 styled.bg = Some(Color::Red);
308 styled
309 }
310 fn on_light_green(self) -> Styled<T> {
311 let mut styled = self.into();
312 styled.bg = Some(Color::LightGreen);
313 styled
314 }
315 fn on_green(self) -> Styled<T> {
316 let mut styled = self.into();
317 styled.bg = Some(Color::Green);
318 styled
319 }
320 fn on_light_yellow(self) -> Styled<T> {
321 let mut styled = self.into();
322 styled.bg = Some(Color::LightYellow);
323 styled
324 }
325 fn on_yellow(self) -> Styled<T> {
326 let mut styled = self.into();
327 styled.bg = Some(Color::Yellow);
328 styled
329 }
330 fn on_light_blue(self) -> Styled<T> {
331 let mut styled = self.into();
332 styled.bg = Some(Color::LightBlue);
333 styled
334 }
335 fn on_blue(self) -> Styled<T> {
336 let mut styled = self.into();
337 styled.bg = Some(Color::Blue);
338 styled
339 }
340 fn on_light_magenta(self) -> Styled<T> {
341 let mut styled = self.into();
342 styled.bg = Some(Color::LightMagenta);
343 styled
344 }
345 fn on_magenta(self) -> Styled<T> {
346 let mut styled = self.into();
347 styled.bg = Some(Color::Magenta);
348 styled
349 }
350 fn on_light_cyan(self) -> Styled<T> {
351 let mut styled = self.into();
352 styled.bg = Some(Color::LightCyan);
353 styled
354 }
355 fn on_cyan(self) -> Styled<T> {
356 let mut styled = self.into();
357 styled.bg = Some(Color::Cyan);
358 styled
359 }
360 fn on_white(self) -> Styled<T> {
361 let mut styled = self.into();
362 styled.bg = Some(Color::White);
363 styled
364 }
365 fn on_grey(self) -> Styled<T> {
366 let mut styled = self.into();
367 styled.bg = Some(Color::Grey);
368 styled
369 }
370 fn on_rgb(self, r: u8, g: u8, b: u8) -> Styled<T> {
371 let mut styled = self.into();
372 styled.bg = Some(Color::Rgb(r, g, b));
373 styled
374 }
375 fn on_ansi(self, ansi: u8) -> Styled<T> {
376 let mut styled = self.into();
377 styled.bg = Some(Color::Ansi(ansi));
378 styled
379 }
380
381 fn bold(self) -> Styled<T> {
382 let mut styled = self.into();
383 styled.attributes |= Attributes::BOLD;
384 styled
385 }
386 fn underlined(self) -> Styled<T> {
387 let mut styled = self.into();
388 styled.attributes |= Attributes::UNDERLINED;
389 styled
390 }
391 fn reverse(self) -> Styled<T> {
392 let mut styled = self.into();
393 styled.attributes |= Attributes::REVERSED;
394 styled
395 }
396 fn dim(self) -> Styled<T> {
397 let mut styled = self.into();
398 styled.attributes |= Attributes::DIM;
399 styled
400 }
401 fn italic(self) -> Styled<T> {
402 let mut styled = self.into();
403 styled.attributes |= Attributes::ITALIC;
404 styled
405 }
406 fn slow_blink(self) -> Styled<T> {
407 let mut styled = self.into();
408 styled.attributes |= Attributes::SLOW_BLINK;
409 styled
410 }
411 fn rapid_blink(self) -> Styled<T> {
412 let mut styled = self.into();
413 styled.attributes |= Attributes::RAPID_BLINK;
414 styled
415 }
416 fn hidden(self) -> Styled<T> {
417 let mut styled = self.into();
418 styled.attributes |= Attributes::HIDDEN;
419 styled
420 }
421 fn crossed_out(self) -> Styled<T> {
422 let mut styled = self.into();
423 styled.attributes |= Attributes::CROSSED_OUT;
424 styled
425 }
426}