refactor(cli): replace embedded xterm colors file with ansi_colours

This commit is contained in:
Amaan Qureshi 2025-01-25 16:14:53 -05:00
parent 8f3ceb471a
commit 4b6723192e
5 changed files with 81 additions and 334 deletions

View file

@ -28,6 +28,7 @@ harness = false
wasm = ["tree-sitter/wasm", "tree-sitter-loader/wasm"]
[dependencies]
ansi_colours.workspace = true
anstyle.workspace = true
anyhow.workspace = true
bstr.workspace = true

View file

@ -5,10 +5,11 @@ use std::{
io::{self, Write as _},
path::{self, Path, PathBuf},
str,
sync::{atomic::AtomicUsize, Arc, LazyLock},
sync::{atomic::AtomicUsize, Arc},
time::Instant,
};
use ansi_colours::{ansi256_from_rgb, rgb_from_ansi256};
use anstyle::{Ansi256Color, AnsiColor, Color, Effects, RgbColor};
use anyhow::Result;
use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer};
@ -44,9 +45,6 @@ pub const HTML_FOOTER: &str = "
</body>
";
static CSS_STYLES_BY_COLOR_ID: LazyLock<Vec<String>> =
LazyLock::new(|| serde_json::from_str(include_str!("../vendor/xterm-colors.json")).unwrap());
#[derive(Debug, Default)]
pub struct Style {
pub ansi: anstyle::Style,
@ -224,9 +222,8 @@ fn parse_style(style: &mut Style, json: Value) {
if let Some(Color::Rgb(RgbColor(red, green, blue))) = style.ansi.get_fg_color() {
if !terminal_supports_truecolor() {
style.ansi = style
.ansi
.fg_color(Some(closest_xterm_color(red, green, blue)));
let ansi256 = Color::Ansi256(Ansi256Color(ansi256_from_rgb((red, green, blue))));
style.ansi = style.ansi.fg_color(Some(ansi256));
}
}
}
@ -303,7 +300,8 @@ fn write_color(buffer: &mut String, color: Color) {
_ => unreachable!(),
},
Color::Ansi256(Ansi256Color(n)) => {
write!(buffer, "color: {}", CSS_STYLES_BY_COLOR_ID[n as usize]).unwrap();
let (r, g, b) = rgb_from_ansi256(n);
write!(buffer, "color: #{r:02x}{g:02x}{b:02x}").unwrap();
}
Color::Rgb(RgbColor(r, g, b)) => write!(buffer, "color: #{r:02x}{g:02x}{b:02x}").unwrap(),
}
@ -314,30 +312,6 @@ fn terminal_supports_truecolor() -> bool {
.is_ok_and(|truecolor| truecolor == "truecolor" || truecolor == "24bit")
}
fn closest_xterm_color(red: u8, green: u8, blue: u8) -> Color {
use std::cmp::{max, min};
let colors = CSS_STYLES_BY_COLOR_ID
.iter()
.enumerate()
.map(|(color_id, hex)| (color_id as u8, hex_string_to_rgb(hex).unwrap()));
// Get the xterm color with the minimum Euclidean distance to the target color
// i.e. distance = √ (r2 - r1)² + (g2 - g1)² + (b2 - b1)²
let distances = colors.map(|(color_id, (r, g, b))| {
let r_delta = (max(r, red) - min(r, red)) as u32;
let g_delta = (max(g, green) - min(g, green)) as u32;
let b_delta = (max(b, blue) - min(b, blue)) as u32;
let distance = r_delta.pow(2) + g_delta.pow(2) + b_delta.pow(2);
// don't need to actually take the square root for the sake of comparison
(color_id, distance)
});
Color::Ansi256(Ansi256Color(
distances.min_by(|(_, d1), (_, d2)| d1.cmp(d2)).unwrap().0,
))
}
pub struct HighlightOptions {
pub theme: Theme,
pub check: bool,
@ -518,12 +492,12 @@ mod tests {
);
assert_eq!(style.css, Some("color: #26a69a".to_string()));
// junglegreen gets approximated as darkcyan when the terminal does not support it
// junglegreen gets approximated as cadetblue when the terminal does not support it
env::set_var("COLORTERM", "");
parse_style(&mut style, Value::String(JUNGLE_GREEN.to_string()));
assert_eq!(
style.ansi.get_fg_color(),
Some(Color::Ansi256(Ansi256Color(36)))
Some(Color::Ansi256(Ansi256Color(72)))
);
assert_eq!(style.css, Some("color: #26a69a".to_string()));

View file

@ -1,258 +0,0 @@
[
"#000000",
"#800000",
"#008000",
"#808000",
"#000080",
"#800080",
"#008080",
"#c0c0c0",
"#808080",
"#ff0000",
"#00ff00",
"#ffff00",
"#0000ff",
"#ff00ff",
"#00ffff",
"#ffffff",
"#000000",
"#00005f",
"#000087",
"#0000af",
"#0000d7",
"#0000ff",
"#005f00",
"#005f5f",
"#005f87",
"#005faf",
"#005fd7",
"#005fff",
"#008700",
"#00875f",
"#008787",
"#0087af",
"#0087d7",
"#0087ff",
"#00af00",
"#00af5f",
"#00af87",
"#00afaf",
"#00afd7",
"#00afff",
"#00d700",
"#00d75f",
"#00d787",
"#00d7af",
"#00d7d7",
"#00d7ff",
"#00ff00",
"#00ff5f",
"#00ff87",
"#00ffaf",
"#00ffd7",
"#00ffff",
"#5f0000",
"#5f005f",
"#5f0087",
"#5f00af",
"#5f00d7",
"#5f00ff",
"#5f5f00",
"#5f5f5f",
"#5f5f87",
"#5f5faf",
"#5f5fd7",
"#5f5fff",
"#5f8700",
"#5f875f",
"#5f8787",
"#5f87af",
"#5f87d7",
"#5f87ff",
"#5faf00",
"#5faf5f",
"#5faf87",
"#5fafaf",
"#5fafd7",
"#5fafff",
"#5fd700",
"#5fd75f",
"#5fd787",
"#5fd7af",
"#5fd7d7",
"#5fd7ff",
"#5fff00",
"#5fff5f",
"#5fff87",
"#5fffaf",
"#5fffd7",
"#5fffff",
"#870000",
"#87005f",
"#870087",
"#8700af",
"#8700d7",
"#8700ff",
"#875f00",
"#875f5f",
"#875f87",
"#875faf",
"#875fd7",
"#875fff",
"#878700",
"#87875f",
"#878787",
"#8787af",
"#8787d7",
"#8787ff",
"#87af00",
"#87af5f",
"#87af87",
"#87afaf",
"#87afd7",
"#87afff",
"#87d700",
"#87d75f",
"#87d787",
"#87d7af",
"#87d7d7",
"#87d7ff",
"#87ff00",
"#87ff5f",
"#87ff87",
"#87ffaf",
"#87ffd7",
"#87ffff",
"#af0000",
"#af005f",
"#af0087",
"#af00af",
"#af00d7",
"#af00ff",
"#af5f00",
"#af5f5f",
"#af5f87",
"#af5faf",
"#af5fd7",
"#af5fff",
"#af8700",
"#af875f",
"#af8787",
"#af87af",
"#af87d7",
"#af87ff",
"#afaf00",
"#afaf5f",
"#afaf87",
"#afafaf",
"#afafd7",
"#afafff",
"#afd700",
"#afd75f",
"#afd787",
"#afd7af",
"#afd7d7",
"#afd7ff",
"#afff00",
"#afff5f",
"#afff87",
"#afffaf",
"#afffd7",
"#afffff",
"#d70000",
"#d7005f",
"#d70087",
"#d700af",
"#d700d7",
"#d700ff",
"#d75f00",
"#d75f5f",
"#d75f87",
"#d75faf",
"#d75fd7",
"#d75fff",
"#d78700",
"#d7875f",
"#d78787",
"#d787af",
"#d787d7",
"#d787ff",
"#d7af00",
"#d7af5f",
"#d7af87",
"#d7afaf",
"#d7afd7",
"#d7afff",
"#d7d700",
"#d7d75f",
"#d7d787",
"#d7d7af",
"#d7d7d7",
"#d7d7ff",
"#d7ff00",
"#d7ff5f",
"#d7ff87",
"#d7ffaf",
"#d7ffd7",
"#d7ffff",
"#ff0000",
"#ff005f",
"#ff0087",
"#ff00af",
"#ff00d7",
"#ff00ff",
"#ff5f00",
"#ff5f5f",
"#ff5f87",
"#ff5faf",
"#ff5fd7",
"#ff5fff",
"#ff8700",
"#ff875f",
"#ff8787",
"#ff87af",
"#ff87d7",
"#ff87ff",
"#ffaf00",
"#ffaf5f",
"#ffaf87",
"#ffafaf",
"#ffafd7",
"#ffafff",
"#ffd700",
"#ffd75f",
"#ffd787",
"#ffd7af",
"#ffd7d7",
"#ffd7ff",
"#ffff00",
"#ffff5f",
"#ffff87",
"#ffffaf",
"#ffffd7",
"#ffffff",
"#080808",
"#121212",
"#1c1c1c",
"#262626",
"#303030",
"#3a3a3a",
"#444444",
"#4e4e4e",
"#585858",
"#626262",
"#6c6c6c",
"#767676",
"#808080",
"#8a8a8a",
"#949494",
"#9e9e9e",
"#a8a8a8",
"#b2b2b2",
"#bcbcbc",
"#c6c6c6",
"#d0d0d0",
"#dadada",
"#e4e4e4",
"#eeeeee"
]