facet_ansi/
lib.rs

1use std::fmt::{self, Debug, Display, Formatter};
2
3/// A struct to represent a text style including color and formatting.
4#[derive(Default, Clone, Copy)]
5pub struct Style {
6    color: Option<Color>,
7    bold: bool,
8    underline: bool,
9    dimmed: bool,
10}
11
12/// Available colors for text styling.
13#[derive(Clone, Copy)]
14pub enum Color {
15    Red,
16    Green,
17    Blue,
18    Yellow,
19    Magenta,
20    Cyan,
21    White,
22    Black,
23    BrightRed,
24    BrightGreen,
25    BrightBlue,
26    BrightYellow,
27    BrightMagenta,
28    BrightCyan,
29    BrightWhite,
30}
31
32impl Style {
33    /// Create a new style with no color or formatting.
34    pub fn new() -> Self {
35        Style {
36            color: None,
37            bold: false,
38            underline: false,
39            dimmed: false,
40        }
41    }
42
43    /// Set the style color to red.
44    pub fn red(self) -> Self {
45        Style {
46            color: Some(Color::Red),
47            bold: self.bold,
48            underline: self.underline,
49            dimmed: self.dimmed,
50        }
51    }
52
53    /// Set the style color to green.
54    pub fn green(self) -> Self {
55        Style {
56            color: Some(Color::Green),
57            bold: self.bold,
58            underline: self.underline,
59            dimmed: self.dimmed,
60        }
61    }
62
63    /// Set the style color to blue.
64    pub fn blue(self) -> Self {
65        Style {
66            color: Some(Color::Blue),
67            bold: self.bold,
68            underline: self.underline,
69            dimmed: self.dimmed,
70        }
71    }
72
73    /// Set the style color to yellow.
74    pub fn yellow(self) -> Self {
75        Style {
76            color: Some(Color::Yellow),
77            bold: self.bold,
78            underline: self.underline,
79            dimmed: self.dimmed,
80        }
81    }
82
83    /// Set the style color to magenta.
84    pub fn magenta(self) -> Self {
85        Style {
86            color: Some(Color::Magenta),
87            bold: self.bold,
88            underline: self.underline,
89            dimmed: self.dimmed,
90        }
91    }
92
93    /// Set the style color to cyan.
94    pub fn cyan(self) -> Self {
95        Style {
96            color: Some(Color::Cyan),
97            bold: self.bold,
98            underline: self.underline,
99            dimmed: self.dimmed,
100        }
101    }
102
103    /// Set the style color to white.
104    pub fn white(self) -> Self {
105        Style {
106            color: Some(Color::White),
107            bold: self.bold,
108            underline: self.underline,
109            dimmed: self.dimmed,
110        }
111    }
112
113    /// Set the style color to black.
114    pub fn black(self) -> Self {
115        Style {
116            color: Some(Color::Black),
117            bold: self.bold,
118            underline: self.underline,
119            dimmed: self.dimmed,
120        }
121    }
122
123    /// Set the style color to bright red.
124    pub fn bright_red(self) -> Self {
125        Style {
126            color: Some(Color::BrightRed),
127            bold: self.bold,
128            underline: self.underline,
129            dimmed: self.dimmed,
130        }
131    }
132
133    /// Set the style color to bright green.
134    pub fn bright_green(self) -> Self {
135        Style {
136            color: Some(Color::BrightGreen),
137            bold: self.bold,
138            underline: self.underline,
139            dimmed: self.dimmed,
140        }
141    }
142
143    /// Set the style color to bright blue.
144    pub fn bright_blue(self) -> Self {
145        Style {
146            color: Some(Color::BrightBlue),
147            bold: self.bold,
148            underline: self.underline,
149            dimmed: self.dimmed,
150        }
151    }
152
153    /// Set the style color to bright yellow.
154    pub fn bright_yellow(self) -> Self {
155        Style {
156            color: Some(Color::BrightYellow),
157            bold: self.bold,
158            underline: self.underline,
159            dimmed: self.dimmed,
160        }
161    }
162
163    /// Set the style color to bright magenta.
164    pub fn bright_magenta(self) -> Self {
165        Style {
166            color: Some(Color::BrightMagenta),
167            bold: self.bold,
168            underline: self.underline,
169            dimmed: self.dimmed,
170        }
171    }
172
173    /// Set the style color to bright cyan.
174    pub fn bright_cyan(self) -> Self {
175        Style {
176            color: Some(Color::BrightCyan),
177            bold: self.bold,
178            underline: self.underline,
179            dimmed: self.dimmed,
180        }
181    }
182
183    /// Set the style color to bright white.
184    pub fn bright_white(self) -> Self {
185        Style {
186            color: Some(Color::BrightWhite),
187            bold: self.bold,
188            underline: self.underline,
189            dimmed: self.dimmed,
190        }
191    }
192
193    /// Set the text style to bold.
194    pub fn bold(self) -> Self {
195        Style {
196            color: self.color,
197            bold: true,
198            underline: self.underline,
199            dimmed: self.dimmed,
200        }
201    }
202
203    /// Set the text style to underlined.
204    pub fn underline(self) -> Self {
205        Style {
206            color: self.color,
207            bold: self.bold,
208            underline: true,
209            dimmed: self.dimmed,
210        }
211    }
212
213    /// Set the text style to dimmed.
214    pub fn dimmed(self) -> Self {
215        Style {
216            color: self.color,
217            bold: self.bold,
218            underline: self.underline,
219            dimmed: true,
220        }
221    }
222}
223
224/// A struct that wraps a value and its style.
225pub struct StyledDisplay<T> {
226    value: T,
227    style: Style,
228}
229
230impl Color {
231    fn ansi_code(&self) -> &'static str {
232        match self {
233            Color::Red => "\x1b[31m",
234            Color::Green => "\x1b[32m",
235            Color::Blue => "\x1b[34m",
236            Color::Yellow => "\x1b[33m",
237            Color::Magenta => "\x1b[35m",
238            Color::Cyan => "\x1b[36m",
239            Color::White => "\x1b[37m",
240            Color::Black => "\x1b[30m",
241            Color::BrightRed => "\x1b[91m",
242            Color::BrightGreen => "\x1b[92m",
243            Color::BrightBlue => "\x1b[94m",
244            Color::BrightYellow => "\x1b[93m",
245            Color::BrightMagenta => "\x1b[95m",
246            Color::BrightCyan => "\x1b[96m",
247            Color::BrightWhite => "\x1b[97m",
248        }
249    }
250}
251
252impl Style {
253    // Helper method to generate formatting codes
254    fn format_codes(&self) -> String {
255        let mut format_codes = String::new();
256
257        if self.bold {
258            format_codes.push_str("\x1b[1m");
259        }
260
261        if self.underline {
262            format_codes.push_str("\x1b[4m");
263        }
264
265        if self.dimmed {
266            format_codes.push_str("\x1b[2m");
267        }
268
269        if let Some(color) = self.color {
270            format_codes.push_str(color.ansi_code());
271        }
272
273        format_codes
274    }
275}
276
277impl<T: Display> Display for StyledDisplay<T> {
278    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
279        let format_codes = self.style.format_codes();
280
281        if format_codes.is_empty() {
282            write!(f, "{}", self.value)
283        } else {
284            write!(f, "{}{}\x1b[0m", format_codes, self.value)
285        }
286    }
287}
288
289impl<T: Debug> Debug for StyledDisplay<T> {
290    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
291        let format_codes = self.style.format_codes();
292
293        if format_codes.is_empty() {
294            write!(f, "{:?}", self.value)
295        } else {
296            write!(f, "{}{:?}\x1b[0m", format_codes, self.value)
297        }
298    }
299}
300
301/// Extension trait for styling any Display value.
302pub trait Stylize {
303    /// Apply a style to a value.
304    fn style(self, style: Style) -> StyledDisplay<Self>
305    where
306        Self: Sized;
307
308    /// Apply red color style to a value.
309    fn red(self) -> StyledDisplay<Self>
310    where
311        Self: Sized;
312
313    /// Apply green color style to a value.
314    fn green(self) -> StyledDisplay<Self>
315    where
316        Self: Sized;
317
318    /// Apply blue color style to a value.
319    fn blue(self) -> StyledDisplay<Self>
320    where
321        Self: Sized;
322
323    /// Apply yellow color style to a value.
324    fn yellow(self) -> StyledDisplay<Self>
325    where
326        Self: Sized;
327
328    /// Apply magenta color style to a value.
329    fn magenta(self) -> StyledDisplay<Self>
330    where
331        Self: Sized;
332
333    /// Apply cyan color style to a value.
334    fn cyan(self) -> StyledDisplay<Self>
335    where
336        Self: Sized;
337
338    /// Apply white color style to a value.
339    fn white(self) -> StyledDisplay<Self>
340    where
341        Self: Sized;
342
343    /// Apply black color style to a value.
344    fn black(self) -> StyledDisplay<Self>
345    where
346        Self: Sized;
347
348    /// Apply bright red color style to a value.
349    fn bright_red(self) -> StyledDisplay<Self>
350    where
351        Self: Sized;
352
353    /// Apply bright green color style to a value.
354    fn bright_green(self) -> StyledDisplay<Self>
355    where
356        Self: Sized;
357
358    /// Apply bright blue color style to a value.
359    fn bright_blue(self) -> StyledDisplay<Self>
360    where
361        Self: Sized;
362
363    /// Apply bright yellow color style to a value.
364    fn bright_yellow(self) -> StyledDisplay<Self>
365    where
366        Self: Sized;
367
368    /// Apply bright magenta color style to a value.
369    fn bright_magenta(self) -> StyledDisplay<Self>
370    where
371        Self: Sized;
372
373    /// Apply bright cyan color style to a value.
374    fn bright_cyan(self) -> StyledDisplay<Self>
375    where
376        Self: Sized;
377
378    /// Apply bright white color style to a value.
379    fn bright_white(self) -> StyledDisplay<Self>
380    where
381        Self: Sized;
382
383    /// Apply bold style to a value.
384    fn bold(self) -> StyledDisplay<Self>
385    where
386        Self: Sized;
387
388    /// Apply underline style to a value.
389    fn underline(self) -> StyledDisplay<Self>
390    where
391        Self: Sized;
392
393    /// Apply dimmed style to a value.
394    fn dimmed(self) -> StyledDisplay<Self>
395    where
396        Self: Sized;
397}
398
399impl<T: Display> Stylize for T {
400    fn style(self, style: Style) -> StyledDisplay<Self> {
401        StyledDisplay { value: self, style }
402    }
403
404    fn red(self) -> StyledDisplay<Self> {
405        StyledDisplay {
406            value: self,
407            style: Style::new().red(),
408        }
409    }
410
411    fn green(self) -> StyledDisplay<Self> {
412        StyledDisplay {
413            value: self,
414            style: Style::new().green(),
415        }
416    }
417
418    fn blue(self) -> StyledDisplay<Self> {
419        StyledDisplay {
420            value: self,
421            style: Style::new().blue(),
422        }
423    }
424
425    fn yellow(self) -> StyledDisplay<Self> {
426        StyledDisplay {
427            value: self,
428            style: Style::new().yellow(),
429        }
430    }
431
432    fn magenta(self) -> StyledDisplay<Self> {
433        StyledDisplay {
434            value: self,
435            style: Style::new().magenta(),
436        }
437    }
438
439    fn cyan(self) -> StyledDisplay<Self> {
440        StyledDisplay {
441            value: self,
442            style: Style::new().cyan(),
443        }
444    }
445
446    fn white(self) -> StyledDisplay<Self> {
447        StyledDisplay {
448            value: self,
449            style: Style::new().white(),
450        }
451    }
452
453    fn black(self) -> StyledDisplay<Self> {
454        StyledDisplay {
455            value: self,
456            style: Style::new().black(),
457        }
458    }
459
460    fn bright_red(self) -> StyledDisplay<Self> {
461        StyledDisplay {
462            value: self,
463            style: Style::new().bright_red(),
464        }
465    }
466
467    fn bright_green(self) -> StyledDisplay<Self> {
468        StyledDisplay {
469            value: self,
470            style: Style::new().bright_green(),
471        }
472    }
473
474    fn bright_blue(self) -> StyledDisplay<Self> {
475        StyledDisplay {
476            value: self,
477            style: Style::new().bright_blue(),
478        }
479    }
480
481    fn bright_yellow(self) -> StyledDisplay<Self> {
482        StyledDisplay {
483            value: self,
484            style: Style::new().bright_yellow(),
485        }
486    }
487
488    fn bright_magenta(self) -> StyledDisplay<Self> {
489        StyledDisplay {
490            value: self,
491            style: Style::new().bright_magenta(),
492        }
493    }
494
495    fn bright_cyan(self) -> StyledDisplay<Self> {
496        StyledDisplay {
497            value: self,
498            style: Style::new().bright_cyan(),
499        }
500    }
501
502    fn bright_white(self) -> StyledDisplay<Self> {
503        StyledDisplay {
504            value: self,
505            style: Style::new().bright_white(),
506        }
507    }
508
509    fn bold(self) -> StyledDisplay<Self> {
510        StyledDisplay {
511            value: self,
512            style: Style::new().bold(),
513        }
514    }
515
516    fn underline(self) -> StyledDisplay<Self> {
517        StyledDisplay {
518            value: self,
519            style: Style::new().underline(),
520        }
521    }
522
523    fn dimmed(self) -> StyledDisplay<Self> {
524        StyledDisplay {
525            value: self,
526            style: Style::new().dimmed(),
527        }
528    }
529}