use anstyle::{AnsiColor, Effects};
use std::{
io::{Result, Write},
sync::OnceLock,
};
use syntect::highlighting::{FontStyle, Highlighter, Style, Theme};
static SOLARIZED_DARK_DUMP: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/theme.dump"));
static THEME: OnceLock<Theme> = OnceLock::new();
static HIGHLIGHTER: OnceLock<Highlighter> = OnceLock::new();
fn theme() -> &'static Theme {
THEME.get_or_init(|| syntect::dumps::from_binary(SOLARIZED_DARK_DUMP))
}
pub fn highlighter() -> &'static Highlighter<'static> {
HIGHLIGHTER.get_or_init(|| Highlighter::new(theme()))
}
pub fn write_as_ansi<'a, W: Write, I: Iterator<Item = (Style, &'a str)>>(
writer: &mut W,
regions: I,
) -> Result<()> {
for (style, text) in regions {
let rgb = {
let fg = style.foreground;
(fg.r, fg.g, fg.b)
};
let color = match rgb {
(0x00, 0x2b, 0x36)
| (0x07, 0x36, 0x42)
| (0x58, 0x6e, 0x75)
| (0x65, 0x7b, 0x83)
| (0x83, 0x94, 0x96)
| (0x93, 0xa1, 0xa1)
| (0xee, 0xe8, 0xd5)
| (0xfd, 0xf6, 0xe3) => None,
(0xb5, 0x89, 0x00) => Some(AnsiColor::Yellow.into()),
(0xcb, 0x4b, 0x16) => Some(AnsiColor::BrightRed.into()),
(0xdc, 0x32, 0x2f) => Some(AnsiColor::Red.into()),
(0xd3, 0x36, 0x82) => Some(AnsiColor::Magenta.into()),
(0x6c, 0x71, 0xc4) => Some(AnsiColor::BrightMagenta.into()),
(0x26, 0x8b, 0xd2) => Some(AnsiColor::Blue.into()),
(0x2a, 0xa1, 0x98) => Some(AnsiColor::Cyan.into()),
(0x85, 0x99, 0x00) => Some(AnsiColor::Green.into()),
(r, g, b) => panic!("Unexpected RGB colour: #{r:2>0x}{g:2>0x}{b:2>0x}"),
};
let font = style.font_style;
let effects = Effects::new()
.set(Effects::BOLD, font.contains(FontStyle::BOLD))
.set(Effects::ITALIC, font.contains(FontStyle::ITALIC))
.set(Effects::UNDERLINE, font.contains(FontStyle::UNDERLINE));
let style = anstyle::Style::new().fg_color(color).effects(effects);
write!(writer, "{}{}{}", style.render(), text, style.render_reset())?;
}
Ok(())
}