1use once_cell::sync::Lazy;
2use regex::Regex;
3use tree_sitter::{query, Grammar};
4
5use crate::highlighter::{Highlight, HighlightQuery};
6use crate::injections_query::{InjectionLanguageMarker, InjectionsQuery};
7use crate::Language;
8
9use std::fmt::Write;
10
11#[derive(Debug)]
12pub struct LanguageConfig {
13 pub grammar: Grammar,
14 pub highlight_query: HighlightQuery,
15 pub injection_query: InjectionsQuery,
16}
17
18impl LanguageConfig {
19 pub fn new(
20 grammar: Grammar,
21 highlight_query_text: &str,
22 injection_query_text: &str,
23 local_query_text: &str,
24 ) -> Result<Self, query::ParseError> {
25 let injection_query =
29 InjectionsQuery::new(grammar, injection_query_text, local_query_text)?;
30 let highlight_query = HighlightQuery::new(grammar, highlight_query_text, local_query_text)?;
31
32 Ok(Self {
33 grammar,
34 highlight_query,
35 injection_query,
36 })
37 }
38
39 pub fn configure(&self, mut f: impl FnMut(&str) -> Option<Highlight>) {
40 self.highlight_query.configure(&mut f);
41 self.injection_query.configure(&mut f);
42 }
43}
44
45static INHERITS_REGEX: Lazy<Regex> =
46 Lazy::new(|| Regex::new(r";+\s*inherits\s*:?\s*([a-z_,()-]+)\s*").unwrap());
47
48pub fn read_query(language: &str, mut read_query_text: impl FnMut(&str) -> String) -> String {
50 fn read_query_impl(language: &str, read_query_text: &mut impl FnMut(&str) -> String) -> String {
51 let query = read_query_text(language);
52
53 INHERITS_REGEX
55 .replace_all(&query, |captures: ®ex::Captures| {
56 captures[1]
57 .split(',')
58 .fold(String::new(), |mut output, language| {
59 write!(
61 output,
62 "\n{}\n",
63 read_query_impl(language, &mut *read_query_text)
64 )
65 .unwrap();
66 output
67 })
68 })
69 .into_owned()
70 }
71 read_query_impl(language, &mut read_query_text)
72}
73
74pub trait LanguageLoader {
75 fn language_for_marker(&self, marker: InjectionLanguageMarker) -> Option<Language>;
76 fn get_config(&self, lang: Language) -> Option<&LanguageConfig>;
77}
78
79impl<T> LanguageLoader for &'_ T
80where
81 T: LanguageLoader,
82{
83 fn language_for_marker(&self, marker: InjectionLanguageMarker) -> Option<Language> {
84 T::language_for_marker(self, marker)
85 }
86
87 fn get_config(&self, lang: Language) -> Option<&LanguageConfig> {
88 T::get_config(self, lang)
89 }
90}