cli_colors/
lib.rs

1use std::fmt::Display;
2
3pub enum Color {
4    Black = 30,
5    Red = 31,
6    Green = 32,
7    Yellow = 33,
8    Blue = 34,
9    Magenta = 35,
10    Cyan = 36,
11    White = 37,
12    // Bright colors (requires aixterm)
13    BrightBlack = 90,
14    BrightRed = 91,
15    BrightGreen = 92,
16    BrightYellow = 93,
17    BrightBlue = 94,
18    BrightMagenta = 95,
19    BrightCyan = 96,
20    BrightWhite = 97,
21}
22
23pub struct Colorizer;
24
25impl Colorizer {
26    pub fn new() -> Colorizer {
27        Colorizer
28    }
29
30    /// This is needed to determine if features such as bright colors are supported.
31    fn supports_aixterm() -> bool {
32        std::env::var("TERM").unwrap_or_default().contains("xterm")
33    }
34
35    fn ansi<T: Display>(&self, input: T, ansi_code: u8) -> String {
36        format!("\x1b[{}m{}\x1b[0m", ansi_code, input)
37    }
38
39    pub fn underline<T: Display>(&self, input: T) -> String {
40        self.ansi(input, 4)
41    }
42
43    pub fn bold<T: Display>(&self, input: T) -> String {
44        self.ansi(input, 1)
45    }
46
47    pub fn italic<T: Display>(&self, input: T) -> String {
48        self.ansi(input, 3)
49    }
50
51    pub fn strikethrough<T: Display>(&self, input: T) -> String {
52        self.ansi(input, 9)
53    }
54
55    pub fn black<T: Display>(&self, input: T) -> String {
56        self.ansi(input, Color::Black as u8)
57    }
58
59    pub fn red<T: Display>(&self, input: T) -> String {
60        self.ansi(input, Color::Red as u8)
61    }
62
63    pub fn green<T: Display>(&self, input: T) -> String {
64        self.ansi(input, Color::Green as u8)
65    }
66
67    pub fn yellow<T: Display>(&self, input: T) -> String {
68        self.ansi(input, Color::Yellow as u8)
69    }
70
71    pub fn blue<T: Display>(&self, input: T) -> String {
72        self.ansi(input, Color::Blue as u8)
73    }
74
75    pub fn magenta<T: Display>(&self, input: T) -> String {
76        self.ansi(input, Color::Magenta as u8)
77    }
78
79    pub fn cyan<T: Display>(&self, input: T) -> String {
80        self.ansi(input, Color::Cyan as u8)
81    }
82
83    pub fn white<T: Display>(&self, input: T) -> String {
84        self.ansi(input, Color::White as u8)
85    }
86
87    pub fn bright_black<T: Display>(&self, input: T) -> String {
88        assert!(
89            Self::supports_aixterm(),
90            "Bright colors require aixterm support",
91        );
92        self.ansi(input, Color::BrightBlack as u8)
93    }
94
95    pub fn bright_red<T: Display>(&self, input: T) -> String {
96        assert!(
97            Self::supports_aixterm(),
98            "Bright colors require aixterm support",
99        );
100        self.ansi(input, Color::BrightRed as u8)
101    }
102
103    pub fn bright_green<T: Display>(&self, input: T) -> String {
104        assert!(
105            Self::supports_aixterm(),
106            "Bright colors require aixterm support",
107        );
108        self.ansi(input, Color::BrightGreen as u8)
109    }
110
111    pub fn bright_yellow<T: Display>(&self, input: T) -> String {
112        assert!(
113            Self::supports_aixterm(),
114            "Bright colors require aixterm support",
115        );
116        self.ansi(input, Color::BrightYellow as u8)
117    }
118
119    pub fn bright_blue<T: Display>(&self, input: T) -> String {
120        assert!(
121            Self::supports_aixterm(),
122            "Bright colors require aixterm support",
123        );
124        self.ansi(input, Color::BrightBlue as u8)
125    }
126
127    pub fn bright_magenta<T: Display>(&self, input: T) -> String {
128        assert!(
129            Self::supports_aixterm(),
130            "Bright colors require aixterm support",
131        );
132        self.ansi(input, Color::BrightMagenta as u8)
133    }
134
135    pub fn bright_cyan<T: Display>(&self, input: T) -> String {
136        assert!(
137            Self::supports_aixterm(),
138            "Bright colors require aixterm support",
139        );
140        self.ansi(input, Color::BrightCyan as u8)
141    }
142
143    pub fn bright_white<T: Display>(&self, input: T) -> String {
144        assert!(
145            Self::supports_aixterm(),
146            "Bright colors require aixterm support",
147        );
148        self.ansi(input, Color::BrightWhite as u8)
149    }
150
151    pub fn bg_black<T: Display>(&self, input: T) -> String {
152        format!("\x1b[40m{}\x1b[0m", input)
153    }
154
155    pub fn bg_red<T: Display>(&self, input: T) -> String {
156        format!("\x1b[41m{}\x1b[0m", input)
157    }
158
159    pub fn bg_green<T: Display>(&self, input: T) -> String {
160        format!("\x1b[42m{}\x1b[0m", input)
161    }
162
163    pub fn bg_yellow<T: Display>(&self, input: T) -> String {
164        format!("\x1b[43m{}\x1b[0m", input)
165    }
166
167    pub fn bg_blue<T: Display>(&self, input: T) -> String {
168        format!("\x1b[44m{}\x1b[0m", input)
169    }
170
171    pub fn bg_magenta<T: Display>(&self, input: T) -> String {
172        format!("\x1b[45m{}\x1b[0m", input)
173    }
174
175    pub fn bg_cyan<T: Display>(&self, input: T) -> String {
176        format!("\x1b[46m{}\x1b[0m", input)
177    }
178
179    pub fn bg_white<T: Display>(&self, input: T) -> String {
180        format!("\x1b[47m{}\x1b[0m", input)
181    }
182
183    pub fn rgb<T: Display>(&self, input: T, r: u8, g: u8, b: u8) -> String {
184        format!("\x1b[38;2;{};{};{}m{}\x1b[0m", r, g, b, input)
185    }
186
187    pub fn bg_rgb<T: Display>(&self, input: T, r: u8, g: u8, b: u8) -> String {
188        format!("\x1b[48;2;{};{};{}m{}\x1b[0m", r, g, b, input)
189    }
190
191    pub fn rgb256<T: Display>(&self, input: T, r: u8, g: u8, b: u8) -> String {
192        format!("\x1b[38;5;{}m{}\x1b[0m", 16 + 36 * r + 6 * g + b, input)
193    }
194
195    pub fn bg_rgb256<T: Display>(&self, input: T, r: u8, g: u8, b: u8) -> String {
196        format!("\x1b[48;5;{}m{}\x1b[0m", 16 + 36 * r + 6 * g + b, input)
197    }
198
199    pub fn reset<T: Display>(&self, input: T) -> String {
200        format!("\x1b[0m{}\x1b[0m", input)
201    }
202
203    pub fn bold_underline<T: Display>(&self, input: T) -> String {
204        self.ansi(self.underline(self.bold(input)), 1)
205    }
206
207    pub fn bold_italic<T: Display>(&self, input: T) -> String {
208        self.ansi(self.italic(self.bold(input)), 1)
209    }
210
211    pub fn bold_strikethrough<T: Display>(&self, input: T) -> String {
212        self.ansi(self.strikethrough(self.bold(input)), 1)
213    }
214
215    pub fn underline_italic<T: Display>(&self, input: T) -> String {
216        self.ansi(self.italic(self.underline(input)), 1)
217    }
218
219    pub fn underline_strikethrough<T: Display>(&self, input: T) -> String {
220        self.ansi(self.strikethrough(self.underline(input)), 1)
221    }
222
223    pub fn italic_strikethrough<T: Display>(&self, input: T) -> String {
224        self.ansi(self.strikethrough(self.italic(input)), 1)
225    }
226
227    pub fn bold_underline_italic<T: Display>(&self, input: T) -> String {
228        self.ansi(self.italic(self.underline(self.bold(input))), 1)
229    }
230
231    pub fn bold_underline_strikethrough<T: Display>(&self, input: T) -> String {
232        self.ansi(self.strikethrough(self.underline(self.bold(input))), 1)
233    }
234
235    pub fn bold_italic_strikethrough<T: Display>(&self, input: T) -> String {
236        self.ansi(self.strikethrough(self.italic(self.bold(input))), 1)
237    }
238
239    pub fn underline_italic_strikethrough<T: Display>(&self, input: T) -> String {
240        self.ansi(self.strikethrough(self.italic(self.underline(input))), 1)
241    }
242
243    pub fn rainbow<T: Display>(&self, input: T) -> String {
244        let mut rainbow = String::new();
245        for (i, c) in input.to_string().chars().enumerate() {
246            let color = match i % 6 {
247                0 => self.red(c),
248                1 => self.yellow(c),
249                2 => self.green(c),
250                3 => self.cyan(c),
251                4 => self.blue(c),
252                5 => self.magenta(c),
253                _ => unreachable!(),
254            };
255            rainbow.push_str(&color);
256        }
257        rainbow
258    }
259
260    pub fn bg_rainbow<T: Display>(&self, input: T) -> String {
261        let mut rainbow = String::new();
262        for (i, c) in input.to_string().chars().enumerate() {
263            let color = match i % 6 {
264                0 => self.bg_red(c),
265                1 => self.bg_yellow(c),
266                2 => self.bg_green(c),
267                3 => self.bg_cyan(c),
268                4 => self.bg_blue(c),
269                5 => self.bg_magenta(c),
270                _ => unreachable!(),
271            };
272            rainbow.push_str(&color);
273        }
274        rainbow
275    }
276
277    pub fn bg_rainbow256<T: Display>(&self, input: T) -> String {
278        let mut rainbow = String::new();
279        for (i, c) in input.to_string().chars().enumerate() {
280            let color = match i % 6 {
281                0 => self.bg_rgb256(c, 5, 0, 0),
282                1 => self.bg_rgb256(c, 5, 5, 0),
283                2 => self.bg_rgb256(c, 0, 5, 0),
284                3 => self.bg_rgb256(c, 0, 5, 5),
285                4 => self.bg_rgb256(c, 0, 0, 5),
286                5 => self.bg_rgb256(c, 5, 0, 5),
287                _ => unreachable!(),
288            };
289            rainbow.push_str(&color);
290        }
291        rainbow
292    }
293
294    pub fn bg_rainbow_rgb<T: Display>(&self, input: T) -> String {
295        let mut rainbow = String::new();
296        for (i, c) in input.to_string().chars().enumerate() {
297            let color = match i % 6 {
298                0 => self.bg_rgb(c, 255, 0, 0),
299                1 => self.bg_rgb(c, 255, 255, 0),
300                2 => self.bg_rgb(c, 0, 255, 0),
301                3 => self.bg_rgb(c, 0, 255, 255),
302                4 => self.bg_rgb(c, 0, 0, 255),
303                5 => self.bg_rgb(c, 255, 0, 255),
304                _ => unreachable!(),
305            };
306            rainbow.push_str(&color);
307        }
308        rainbow
309    }
310}