Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 53 additions & 1 deletion highlighter/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ impl LanguageConfig {
static INHERITS_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r";+\s*inherits\s*:?\s*([a-z_,()-]+)\s*").unwrap());

/// reads a query by invoking `read_query_text`, handles any `inherits` directives
static EXTENDS_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r";+\s*extends\s*").unwrap());

/// reads a query by invoking `read_query_text`, handles any `inherits` directives.
///
/// if you need to also handle `extends` directives, you can use the [`read_query_extends`]
/// function.
pub fn read_query(language: &str, mut read_query_text: impl FnMut(&str) -> String) -> String {
fn read_query_impl(language: &str, read_query_text: &mut impl FnMut(&str) -> String) -> String {
let query = read_query_text(language);
Expand All @@ -71,6 +76,53 @@ pub fn read_query(language: &str, mut read_query_text: impl FnMut(&str) -> Strin
read_query_impl(language, &mut read_query_text)
}

/// gets a list of queries in priority order from highest to lowest by invoking
/// `read_lang_queries`, handles any `extends` and `inherits` directives.
///
/// this function is very similar to [`read_query`], however it also handles `extends`
/// directives in addition to `inherits`.
pub fn read_query_extends<I>(language: &str, mut read_lang_queries: impl FnMut(&str) -> I) -> String
where
I: Iterator<Item = String>,
{
fn read_query_impl<I>(read_lang_queries: &mut impl FnMut(&str) -> I, mut queries: I) -> String
where
I: Iterator<Item = String>,
{
let Some(mut query) = queries.next() else {
return String::new();
};

// replace all "; extends" with the queries of the current language, one precedence level up
if let Some(m) = EXTENDS_REGEX.find(&query) {
let q = read_query_impl(read_lang_queries, queries);
query.replace_range(m.range(), &q);
}

// replaces all "; inherits <language>(,<language>)*" with the queries of the given language(s)
INHERITS_REGEX
.replace_all(&query, |captures: &regex::Captures| {
captures[1]
.split(',')
.fold(String::new(), |mut output, language| {
let queries = read_lang_queries(language);
// `write!` to a String cannot fail.
write!(
output,
"\n{}\n",
read_query_impl(&mut *read_lang_queries, queries)
)
.unwrap();
output
})
})
.into_owned()
}

let queries = read_lang_queries(language);
read_query_impl(&mut read_lang_queries, queries)
}

pub trait LanguageLoader {
fn language_for_marker(&self, marker: InjectionLanguageMarker) -> Option<Language>;
fn get_config(&self, lang: Language) -> Option<&LanguageConfig>;
Expand Down
2 changes: 1 addition & 1 deletion highlighter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::hash::{Hash, Hasher};
use std::time::Duration;
use tree_sitter::{IncompatibleGrammarError, Node, Tree};

pub use crate::config::{read_query, LanguageConfig, LanguageLoader};
pub use crate::config::{read_query, read_query_extends, LanguageConfig, LanguageLoader};
pub use crate::injections_query::{InjectionLanguageMarker, InjectionsQuery};
use crate::parse::LayerUpdateFlags;
pub use crate::tree_cursor::TreeCursor;
Expand Down