1use ratatui::style::Color;
2
3use crate::config::{ARRAY_GRADIENT, COLORER};
4
5pub const MAX_GRADIENT_NORMAL: usize = 254;
9
10pub struct NormalFileColorer {}
13
14impl NormalFileColorer {
15 #[inline]
16 pub fn colorer(hash: usize) -> Color {
17 let gradient = ARRAY_GRADIENT
18 .get()
19 .expect("Gradient normal file should be set");
20 gradient[hash % MAX_GRADIENT_NORMAL]
21 }
22}
23
24#[inline]
25fn sum_hash(string: &str) -> usize {
26 let hash: usize = string
27 .as_bytes()
28 .iter()
29 .map(|s| *s as usize)
30 .reduce(|acc, elt| acc.saturating_mul(MAX_GRADIENT_NORMAL).saturating_add(elt))
31 .unwrap_or_default();
32 hash & MAX_GRADIENT_NORMAL
33}
34
35#[inline]
38pub fn extension_color(extension: &str) -> Color {
39 COLORER.get().expect("Colorer should be set")(sum_hash(extension))
40}
41
42#[derive(Debug, Clone, Copy)]
48pub struct ColorG {
49 pub r: u8,
50 pub g: u8,
51 pub b: u8,
52}
53
54impl Default for ColorG {
55 fn default() -> Self {
56 Self {
57 r: 255,
58 g: 255,
59 b: 0,
60 }
61 }
62}
63
64impl ColorG {
65 pub fn new(r: u8, g: u8, b: u8) -> Self {
66 Self { r, g, b }
67 }
68 pub fn from_ratatui(color: Color) -> Option<Self> {
71 match color {
72 Color::Rgb(r, g, b) => Some(Self { r, g, b }),
73 _ => None,
74 }
75 }
76
77 pub fn as_ratatui(&self) -> Color {
78 Color::Rgb(self.r, self.g, self.b)
79 }
80
81 #[rustfmt::skip]
82 fn from_ansi_desc(color_name: &str) -> Option<Self> {
83 match color_name.to_lowercase().as_str() {
84 "black" => Some(Self::new(0, 0, 0)),
85 "red" => Some(Self::new(255, 0, 0)),
86 "green" => Some(Self::new(0, 255, 0)),
87 "yellow" => Some(Self::new(255, 255, 0)),
88 "blue" => Some(Self::new(0, 0, 255)),
89 "magenta" => Some(Self::new(255, 0, 255)),
90 "cyan" => Some(Self::new(0, 255, 255)),
91 "white" => Some(Self::new(255, 255, 255)),
92
93 "light_black" => Some(Self::new(85, 85, 85)),
94 "light_red" => Some(Self::new(255, 85, 85)),
95 "light_green" => Some(Self::new(85, 255, 85)),
96 "light_yellow" => Some(Self::new(255, 255, 85)),
97 "light_blue" => Some(Self::new(85, 85, 255)),
98 "light_magenta" => Some(Self::new(255, 85, 255)),
99 "light_cyan" => Some(Self::new(85, 255, 255)),
100 "light_white" => Some(Self::new(255, 255, 255)),
101
102 _ => None,
103 }
104 }
105
106 pub fn parse_any_color(text: &str) -> Option<Self> {
112 match parse_text_triplet(text) {
113 Some((r, g, b)) => Some(Self::new(r, g, b)),
114 None => Self::from_ansi_desc(text),
115 }
116 }
117}
118
119#[rustfmt::skip]
127pub fn str_to_ratatui<S>(color: S) -> Color
128where
129 S: AsRef<str>,
130{
131 match color.as_ref() {
132 "white" => Color::White,
133 "red" => Color::Red,
134 "green" => Color::Green,
135 "blue" => Color::Blue,
136 "yellow" => Color::Yellow,
137 "cyan" => Color::Cyan,
138 "magenta" => Color::Magenta,
139 "black" => Color::Black,
140 "light_white" => Color::White,
141 "light_red" => Color::LightRed,
142 "light_green" => Color::LightGreen,
143 "light_blue" => Color::LightBlue,
144 "light_yellow" => Color::LightYellow,
145 "light_cyan" => Color::LightCyan,
146 "light_magenta" => Color::LightMagenta,
147 "light_black" => Color::Black,
148 color => parse_text_triplet_unfaillible(color),
149 }
150}
151
152fn parse_text_triplet_unfaillible(color: &str) -> Color {
153 match parse_text_triplet(color) {
154 Some((r, g, b)) => Color::Rgb(r, g, b),
155 None => Color::Rgb(0, 0, 0),
156 }
157}
158
159fn parse_text_triplet(color: &str) -> Option<(u8, u8, u8)> {
160 let color = color.to_lowercase();
161 if color.starts_with("rgb(") && color.ends_with(')') {
162 return parse_rgb_triplet(&color);
163 } else if color.starts_with('#') && color.len() >= 7 {
164 return parse_hex_triplet(&color);
165 }
166 None
167}
168
169fn parse_rgb_triplet(color: &str) -> Option<(u8, u8, u8)> {
170 let triplet: Vec<u8> = color
171 .replace("rgb(", "")
172 .replace([')', ' '], "")
173 .trim()
174 .split(',')
175 .filter_map(|s| s.parse().ok())
176 .collect();
177 if triplet.len() == 3 {
178 return Some((triplet[0], triplet[1], triplet[2]));
179 }
180 None
181}
182
183fn parse_hex_triplet(color: &str) -> Option<(u8, u8, u8)> {
184 let r = parse_hex_byte(&color[1..3])?;
185 let g = parse_hex_byte(&color[3..5])?;
186 let b = parse_hex_byte(&color[5..7])?;
187 Some((r, g, b))
188}
189
190fn parse_hex_byte(byte: &str) -> Option<u8> {
191 u8::from_str_radix(byte, 16).ok()
192}