zee-grammar 0.4.0

Wrappers for tree sitter grammars used by zee
Documentation
pub mod builder;
pub mod config;

mod git;

use anyhow::Result;
use once_cell::sync::Lazy;
use std::path::Path;
use tree_sitter::{Language, Query};

use self::config::{CommentConfig, FilenamePattern, IndentationConfig, ModeConfig};

#[derive(Debug)]
pub struct Mode {
    pub name: String,
    pub scope: String,
    pub injection_regex: String,
    pub patterns: Vec<FilenamePattern>,
    pub comment: Option<CommentConfig>,
    pub indentation: IndentationConfig,
    grammar: LazyGrammar,
}

impl Mode {
    pub fn new(config: ModeConfig) -> Self {
        let ModeConfig {
            name,
            scope,
            injection_regex,
            patterns,
            comment,
            indentation,
            grammar: grammar_config,
        } = config;
        Self {
            name,
            scope,
            injection_regex,
            patterns,
            comment,
            indentation,
            grammar: Lazy::new(Box::new(move || {
                grammar_config
                    .map(|grammar_config| grammar_config.grammar_id)
                    .map(builder::load_grammar)
            })),
        }
    }

    pub fn matches_by_filename(&self, filename: impl AsRef<Path>) -> bool {
        self.patterns
            .iter()
            .any(|pattern| pattern.matches(filename.as_ref()))
    }

    pub fn language(&self) -> Option<Result<Language, &anyhow::Error>> {
        Some(self.grammar()?.map(|parser| parser.language))
    }

    pub fn grammar(&self) -> Option<std::result::Result<&Grammar, &anyhow::Error>> {
        Lazy::force(&self.grammar)
            .as_ref()
            .map(|result| result.as_ref())
    }
}

impl Default for Mode {
    fn default() -> Self {
        Self {
            name: "Plain".into(),
            scope: "plaintext".into(),
            injection_regex: "".into(),
            patterns: vec![],
            comment: None,
            indentation: Default::default(),
            grammar: Lazy::new(Box::new(|| None)),
        }
    }
}

#[derive(Debug)]
pub struct Grammar {
    pub id: String,
    pub language: Language,
    pub highlights: Option<Query>,
    pub indents: Option<Query>,
    pub injections: Option<Query>,
    pub locals: Option<Query>,
}

impl PartialEq for Mode {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name
    }
}

type LazyGrammar = Lazy<
    Option<Result<Grammar>>,
    Box<dyn FnOnce() -> Option<Result<Grammar>> + Send + Sync + 'static>,
>;