mod queries;
mod registry;
mod render;
mod styles;
#[cfg(test)]
mod tests;
use std::cell::RefCell;
use ratatui::text::Line;
use crate::theme::Theme;
pub struct Highlighter {
styles: styles::StyleTable,
parser: RefCell<tree_sitter_highlight::Highlighter>,
}
impl Default for Highlighter {
fn default() -> Self {
Self::new(&Theme::hone())
}
}
impl Highlighter {
pub fn new(theme: &Theme) -> Self {
Highlighter {
styles: styles::StyleTable::new(theme),
parser: RefCell::new(tree_sitter_highlight::Highlighter::new()),
}
}
pub fn set_theme(&mut self, theme: &Theme) {
self.styles = styles::StyleTable::new(theme);
}
pub fn language(&self, filename: &str) -> String {
registry::detect(filename)
.map(|lang| registry::label(lang).to_owned())
.unwrap_or_else(|| "text".into())
}
pub fn highlight(&self, filename: &str, text: &str) -> Vec<Line<'static>> {
let Some(lang) = registry::detect(filename) else {
return render::plain(text, &self.styles);
};
let Some(config) = registry::config(lang) else {
return render::plain(text, &self.styles);
};
let mut highlighter = self.parser.borrow_mut();
let events = highlighter.highlight(config, text.as_bytes(), None, |name| {
registry::lang_for_injection(name).and_then(registry::config)
});
match events {
Ok(events) => render::styled(text, events.map_while(Result::ok), &self.styles),
Err(_) => render::plain(text, &self.styles),
}
}
}