Skip to main content

create_janustack/utils/
colors.rs

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
33// brand gradient colors
34const 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
155// black
156pub 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}