modcli/output/
gradient.rs

1use crossterm::style::{Color, Stylize};
2
3/// Generates a horizontal gradient between two colors over N steps.
4/// This can be used for printing rainbow text or gradual transitions.
5pub fn generate_gradient(text: &str, start: Color, end: Color) -> Vec<String> {
6    let chars: Vec<char> = text.chars().collect();
7    let steps = chars.len().max(1);
8    let mut result = Vec::with_capacity(steps);
9
10    for (i, c) in chars.iter().enumerate() {
11        let r = interpolate(get_r(&start), get_r(&end), i, steps);
12        let g = interpolate(get_g(&start), get_g(&end), i, steps);
13        let b = interpolate(get_b(&start), get_b(&end), i, steps);
14
15        let color = Color::Rgb { r, g, b };
16        result.push(c.to_string().with(color).to_string());
17    }
18
19    result
20}
21
22/// Print gradient text directly to stdout.
23pub fn print_gradient_line(text: &str, start: Color, end: Color) {
24    let gradient = generate_gradient(text, start, end);
25    for part in gradient {
26        print!("{}", part);
27    }
28    println!();
29}
30
31// ---- Internal RGB utilities ----
32
33fn get_r(c: &Color) -> u8 {
34    match c {
35        Color::Rgb { r, .. } => *r,
36        _ => 255,
37    }
38}
39
40fn get_g(c: &Color) -> u8 {
41    match c {
42        Color::Rgb { g, .. } => *g,
43        _ => 255,
44    }
45}
46
47fn get_b(c: &Color) -> u8 {
48    match c {
49        Color::Rgb { b, .. } => *b,
50        _ => 255,
51    }
52}
53
54fn interpolate(start: u8, end: u8, step: usize, total: usize) -> u8 {
55    let start_f = start as f32;
56    let end_f = end as f32;
57    let ratio = step as f32 / (total - 1).max(1) as f32;
58    (start_f + (end_f - start_f) * ratio).round() as u8
59}