1use std::fmt::{self, Debug, Display, Formatter};
2
3#[derive(Default, Clone, Copy)]
5pub struct Style {
6 color: Option<Color>,
7 bold: bool,
8 underline: bool,
9 dimmed: bool,
10}
11
12#[derive(Clone, Copy)]
14pub enum Color {
15 Red,
16 Green,
17 Blue,
18 Yellow,
19 Magenta,
20 Cyan,
21 White,
22 Black,
23 BrightRed,
24 BrightGreen,
25 BrightBlue,
26 BrightYellow,
27 BrightMagenta,
28 BrightCyan,
29 BrightWhite,
30}
31
32impl Style {
33 pub fn new() -> Self {
35 Style {
36 color: None,
37 bold: false,
38 underline: false,
39 dimmed: false,
40 }
41 }
42
43 pub fn red(self) -> Self {
45 Style {
46 color: Some(Color::Red),
47 bold: self.bold,
48 underline: self.underline,
49 dimmed: self.dimmed,
50 }
51 }
52
53 pub fn green(self) -> Self {
55 Style {
56 color: Some(Color::Green),
57 bold: self.bold,
58 underline: self.underline,
59 dimmed: self.dimmed,
60 }
61 }
62
63 pub fn blue(self) -> Self {
65 Style {
66 color: Some(Color::Blue),
67 bold: self.bold,
68 underline: self.underline,
69 dimmed: self.dimmed,
70 }
71 }
72
73 pub fn yellow(self) -> Self {
75 Style {
76 color: Some(Color::Yellow),
77 bold: self.bold,
78 underline: self.underline,
79 dimmed: self.dimmed,
80 }
81 }
82
83 pub fn magenta(self) -> Self {
85 Style {
86 color: Some(Color::Magenta),
87 bold: self.bold,
88 underline: self.underline,
89 dimmed: self.dimmed,
90 }
91 }
92
93 pub fn cyan(self) -> Self {
95 Style {
96 color: Some(Color::Cyan),
97 bold: self.bold,
98 underline: self.underline,
99 dimmed: self.dimmed,
100 }
101 }
102
103 pub fn white(self) -> Self {
105 Style {
106 color: Some(Color::White),
107 bold: self.bold,
108 underline: self.underline,
109 dimmed: self.dimmed,
110 }
111 }
112
113 pub fn black(self) -> Self {
115 Style {
116 color: Some(Color::Black),
117 bold: self.bold,
118 underline: self.underline,
119 dimmed: self.dimmed,
120 }
121 }
122
123 pub fn bright_red(self) -> Self {
125 Style {
126 color: Some(Color::BrightRed),
127 bold: self.bold,
128 underline: self.underline,
129 dimmed: self.dimmed,
130 }
131 }
132
133 pub fn bright_green(self) -> Self {
135 Style {
136 color: Some(Color::BrightGreen),
137 bold: self.bold,
138 underline: self.underline,
139 dimmed: self.dimmed,
140 }
141 }
142
143 pub fn bright_blue(self) -> Self {
145 Style {
146 color: Some(Color::BrightBlue),
147 bold: self.bold,
148 underline: self.underline,
149 dimmed: self.dimmed,
150 }
151 }
152
153 pub fn bright_yellow(self) -> Self {
155 Style {
156 color: Some(Color::BrightYellow),
157 bold: self.bold,
158 underline: self.underline,
159 dimmed: self.dimmed,
160 }
161 }
162
163 pub fn bright_magenta(self) -> Self {
165 Style {
166 color: Some(Color::BrightMagenta),
167 bold: self.bold,
168 underline: self.underline,
169 dimmed: self.dimmed,
170 }
171 }
172
173 pub fn bright_cyan(self) -> Self {
175 Style {
176 color: Some(Color::BrightCyan),
177 bold: self.bold,
178 underline: self.underline,
179 dimmed: self.dimmed,
180 }
181 }
182
183 pub fn bright_white(self) -> Self {
185 Style {
186 color: Some(Color::BrightWhite),
187 bold: self.bold,
188 underline: self.underline,
189 dimmed: self.dimmed,
190 }
191 }
192
193 pub fn bold(self) -> Self {
195 Style {
196 color: self.color,
197 bold: true,
198 underline: self.underline,
199 dimmed: self.dimmed,
200 }
201 }
202
203 pub fn underline(self) -> Self {
205 Style {
206 color: self.color,
207 bold: self.bold,
208 underline: true,
209 dimmed: self.dimmed,
210 }
211 }
212
213 pub fn dimmed(self) -> Self {
215 Style {
216 color: self.color,
217 bold: self.bold,
218 underline: self.underline,
219 dimmed: true,
220 }
221 }
222}
223
224pub struct StyledDisplay<T> {
226 value: T,
227 style: Style,
228}
229
230impl Color {
231 fn ansi_code(&self) -> &'static str {
232 match self {
233 Color::Red => "\x1b[31m",
234 Color::Green => "\x1b[32m",
235 Color::Blue => "\x1b[34m",
236 Color::Yellow => "\x1b[33m",
237 Color::Magenta => "\x1b[35m",
238 Color::Cyan => "\x1b[36m",
239 Color::White => "\x1b[37m",
240 Color::Black => "\x1b[30m",
241 Color::BrightRed => "\x1b[91m",
242 Color::BrightGreen => "\x1b[92m",
243 Color::BrightBlue => "\x1b[94m",
244 Color::BrightYellow => "\x1b[93m",
245 Color::BrightMagenta => "\x1b[95m",
246 Color::BrightCyan => "\x1b[96m",
247 Color::BrightWhite => "\x1b[97m",
248 }
249 }
250}
251
252impl Style {
253 fn format_codes(&self) -> String {
255 let mut format_codes = String::new();
256
257 if self.bold {
258 format_codes.push_str("\x1b[1m");
259 }
260
261 if self.underline {
262 format_codes.push_str("\x1b[4m");
263 }
264
265 if self.dimmed {
266 format_codes.push_str("\x1b[2m");
267 }
268
269 if let Some(color) = self.color {
270 format_codes.push_str(color.ansi_code());
271 }
272
273 format_codes
274 }
275}
276
277impl<T: Display> Display for StyledDisplay<T> {
278 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
279 let format_codes = self.style.format_codes();
280
281 if format_codes.is_empty() {
282 write!(f, "{}", self.value)
283 } else {
284 write!(f, "{}{}\x1b[0m", format_codes, self.value)
285 }
286 }
287}
288
289impl<T: Debug> Debug for StyledDisplay<T> {
290 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
291 let format_codes = self.style.format_codes();
292
293 if format_codes.is_empty() {
294 write!(f, "{:?}", self.value)
295 } else {
296 write!(f, "{}{:?}\x1b[0m", format_codes, self.value)
297 }
298 }
299}
300
301pub trait Stylize {
303 fn style(self, style: Style) -> StyledDisplay<Self>
305 where
306 Self: Sized;
307
308 fn red(self) -> StyledDisplay<Self>
310 where
311 Self: Sized;
312
313 fn green(self) -> StyledDisplay<Self>
315 where
316 Self: Sized;
317
318 fn blue(self) -> StyledDisplay<Self>
320 where
321 Self: Sized;
322
323 fn yellow(self) -> StyledDisplay<Self>
325 where
326 Self: Sized;
327
328 fn magenta(self) -> StyledDisplay<Self>
330 where
331 Self: Sized;
332
333 fn cyan(self) -> StyledDisplay<Self>
335 where
336 Self: Sized;
337
338 fn white(self) -> StyledDisplay<Self>
340 where
341 Self: Sized;
342
343 fn black(self) -> StyledDisplay<Self>
345 where
346 Self: Sized;
347
348 fn bright_red(self) -> StyledDisplay<Self>
350 where
351 Self: Sized;
352
353 fn bright_green(self) -> StyledDisplay<Self>
355 where
356 Self: Sized;
357
358 fn bright_blue(self) -> StyledDisplay<Self>
360 where
361 Self: Sized;
362
363 fn bright_yellow(self) -> StyledDisplay<Self>
365 where
366 Self: Sized;
367
368 fn bright_magenta(self) -> StyledDisplay<Self>
370 where
371 Self: Sized;
372
373 fn bright_cyan(self) -> StyledDisplay<Self>
375 where
376 Self: Sized;
377
378 fn bright_white(self) -> StyledDisplay<Self>
380 where
381 Self: Sized;
382
383 fn bold(self) -> StyledDisplay<Self>
385 where
386 Self: Sized;
387
388 fn underline(self) -> StyledDisplay<Self>
390 where
391 Self: Sized;
392
393 fn dimmed(self) -> StyledDisplay<Self>
395 where
396 Self: Sized;
397}
398
399impl<T: Display> Stylize for T {
400 fn style(self, style: Style) -> StyledDisplay<Self> {
401 StyledDisplay { value: self, style }
402 }
403
404 fn red(self) -> StyledDisplay<Self> {
405 StyledDisplay {
406 value: self,
407 style: Style::new().red(),
408 }
409 }
410
411 fn green(self) -> StyledDisplay<Self> {
412 StyledDisplay {
413 value: self,
414 style: Style::new().green(),
415 }
416 }
417
418 fn blue(self) -> StyledDisplay<Self> {
419 StyledDisplay {
420 value: self,
421 style: Style::new().blue(),
422 }
423 }
424
425 fn yellow(self) -> StyledDisplay<Self> {
426 StyledDisplay {
427 value: self,
428 style: Style::new().yellow(),
429 }
430 }
431
432 fn magenta(self) -> StyledDisplay<Self> {
433 StyledDisplay {
434 value: self,
435 style: Style::new().magenta(),
436 }
437 }
438
439 fn cyan(self) -> StyledDisplay<Self> {
440 StyledDisplay {
441 value: self,
442 style: Style::new().cyan(),
443 }
444 }
445
446 fn white(self) -> StyledDisplay<Self> {
447 StyledDisplay {
448 value: self,
449 style: Style::new().white(),
450 }
451 }
452
453 fn black(self) -> StyledDisplay<Self> {
454 StyledDisplay {
455 value: self,
456 style: Style::new().black(),
457 }
458 }
459
460 fn bright_red(self) -> StyledDisplay<Self> {
461 StyledDisplay {
462 value: self,
463 style: Style::new().bright_red(),
464 }
465 }
466
467 fn bright_green(self) -> StyledDisplay<Self> {
468 StyledDisplay {
469 value: self,
470 style: Style::new().bright_green(),
471 }
472 }
473
474 fn bright_blue(self) -> StyledDisplay<Self> {
475 StyledDisplay {
476 value: self,
477 style: Style::new().bright_blue(),
478 }
479 }
480
481 fn bright_yellow(self) -> StyledDisplay<Self> {
482 StyledDisplay {
483 value: self,
484 style: Style::new().bright_yellow(),
485 }
486 }
487
488 fn bright_magenta(self) -> StyledDisplay<Self> {
489 StyledDisplay {
490 value: self,
491 style: Style::new().bright_magenta(),
492 }
493 }
494
495 fn bright_cyan(self) -> StyledDisplay<Self> {
496 StyledDisplay {
497 value: self,
498 style: Style::new().bright_cyan(),
499 }
500 }
501
502 fn bright_white(self) -> StyledDisplay<Self> {
503 StyledDisplay {
504 value: self,
505 style: Style::new().bright_white(),
506 }
507 }
508
509 fn bold(self) -> StyledDisplay<Self> {
510 StyledDisplay {
511 value: self,
512 style: Style::new().bold(),
513 }
514 }
515
516 fn underline(self) -> StyledDisplay<Self> {
517 StyledDisplay {
518 value: self,
519 style: Style::new().underline(),
520 }
521 }
522
523 fn dimmed(self) -> StyledDisplay<Self> {
524 StyledDisplay {
525 value: self,
526 style: Style::new().dimmed(),
527 }
528 }
529}