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