ansi_style/
lib.rs

1//! # ansi-style
2//!
3//! ## Usage
4//!
5//! ```rust
6//! use ansi_style::{Color, Style};
7//!
8//! // You can either color the text directly with the Color enumeration
9//! println!(
10//!     "{}Cyan colored \"Hello World!\"{}",
11//!     Color::Cyan.open(),
12//!     Color::Cyan.close()
13//! );
14//!
15//! // or you can use the builder function from within the Style stuct
16//! // to create a style that can be used for more than one instance of
17//! // a string and you wouldn't need to have an open and close function
18//! // prepended and appended to every text you type like the above example
19//!
20//! let style = Style::builder().red().strikethrough().build();
21//!
22//! println!(
23//!     "{}",
24//!     style.stylize("Hello World in red with strikethrough")
25//! )
26//! ```
27
28#![no_std]
29
30extern crate alloc;
31
32use core::fmt::Display;
33
34use alloc::{format, string::String};
35
36/// A helper struct for creating the [`Style`] object
37pub struct StyleBuilder {
38    bold: bool,
39    dim: bool,
40    italic: bool,
41    underline: bool,
42    blink: bool,
43    inverse: bool,
44    hidden: bool,
45    strikethrough: bool,
46    overline: bool,
47    color: Option<Color>,
48    bg_color: Option<BGColor>,
49}
50
51impl StyleBuilder {
52    /// Creates a new [`StyleBuilder`] struct for creating styles
53    #[must_use]
54    pub fn new() -> Self {
55        Self {
56            bold: false,
57            dim: false,
58            italic: false,
59            underline: false,
60            blink: false,
61            inverse: false,
62            hidden: false,
63            strikethrough: false,
64            overline: false,
65            color: None,
66            bg_color: None,
67        }
68    }
69
70    /// Sets the `bold` property to true
71    #[must_use]
72    pub fn bold(mut self) -> Self {
73        self.bold = true;
74        self
75    }
76
77    /// Sets the `dim` property to true
78    #[must_use]
79    pub fn dim(mut self) -> Self {
80        self.dim = true;
81        self
82    }
83
84    /// Sets the `italic` property to true
85    #[must_use]
86    pub fn italic(mut self) -> Self {
87        self.italic = true;
88        self
89    }
90
91    /// Sets the `underline` property to true
92    #[must_use]
93    pub fn underline(mut self) -> Self {
94        self.underline = true;
95        self
96    }
97
98    /// Sets the `blink` property to true
99    #[must_use]
100    pub fn blink(mut self) -> Self {
101        self.blink = true;
102        self
103    }
104
105    /// Sets the `inverse` property to true
106    #[must_use]
107    pub fn inverse(mut self) -> Self {
108        self.inverse = true;
109        self
110    }
111
112    /// Sets the `hidden` property to true
113    #[must_use]
114    pub fn hidden(mut self) -> Self {
115        self.hidden = true;
116        self
117    }
118
119    /// Sets the `strikethrough` property to true
120    #[must_use]
121    pub fn strikethrough(mut self) -> Self {
122        self.strikethrough = true;
123        self
124    }
125
126    /// Sets the `overline` property to true
127    #[must_use]
128    pub fn overline(mut self) -> Self {
129        self.overline = true;
130        self
131    }
132
133    /// Sets the text color to black
134    #[must_use]
135    pub fn black(mut self) -> Self {
136        self.color = Some(Color::Black);
137        self
138    }
139
140    /// Sets the text color to red
141    #[must_use]
142    pub fn red(mut self) -> Self {
143        self.color = Some(Color::Red);
144        self
145    }
146
147    /// Sets the text color to green
148    #[must_use]
149    pub fn green(mut self) -> Self {
150        self.color = Some(Color::Green);
151        self
152    }
153
154    /// Sets the text color to yellow
155    #[must_use]
156    pub fn yellow(mut self) -> Self {
157        self.color = Some(Color::Yellow);
158        self
159    }
160
161    /// Sets the text color to blue
162    #[must_use]
163    pub fn blue(mut self) -> Self {
164        self.color = Some(Color::Blue);
165        self
166    }
167
168    /// Sets the text color to magenta
169    #[must_use]
170    pub fn magenta(mut self) -> Self {
171        self.color = Some(Color::Magenta);
172        self
173    }
174
175    /// Sets the text color to cyan
176    #[must_use]
177    pub fn cyan(mut self) -> Self {
178        self.color = Some(Color::Cyan);
179        self
180    }
181
182    /// Sets the text color to white
183    #[must_use]
184    pub fn white(mut self) -> Self {
185        self.color = Some(Color::White);
186        self
187    }
188
189    /// Sets the text color to a bright black (gray)
190    #[must_use]
191    pub fn black_bright(mut self) -> Self {
192        self.color = Some(Color::BlackBright);
193        self
194    }
195
196    /// Sets the text color to a bright red
197    #[must_use]
198    pub fn red_bright(mut self) -> Self {
199        self.color = Some(Color::RedBright);
200        self
201    }
202
203    /// Sets the text color to a bright green
204    #[must_use]
205    pub fn green_bright(mut self) -> Self {
206        self.color = Some(Color::GreenBright);
207        self
208    }
209
210    /// Sets the text color to a bright yellow
211    #[must_use]
212    pub fn yellow_bright(mut self) -> Self {
213        self.color = Some(Color::YellowBright);
214        self
215    }
216
217    /// Sets the text color to a bright blue
218    #[must_use]
219    pub fn blue_bright(mut self) -> Self {
220        self.color = Some(Color::BlueBright);
221        self
222    }
223
224    /// Sets the text color to a bright magenta
225    #[must_use]
226    pub fn magenta_bright(mut self) -> Self {
227        self.color = Some(Color::MagentaBright);
228        self
229    }
230
231    /// Sets the text color to a bright cyan
232    #[must_use]
233    pub fn cyan_bright(mut self) -> Self {
234        self.color = Some(Color::CyanBright);
235        self
236    }
237
238    /// Sets the text color to a bright white
239    #[must_use]
240    pub fn white_bright(mut self) -> Self {
241        self.color = Some(Color::WhiteBright);
242        self
243    }
244
245    /// Sets the text's bckground color to black
246    #[must_use]
247    pub fn bg_black(mut self) -> Self {
248        self.bg_color = Some(BGColor::Black);
249        self
250    }
251
252    /// Sets the text's bckground color to red
253    #[must_use]
254    pub fn bg_red(mut self) -> Self {
255        self.bg_color = Some(BGColor::Red);
256        self
257    }
258
259    /// Sets the text's bckground color to green
260    #[must_use]
261    pub fn bg_green(mut self) -> Self {
262        self.bg_color = Some(BGColor::Green);
263        self
264    }
265
266    /// Sets the text's bckground color to yellow
267    #[must_use]
268    pub fn bg_yellow(mut self) -> Self {
269        self.bg_color = Some(BGColor::Yellow);
270        self
271    }
272
273    /// Sets the text's bckground color to blue
274    #[must_use]
275    pub fn bg_blue(mut self) -> Self {
276        self.bg_color = Some(BGColor::Blue);
277        self
278    }
279
280    /// Sets the text's bckground color to magenta
281    #[must_use]
282    pub fn bg_magenta(mut self) -> Self {
283        self.bg_color = Some(BGColor::Magenta);
284        self
285    }
286
287    /// Sets the text's bckground color to cyan
288    #[must_use]
289    pub fn bg_cyan(mut self) -> Self {
290        self.bg_color = Some(BGColor::Cyan);
291        self
292    }
293
294    /// Sets the text's bckground color to white
295    #[must_use]
296    pub fn bg_white(mut self) -> Self {
297        self.bg_color = Some(BGColor::White);
298        self
299    }
300
301    /// Sets the text's bckground color to a bright black (gray)
302    #[must_use]
303    pub fn bg_black_bright(mut self) -> Self {
304        self.bg_color = Some(BGColor::BlackBright);
305        self
306    }
307
308    /// Sets the text's bckground color to a bright red
309    #[must_use]
310    pub fn bg_red_bright(mut self) -> Self {
311        self.bg_color = Some(BGColor::RedBright);
312        self
313    }
314
315    /// Sets the text's bckground color to a bright green
316    #[must_use]
317    pub fn bg_green_bright(mut self) -> Self {
318        self.bg_color = Some(BGColor::GreenBright);
319        self
320    }
321
322    /// Sets the text's bckground color to a bright yellow
323    #[must_use]
324    pub fn bg_yellow_bright(mut self) -> Self {
325        self.bg_color = Some(BGColor::YellowBright);
326        self
327    }
328
329    /// Sets the text's bckground color to a bright blue
330    #[must_use]
331    pub fn bg_blue_bright(mut self) -> Self {
332        self.bg_color = Some(BGColor::BlueBright);
333        self
334    }
335
336    /// Sets the text's bckground color to a bright magenta
337    #[must_use]
338    pub fn bg_magenta_bright(mut self) -> Self {
339        self.bg_color = Some(BGColor::MagentaBright);
340        self
341    }
342
343    /// Sets the text's bckground color to a bright cyan
344    #[must_use]
345    pub fn bg_cyan_bright(mut self) -> Self {
346        self.bg_color = Some(BGColor::CyanBright);
347        self
348    }
349
350    /// Sets the text's bckground color to a bright white
351    #[must_use]
352    pub fn bg_white_bright(mut self) -> Self {
353        self.bg_color = Some(BGColor::WhiteBright);
354        self
355    }
356
357    /// Builds a [`Style`] struct from a the current instance of
358    /// the [`StyleBuilder`] struct
359    #[must_use]
360    pub fn build(self) -> Style {
361        let StyleBuilder {
362            bold,
363            dim,
364            italic,
365            underline,
366            blink,
367            inverse,
368            hidden,
369            strikethrough,
370            overline,
371            color,
372            bg_color,
373        } = self;
374
375        Style {
376            bold,
377            dim,
378            italic,
379            underline,
380            blink,
381            inverse,
382            hidden,
383            strikethrough,
384            overline,
385            color,
386            bg_color,
387        }
388    }
389}
390
391impl Default for StyleBuilder {
392    fn default() -> Self {
393        Self::new()
394    }
395}
396
397/// A  collection of properties that can be used to format a string using ANSI escape codes.
398#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
399pub struct Style {
400    bold: bool,
401    dim: bool,
402    italic: bool,
403    underline: bool,
404    blink: bool,
405    inverse: bool,
406    hidden: bool,
407    strikethrough: bool,
408    overline: bool,
409    color: Option<Color>,
410    bg_color: Option<BGColor>,
411}
412
413impl Style {
414    /// Creates a new [`Style`] struct
415    #[must_use]
416    pub fn new() -> Self {
417        Self {
418            bold: false,
419            dim: false,
420            italic: false,
421            underline: false,
422            blink: false,
423            inverse: false,
424            hidden: false,
425            strikethrough: false,
426            overline: false,
427            color: None,
428            bg_color: None,
429        }
430    }
431
432    /// Creates a new [`StyleBuilder`] struct
433    #[must_use]
434    pub fn builder() -> StyleBuilder {
435        StyleBuilder::new()
436    }
437
438    /// Checks whether or not the text's style is bold
439    #[must_use]
440    pub fn bold(&self) -> bool {
441        self.bold
442    }
443
444    /// Checks whether or not the text's style is dim
445    #[must_use]
446    pub fn dim(&self) -> bool {
447        self.dim
448    }
449
450    /// Checks whether or not the text's style is italic
451    #[must_use]
452    pub fn italic(&self) -> bool {
453        self.italic
454    }
455
456    /// Checks whether or not the text's style is underline
457    #[must_use]
458    pub fn underline(&self) -> bool {
459        self.underline
460    }
461
462    /// Checks whether or not the text's style is blink
463    #[must_use]
464    pub fn blink(&self) -> bool {
465        self.blink
466    }
467
468    /// Checks whether or not the text's style is inverse
469    #[must_use]
470    pub fn inverse(&self) -> bool {
471        self.inverse
472    }
473
474    /// Checks whether or not the text's style is hidden
475    #[must_use]
476    pub fn hidden(&self) -> bool {
477        self.hidden
478    }
479
480    /// Checks whether or not the text's style is strikethrough
481    #[must_use]
482    pub fn strikethrough(&self) -> bool {
483        self.strikethrough
484    }
485
486    /// Checks whether or not the text's style is overline
487    #[must_use]
488    pub fn overline(&self) -> bool {
489        self.overline
490    }
491
492    /// Checks whether oor not the current style has a text color if no color is
493    /// provided a default color [`Color::Any`] will be provided
494    #[must_use]
495    pub fn color(&self) -> Color {
496        match self.color {
497            Some(color) => color,
498            None => Color::Any,
499        }
500    }
501
502    /// Checks whether oor not the current style has a text background color if no color is
503    /// provided a default color [`BGColor::Any`] will be provided
504    #[must_use]
505    pub fn bg_color(&self) -> BGColor {
506        match self.bg_color {
507            Some(color) => color,
508            None => BGColor::Any,
509        }
510    }
511
512    /// Converts three values (red, green, blue) to an ansi 256-color lookup (8-bit)
513    ///
514    /// # Arguments
515    ///
516    /// * `red` - a number representation for red
517    /// * `green` - a number representation for green
518    /// * `blue` - a number representation for blue
519    #[must_use]
520    pub fn rgb_to_ansi256(red: u8, green: u8, blue: u8) -> u8 {
521        if red == green && green == blue {
522            if red < 8 {
523                return 16;
524            }
525
526            if red > 248 {
527                return 231;
528            }
529
530            return ((((red as f32 - 8.) / 247.) * 24.) + 232.) as u8;
531        }
532
533        (16. + (36. * (red as f32 / 255. * 5.))
534            + (6. * (green as f32 / 255. * 5.))
535            + (blue as f32 / 255. * 5.)) as u8
536    }
537
538    /// Adds style to a given text
539    ///
540    /// * `text` - the string of characters to add style to  
541    #[must_use]
542    pub fn stylize(&self, text: &str) -> String {
543        format!("{self}{text}{}", Self::reset())
544    }
545
546    fn is_default(&self) -> bool {
547        *self == Self::default()
548    }
549
550    fn reset() -> &'static str {
551        "\x1B[0m"
552    }
553}
554
555impl Display for Style {
556    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
557        if self.is_default() {
558            return Ok(());
559        }
560
561        write!(f, "\x1B[")?;
562
563        let mut written = false;
564
565        {
566            let mut write_char = |c| {
567                if written {
568                    write!(f, ";")?;
569                }
570                written = true;
571                write!(f, "{}", c)?;
572                Ok(())
573            };
574
575            if self.bold {
576                write_char('1')?;
577            }
578
579            if self.dim {
580                write_char('2')?;
581            }
582
583            if self.italic {
584                write_char('3')?;
585            }
586
587            if self.underline {
588                write_char('4')?;
589            }
590
591            if self.blink {
592                write_char('5')?;
593            }
594
595            if self.inverse {
596                write_char('7')?;
597            }
598
599            if self.hidden {
600                write_char('8')?;
601            }
602
603            if self.strikethrough {
604                write_char('9')?;
605            }
606
607            if self.overline {
608                write!(f, "53")?;
609            }
610        }
611
612        if let Some(color) = self.bg_color {
613            if written {
614                write!(f, ";{color}")?;
615            } else {
616                write!(f, "{color}")?;
617                written = true;
618            }
619        }
620
621        if let Some(color) = self.color {
622            if written {
623                write!(f, ";{color}")?;
624            } else {
625                write!(f, "{color}")?;
626            }
627        }
628
629        write!(f, "m")
630    }
631}
632
633impl Default for Style {
634    fn default() -> Self {
635        Self::new()
636    }
637}
638
639/// The [`Color`] enumeration can be used to directly add color in ANSI
640/// compatible environments without the use of the [`Style`] struct.
641#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
642pub enum Color {
643    /// A generic color
644    Any,
645    /// A black text color
646    Black,
647    /// A red text color
648    Red,
649    /// A green text color
650    Green,
651    /// A yellow text color
652    Yellow,
653    /// A blue text color
654    Blue,
655    /// A magenta text color
656    Magenta,
657    /// A cyan text color
658    Cyan,
659    /// A white text color
660    White,
661
662    /// A bright black (gray) text color
663    BlackBright,
664    /// A bright red text color
665    RedBright,
666    /// A bright green text color
667    GreenBright,
668    /// A bright yellow text color
669    YellowBright,
670    /// A bright blue text color
671    BlueBright,
672    /// A bright magenta text color
673    MagentaBright,
674    /// A bright cyan text color
675    CyanBright,
676    /// A bright white text color
677    WhiteBright,
678
679    /// An 8-bit color from  0 to 255
680    Ansi256(u8),
681    /// A 24-bit RGB color, as specified by ISO-8613-3.
682    RGB(u8, u8, u8),
683}
684
685impl Color {
686    /// Closes the terminal from adding selected color to text
687    #[must_use]
688    pub fn close(&self) -> &'static str {
689        "\x1B[39m"
690    }
691
692    /// Opens the terminal for adding selected color to text
693    #[must_use]
694    pub fn open(&self) -> String {
695        format!("\x1B[{self}m")
696    }
697
698    /// Adds color to a given text
699    ///
700    /// * `text` - the string of characters to add background color to  
701    #[must_use]
702    pub fn paint(&self, text: &str) -> String {
703        format!("{}{text}{}", self.open(), self.close())
704    }
705}
706
707impl Display for Color {
708    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
709        match self {
710            Color::Any => write!(f, ""),
711            Color::Black => write!(f, "30"),
712            Color::Red => write!(f, "31"),
713            Color::Green => write!(f, "32"),
714            Color::Yellow => write!(f, "33"),
715            Color::Blue => write!(f, "34"),
716            Color::Magenta => write!(f, "35"),
717            Color::Cyan => write!(f, "36"),
718            Color::White => write!(f, "37"),
719            Color::BlackBright => write!(f, "90"),
720            Color::RedBright => write!(f, "91"),
721            Color::GreenBright => write!(f, "92"),
722            Color::YellowBright => write!(f, "93"),
723            Color::BlueBright => write!(f, "94"),
724            Color::MagentaBright => write!(f, "95"),
725            Color::CyanBright => write!(f, "96"),
726            Color::WhiteBright => write!(f, "97"),
727            Color::Ansi256(num) => write!(f, "38;5;{}", &num),
728            Color::RGB(r, g, b) => write!(f, "38;2;{};{};{}", &r, &g, &b),
729        }
730    }
731}
732
733/// The [`BGColor`] enumeration can be used to directly add color in ANSI
734/// compatible environments without the use of the [`Style`] struct.
735#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
736pub enum BGColor {
737    /// A generic color
738    Any,
739    /// A black background color
740    Black,
741    /// A red background color
742    Red,
743    /// A green background color
744    Green,
745    /// A yellow background color
746    Yellow,
747    /// A blue background color
748    Blue,
749    /// A magenta background color
750    Magenta,
751    /// A cyan background color
752    Cyan,
753    /// A white background color
754    White,
755
756    /// A bright black (gray) background color
757    BlackBright,
758    /// A bright red background color
759    RedBright,
760    /// A bright green background color
761    GreenBright,
762    /// A bright yellow background color
763    YellowBright,
764    /// A bright blue background color
765    BlueBright,
766    /// A bright magenta background color
767    MagentaBright,
768    /// A bright cyan background color
769    CyanBright,
770    /// A bright white background color
771    WhiteBright,
772
773    /// An 8-bit color from  0 to 255
774    Ansi256(u8),
775    /// A 24-bit RGB color, as specified by ISO-8613-3.
776    RGB(u8, u8, u8),
777}
778
779impl BGColor {
780    /// Closes the terminal from adding selected color to text's background
781    #[must_use]
782    pub fn close(&self) -> &'static str {
783        "\x1B[49m"
784    }
785
786    /// Opens the terminal to adding selected color to text's background
787    #[must_use]
788    pub fn open(&self) -> String {
789        format!("\x1B[{self}m")
790    }
791
792    /// Adds background color to a given text
793    ///
794    /// * `text` - the string of characters to add color to  
795    #[must_use]
796    pub fn paint(&self, text: &str) -> String {
797        format!("{}{text}{}", self.open(), self.close())
798    }
799}
800
801impl Display for BGColor {
802    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
803        match self {
804            BGColor::Any => write!(f, ""),
805            BGColor::Black => write!(f, "40"),
806            BGColor::Red => write!(f, "41"),
807            BGColor::Green => write!(f, "42"),
808            BGColor::Yellow => write!(f, "43"),
809            BGColor::Blue => write!(f, "44"),
810            BGColor::Magenta => write!(f, "45"),
811            BGColor::Cyan => write!(f, "46"),
812            BGColor::White => write!(f, "47"),
813            BGColor::BlackBright => write!(f, "100"),
814            BGColor::RedBright => write!(f, "101"),
815            BGColor::GreenBright => write!(f, "102"),
816            BGColor::YellowBright => write!(f, "103"),
817            BGColor::BlueBright => write!(f, "104"),
818            BGColor::MagentaBright => write!(f, "105"),
819            BGColor::CyanBright => write!(f, "106"),
820            BGColor::WhiteBright => write!(f, "107"),
821            BGColor::Ansi256(num) => write!(f, "48;5;{}", &num),
822            BGColor::RGB(r, g, b) => write!(f, "48;2;{};{};{}", &r, &g, &b),
823        }
824    }
825}