aether-wisp 0.7.0

A terminal UI for AI coding agents via the Agent Client Protocol (ACP)
Documentation
use crate::theme::Theme;
use clankerdiff_ratatui::highlighted_line;
use clankerdiff_ratatui::syntax::LanguageHint;
use clankerdiff_ratatui::theme::Fingerprint;
use ratatui::style::Style;
use ratatui::text::Line;
use std::rc::Rc;

#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct HighlightStats {
    pub calls: u64,
    pub cache_misses: u64,
    pub bytes_highlighted: u64,
}

pub type HighlightedLines = Rc<[Line<'static>]>;

#[derive(Default)]
pub struct SyntaxHighlighter {
    pub(crate) inner: clankerdiff_ratatui::syntax::SyntaxHighlighter,
}

impl SyntaxHighlighter {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn take_stats(&mut self) -> HighlightStats {
        let stats = self.inner.take_stats();
        HighlightStats { calls: stats.calls, cache_misses: stats.misses, bytes_highlighted: stats.bytes as u64 }
    }

    pub fn highlight(&mut self, code: &str, language: &str, theme: &Theme) -> HighlightedLines {
        let highlights = self.inner.with_theme(&theme.review().syntax).highlight_document(
            Fingerprint::of([code.as_bytes()]),
            LanguageHint::InfoString(language),
            || code,
        );
        let base = Style::new().fg(theme.code_fg).bg(theme.code_bg);
        match highlights {
            Ok(highlights) => code
                .split('\n')
                .enumerate()
                .map(|(index, source)| highlighted_line(source, highlights.line(index).unwrap_or_default(), base))
                .collect::<Vec<_>>()
                .into(),
            Err(error) => {
                tracing::warn!(%error, "Could not highlight source snippet");
                vec![Line::styled(format!("Could not highlight source: {error}"), base)].into()
            }
        }
    }
}