1use super::concerns::Ansi;
2use super::keys::FromKey;
3use std::str::FromStr;
4
5pub enum Color {
6 Black,
7 Red,
8 Green,
9 Yellow,
10 Blue,
11 Magenta,
12 Cyan,
13 White,
14 BrightBlack,
15 BrightRed,
16 BrightGreen,
17 BrightYellow,
18 BrightBlue,
19 BrightMagenta,
20 BrightCyan,
21 BrightWhite,
22
23 BackgroundReset,
24 ForegroundReset,
25 Reset,
26
27 None, }
30
31impl Color {
32 pub fn get_fg_value(&self) -> u8 {
33 match *self {
34 Color::Black => 30,
35 Color::Red => 31,
36 Color::Green => 32,
37 Color::Yellow => 33,
38 Color::Blue => 34,
39 Color::Magenta => 35,
40 Color::Cyan => 36,
41 Color::White => 37,
42 Color::BrightBlack => 90,
43 Color::BrightRed => 91,
44 Color::BrightGreen => 92,
45 Color::BrightYellow => 93,
46 Color::BrightBlue => 94,
47 Color::BrightMagenta => 95,
48 Color::BrightCyan => 96,
49 Color::BrightWhite => 97,
50
51 Color::ForegroundReset => 39,
52 Color::BackgroundReset => 49,
53 Color::Reset => 0,
54
55 Color::None => 0,
56 }
57 }
58
59 pub fn get_bg_value(&self) -> u8 {
60 match *self {
61 Color::Black => 40,
62 Color::Red => 41,
63 Color::Green => 42,
64 Color::Yellow => 43,
65 Color::Blue => 44,
66 Color::Magenta => 45,
67 Color::Cyan => 46,
68 Color::White => 47,
69 Color::BrightBlack => 100,
70 Color::BrightRed => 101,
71 Color::BrightGreen => 102,
72 Color::BrightYellow => 103,
73 Color::BrightBlue => 104,
74 Color::BrightMagenta => 105,
75 Color::BrightCyan => 106,
76 Color::BrightWhite => 107,
77
78 Color::ForegroundReset => 39,
79 Color::BackgroundReset => 49,
80 Color::Reset => 0,
81
82 Color::None => 0,
83 }
84 }
85}
86
87impl<'a> From<&'a str> for Color {
88 fn from(s: &str) -> Self {
89 s.parse().unwrap_or(Color::None)
90 }
91}
92
93impl FromStr for Color {
94 type Err = ();
95
96 fn from_str(s: &str) -> Result<Self, Self::Err> {
97 let s = s.to_lowercase();
98
99 match s.as_ref() {
100 "black" => Ok(Color::Black),
101 "red" => Ok(Color::Red),
102 "green" => Ok(Color::Green),
103 "yellow" => Ok(Color::Yellow),
104 "blue" => Ok(Color::Blue),
105 "magenta" => Ok(Color::Magenta),
106 "cyan" => Ok(Color::Cyan),
107 "white" => Ok(Color::White),
108 "bright black" => Ok(Color::BrightBlack),
109 "bright red" => Ok(Color::BrightRed),
110 "bright green" => Ok(Color::BrightGreen),
111 "bright yellow" => Ok(Color::BrightYellow),
112 "bright blue" => Ok(Color::BrightBlue),
113 "bright magenta" => Ok(Color::BrightMagenta),
114 "bright cyan" => Ok(Color::BrightCyan),
115 "bright white" => Ok(Color::BrightWhite),
116
117 "///" => Ok(Color::BackgroundReset),
119 "//" => Ok(Color::ForegroundReset),
120 "/" => Ok(Color::Reset),
121
122 _ => Err(()),
123 }
124 }
125}
126
127impl FromKey for Color {
128 fn from_key(key: &str) -> Option<String> {
137 let is_bg = key.starts_with("on");
138
139 let color = Color::from(key.trim_start_matches("on "));
140
141 match color {
142 Color::None => None,
143 _ => {
144 if is_bg {
145 return Some(Ansi::escape(color.get_bg_value()));
146 }
147
148 Some(Ansi::escape(color.get_fg_value()))
149 }
150 }
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157
158 macro_rules! color_test {
159 ($name:ident, $key:expr, $value:expr) => {
160 #[test]
161 fn $name() {
162 let v = String::from(format!("\x1B[{}m", $value));
163 let c = Color::from_key($key).unwrap();
164
165 assert_eq!(c, v);
166 }
167 };
168 }
169
170 color_test!(reset, "/", 0);
171 color_test!(background, "on red", 41);
172 color_test!(foreground, "red", 31);
173}