1use std::fmt::{Display, Error as FmtError, Formatter, Result as FmtResult};
7
8#[derive(Debug, Clone, Copy)]
9pub enum Color {
10 Black,
11 Red,
12 Green,
13 Yellow,
14 Blue,
15 Magenta,
16 Cyan,
17 White,
18 BrightBlack,
19 BrightRed,
20 BrightGreen,
21 BrightYellow,
22 BrightBlue,
23 BrightMagenta,
24 BrightCyan,
25 BrightWhite,
26}
27impl Color {
28 pub fn from(s: &str) -> Self {
29 match s {
30 "black" => Color::Black,
31 "red" => Color::Red,
32 "green" => Color::Green,
33 "yellow" => Color::Yellow,
34 "blue" => Color::Blue,
35 "magenta" => Color::Magenta,
36 "cyan" => Color::Cyan,
37 "white" => Color::White,
38 "bright black" => Color::BrightBlack,
39 "bright red" => Color::BrightRed,
40 "bright green" => Color::BrightGreen,
41 "bright yellow" => Color::BrightYellow,
42 "bright blue" => Color::BrightBlue,
43 "bright magenta" => Color::BrightMagenta,
44 "bright cyan" => Color::BrightCyan,
45 "bright white" => Color::BrightWhite,
46
47 _ => {
48 let ret = Color::White;
49 log::warn!("錯誤的顏色 {},改用 {:?}", s, ret);
50 ret
51 }
52 }
53 }
54}
55
56const BOLD: u8 = 0;
57const DIMMED: u8 = 1;
58const ITALIC: u8 = 2;
59const UNDERLINE: u8 = 3;
60
61#[derive(Default, Debug, Clone, Copy)]
62struct Style {
63 color: Option<Color>,
64 style_map: u8,
65}
66
67impl Style {
68 fn is_plain(&self) -> bool {
69 let Self { color, style_map } = self;
70 color.is_none() && *style_map == 0
71 }
72}
73
74pub struct StyleObj<T> {
75 obj: T,
76 style: Style,
77}
78
79impl<T> StyleObj<T> {
80 pub fn done(&self) -> () {
81 ()
82 }
83 pub fn bold(&mut self) -> &mut Self {
84 self.style.style_map |= 1 << BOLD;
85 self
86 }
87 pub fn dimmed(&mut self) -> &mut Self {
88 self.style.style_map |= 1 << DIMMED;
89 self
90 }
91 pub fn italic(&mut self) -> &mut Self {
92 self.style.style_map |= 1 << ITALIC;
93 self
94 }
95 pub fn underline(&mut self) -> &mut Self {
96 self.style.style_map |= 1 << UNDERLINE;
97 self
98 }
99 pub fn color(&mut self, color: Color) -> &mut Self {
100 self.style.color = Some(color);
101 self
102 }
103}
104
105pub trait Stylize<T> {
106 fn stylize(self) -> StyleObj<T>;
107}
108
109impl<T: Display> Stylize<T> for T {
110 fn stylize(self) -> StyleObj<T> {
111 StyleObj {
112 obj: self,
113 style: Default::default(),
114 }
115 }
116}
117
118fn fmt_stylemap(f: &mut Formatter<'_>, style_map: u8) -> Result<bool, FmtError> {
119 let mut first = true;
120
121 let mut my_write = |s: &'static str| -> FmtResult {
122 if !first {
123 write!(f, ";")?;
124 } else {
125 first = false;
126 }
127 write!(f, "{}", s)
128 };
129
130 if style_map & 1 << BOLD != 0 {
131 my_write("1")?;
132 }
133 if style_map & 1 << DIMMED != 0 {
134 my_write("2")?;
135 }
136 if style_map & 1 << ITALIC != 0 {
137 my_write("3")?;
138 }
139 if style_map & 1 << UNDERLINE != 0 {
140 my_write("4")?;
141 }
142
143 Ok(first)
144}
145fn fmt_color(f: &mut Formatter, color: Color) -> FmtResult {
146 let s = match color {
147 Color::Black => "30",
148 Color::Red => "31",
149 Color::Green => "32",
150 Color::Yellow => "33",
151 Color::Blue => "34",
152 Color::Magenta => "35",
153 Color::Cyan => "36",
154 Color::White => "37",
155 Color::BrightBlack => "90",
156 Color::BrightRed => "91",
157 Color::BrightGreen => "92",
158 Color::BrightYellow => "93",
159 Color::BrightBlue => "94",
160 Color::BrightMagenta => "95",
161 Color::BrightCyan => "96",
162 Color::BrightWhite => "97",
163 };
164 write!(f, "{}", s)
165}
166
167impl<T: Display> Display for StyleObj<T> {
168 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
169 if self.style.is_plain() {
170 return write!(f, "{}", self.obj);
171 }
172
173 write!(f, "\x1B[")?;
174 let first = fmt_stylemap(f, self.style.style_map)?;
175
176 if let Some(color) = self.style.color {
177 if !first {
178 write!(f, ";")?;
179 }
180 fmt_color(f, color)?;
181 }
182
183 write!(f, "m")?;
184 write!(f, "{}", self.obj)?;
185 write!(f, "\x1B[0m")
186 }
187}