prettylogger/
colors.rs

1//! Contains cosmetic, color-related utilities.
2
3/// Contains various color-related utilities for cosmetic customization.
4use std::{
5    collections::HashMap,
6    fmt::{Display, Formatter},
7};
8use serde::{Serialize, Deserialize};
9use lazy_static::lazy_static;
10
11/// Represents different colors. Used to color text or modify the appearance of
12/// log headers.
13#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default,
14    Serialize, Deserialize)]
15pub enum Color
16{
17    None = 0,
18    Black = 1,
19    #[default]
20    Blue = 2,
21    Cyan = 3,
22    Green = 4,
23    Gray = 5,
24    Magenta = 6,
25    Red = 7,
26    White = 8,
27    Yellow = 9,
28
29    BrightBlack = 10,
30    BrightBlue = 11,
31    BrightCyan = 12,
32    BrightGreen = 13,
33    BrightMagenta = 14,
34    BrightRed = 15,
35    BrightWhite = 16,
36    BrightYellow = 17,
37}
38
39static BLACK: &str = "\x1b[30m";
40static BLUE: &str = "\x1b[34m";
41static CYAN: &str = "\x1b[36m";
42static GREEN: &str = "\x1b[32m";
43static GRAY: &str = "\x1b[90m";
44static MAGENTA: &str = "\x1b[35m";
45static RED: &str = "\x1b[31m";
46static WHITE: &str = "\x1b[37m";
47static YELLOW: &str = "\x1b[33m";
48
49static BRIGHT_BLACK: &str = "\x1b[90m";
50static BRIGHT_BLUE: &str = "\x1b[94m";
51static BRIGHT_CYAN: &str = "\x1b[96m";
52static BRIGHT_GREEN: &str = "\x1b[92m";
53static BRIGHT_MAGENTA: &str = "\x1b[95m";
54static BRIGHT_RED: &str = "\x1b[91m";
55static BRIGHT_WHITE: &str = "\x1b[97m";
56static BRIGHT_YELLOW: &str = "\x1b[93m";
57
58pub(crate) static RESET: &str = "\x1b[0m";
59
60lazy_static! {
61    static ref COLOR_MAP: HashMap<i32, &'static str> =  {
62        let mut m = HashMap::new();
63        m.insert(Color::None as i32, "");
64        m.insert(Color::Black as i32, BLACK);
65        m.insert(Color::Blue as i32, BLUE);
66        m.insert(Color::Cyan as i32, CYAN);
67        m.insert(Color::Green as i32, GREEN);
68        m.insert(Color::Gray as i32, GRAY);
69        m.insert(Color::Magenta as i32, MAGENTA);
70        m.insert(Color::Red as i32, RED);
71        m.insert(Color::White as i32, WHITE);
72        m.insert(Color::Yellow as i32, YELLOW);
73
74        m.insert(Color::BrightBlack as i32, BRIGHT_BLACK);
75        m.insert(Color::BrightBlue as i32, BRIGHT_BLUE);
76        m.insert(Color::BrightCyan as i32, BRIGHT_CYAN);
77        m.insert(Color::BrightGreen as i32, BRIGHT_GREEN);
78        m.insert(Color::BrightMagenta as i32, BRIGHT_MAGENTA);
79        m.insert(Color::BrightRed as i32, BRIGHT_RED);
80        m.insert(Color::BrightWhite as i32, BRIGHT_WHITE);
81        m.insert(Color::BrightYellow as i32, BRIGHT_YELLOW);
82        return m;
83    };
84}
85
86/// Colors given text based on `color` value using ANSII escape codes.
87///
88/// # Example
89/// ```
90/// # use prettylogger::colors::{Color, color_text};
91/// let colored_text = color_text("a piece of text", Color::Red);
92/// assert_eq!(colored_text, "\x1b[31ma piece of text\x1b[0m");
93/// ```
94pub fn color_text(text: &str, color: Color) -> String {
95    if color != Color::None {
96        return COLOR_MAP[&(color as i32)].to_string() + text + RESET;
97    }
98    return String::from(text)
99}
100
101impl Display for Color {
102    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
103        let level_str = match *self {
104            Color::None => "None",
105            Color:: Black => "Black",
106            Color::Blue => "Blue",
107            Color::Cyan => "Cyan",
108            Color::Green => "Green",
109            Color::Gray => "Gray",
110            Color::Magenta => "Magenta",
111            Color::Red => "Red",
112            Color::White => "White",
113            Color::Yellow => "Yellow",
114
115            Color::BrightBlack => "BrightBlack",
116            Color::BrightBlue => "BrightBlue",
117            Color::BrightCyan => "BrightCyan",
118            Color::BrightGreen => "BrightGreen",
119            Color::BrightMagenta => "BrightMagenta",
120            Color::BrightRed => "BrightRed",
121            Color::BrightWhite => "BrightWhite",
122            Color::BrightYellow => "BrightYellow",
123        };
124        return write!(f, "{}", level_str)
125    }
126}
127
128impl TryFrom<i32> for Color {
129    type Error = &'static str;
130    fn try_from(value: i32) -> Result<Self, Self::Error> {
131        match value {
132            0 => Ok(Color::None),
133            1 => Ok(Color::Black),
134            2 => Ok(Color::Blue),
135            3 => Ok(Color::Cyan),
136            4 => Ok(Color::Green),
137            5 => Ok(Color::Gray),
138            6 => Ok(Color::Magenta),
139            7 => Ok(Color::Red),
140            8 => Ok(Color::White),
141            9 => Ok(Color::Yellow),
142
143            10 => Ok(Color::BrightBlack),
144            11 => Ok(Color::BrightBlue),
145            12 => Ok(Color::BrightCyan),
146            13 => Ok(Color::BrightGreen),
147            14 => Ok(Color::BrightMagenta),
148            15 => Ok(Color::BrightRed),
149            16 => Ok(Color::BrightWhite),
150            17 => Ok(Color::BrightYellow),
151            _ => Err("Invalid value! Please provide a value in range 0-9."),
152        }
153    }
154}
155
156impl AsRef<str> for Color {
157    fn as_ref(&self) -> &str {
158        match self {
159            Color::None => "None",
160            Color:: Black => "Black",
161            Color::Blue => "Blue",
162            Color::Cyan => "Cyan",
163            Color::Green => "Green",
164            Color::Gray => "Gray",
165            Color::Magenta => "Magenta",
166            Color::Red => "Red",
167            Color::White => "White",
168            Color::Yellow => "Yellow",
169
170            Color::BrightBlack => "BrightBlack",
171            Color::BrightBlue => "BrightBlue",
172            Color::BrightCyan => "BrightCyan",
173            Color::BrightGreen => "BrightGreen",
174            Color::BrightMagenta => "BrightMagenta",
175            Color::BrightRed => "BrightRed",
176            Color::BrightWhite => "BrightWhite",
177            Color::BrightYellow => "BrightYellow",
178        }
179    }
180}