1use alacritty_terminal::term::color::Colors;
2use alacritty_terminal::vte::ansi::{Color, NamedColor, Rgb};
3use gpui::Hsla;
4
5#[derive(Debug, Clone)]
6pub struct ColorPalette {
7 ansi_colors: [Hsla; 16],
8
9 extended_colors: [Hsla; 256],
10
11 foreground: Hsla,
12
13 background: Hsla,
14
15 cursor: Hsla,
16}
17
18impl Default for ColorPalette {
19 fn default() -> Self {
20 let ansi_colors = [
21 rgb_to_hsla(Rgb {
22 r: 0x00,
23 g: 0x00,
24 b: 0x00,
25 }),
26 rgb_to_hsla(Rgb {
27 r: 0xcc,
28 g: 0x00,
29 b: 0x00,
30 }),
31 rgb_to_hsla(Rgb {
32 r: 0x4e,
33 g: 0x9a,
34 b: 0x06,
35 }),
36 rgb_to_hsla(Rgb {
37 r: 0xc4,
38 g: 0xa0,
39 b: 0x00,
40 }),
41 rgb_to_hsla(Rgb {
42 r: 0x34,
43 g: 0x65,
44 b: 0xa4,
45 }),
46 rgb_to_hsla(Rgb {
47 r: 0x75,
48 g: 0x50,
49 b: 0x7b,
50 }),
51 rgb_to_hsla(Rgb {
52 r: 0x06,
53 g: 0x98,
54 b: 0x9a,
55 }),
56 rgb_to_hsla(Rgb {
57 r: 0xd3,
58 g: 0xd7,
59 b: 0xcf,
60 }),
61 rgb_to_hsla(Rgb {
62 r: 0x55,
63 g: 0x57,
64 b: 0x53,
65 }),
66 rgb_to_hsla(Rgb {
67 r: 0xef,
68 g: 0x29,
69 b: 0x29,
70 }),
71 rgb_to_hsla(Rgb {
72 r: 0x8a,
73 g: 0xe2,
74 b: 0x34,
75 }),
76 rgb_to_hsla(Rgb {
77 r: 0xfc,
78 g: 0xe9,
79 b: 0x4f,
80 }),
81 rgb_to_hsla(Rgb {
82 r: 0x72,
83 g: 0x9f,
84 b: 0xcf,
85 }),
86 rgb_to_hsla(Rgb {
87 r: 0xad,
88 g: 0x7f,
89 b: 0xa8,
90 }),
91 rgb_to_hsla(Rgb {
92 r: 0x34,
93 g: 0xe2,
94 b: 0xe2,
95 }),
96 rgb_to_hsla(Rgb {
97 r: 0xee,
98 g: 0xee,
99 b: 0xec,
100 }),
101 ];
102
103 let mut extended_colors = [Hsla::default(); 256];
104
105 extended_colors[0..16].copy_from_slice(&ansi_colors);
106
107 let mut idx = 16;
108 for r in 0..6 {
109 for g in 0..6 {
110 for b in 0..6 {
111 let rgb = Rgb {
112 r: if r == 0 { 0 } else { 55 + r * 40 },
113 g: if g == 0 { 0 } else { 55 + g * 40 },
114 b: if b == 0 { 0 } else { 55 + b * 40 },
115 };
116 extended_colors[idx] = rgb_to_hsla(rgb);
117 idx += 1;
118 }
119 }
120 }
121
122 for i in 0..24 {
123 let gray = (8 + i * 10) as u8;
124 extended_colors[232 + i] = rgb_to_hsla(Rgb {
125 r: gray,
126 g: gray,
127 b: gray,
128 });
129 }
130
131 let foreground = rgb_to_hsla(Rgb {
132 r: 0xd4,
133 g: 0xd4,
134 b: 0xd4,
135 });
136 let background = rgb_to_hsla(Rgb {
137 r: 0x1e,
138 g: 0x1e,
139 b: 0x1e,
140 });
141 let cursor = rgb_to_hsla(Rgb {
142 r: 0xff,
143 g: 0xff,
144 b: 0xff,
145 });
146
147 Self {
148 ansi_colors,
149 extended_colors,
150 foreground,
151 background,
152 cursor,
153 }
154 }
155}
156
157impl ColorPalette {
158 pub fn new() -> Self {
159 Self::default()
160 }
161
162 pub fn builder() -> ColorPaletteBuilder {
163 ColorPaletteBuilder::new()
164 }
165
166 pub fn resolve(&self, color: Color, colors: &Colors) -> Hsla {
167 match color {
168 Color::Named(named) => {
169 if let Some(rgb) = colors[named] {
170 return rgb_to_hsla(rgb);
171 }
172
173 let idx = named as usize;
174 if idx < 16 {
175 self.ansi_colors[idx]
176 } else {
177 match named {
178 NamedColor::Foreground => self.foreground,
179 NamedColor::Background => self.background,
180 NamedColor::Cursor => self.cursor,
181 NamedColor::DimForeground => {
182 let mut dim = self.foreground;
183 dim.l *= 0.7;
184 dim
185 }
186 NamedColor::BrightForeground => {
187 let mut bright = self.foreground;
188 bright.l = (bright.l * 1.2).min(1.0);
189 bright
190 }
191 NamedColor::DimBlack
192 | NamedColor::DimRed
193 | NamedColor::DimGreen
194 | NamedColor::DimYellow
195 | NamedColor::DimBlue
196 | NamedColor::DimMagenta
197 | NamedColor::DimCyan
198 | NamedColor::DimWhite => {
199 let base_idx = match named {
200 NamedColor::DimBlack => 0,
201 NamedColor::DimRed => 1,
202 NamedColor::DimGreen => 2,
203 NamedColor::DimYellow => 3,
204 NamedColor::DimBlue => 4,
205 NamedColor::DimMagenta => 5,
206 NamedColor::DimCyan => 6,
207 NamedColor::DimWhite => 7,
208 _ => 7,
209 };
210 let mut dim = self.ansi_colors[base_idx];
211 dim.l *= 0.7;
212 dim
213 }
214 _ => self.foreground,
215 }
216 }
217 }
218 Color::Spec(rgb) => rgb_to_hsla(rgb),
219 Color::Indexed(idx) => self.extended_colors[idx as usize],
220 }
221 }
222
223 pub fn ansi_colors(&self) -> &[Hsla; 16] {
224 &self.ansi_colors
225 }
226
227 pub fn extended_colors(&self) -> &[Hsla; 256] {
228 &self.extended_colors
229 }
230
231 pub fn foreground(&self) -> Hsla {
232 self.foreground
233 }
234
235 pub fn background(&self) -> Hsla {
236 self.background
237 }
238
239 pub fn cursor(&self) -> Hsla {
240 self.cursor
241 }
242}
243
244fn rgb_to_hsla(rgb: Rgb) -> Hsla {
245 let r = rgb.r as f32 / 255.0;
246 let g = rgb.g as f32 / 255.0;
247 let b = rgb.b as f32 / 255.0;
248
249 let max = r.max(g).max(b);
250 let min = r.min(g).min(b);
251 let delta = max - min;
252
253 let l = (max + min) / 2.0;
254
255 let s = if delta == 0.0 {
256 0.0
257 } else {
258 delta / (1.0 - (2.0 * l - 1.0).abs())
259 };
260
261 let h = if delta == 0.0 {
262 0.0
263 } else if max == r {
264 60.0 * (((g - b) / delta) % 6.0)
265 } else if max == g {
266 60.0 * (((b - r) / delta) + 2.0)
267 } else {
268 60.0 * (((r - g) / delta) + 4.0)
269 };
270
271 let h = if h < 0.0 { h + 360.0 } else { h } / 360.0;
272
273 Hsla { h, s, l, a: 1.0 }
274}
275
276#[derive(Debug, Clone)]
277pub struct ColorPaletteBuilder {
278 palette: ColorPalette,
279}
280
281impl Default for ColorPaletteBuilder {
282 fn default() -> Self {
283 Self::new()
284 }
285}
286
287impl ColorPaletteBuilder {
288 pub fn new() -> Self {
289 Self {
290 palette: ColorPalette::default(),
291 }
292 }
293
294 pub fn background(mut self, r: u8, g: u8, b: u8) -> Self {
295 self.palette.background = rgb_to_hsla(Rgb { r, g, b });
296 self
297 }
298
299 pub fn foreground(mut self, r: u8, g: u8, b: u8) -> Self {
300 self.palette.foreground = rgb_to_hsla(Rgb { r, g, b });
301 self
302 }
303
304 pub fn cursor(mut self, r: u8, g: u8, b: u8) -> Self {
305 self.palette.cursor = rgb_to_hsla(Rgb { r, g, b });
306 self
307 }
308
309 pub fn black(mut self, r: u8, g: u8, b: u8) -> Self {
310 self.set_ansi_color(0, r, g, b);
311 self
312 }
313
314 pub fn red(mut self, r: u8, g: u8, b: u8) -> Self {
315 self.set_ansi_color(1, r, g, b);
316 self
317 }
318
319 pub fn green(mut self, r: u8, g: u8, b: u8) -> Self {
320 self.set_ansi_color(2, r, g, b);
321 self
322 }
323
324 pub fn yellow(mut self, r: u8, g: u8, b: u8) -> Self {
325 self.set_ansi_color(3, r, g, b);
326 self
327 }
328
329 pub fn blue(mut self, r: u8, g: u8, b: u8) -> Self {
330 self.set_ansi_color(4, r, g, b);
331 self
332 }
333
334 pub fn magenta(mut self, r: u8, g: u8, b: u8) -> Self {
335 self.set_ansi_color(5, r, g, b);
336 self
337 }
338
339 pub fn cyan(mut self, r: u8, g: u8, b: u8) -> Self {
340 self.set_ansi_color(6, r, g, b);
341 self
342 }
343
344 pub fn white(mut self, r: u8, g: u8, b: u8) -> Self {
345 self.set_ansi_color(7, r, g, b);
346 self
347 }
348
349 pub fn bright_black(mut self, r: u8, g: u8, b: u8) -> Self {
350 self.set_ansi_color(8, r, g, b);
351 self
352 }
353
354 pub fn bright_red(mut self, r: u8, g: u8, b: u8) -> Self {
355 self.set_ansi_color(9, r, g, b);
356 self
357 }
358
359 pub fn bright_green(mut self, r: u8, g: u8, b: u8) -> Self {
360 self.set_ansi_color(10, r, g, b);
361 self
362 }
363
364 pub fn bright_yellow(mut self, r: u8, g: u8, b: u8) -> Self {
365 self.set_ansi_color(11, r, g, b);
366 self
367 }
368
369 pub fn bright_blue(mut self, r: u8, g: u8, b: u8) -> Self {
370 self.set_ansi_color(12, r, g, b);
371 self
372 }
373
374 pub fn bright_magenta(mut self, r: u8, g: u8, b: u8) -> Self {
375 self.set_ansi_color(13, r, g, b);
376 self
377 }
378
379 pub fn bright_cyan(mut self, r: u8, g: u8, b: u8) -> Self {
380 self.set_ansi_color(14, r, g, b);
381 self
382 }
383
384 pub fn bright_white(mut self, r: u8, g: u8, b: u8) -> Self {
385 self.set_ansi_color(15, r, g, b);
386 self
387 }
388
389 fn set_ansi_color(&mut self, idx: usize, r: u8, g: u8, b: u8) {
390 let color = rgb_to_hsla(Rgb { r, g, b });
391 self.palette.ansi_colors[idx] = color;
392 self.palette.extended_colors[idx] = color;
393 }
394
395 pub fn build(self) -> ColorPalette {
396 self.palette
397 }
398}
399
400#[cfg(test)]
401mod tests {
402 use super::*;
403
404 #[test]
405 fn test_rgb_to_hsla_black() {
406 let rgb = Rgb { r: 0, g: 0, b: 0 };
407 let hsla = rgb_to_hsla(rgb);
408 assert_eq!(hsla.l, 0.0);
409 assert_eq!(hsla.s, 0.0);
410 assert_eq!(hsla.a, 1.0);
411 }
412
413 #[test]
414 fn test_rgb_to_hsla_white() {
415 let rgb = Rgb {
416 r: 255,
417 g: 255,
418 b: 255,
419 };
420 let hsla = rgb_to_hsla(rgb);
421 assert_eq!(hsla.l, 1.0);
422 assert_eq!(hsla.s, 0.0);
423 assert_eq!(hsla.a, 1.0);
424 }
425
426 #[test]
427 fn test_rgb_to_hsla_red() {
428 let rgb = Rgb { r: 255, g: 0, b: 0 };
429 let hsla = rgb_to_hsla(rgb);
430 assert_eq!(hsla.h, 0.0);
431 assert_eq!(hsla.s, 1.0);
432 assert_eq!(hsla.a, 1.0);
433 }
434
435 #[test]
436 fn test_color_palette_default() {
437 let palette = ColorPalette::default();
438 assert_eq!(palette.ansi_colors.len(), 16);
439 assert_eq!(palette.extended_colors.len(), 256);
440 }
441
442 #[test]
443 fn test_resolve_named_color() {
444 use alacritty_terminal::vte::ansi::NamedColor;
445
446 let palette = ColorPalette::new();
447 let colors = Colors::default();
448 let hsla = palette.resolve(Color::Named(NamedColor::Red), &colors);
449 assert!(hsla.a > 0.0);
450 }
451
452 #[test]
453 fn test_resolve_indexed_color() {
454 let palette = ColorPalette::new();
455 let colors = Colors::default();
456 let hsla = palette.resolve(Color::Indexed(42), &colors);
457 assert_eq!(hsla.a, 1.0);
458 }
459
460 #[test]
461 fn test_resolve_spec_color() {
462 let palette = ColorPalette::new();
463 let colors = Colors::default();
464 let rgb = Rgb {
465 r: 128,
466 g: 64,
467 b: 192,
468 };
469 let hsla = palette.resolve(Color::Spec(rgb), &colors);
470 assert_eq!(hsla.a, 1.0);
471 }
472}