Skip to main content

freya_terminal/
colors.rs

1use alacritty_terminal::vte::ansi::{
2    Color as AnsiColor,
3    NamedColor,
4};
5use freya_core::prelude::Color;
6
7/// ANSI 16-color palette (matches WezTerm defaults)
8const ANSI_COLORS: [(u8, u8, u8); 16] = [
9    (0, 0, 0),       // Black
10    (204, 85, 85),   // Red
11    (85, 204, 85),   // Green
12    (215, 215, 0),   // Yellow
13    (84, 85, 203),   // Blue
14    (204, 85, 204),  // Magenta
15    (122, 202, 202), // Cyan
16    (204, 204, 204), // White
17    (85, 85, 85),    // Bright Black
18    (255, 85, 85),   // Bright Red
19    (85, 255, 85),   // Bright Green
20    (255, 255, 0),   // Bright Yellow
21    (85, 85, 255),   // Bright Blue
22    (255, 85, 255),  // Bright Magenta
23    (85, 255, 255),  // Bright Cyan
24    (255, 255, 255), // Bright White
25];
26
27/// 6x6x6 RGB cube levels for 256-color palette
28const RGB_LEVELS: [u8; 6] = [0u8, 95u8, 135u8, 175u8, 215u8, 255u8];
29
30/// Map an alacritty `Color` to a Freya `Color`. `default_fg` / `default_bg`
31/// resolve `NamedColor::Foreground` / `Background` to the configured colors.
32pub fn map_ansi_color(c: AnsiColor, default_fg: Color, default_bg: Color) -> Color {
33    match c {
34        AnsiColor::Named(name) => named_color(name, default_fg, default_bg),
35        AnsiColor::Spec(rgb) => Color::from_rgb(rgb.r, rgb.g, rgb.b),
36        AnsiColor::Indexed(idx) => indexed_color(idx, default_fg),
37    }
38}
39
40fn named_color(name: NamedColor, default_fg: Color, default_bg: Color) -> Color {
41    match name {
42        NamedColor::Foreground | NamedColor::BrightForeground | NamedColor::DimForeground => {
43            default_fg
44        }
45        NamedColor::Background => default_bg,
46        NamedColor::Cursor => default_fg,
47        other => {
48            // NamedColor::Black..BrightWhite are 0..=15.
49            let idx = other as u8;
50            if idx < 16 {
51                let (r, g, b) = ANSI_COLORS[idx as usize];
52                Color::from_rgb(r, g, b)
53            } else {
54                default_fg
55            }
56        }
57    }
58}
59
60fn indexed_color(idx: u8, default: Color) -> Color {
61    let i = idx as usize;
62
63    // ANSI 16 colors
64    if i < 16 {
65        let (r, g, b) = ANSI_COLORS[i];
66        return Color::from_rgb(r, g, b);
67    }
68
69    // 6x6x6 RGB cube (216 colors, indices 16-231)
70    if (16..=231).contains(&i) {
71        let v = i - 16;
72        let r = v / 36;
73        let g = (v / 6) % 6;
74        let b = v % 6;
75        return Color::from_rgb(RGB_LEVELS[r], RGB_LEVELS[g], RGB_LEVELS[b]);
76    }
77
78    // Grayscale (24 colors, indices 232-255)
79    if (232..=255).contains(&i) {
80        let shade = 8 + ((i - 232) * 10) as u8;
81        return Color::from_rgb(shade, shade, shade);
82    }
83
84    default
85}