1#![allow(unused)]
2use std::fmt;
3
4pub const BLACK: &str = "\x1b[30m";
5pub const RED: &str = "\x1b[31m";
6pub const GREEN: &str = "\x1b[32m";
7pub const YELLOW: &str = "\x1b[33m";
8pub const BLUE: &str = "\x1b[34m";
9pub const WHITE: &str = "\x1b[37m";
10pub const RESET: &str = "\x1b[0m";
11pub const BOLD: &str = "\x1b[1m";
12pub const ITALIC: &str = "\x1b[3m";
13pub const DIM: &str = "\x1b[2m";
14pub const DIMRESET: &str = "\x1b[22m";
15
16pub fn remove_colors(s: &str) -> String {
17 s.replace(BLACK, "")
18 .replace(RED, "")
19 .replace(GREEN, "")
20 .replace(YELLOW, "")
21 .replace(BLUE, "")
22 .replace(WHITE, "")
23 .replace(RESET, "")
24 .replace(BOLD, "")
25 .replace(ITALIC, "")
26 .replace(DIM, "")
27 .replace(DIMRESET, "")
28}
29
30type StylerEnabled = fn(&str) -> String;
31type ColorFunction = fn(&str) -> String;
32
33const GRADIENT_PURPLE_COLOR: [u8; 3] = [176, 106, 179];
35const GRADIENT_PINK_COLOR: [u8; 3] = [198, 66, 110];
36const BRAND_GRADIENT_COLORS: [u8; 3] = [255, 182, 193];
37const BRAND_GRADIENT_COLORS2: [u8; 3] = [128, 0, 128];
38
39pub fn is_color_enabled() -> bool {
40 true
41}
42
43pub fn create_formatter<'a>(open: &'a str, close: &'a str, replace: Option<&'a str>) -> impl Fn(&'a str) -> String + 'a {
44 move |input| {
45 let string = input.to_string();
46 let index = string.find(close).unwrap_or(open.len());
47 if let Some(replace_str) = replace {
48 let mut result = String::new();
49 result.push_str(open);
50 result.push_str(&replace_close(&string, close, replace_str, index));
51 result.push_str(close);
52 result
53 } else {
54 format!("{open}{string}{close}")
55 }
56 }
57}
58
59pub fn replace_close(string: &str, close: &str, replace: &str, index: usize) -> String {
60 let (start, end) = string.split_at(index);
61 let next_index_option = end.find(close).map(|i| i + close.len());
62 let next_index = next_index_option.unwrap_or(0);
63 if next_index != 0 {
64 format!(
65 "{}{}{}",
66 start,
67 replace,
68 replace_close(&end[next_index..], close, replace, next_index)
69 )
70 } else {
71 format!("{start}{replace}")
72 }
73}
74
75pub fn reset(s: &str) -> String {
76 if is_color_enabled() {
77 format!("\x1b[0m{s}")
78 } else {
79 s.to_string()
80 }
81}
82
83pub fn bold(s: &str) -> String {
84 if is_color_enabled() {
85 create_formatter("\x1b[1m", "\x1b[22m", Some("\x1b[22m\x1b[1m"))(s)
86 } else {
87 s.to_string()
88 }
89}
90
91pub fn dim(s: &str) -> String {
92 if is_color_enabled() {
93 create_formatter("\x1b[2m", "\x1b[22m", Some("\x1b[22m\x1b[2m"))(s)
94 } else {
95 s.to_string()
96 }
97}
98
99pub fn italic(s: &str) -> String {
100 if is_color_enabled() {
101 create_formatter("\x1b[3m", "\x1b[23m", None)(s)
102 } else {
103 s.to_string()
104 }
105}
106
107pub fn underline(s: &str) -> String {
108 if is_color_enabled() {
109 create_formatter("\x1b[4m", "\x1b[24m", None)(s)
110 } else {
111 s.to_string()
112 }
113}
114
115pub fn inverse(s: &str) -> String {
116 if is_color_enabled() {
117 create_formatter("\x1b[7m", "\x1b[27m", None)(s)
118 } else {
119 s.to_string()
120 }
121}
122
123pub fn hidden(s: &str) -> String {
124 if is_color_enabled() {
125 create_formatter("\x1b[8m", "\x1b[28m", None)(s)
126 } else {
127 s.to_string()
128 }
129}
130
131pub fn strikethrough(s: &str) -> String {
132 if is_color_enabled() {
133 create_formatter("\x1b[9m", "\x1b[29m", None)(s)
134 } else {
135 s.to_string()
136 }
137}
138
139pub fn debug_color(s: &str) -> String {
140 if is_color_enabled() {
141 create_formatter("\x1b[38;2;255;140;0m", "\x1b[39m", None)(s)
142 } else {
143 s.to_string()
144 }
145}
146
147pub fn brand_color(s: &str) -> String {
148 if is_color_enabled() {
149 create_formatter("\x1b[38;2;113;26;95m", "\x1b[39m", None)(s)
150 } else {
151 s.to_string()
152 }
153}
154
155pub fn black(s: &str) -> String {
157 if is_color_enabled() {
158 create_formatter("\x1b[38;2;0;0;0m", "\x1b[39m", None)(s)
159 } else {
160 s.to_string()
161 }
162}
163
164pub fn red(s: &str) -> String {
165 if is_color_enabled() {
166 create_formatter("\x1b[38;2;219;90;107m", "\x1b[39m", None)(s)
167 } else {
168 s.to_string()
169 }
170}
171
172pub fn green(s: &str) -> String {
173 if is_color_enabled() {
174 create_formatter("\x1b[32m", "\x1b[39m", None)(s)
175 } else {
176 s.to_string()
177 }
178}
179
180pub fn yellow(s: &str) -> String {
181 if is_color_enabled() {
182 create_formatter("\x1b[33m", "\x1b[39m", None)(s)
183 } else {
184 s.to_string()
185 }
186}
187
188pub fn blue(s: &str) -> String {
189 if is_color_enabled() {
190 create_formatter("\x1b[38;2;68;206;246m", "\x1b[39m", None)(s)
191 } else {
192 s.to_string()
193 }
194}
195
196pub fn magenta(s: &str) -> String {
197 if is_color_enabled() {
198 create_formatter("\x1b[38;2;180;0;100m", "\x1b[39m", None)(s)
199 } else {
200 s.to_string()
201 }
202}
203
204pub fn purple(s: &str) -> String {
205 if is_color_enabled() {
206 create_formatter("\x1b[38;2;140;67;86m", "\x1b[39m", None)(s)
207 } else {
208 s.to_string()
209 }
210}
211
212pub fn orange(s: &str) -> String {
213 if is_color_enabled() {
214 create_formatter("\x1b[38;2;255;137;54m", "\x1b[39m", None)(s)
215 } else {
216 s.to_string()
217 }
218}
219
220pub fn cyan(s: &str) -> String {
221 if is_color_enabled() {
222 create_formatter("\x1b[36m", "\x1b[39m", None)(s)
223 } else {
224 s.to_string()
225 }
226}
227
228pub fn white(s: &str) -> String {
229 if is_color_enabled() {
230 create_formatter("\x1b[37m", "\x1b[39m", None)(s)
231 } else {
232 s.to_string()
233 }
234}
235
236pub fn bg_black(s: &str) -> String {
237 if is_color_enabled() {
238 create_formatter("\x1b[40m", "\x1b[49m", None)(s)
239 } else {
240 s.to_string()
241 }
242}
243
244pub fn bg_red(s: &str) -> String {
245 if is_color_enabled() {
246 create_formatter("\x1b[41m", "\x1b[49m", None)(s)
247 } else {
248 s.to_string()
249 }
250}
251
252pub fn bg_green(s: &str) -> String {
253 if is_color_enabled() {
254 create_formatter("\x1b[42m", "\x1b[49m", None)(s)
255 } else {
256 s.to_string()
257 }
258}
259
260pub fn bg_yellow(s: &str) -> String {
261 if is_color_enabled() {
262 create_formatter("\x1b[43m", "\x1b[49m", None)(s)
263 } else {
264 s.to_string()
265 }
266}
267
268pub fn bg_blue(s: &str) -> String {
269 if is_color_enabled() {
270 create_formatter("\x1b[44m", "\x1b[49m", None)(s)
271 } else {
272 s.to_string()
273 }
274}
275
276pub fn bg_magenta(s: &str) -> String {
277 if is_color_enabled() {
278 create_formatter("\x1b[45m", "\x1b[49m", None)(s)
279 } else {
280 s.to_string()
281 }
282}
283
284pub fn bg_cyan(s: &str) -> String {
285 if is_color_enabled() {
286 create_formatter("\x1b[46m", "\x1b[49m", None)(s)
287 } else {
288 s.to_string()
289 }
290}
291
292pub fn bg_white(s: &str) -> String {
293 if is_color_enabled() {
294 create_formatter("\x1b[47m", "\x1b[49m", None)(s)
295 } else {
296 s.to_string()
297 }
298}
299
300pub fn gradient_string(text: &str, colors: &[[u8; 3]]) -> String {
301 let steps = text.len();
302 let gradient = colors
303 .iter()
304 .map(|color| format!("\x1b[38;2;{};{};{}m", color[0], color[1], color[2]))
305 .collect::<Vec<_>>();
306
307 let mut output = String::new();
308
309 for (i, c) in text.chars().enumerate() {
310 let color_index = ((i as f64) / (steps as f64) * (colors.len() as f64 - 1.0)).floor() as usize;
311 output += &format!("{}{}", gradient[color_index], c);
312 }
313
314 output += "\x1b[0m";
315 output
316}
317
318pub fn interpolate_color(color1: &[u8; 3], color2: &[u8; 3], factor: f64) -> [u8; 3] {
319 [
320 (color1[0] as f64 + (color2[0] as f64 - color1[0] as f64) * factor).round() as u8,
321 (color1[1] as f64 + (color2[1] as f64 - color1[1] as f64) * factor).round() as u8,
322 (color1[2] as f64 + (color2[2] as f64 - color1[2] as f64) * factor).round() as u8,
323 ]
324}
325
326pub fn persistent_cache_brand() -> String {
327 let gradient_string = gradient_string(
328 "FULL EXTREME!",
329 &[
330 GRADIENT_PURPLE_COLOR,
331 interpolate_color(&GRADIENT_PURPLE_COLOR, &GRADIENT_PINK_COLOR, 0.1),
332 interpolate_color(&GRADIENT_PURPLE_COLOR, &GRADIENT_PINK_COLOR, 0.2),
333 interpolate_color(&GRADIENT_PURPLE_COLOR, &GRADIENT_PINK_COLOR, 0.3),
334 interpolate_color(&GRADIENT_PURPLE_COLOR, &GRADIENT_PINK_COLOR, 0.4),
335 interpolate_color(&GRADIENT_PURPLE_COLOR, &GRADIENT_PINK_COLOR, 0.5),
336 interpolate_color(&GRADIENT_PURPLE_COLOR, &GRADIENT_PINK_COLOR, 0.6),
337 interpolate_color(&GRADIENT_PURPLE_COLOR, &GRADIENT_PINK_COLOR, 0.7),
338 interpolate_color(&GRADIENT_PURPLE_COLOR, &GRADIENT_PINK_COLOR, 0.8),
339 interpolate_color(&GRADIENT_PURPLE_COLOR, &GRADIENT_PINK_COLOR, 0.9),
340 GRADIENT_PINK_COLOR,
341 ],
342 );
343 format!("{}{}{}", brand_color("⚡️"), gradient_string, reset(""))
344}
345
346pub fn handle_brand_text(text: &str) {
347 let gradient_string = gradient_string(
348 text,
349 &[
350 BRAND_GRADIENT_COLORS,
351 interpolate_color(&BRAND_GRADIENT_COLORS, &BRAND_GRADIENT_COLORS2, 0.2),
352 interpolate_color(&BRAND_GRADIENT_COLORS, &BRAND_GRADIENT_COLORS2, 0.4),
353 interpolate_color(&BRAND_GRADIENT_COLORS, &BRAND_GRADIENT_COLORS2, 0.6),
354 interpolate_color(&BRAND_GRADIENT_COLORS, &BRAND_GRADIENT_COLORS2, 0.8),
355 BRAND_GRADIENT_COLORS2,
356 ],
357 );
358 println!("{gradient_string}");
359}
360
361pub fn brand_text(text: &str) -> String {
362 let gradient_string = gradient_string(
363 &format!("\n{text} \n"),
364 &[
365 BRAND_GRADIENT_COLORS,
366 interpolate_color(&BRAND_GRADIENT_COLORS, &BRAND_GRADIENT_COLORS2, 0.2),
367 interpolate_color(&BRAND_GRADIENT_COLORS, &BRAND_GRADIENT_COLORS2, 0.4),
368 interpolate_color(&BRAND_GRADIENT_COLORS, &BRAND_GRADIENT_COLORS2, 0.6),
369 interpolate_color(&BRAND_GRADIENT_COLORS, &BRAND_GRADIENT_COLORS2, 0.8),
370 BRAND_GRADIENT_COLORS2,
371 ],
372 );
373 gradient_string
374}
375
376pub struct Colors {
377 pub reset: StylerEnabled,
378 pub bold: StylerEnabled,
379 pub dim: StylerEnabled,
380 pub italic: StylerEnabled,
381 pub underline: StylerEnabled,
382 pub inverse: StylerEnabled,
383 pub hidden: StylerEnabled,
384 pub strikethrough: StylerEnabled,
385 pub black: StylerEnabled,
386 pub red: StylerEnabled,
387 pub green: StylerEnabled,
388 pub yellow: StylerEnabled,
389 pub blue: StylerEnabled,
390 pub magenta: StylerEnabled,
391 pub purple: StylerEnabled,
392 pub orange: StylerEnabled,
393 pub cyan: StylerEnabled,
394 pub white: StylerEnabled,
395 pub bg_black: StylerEnabled,
396 pub bg_red: StylerEnabled,
397 pub bg_green: StylerEnabled,
398 pub bg_yellow: StylerEnabled,
399 pub bg_blue: StylerEnabled,
400 pub bg_magenta: StylerEnabled,
401 pub bg_cyan: StylerEnabled,
402 pub bg_white: StylerEnabled,
403 pub debug_color: StylerEnabled,
404 pub brand_color: StylerEnabled,
405 pub handle_brand_text: fn(&str),
406 pub brand_text: fn(&str) -> String,
407}