1use std::{
5 collections::HashMap,
6 fmt::{
7 Display,
8 Formatter
9 }, sync::LazyLock,
10};
11
12use serde::{
13 Serialize,
14 Deserialize
15};
16
17#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default,
50 Serialize, Deserialize)]
51#[repr(i32)]
52pub enum Color
53{
54 None = 0,
55 Black = 1,
56 #[default]
57 Blue = 2,
58 Cyan = 3,
59 Green = 4,
60 Gray = 5,
61 Magenta = 6,
62 Red = 7,
63 White = 8,
64 Yellow = 9,
65
66 Custom(String) = 10,
67}
68
69const BLACK: &str = "\x1b[30m";
70const BLUE: &str = "\x1b[34m";
71const CYAN: &str = "\x1b[36m";
72const GREEN: &str = "\x1b[32m";
73const GRAY: &str = "\x1b[90m";
74const MAGENTA: &str = "\x1b[35m";
75const RED: &str = "\x1b[31m";
76const WHITE: &str = "\x1b[37m";
77const YELLOW: &str = "\x1b[33m";
78
79pub(crate) static RESET: &str = "\x1b[0m";
80
81static COLOR_MAP: LazyLock<HashMap<i32, &str>> = LazyLock::new(|| {
82 let mut m = HashMap::new();
83 m.insert(Color::None.into(), "");
84 m.insert(Color::Black.into(), BLACK);
85 m.insert(Color::Blue.into(), BLUE);
86 m.insert(Color::Cyan.into(), CYAN);
87 m.insert(Color::Green.into(), GREEN);
88 m.insert(Color::Gray.into(), GRAY);
89 m.insert(Color::Magenta.into(), MAGENTA);
90 m.insert(Color::Red.into(), RED);
91 m.insert(Color::White.into(), WHITE);
92 m.insert(Color::Yellow.into(), YELLOW);
93 m
94});
95
96pub fn color_text(text: &str, color: Color) -> String {
115 match color {
116 Color::Custom(s) => {
117 s + text + RESET
118 },
119 _ => {
120 if color != Color::None {
121 COLOR_MAP[&(color.into())].to_string() + text + RESET
122 }
123 else{
124 String::from(text)
125 }
126 }
127 }
128}
129
130impl Display for Color {
131 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
132 let level_str = match self {
133 Color::None => "None",
134 Color:: Black => "Black",
135 Color::Blue => "Blue",
136 Color::Cyan => "Cyan",
137 Color::Green => "Green",
138 Color::Gray => "Gray",
139 Color::Magenta => "Magenta",
140 Color::Red => "Red",
141 Color::White => "White",
142 Color::Yellow => "Yellow",
143
144 Color::Custom(str) => &format!("'{str}'")
145 };
146 write!(f, "{level_str}")
147 }
148}
149
150impl TryFrom<i32> for Color {
151 type Error = &'static str;
152 fn try_from(value: i32) -> Result<Self, Self::Error> {
153 match value {
154 0 => Ok(Color::None),
155 1 => Ok(Color::Black),
156 2 => Ok(Color::Blue),
157 3 => Ok(Color::Cyan),
158 4 => Ok(Color::Green),
159 5 => Ok(Color::Gray),
160 6 => Ok(Color::Magenta),
161 7 => Ok(Color::Red),
162 8 => Ok(Color::White),
163 9 => Ok(Color::Yellow),
164 18 => {Ok(Color::Custom(String::new()))}
165 _ => Err("Invalid value! Please provide a value in range 0-9."),
166 }
167 }
168}
169
170impl From<Color> for i32 {
171 fn from(color: Color) -> Self {
172 match color {
173 Color::None => 0,
174 Color::Black => 1,
175 Color::Blue => 2,
176 Color::Cyan => 3,
177 Color::Green => 4,
178 Color::Gray => 5,
179 Color::Magenta => 6,
180 Color::Red => 7,
181 Color::White => 8,
182 Color::Yellow => 9,
183 Color::Custom(_) => 10,
184 }
185 }
186}
187
188impl AsRef<str> for Color {
189 fn as_ref(&self) -> &str {
190 match self {
191 Color::None => "None",
192 Color:: Black => "Black",
193 Color::Blue => "Blue",
194 Color::Cyan => "Cyan",
195 Color::Green => "Green",
196 Color::Gray => "Gray",
197 Color::Magenta => "Magenta",
198 Color::Red => "Red",
199 Color::White => "White",
200 Color::Yellow => "Yellow",
201 Color::Custom(str) => str.as_str(),
202 }
203 }
204}