Skip to main content

fire_cli_rs/
theme.rs

1#[derive(Clone)]
2pub struct Theme {
3    pub colors: [String; 4],
4}
5
6#[derive(Copy, Clone, PartialEq)]
7pub enum ColorMode {
8    Theme,
9    Rainbow,
10}
11
12impl Theme {
13    
14    pub const CHARS: [char; 10] = [' ', '.', ':', '^', '*', 'x', 's', 'S', '#', '$'];
15    
16    pub fn ash() -> Self {
17        Theme { colors: [
18            "38;2;30;30;30".into(),
19            "38;2;80;80;80".into(),
20            "38;2;160;160;160".into(),
21            "38;2;240;240;240".into(),
22        ]}
23    }
24
25    pub fn aurora() -> Self {
26        Theme { colors: [
27            "38;2;0;20;40".into(),
28            "38;2;0;128;100".into(),
29            "38;2;0;255;180".into(),
30            "38;2;180;255;240".into(),
31        ]}
32    }
33
34    pub fn blue() -> Self {
35        Theme { colors: [
36            "38;2;10;15;28".into(),
37            "38;2;0;95;135".into(),
38            "38;2;0;175;175".into(),
39            "38;2;51;225;255".into(),
40        ]}
41    }
42
43    pub fn classic() -> Self {
44        Theme { colors: [
45            "38;2;20;20;20".into(),
46            "38;2;220;50;47".into(),
47            "38;2;255;200;40".into(),
48            "38;2;70;130;180".into(),
49        ]}
50    }
51    
52    pub fn copper() -> Self {
53        Theme { colors: [
54            "38;2;0;40;40".into(),  
55            "38;2;0;128;128".into(), 
56            "38;2;64;224;208".into(), 
57            "38;2;224;255;255".into(), 
58        ]}
59    }
60
61    pub fn crimson() -> Self {
62        Theme { colors: [
63            "38;2;60;0;0".into(),  
64            "38;2;178;34;34".into(),  
65            "38;2;220;20;60".into(),  
66            "38;2;255;100;100".into(), 
67        ]}
68    }
69
70    pub fn dusk() -> Self {
71        Theme { colors: [
72            "38;2;60;10;40".into(),
73            "38;2;180;50;80".into(),
74            "38;2;255;120;50".into(),
75            "38;2;255;200;120".into(),
76        ]}
77    }
78
79    pub fn ember() -> Self {
80        Theme { colors: [
81            "38;2;60;20;0".into(),  
82            "38;2;139;0;0".into(),  
83            "38;2;204;85;0".into(),  
84            "38;2;255;140;0".into(), 
85        ]}
86    }
87
88    pub fn emerald() -> Self {
89        Theme { colors: [
90            "38;2;0;30;10".into(),
91            "38;2;0;128;0".into(), 
92            "38;2;0;255;127".into(),   
93            "38;2;152;251;152".into(),  
94        ]}
95    }
96
97    pub fn forest() -> Self {
98        Theme { colors: [
99            "38;2;0;40;0".into(),      
100            "38;2;34;139;34".into(),  
101            "38;2;50;205;50".into(),  
102            "38;2;172;255;47".into(), 
103        ]}
104    }
105
106    pub fn frost() -> Self {
107        Theme { colors: [
108            "38;2;20;40;80".into(),
109            "38;2;70;130;200".into(),
110            "38;2;180;210;255".into(),
111            "38;2;240;248;255".into(),
112        ]}
113    }
114
115    pub fn ghost() -> Self {
116        Theme { colors: [
117            "38;2;80;0;80".into(), 
118            "38;2;150;50;250".into(),
119            "38;2;200;130;255".into(),  
120            "38;2;240;220;255".into(),  
121        ]}
122    }
123
124    pub fn gold() -> Self {
125        Theme { colors: [
126            "38;2;101;67;33".into(),  
127            "38;2;184;134;11".into(), 
128            "38;2;218;165;32".into(),  
129            "38;2;255;255;0".into(),  
130        ]}
131    }
132
133    pub fn ice() -> Self {
134        Theme { colors: [
135            "38;2;173;216;230".into(),
136            "38;2;135;206;250".into(),
137            "38;2;0;191;255".into(),
138            "38;2;240;248;255".into(),
139        ]}
140    }
141
142    pub fn magma() -> Self {
143        Theme { colors: [
144            "38;2;40;0;0".into(),      
145            "38;2;120;0;0".into(),     
146            "38;2;255;69;0".into(),    
147            "38;2;255;140;0".into(),   
148        ]}
149    }
150
151    pub fn nebula() -> Self {
152        Theme { colors: [
153            "38;2;25;25;112".into(), 
154            "38;2;75;0;130".into(),  
155            "38;2;219;112;147".into(),
156            "38;2;255;182;193".into(), 
157        ]}
158    }
159
160    pub fn pink() -> Self {
161        Theme { colors: [
162            "38;2;255;105;180".into(),
163            "38;2;255;182;193".into(),
164            "38;2;255;240;245".into(),
165            "38;2;255;255;255".into(),
166        ]}
167    }
168
169    pub fn plasma() -> Self {
170        Theme { colors: [
171            "38;2;10;0;30".into(),      
172            "38;2;75;0;130".into(),    
173            "38;2;0;0;255".into(),     
174            "38;2;100;149;237".into(),  
175        ]}
176    }
177
178    pub fn sakura() -> Self {
179        Theme { colors: [
180            "38;2;80;20;40".into(),
181            "38;2;180;80;120".into(),
182            "38;2;255;150;180".into(),
183            "38;2;255;220;230".into(),
184        ]}
185    }
186
187    pub fn solar() -> Self {
188        Theme { colors: [
189            "38;2;139;69;19".into(),  
190            "38;2;255;165;0".into(),   
191            "38;2;255;215;0".into(),   
192            "38;2;255;255;224".into(),
193        ]}
194    }
195
196    pub fn std() -> Self {
197        Theme { colors: [
198            "38;2;255;0;0".into(),
199            "38;2;255;85;0".into(),
200            "38;2;255;170;0".into(),
201            "38;2;255;255;0".into(),
202        ]}
203    }
204
205    pub fn sulfur() -> Self {
206        Theme { colors: [
207            "38;2;0;20;50".into(),   
208            "38;2;65;105;225".into(),
209            "38;2;0;191;255".into(),  
210            "38;2;175;238;238".into(), 
211        ]}
212    }
213
214}
215
216fn rgb_to_ansi_str(rgb: (u8, u8, u8)) -> String {
217    format!("38;2;{};{};{}", rgb.0, rgb.1, rgb.2)
218}
219
220pub fn parse_custom_theme(input: &str) -> Option<Theme> {
221    // custom:
222    let parts: Vec<&str> = input.split('.').collect();
223    if parts.is_empty() || parts.len() > 4 {
224        return None;
225    }
226
227    let mut rgb_list: Vec<(u8, u8, u8)> = Vec::new();
228    for part in &parts {
229        match parse_hex_color(part.trim()) {
230            Some(c) => rgb_list.push(c),
231            None => return None,
232        }
233    }
234
235    while rgb_list.len() < 4 {
236        let last = *rgb_list.last().unwrap();
237        rgb_list.push(last);
238    }
239
240    Some(Theme {
241        colors: [
242            rgb_to_ansi_str(rgb_list[0]),
243            rgb_to_ansi_str(rgb_list[1]),
244            rgb_to_ansi_str(rgb_list[2]),
245            rgb_to_ansi_str(rgb_list[3]),
246        ],
247    })
248}
249
250fn parse_hex_color(s: &str) -> Option<(u8, u8, u8)> {
251    let s = s.trim_start_matches('#');
252    if s.len() != 6 {
253        return None;
254    }
255    let r = u8::from_str_radix(&s[0..2], 16).ok()?;
256    let g = u8::from_str_radix(&s[2..4], 16).ok()?;
257    let b = u8::from_str_radix(&s[4..6], 16).ok()?;
258    Some((r, g, b))
259}
260
261pub fn hue_to_color_bytes(hue: f32, heat: usize) -> [u8; 3] {
262    let v = match heat {
263        0..=4   => 0.4,
264        5..=9   => 0.6,
265        10..=15 => 0.85,
266        _       => 1.0,
267    };
268
269    // groups adjacent pixels of the same color [4]
270    let hue = (hue / 4.0).round() * 4.0;
271
272    let h = hue / 60.0;
273    let i = h.floor() as u32;
274    let f = h - h.floor();
275    let p = 0.0f32; 
276    let q = v * (1.0 - f);
277    let t = v * f;
278
279    let (r, g, b) = match i % 6 {
280        0 => (v, t, p),
281        1 => (q, v, p),
282        2 => (p, v, t),
283        3 => (p, q, v),
284        4 => (t, p, v),
285        _ => (v, p, q),
286    };
287
288    [(r * 255.0) as u8, (g * 255.0) as u8, (b * 255.0) as u8]
289}