pub mod cache;
pub mod checkpoint;
pub mod counters;
pub mod grammar;
pub(crate) mod grammar_closure;
pub(crate) mod grammar_ir;
pub(crate) mod hashing;
pub mod line;
pub mod regex;
pub mod scopes;
pub mod state;
pub mod tokenizer;
#[cfg(test)]
mod closure_parity_tests;
use crate::{Error, Result};
use tokenizer::{GrammarSet, LazyGrammar};
pub(crate) fn load_grammar_set(language: &str) -> Result<(GrammarSet, state::GrammarId)> {
load_catalog_grammar_set(crate::grammars::embedded_bundle_shared(), language)
}
pub(crate) fn load_catalog_grammar_set(
bundle: &std::sync::Arc<crate::grammars::bundle::Bundle>,
language: &str,
) -> Result<(GrammarSet, state::GrammarId)> {
let missing = || {
Error::Bundle(crate::BundleError::new(
crate::BundleErrorKind::MissingGrammar,
Some(language.to_owned()),
format!("bundled TextMate grammar `{language}` is missing"),
))
};
let root_index = bundle
.grammar_blob_index_for_language(language)
.ok_or_else(missing)?;
let root_blob = &bundle.grammar_blobs[root_index];
let mut grammars = GrammarSet::new();
let mut root = None;
let root_graph = bundle.grammar_graphs.get(root_index).ok_or_else(missing)?;
for member in &root_graph.closure {
let blob = &bundle.grammar_blobs[member.blob as usize];
let grammar_id = grammars.add_lazy(LazyGrammar {
bundle: std::sync::Arc::clone(bundle),
index: member.blob as usize,
traits: member.traits,
});
if blob.scope_name == root_blob.scope_name {
root = Some(grammar_id);
}
}
let root = root.ok_or_else(missing)?;
if grammars.grammar(root).is_none() {
let error = root_blob.compiled_grammar(root).err();
return Err(Error::Bundle(crate::BundleError::new(
crate::BundleErrorKind::Decode,
Some(root_blob.language.to_string()),
format!(
"failed to decode bundled TextMate grammar `{}`: {error:?}",
root_blob.language
),
)));
}
Ok((grammars, root))
}
#[cfg(test)]
fn compiled_grammar_closure(
bundle: &crate::grammars::bundle::Bundle,
root_scope: &str,
) -> Result<Vec<grammar::CompiledGrammar>> {
let mut grammars = decode_bundle_grammars(bundle);
let root = grammars
.iter()
.rposition(|grammar| grammar.scope_name == root_scope)
.ok_or_else(|| {
Error::Bundle(crate::BundleError::new(
crate::BundleErrorKind::MissingGrammar,
Some(root_scope.to_owned()),
format!("missing root `{root_scope}`"),
))
})?;
let members = grammar_closure::dependency_closure(&grammars, root);
let mut closure = Vec::with_capacity(members.len());
for index in members.into_iter().rev() {
closure.push(grammars.swap_remove(index));
}
closure.reverse();
for (id, grammar) in closure.iter_mut().enumerate() {
grammar.id = state::GrammarId(u16::try_from(id).expect("closure fits in GrammarId"));
}
Ok(closure)
}
#[cfg(test)]
fn decode_bundle_grammars(
bundle: &crate::grammars::bundle::Bundle,
) -> Vec<grammar::CompiledGrammar> {
bundle
.grammar_blobs
.iter()
.map(|blob| {
blob.compiled_grammar(state::GrammarId(0))
.unwrap_or_else(|error| panic!("{}: {error:?}", blob.language))
})
.collect()
}