nu_ansi_term/
gradient.rs

1use crate::{rgb::Rgb, Color};
2use alloc::{format, string::String};
3
4/// Linear color gradient between two color stops
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct Gradient {
7    /// Start Color of Gradient
8    pub start: Rgb,
9
10    /// End Color of Gradient
11    pub end: Rgb,
12}
13
14impl Gradient {
15    /// Creates a new [Gradient] with two [Rgb] colors, `start` and `end`
16    #[inline]
17    pub const fn new(start: Rgb, end: Rgb) -> Self {
18        Self { start, end }
19    }
20
21    pub const fn from_color_rgb(start: Color, end: Color) -> Self {
22        let start_grad = match start {
23            Color::Rgb(r, g, b) => Rgb { r, g, b },
24            _ => Rgb { r: 0, g: 0, b: 0 },
25        };
26        let end_grad = match end {
27            Color::Rgb(r, g, b) => Rgb { r, g, b },
28            _ => Rgb { r: 0, g: 0, b: 0 },
29        };
30
31        Self {
32            start: start_grad,
33            end: end_grad,
34        }
35    }
36
37    /// Computes the [Rgb] color between `start` and `end` for `t`
38    pub fn at(&self, t: f32) -> Rgb {
39        self.start.lerp(self.end, t)
40    }
41
42    /// Returns the reverse of `self`
43    #[inline]
44    pub const fn reverse(&self) -> Self {
45        Self::new(self.end, self.start)
46    }
47
48    pub fn build(&self, text: &str, target: TargetGround) -> String {
49        let delta = 1.0 / text.len() as f32;
50        let mut result = text.char_indices().fold(String::new(), |mut acc, (i, c)| {
51            let temp = format!(
52                "\x1B[{}m{}",
53                self.at(i as f32 * delta).ansi_color_code(target),
54                c
55            );
56            acc.push_str(&temp);
57            acc
58        });
59
60        result.push_str("\x1B[0m");
61        result
62    }
63}
64
65pub fn build_all_gradient_text(text: &str, foreground: Gradient, background: Gradient) -> String {
66    let delta = 1.0 / text.len() as f32;
67    let mut result = text.char_indices().fold(String::new(), |mut acc, (i, c)| {
68        let step = i as f32 * delta;
69        let temp = format!(
70            "\x1B[{};{}m{}",
71            foreground
72                .at(step)
73                .ansi_color_code(TargetGround::Foreground),
74            background
75                .at(step)
76                .ansi_color_code(TargetGround::Background),
77            c
78        );
79        acc.push_str(&temp);
80        acc
81    });
82
83    result.push_str("\x1B[0m");
84    result
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq)]
88pub enum TargetGround {
89    Foreground,
90    Background,
91}
92
93impl TargetGround {
94    #[inline]
95    pub const fn code(&self) -> u8 {
96        match self {
97            Self::Foreground => 30,
98            Self::Background => 40,
99        }
100    }
101}
102
103pub trait ANSIColorCode {
104    fn ansi_color_code(&self, target: TargetGround) -> String;
105}