use std::{ops::Range, sync::Arc};
use theme::HighlightKind;
use tree_sitter::Language;
use tree_sitter_highlight::HighlightConfiguration;
use tree_sitter_language::LanguageFn;
pub enum Grammar {
Native(LanguageFn),
Wasm(Arc<[u8]>),
}
impl Grammar {
pub fn language(&self) -> Option<Language> {
match self {
Self::Native(grammar) => Some((*grammar).into()),
Self::Wasm(_) => None,
}
}
}
pub struct Lang {
pub name: &'static str,
pub aliases: &'static [&'static str],
pub grammar: Grammar,
pub query: &'static str,
pub injections: &'static str,
}
pub const NAMES: &[&str] = &[
"comment",
"comment.documentation",
"keyword",
"keyword.function",
"keyword.return",
"keyword.operator",
"keyword.conditional",
"keyword.conditional.ternary",
"keyword.coroutine",
"keyword.directive",
"keyword.exception",
"keyword.import",
"keyword.modifier",
"keyword.repeat",
"keyword.type",
"string",
"string.special",
"string.special.key",
"string.special.url",
"string.regexp",
"character.special",
"escape",
"string.escape",
"number",
"boolean",
"type",
"type.interface",
"type.builtin",
"constructor",
"function",
"function.method",
"function.method.call",
"function.call",
"function.builtin",
"macro",
"function.macro",
"property",
"property.definition",
"variable.member",
"constant",
"constant.builtin",
"module",
"module.builtin",
"variable",
"variable.builtin",
"variable.special",
"self",
"variable.parameter",
"parameter",
"operator",
"punctuation",
"punctuation.bracket",
"punctuation.delimiter",
"punctuation.special",
"tag",
"tag.builtin",
"tag.delimiter",
"attribute",
"tag.attribute",
"label",
"invalid",
];
pub struct Compiled {
pub config: HighlightConfiguration,
pub injected: Vec<String>,
}
impl Lang {
pub const fn new(
name: &'static str,
aliases: &'static [&'static str],
grammar: Grammar,
query: &'static str,
) -> Self {
Self {
name,
aliases,
grammar,
query,
injections: "",
}
}
pub const fn with_injections(mut self, injections: &'static str) -> Self {
self.injections = injections;
self
}
pub fn highlight(&'static self, source: &str) -> Option<Vec<(Range<usize>, HighlightKind)>> {
crate::session::with(|session| session.highlight(self, source))
}
pub(crate) fn compile_with(&self, grammar: Language) -> Option<Compiled> {
let mut config =
HighlightConfiguration::new(grammar, self.name, self.query, self.injections, "")
.ok()?;
config.configure(NAMES);
let injected = (0..config.query.pattern_count())
.flat_map(|pattern| config.query.property_settings(pattern))
.filter(|property| property.key.as_ref() == "injection.language")
.filter_map(|property| property.value.as_ref().map(|value| value.to_string()))
.collect();
Some(Compiled { config, injected })
}
}
pub fn resolve(tag: &str) -> Option<&'static Lang> {
crate::registry::of_tag(tag)?.lang()
}
pub fn kind_of(name: &str) -> HighlightKind {
match name {
"comment" | "comment.documentation" => HighlightKind::Comment,
"keyword"
| "keyword.function"
| "keyword.return"
| "keyword.operator"
| "keyword.conditional"
| "keyword.conditional.ternary"
| "keyword.coroutine"
| "keyword.directive"
| "keyword.exception"
| "keyword.import"
| "keyword.modifier"
| "keyword.repeat"
| "keyword.type" => HighlightKind::Keyword,
"string" => HighlightKind::String,
"string.special" | "string.special.key" | "string.special.url" | "string.regexp"
| "character.special" => HighlightKind::StringSpecial,
"escape" | "string.escape" => HighlightKind::Escape,
"number" => HighlightKind::Number,
"boolean" => HighlightKind::Boolean,
"type" | "type.interface" => HighlightKind::TypeName,
"type.builtin" => HighlightKind::TypeBuiltin,
"constructor" => HighlightKind::Constructor,
"function" | "function.method" | "function.method.call" | "function.call" => {
HighlightKind::Function
}
"function.builtin" => HighlightKind::FunctionBuiltin,
"macro" | "function.macro" => HighlightKind::MacroName,
"property" | "property.definition" | "variable.member" => HighlightKind::Property,
"constant" | "constant.builtin" | "module" | "module.builtin" => HighlightKind::Constant,
"variable" | "variable.builtin" => HighlightKind::Variable,
"variable.special" | "self" => HighlightKind::VariableSpecial,
"variable.parameter" | "parameter" => HighlightKind::Parameter,
"operator" => HighlightKind::Operator,
"punctuation" | "punctuation.bracket" | "punctuation.delimiter" | "punctuation.special" => {
HighlightKind::Punctuation
}
"tag" | "tag.builtin" => HighlightKind::Tag,
"tag.delimiter" => HighlightKind::Punctuation,
"attribute" | "tag.attribute" => HighlightKind::Attribute,
"label" => HighlightKind::Label,
"invalid" => HighlightKind::Invalid,
_ => HighlightKind::Variable,
}
}