use crate::ui::config;
use std::sync::OnceLock;
use syntect::easy::HighlightLines;
use syntect::highlighting::{Style, ThemeSet};
use syntect::parsing::SyntaxSet;
pub struct RustCodeLineRenderer<'a> {
syntax_set: &'a SyntaxSet,
highlighter: Option<HighlightLines<'a>>,
}
pub enum StylizedLine<'a> {
NoneStyle(&'a str),
Stylized(Vec<(Style, &'a str)>),
}
impl RustCodeLineRenderer<'_> {
pub fn render_line<'s>(&mut self, line: &'s str) -> anyhow::Result<StylizedLine<'s>> {
match &mut self.highlighter {
None => Ok(StylizedLine::NoneStyle(line)),
Some(h) => Ok(StylizedLine::Stylized(
h.highlight_line(line, self.syntax_set)?,
)),
}
}
}
pub struct RustCodeRenderer {
syntax_set: SyntaxSet,
theme_set: ThemeSet,
}
impl Default for RustCodeRenderer {
fn default() -> Self {
Self {
syntax_set: SyntaxSet::load_defaults_newlines(),
theme_set: ThemeSet::load_defaults(),
}
}
}
impl RustCodeRenderer {
const RUST_EXT: &'static str = "rs";
pub fn line_renderer(&self) -> RustCodeLineRenderer<'_> {
let theme = match config::current().theme.to_syntect_name() {
None => {
return RustCodeLineRenderer {
syntax_set: &self.syntax_set,
highlighter: None,
};
}
Some(theme_name) => &self.theme_set.themes[theme_name],
};
let syntax_ref = self
.syntax_set
.find_syntax_by_extension(Self::RUST_EXT)
.expect("rust syntax should exist");
let highlighter = HighlightLines::new(syntax_ref, theme);
RustCodeLineRenderer {
syntax_set: &self.syntax_set,
highlighter: Some(highlighter),
}
}
}
static RENDERER: OnceLock<RustCodeRenderer> = OnceLock::new();
pub fn rust_syntax_renderer() -> &'static RustCodeRenderer {
RENDERER.get_or_init(RustCodeRenderer::default)
}