1use crate::background_colors::BackgroundColors;
2use crate::foreground_colors::ForegroundColors;
3use std::fmt;
4use std::ops::Add;
5
6pub enum FontMode {
7 Bold(&'static str),
8 Dim(&'static str),
9 Italic(&'static str),
10 Underline(&'static str),
11 Blinking(&'static str),
12 Reverse(&'static str),
13 Invisible(&'static str),
14 Strikethrough(&'static str),
15 ResetAll(&'static str),
16 ResetBold(&'static str),
17 ResetDim(&'static str),
18 ResetItalic(&'static str),
19 ResetUnderline(&'static str),
20 ResetBlinking(&'static str),
21 ResetReverse(&'static str),
22 ResetInvisible(&'static str),
23 ResetStrikethrough(&'static str),
24}
25
26impl FontMode {
27 pub fn bold() -> Self {
28 FontMode::Bold("\x1B[1m")
29 }
30
31 pub fn dim() -> Self {
32 FontMode::Dim("\x1B[2m")
33 }
34
35 pub fn italic() -> Self {
36 FontMode::Italic("\x1B[3m")
37 }
38
39 pub fn underline() -> Self {
40 FontMode::Underline("\x1B[4m")
41 }
42
43 pub fn blinking() -> Self {
44 FontMode::Blinking("\x1B[5m")
45 }
46
47 pub fn reverse() -> Self {
48 FontMode::Reverse("\x1B[7m")
49 }
50
51 pub fn invisible() -> Self {
52 FontMode::Invisible("\x1B[8m")
53 }
54
55 pub fn strikethrough() -> Self {
56 FontMode::Strikethrough("\x1B[9m")
57 }
58
59 pub fn reset_all() -> Self {
60 FontMode::ResetAll("\x1B[0m")
61 }
62
63 pub fn reset_bold() -> Self {
64 FontMode::ResetBold("\x1B[22m")
65 }
66
67 pub fn reset_dim() -> Self {
68 FontMode::ResetDim("\x1B[22m")
69 }
70
71 pub fn reset_italic() -> Self {
72 FontMode::ResetItalic("\x1B[23m")
73 }
74
75 pub fn reset_underline() -> Self {
76 FontMode::ResetUnderline("\x1B[24m")
77 }
78
79 pub fn reset_blinking() -> Self {
80 FontMode::ResetBlinking("\x1B[25m")
81 }
82
83 pub fn reset_reverse() -> Self {
84 FontMode::ResetReverse("\x1B[27m")
85 }
86
87 pub fn reset_invisible() -> Self {
88 FontMode::ResetInvisible("\x1B[28m")
89 }
90
91 pub fn reset_strikethrough() -> Self {
92 FontMode::ResetStrikethrough("\x1B[29m")
93 }
94}
95
96impl fmt::Display for FontMode {
97 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 match self {
99 FontMode::Bold(s) => write!(f, "{}", s),
100 FontMode::Dim(s) => write!(f, "{}", s),
101 FontMode::Italic(s) => write!(f, "{}", s),
102 FontMode::Underline(s) => write!(f, "{}", s),
103 FontMode::Blinking(s) => write!(f, "{}", s),
104 FontMode::Reverse(s) => write!(f, "{}", s),
105 FontMode::Invisible(s) => write!(f, "{}", s),
106 FontMode::Strikethrough(s) => write!(f, "{}", s),
107 FontMode::ResetAll(s) => write!(f, "{}", s),
108 FontMode::ResetBold(s) => write!(f, "{}", s),
109 FontMode::ResetDim(s) => write!(f, "{}", s),
110 FontMode::ResetItalic(s) => write!(f, "{}", s),
111 FontMode::ResetUnderline(s) => write!(f, "{}", s),
112 FontMode::ResetBlinking(s) => write!(f, "{}", s),
113 FontMode::ResetReverse(s) => write!(f, "{}", s),
114 FontMode::ResetInvisible(s) => write!(f, "{}", s),
115 FontMode::ResetStrikethrough(s) => write!(f, "{}", s),
116 }
117 }
118}
119
120impl Add<BackgroundColors> for FontMode {
121 type Output = String;
122
123 fn add(self, rhs: BackgroundColors) -> Self::Output {
124 let font_mode = self.to_string().replace("\x1B[", "").replace("m", "");
125 let background_color = rhs.to_string().replace("\x1B[", "").replace("m", "");
126
127 format!("\x1B[{};{}m", font_mode, background_color)
128 }
129}
130
131impl Add<ForegroundColors> for FontMode {
132 type Output = String;
133
134 fn add(self, rhs: ForegroundColors) -> Self::Output {
135 let font_mode = self.to_string().replace("\x1B[", "").replace("m", "");
136 let foreground_color = rhs.to_string().replace("\x1B[", "").replace("m", "");
137
138 format!("\x1B[{};{}m", font_mode, foreground_color)
139 }
140}
141
142impl Add<FontMode> for FontMode {
143 type Output = String;
144
145 fn add(self, rhs: FontMode) -> Self::Output {
146 let font_mode_lhs = self.to_string().replace("\x1B[", "").replace("m", "");
147 let font_mode_rhs = rhs.to_string().replace("\x1B[", "").replace("m", "");
148
149 format!("\x1B[{};{}m", font_mode_lhs, font_mode_rhs)
150 }
151}
152
153impl Add<String> for FontMode {
154 type Output = String;
155
156 fn add(self, rhs: String) -> Self::Output {
157 let font_mode = self.to_string().replace("\x1B[", "").replace("m", "");
158 let string = rhs.to_string().replace("\x1B[", "").replace("m", "");
159
160 format!("\x1B[{};{}m", font_mode, string)
161 }
162}
163
164impl Add<FontMode> for String {
165 type Output = String;
166
167 fn add(self, rhs: FontMode) -> Self::Output {
168 let string = self.to_string().replace("\x1B[", "").replace("m", "");
169 let font_mode = rhs.to_string().replace("\x1B[", "").replace("m", "");
170
171 format!("\x1B[{};{}m", string, font_mode)
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178
179 #[test]
180 fn test_bold() {
181 assert_eq!("\x1B[1m", FontMode::bold().to_string());
182 }
183
184 #[test]
185 fn test_dim() {
186 assert_eq!("\x1B[2m", FontMode::dim().to_string());
187 }
188
189 #[test]
190 fn test_italic() {
191 assert_eq!("\x1B[3m", FontMode::italic().to_string());
192 }
193
194 #[test]
195 fn test_underline() {
196 assert_eq!("\x1B[4m", FontMode::underline().to_string());
197 }
198
199 #[test]
200 fn test_blinking() {
201 assert_eq!("\x1B[5m", FontMode::blinking().to_string());
202 }
203
204 #[test]
205 fn test_reverse() {
206 assert_eq!("\x1B[7m", FontMode::reverse().to_string());
207 }
208
209 #[test]
210 fn test_invisible() {
211 assert_eq!("\x1B[8m", FontMode::invisible().to_string());
212 }
213
214 #[test]
215 fn test_strikethrough() {
216 assert_eq!("\x1B[9m", FontMode::strikethrough().to_string());
217 }
218
219 #[test]
220 fn test_reset_all() {
221 assert_eq!("\x1B[0m", FontMode::reset_all().to_string());
222 }
223
224 #[test]
225 fn test_reset_bold() {
226 assert_eq!("\x1B[22m", FontMode::reset_bold().to_string());
227 }
228
229 #[test]
230 fn test_reset_dim() {
231 assert_eq!("\x1B[22m", FontMode::reset_dim().to_string());
232 }
233
234 #[test]
235 fn test_reset_italic() {
236 assert_eq!("\x1B[23m", FontMode::reset_italic().to_string());
237 }
238
239 #[test]
240 fn test_reset_underline() {
241 assert_eq!("\x1B[24m", FontMode::reset_underline().to_string());
242 }
243
244 #[test]
245 fn test_reset_blinking() {
246 assert_eq!("\x1B[25m", FontMode::reset_blinking().to_string());
247 }
248
249 #[test]
250 fn test_reset_reverse() {
251 assert_eq!("\x1B[27m", FontMode::reset_reverse().to_string());
252 }
253
254 #[test]
255 fn test_reset_invisible() {
256 assert_eq!("\x1B[28m", FontMode::reset_invisible().to_string());
257 }
258
259 #[test]
260 fn test_reset_strikethrough() {
261 assert_eq!("\x1B[29m", FontMode::reset_strikethrough().to_string());
262 }
263
264 #[test]
265 fn test_font_mode_add_foreground_color() {
266 let font_mode = FontMode::blinking();
267 let foreground_color = ForegroundColors::blue();
268
269 assert_eq!("\x1B[5;34m", font_mode + foreground_color);
270 }
271
272 #[test]
273 fn test_font_mode_add_background_color() {
274 let font_mode = FontMode::blinking();
275 let background_color = BackgroundColors::blue();
276
277 assert_eq!("\x1B[5;44m", font_mode + background_color);
278 }
279
280 #[test]
281 fn test_font_mode_add_font_mode() {
282 let font_mode_one = FontMode::blinking();
283 let font_mode_two = FontMode::bold();
284
285 assert_eq!("\x1B[5;1m", font_mode_one + font_mode_two);
286 }
287
288 #[test]
289 fn test_font_mode_add_string() {
290 let font_mode = FontMode::underline();
291 let string = BackgroundColors::yellow() + ForegroundColors::bright_magenta();
292
293 assert_eq!("\x1B[4;43;95m", font_mode + string);
294 }
295
296 #[test]
297 fn test_string_add_font_mode() {
298 let string = BackgroundColors::yellow() + ForegroundColors::bright_magenta();
299 let font_mode = FontMode::underline();
300
301 assert_eq!("\x1B[43;95;4m", string + font_mode);
302 }
303}