1 | use std::{borrow::Cow, str::FromStr}; |
2 | |
3 | /// The 8 standard colors. |
4 | #[derive (Clone, Copy, Debug, PartialEq, Eq)] |
5 | #[allow (missing_docs)] |
6 | pub enum Color { |
7 | Black, |
8 | Red, |
9 | Green, |
10 | Yellow, |
11 | Blue, |
12 | Magenta, |
13 | Cyan, |
14 | White, |
15 | BrightBlack, |
16 | BrightRed, |
17 | BrightGreen, |
18 | BrightYellow, |
19 | BrightBlue, |
20 | BrightMagenta, |
21 | BrightCyan, |
22 | BrightWhite, |
23 | TrueColor { r: u8, g: u8, b: u8 }, |
24 | } |
25 | |
26 | #[allow (missing_docs)] |
27 | impl Color { |
28 | pub fn to_fg_str(&self) -> Cow<'static, str> { |
29 | match *self { |
30 | Color::Black => "30" .into(), |
31 | Color::Red => "31" .into(), |
32 | Color::Green => "32" .into(), |
33 | Color::Yellow => "33" .into(), |
34 | Color::Blue => "34" .into(), |
35 | Color::Magenta => "35" .into(), |
36 | Color::Cyan => "36" .into(), |
37 | Color::White => "37" .into(), |
38 | Color::BrightBlack => "90" .into(), |
39 | Color::BrightRed => "91" .into(), |
40 | Color::BrightGreen => "92" .into(), |
41 | Color::BrightYellow => "93" .into(), |
42 | Color::BrightBlue => "94" .into(), |
43 | Color::BrightMagenta => "95" .into(), |
44 | Color::BrightCyan => "96" .into(), |
45 | Color::BrightWhite => "97" .into(), |
46 | Color::TrueColor { r, g, b } => format!("38;2; {}; {}; {}" , r, g, b).into(), |
47 | } |
48 | } |
49 | |
50 | pub fn to_bg_str(&self) -> Cow<'static, str> { |
51 | match *self { |
52 | Color::Black => "40" .into(), |
53 | Color::Red => "41" .into(), |
54 | Color::Green => "42" .into(), |
55 | Color::Yellow => "43" .into(), |
56 | Color::Blue => "44" .into(), |
57 | Color::Magenta => "45" .into(), |
58 | Color::Cyan => "46" .into(), |
59 | Color::White => "47" .into(), |
60 | Color::BrightBlack => "100" .into(), |
61 | Color::BrightRed => "101" .into(), |
62 | Color::BrightGreen => "102" .into(), |
63 | Color::BrightYellow => "103" .into(), |
64 | Color::BrightBlue => "104" .into(), |
65 | Color::BrightMagenta => "105" .into(), |
66 | Color::BrightCyan => "106" .into(), |
67 | Color::BrightWhite => "107" .into(), |
68 | Color::TrueColor { r, g, b } => format!("48;2; {}; {}; {}" , r, g, b).into(), |
69 | } |
70 | } |
71 | } |
72 | |
73 | impl<'a> From<&'a str> for Color { |
74 | fn from(src: &str) -> Self { |
75 | src.parse().unwrap_or(default:Color::White) |
76 | } |
77 | } |
78 | |
79 | impl From<String> for Color { |
80 | fn from(src: String) -> Self { |
81 | src.parse().unwrap_or(default:Color::White) |
82 | } |
83 | } |
84 | |
85 | impl FromStr for Color { |
86 | type Err = (); |
87 | |
88 | fn from_str(src: &str) -> Result<Self, Self::Err> { |
89 | let src = src.to_lowercase(); |
90 | |
91 | match src.as_ref() { |
92 | "black" => Ok(Color::Black), |
93 | "red" => Ok(Color::Red), |
94 | "green" => Ok(Color::Green), |
95 | "yellow" => Ok(Color::Yellow), |
96 | "blue" => Ok(Color::Blue), |
97 | "magenta" => Ok(Color::Magenta), |
98 | "purple" => Ok(Color::Magenta), |
99 | "cyan" => Ok(Color::Cyan), |
100 | "white" => Ok(Color::White), |
101 | "bright black" => Ok(Color::BrightBlack), |
102 | "bright red" => Ok(Color::BrightRed), |
103 | "bright green" => Ok(Color::BrightGreen), |
104 | "bright yellow" => Ok(Color::BrightYellow), |
105 | "bright blue" => Ok(Color::BrightBlue), |
106 | "bright magenta" => Ok(Color::BrightMagenta), |
107 | "bright cyan" => Ok(Color::BrightCyan), |
108 | "bright white" => Ok(Color::BrightWhite), |
109 | _ => Err(()), |
110 | } |
111 | } |
112 | } |
113 | |
114 | #[cfg (test)] |
115 | mod tests { |
116 | pub use super::*; |
117 | |
118 | mod from_str { |
119 | pub use super::*; |
120 | |
121 | macro_rules! make_test { |
122 | ( $( $name:ident: $src:expr => $dst:expr),* ) => { |
123 | |
124 | $( |
125 | #[test] |
126 | fn $name() { |
127 | let color : Color = $src.into(); |
128 | assert_eq!($dst, color) |
129 | } |
130 | )* |
131 | } |
132 | } |
133 | |
134 | make_test!( |
135 | black: "black" => Color::Black, |
136 | red: "red" => Color::Red, |
137 | green: "green" => Color::Green, |
138 | yellow: "yellow" => Color::Yellow, |
139 | blue: "blue" => Color::Blue, |
140 | magenta: "magenta" => Color::Magenta, |
141 | purple: "purple" => Color::Magenta, |
142 | cyan: "cyan" => Color::Cyan, |
143 | white: "white" => Color::White, |
144 | brightblack: "bright black" => Color::BrightBlack, |
145 | brightred: "bright red" => Color::BrightRed, |
146 | brightgreen: "bright green" => Color::BrightGreen, |
147 | brightyellow: "bright yellow" => Color::BrightYellow, |
148 | brightblue: "bright blue" => Color::BrightBlue, |
149 | brightmagenta: "bright magenta" => Color::BrightMagenta, |
150 | brightcyan: "bright cyan" => Color::BrightCyan, |
151 | brightwhite: "bright white" => Color::BrightWhite, |
152 | |
153 | invalid: "invalid" => Color::White, |
154 | capitalized: "BLUE" => Color::Blue, |
155 | mixed_case: "bLuE" => Color::Blue |
156 | ); |
157 | } |
158 | |
159 | mod from_string { |
160 | pub use super::*; |
161 | |
162 | macro_rules! make_test { |
163 | ( $( $name:ident: $src:expr => $dst:expr),* ) => { |
164 | |
165 | $( |
166 | #[test] |
167 | fn $name() { |
168 | let src = String::from($src); |
169 | let color : Color = src.into(); |
170 | assert_eq!($dst, color) |
171 | } |
172 | )* |
173 | } |
174 | } |
175 | |
176 | make_test!( |
177 | black: "black" => Color::Black, |
178 | red: "red" => Color::Red, |
179 | green: "green" => Color::Green, |
180 | yellow: "yellow" => Color::Yellow, |
181 | blue: "blue" => Color::Blue, |
182 | magenta: "magenta" => Color::Magenta, |
183 | cyan: "cyan" => Color::Cyan, |
184 | white: "white" => Color::White, |
185 | brightblack: "bright black" => Color::BrightBlack, |
186 | brightred: "bright red" => Color::BrightRed, |
187 | brightgreen: "bright green" => Color::BrightGreen, |
188 | brightyellow: "bright yellow" => Color::BrightYellow, |
189 | brightblue: "bright blue" => Color::BrightBlue, |
190 | brightmagenta: "bright magenta" => Color::BrightMagenta, |
191 | brightcyan: "bright cyan" => Color::BrightCyan, |
192 | brightwhite: "bright white" => Color::BrightWhite, |
193 | |
194 | invalid: "invalid" => Color::White, |
195 | capitalized: "BLUE" => Color::Blue, |
196 | mixed_case: "bLuE" => Color::Blue |
197 | ); |
198 | } |
199 | |
200 | mod fromstr { |
201 | pub use super::*; |
202 | |
203 | #[test ] |
204 | fn parse() { |
205 | let color: Result<Color, _> = "blue" .parse(); |
206 | assert_eq!(Ok(Color::Blue), color) |
207 | } |
208 | |
209 | #[test ] |
210 | fn error() { |
211 | let color: Result<Color, ()> = "bloublou" .parse(); |
212 | assert_eq!(Err(()), color) |
213 | } |
214 | } |
215 | } |
216 | |