clankerdiff-syntax 0.1.6

Portable Tree-sitter syntax highlighting
Documentation
use clankerdiff_syntax::{
    CacheConfig, DocumentHighlights, Fingerprint, HighlightSpan, SyntaxError, SyntaxHighlighter,
    SyntaxStream, SyntaxStreamUpdate, SyntaxTheme,
};
use std::{error::Error, sync::Arc};

pub type TestResult = Result<(), Box<dyn Error>>;

pub struct CacheBuilder {
    config: CacheConfig,
    language: String,
    theme: SyntaxTheme,
}

impl Default for CacheBuilder {
    fn default() -> Self {
        Self {
            config: CacheConfig::default(),
            language: "rust".to_owned(),
            theme: SyntaxTheme::default(),
        }
    }
}

impl CacheBuilder {
    pub fn entries(mut self, limit: usize) -> Self {
        self.config.max_documents = limit;
        self
    }

    pub fn source_limit(mut self, limit: usize) -> Self {
        self.config.max_source_bytes = limit;
        self
    }

    pub fn language(mut self, language: &str) -> Self {
        language.clone_into(&mut self.language);
        self
    }

    pub fn build(self) -> SyntaxFixture {
        SyntaxFixture {
            highlighter: SyntaxHighlighter::new(self.config),
            stream: SyntaxStream::new(self.language.as_str()),
            theme: self.theme,
            language: self.language,
        }
    }
}

pub struct SyntaxFixture {
    pub highlighter: SyntaxHighlighter,
    pub stream: SyntaxStream,
    pub theme: SyntaxTheme,
    language: String,
}

impl SyntaxFixture {
    pub fn highlight(&mut self, source: &str) -> Result<Arc<DocumentHighlights>, SyntaxError> {
        self.highlighter.with_theme(&self.theme).highlight_document(
            Fingerprint::of([source]),
            self.language.as_str(),
            || source,
        )
    }

    pub fn append(&mut self, source: &str) -> Result<SyntaxStreamUpdate, SyntaxError> {
        self.highlighter
            .with_theme(&self.theme)
            .append(&mut self.stream, source)
    }

    pub fn assert_equivalent(&mut self) -> TestResult {
        let source = self.stream.source();
        let complete = SyntaxHighlighter::new(0)
            .with_theme(&self.theme)
            .highlight_document(Fingerprint::of([source]), self.language.as_str(), || source)?;
        assert_eq!(self.stream.highlights().line_count(), complete.line_count());
        for index in 0..complete.line_count() {
            assert_eq!(
                self.stream.highlights().line(index),
                complete.line(index),
                "{}: {source:?}, line {index}",
                self.language
            );
        }
        Ok(())
    }
}

pub fn line(
    highlights: &DocumentHighlights,
    index: usize,
) -> Result<&[HighlightSpan], Box<dyn Error>> {
    highlights
        .line(index)
        .ok_or_else(|| format!("missing line {index}").into())
}