use tree_sitter_highlight::HighlightConfiguration;
use crate::Highlighter;
use crate::util::cmp_ignore_case_ascii;
#[derive(Debug, Copy, Clone)]
pub struct Language {
pub name: &'static str,
pub file_types: &'static [&'static str],
pub(crate) language: fn() -> tree_sitter::Language,
pub(crate) queries: &'static [(&'static str, &'static str)],
}
macro_rules! define_lang {
($($m:ident),*) => {
$(
#[allow(non_upper_case_globals)]
#[doc = concat!("[`raw::", stringify!($m), "`](crate::raw::", stringify!($m), ").")]
pub const $m: Language = Language {
name: crate::raw::$m::NAME,
file_types: crate::raw::$m::FILE_TYPES,
language: crate::raw::$m::language,
queries: crate::raw::$m::QUERIES,
};
)*
}
}
macro_rules! collect {
($($m:ident),*) => {
&[$(&Language::$m),*]
}
}
impl Language {
#[inline]
pub fn find(token: &str) -> Option<&'static Language> {
Self::find_by_name(token).or_else(|| Self::find_by_file_type(token))
}
#[inline]
pub fn find_by_name(name: &str) -> Option<&'static Language> {
Self::position_by_name(name).and_then(|i| Language::ALL.get(i).copied())
}
#[inline]
pub fn find_by_file_type(file_type: &str) -> Option<&'static Language> {
Self::position_by_file_type(file_type).and_then(|i| Language::ALL.get(i).copied())
}
pub fn position_by_name(name: &str) -> Option<usize> {
Language::ALL.binary_search_by(|l| cmp_ignore_case_ascii(l.name, name)).ok()
}
pub fn position_by_file_type(file_type: &str) -> Option<usize> {
Language::ALL.iter()
.map(|l| l.file_types)
.position(|a| a.binary_search_by(|v| cmp_ignore_case_ascii(v, file_type)).is_ok())
}
#[inline]
pub fn position(token: &str) -> Option<usize> {
Self::position_by_name(token).or_else(|| Self::position_by_file_type(token))
}
pub fn query(self: &'static Self, name: &str) -> Option<&'static str> {
self.queries.iter()
.find(|(k, _)| *k == name)
.map(|(_, v)| *v)
}
pub fn highlight_config(self: &'static Self, highlights: &[&str]) -> HighlightConfiguration {
let mut config = HighlightConfiguration::new(
(self.language)(),
self.query("highlights").unwrap_or(""),
self.query("injections").unwrap_or(""),
self.query("locals").unwrap_or(""),
).expect("all queries pre-tested");
config.configure(highlights);
config
}
#[inline]
pub fn highlighter<'a>(self: &'static Self, highlights: &'a [&'a str]) -> Highlighter<'a> {
Highlighter::new(self, highlights)
}
}
impl Language {
pub const ALL: &'static [&'static Language] = with_all_languages!(collect);
with_all_languages!(define_lang);
}