From da6affaf940509e09f2a38262ae617fd244fbe95 Mon Sep 17 00:00:00 2001 From: Amaan Qureshi Date: Mon, 21 Aug 2023 00:53:04 -0400 Subject: [PATCH 1/2] feat: allow `@injection.self` to inject the node w/ itself --- highlight/src/lib.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/highlight/src/lib.rs b/highlight/src/lib.rs index 20ac5edf..9f4e5b8e 100644 --- a/highlight/src/lib.rs +++ b/highlight/src/lib.rs @@ -112,6 +112,7 @@ pub struct HighlightConfiguration { non_local_variable_patterns: Vec, injection_content_capture_index: Option, injection_language_capture_index: Option, + injection_self_capture_index: Option, local_scope_capture_index: Option, local_def_capture_index: Option, local_def_value_capture_index: Option, @@ -309,6 +310,7 @@ impl HighlightConfiguration { // Store the numeric ids for all of the special captures. let mut injection_content_capture_index = None; let mut injection_language_capture_index = None; + let mut injection_self_capture_index = None; let mut local_def_capture_index = None; let mut local_def_value_capture_index = None; let mut local_ref_capture_index = None; @@ -318,6 +320,7 @@ impl HighlightConfiguration { match name.as_str() { "injection.content" => injection_content_capture_index = i, "injection.language" => injection_language_capture_index = i, + "injection.self" => injection_self_capture_index = i, "local.definition" => local_def_capture_index = i, "local.definition-value" => local_def_value_capture_index = i, "local.reference" => local_ref_capture_index = i, @@ -339,6 +342,7 @@ impl HighlightConfiguration { non_local_variable_patterns, injection_content_capture_index, injection_language_capture_index, + injection_self_capture_index, local_def_capture_index, local_def_value_capture_index, local_ref_capture_index, @@ -1120,6 +1124,7 @@ fn injection_for_match<'a>( ) -> (Option<&'a str>, Option>, bool) { let content_capture_index = config.injection_content_capture_index; let language_capture_index = config.injection_language_capture_index; + let self_capture_index = config.injection_self_capture_index; let mut language_name = None; let mut content_node = None; @@ -1129,6 +1134,11 @@ fn injection_for_match<'a>( language_name = capture.node.utf8_text(source).ok(); } else if index == content_capture_index { content_node = Some(capture.node); + } else if index == self_capture_index { + if let Ok(name) = capture.node.utf8_text(source) { + language_name = Some(name); + content_node = Some(capture.node); + } } } @@ -1144,6 +1154,9 @@ fn injection_for_match<'a>( } } + // Setting the `injection.self` key can be used to specify that the + // language name should be the same as the language of the current + // layer. "injection.self" => { if language_name.is_none() { language_name = Some(config.language_name.as_str()); From e3a5863287e1da35f41bd764a96de1b06222129e Mon Sep 17 00:00:00 2001 From: Amaan Qureshi Date: Mon, 21 Aug 2023 00:53:46 -0400 Subject: [PATCH 2/2] feat: add `@injection.parent` to inject an injection's node with the parent language --- cli/src/tests/highlight_test.rs | 1 + highlight/src/lib.rs | 37 ++++++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/cli/src/tests/highlight_test.rs b/cli/src/tests/highlight_test.rs index c4ca0b49..e400b047 100644 --- a/cli/src/tests/highlight_test.rs +++ b/cli/src/tests/highlight_test.rs @@ -24,6 +24,7 @@ lazy_static! { get_highlight_config("rust", Some("injections.scm"), &HIGHLIGHT_NAMES); static ref HIGHLIGHT_NAMES: Vec = [ "attribute", + "boolean", "carriage-return", "comment", "constant", diff --git a/highlight/src/lib.rs b/highlight/src/lib.rs index 9f4e5b8e..e118530f 100644 --- a/highlight/src/lib.rs +++ b/highlight/src/lib.rs @@ -19,6 +19,7 @@ const BUFFER_LINES_RESERVE_CAPACITY: usize = 1000; lazy_static! { static ref STANDARD_CAPTURE_NAMES: HashSet<&'static str> = vec![ "attribute", + "boolean", "carriage-return", "comment", "comment.documentation", @@ -112,6 +113,7 @@ pub struct HighlightConfiguration { non_local_variable_patterns: Vec, injection_content_capture_index: Option, injection_language_capture_index: Option, + injection_parent_capture_index: Option, injection_self_capture_index: Option, local_scope_capture_index: Option, local_def_capture_index: Option, @@ -155,6 +157,7 @@ where F: FnMut(&str) -> Option<&'a HighlightConfiguration> + 'a, { source: &'a [u8], + language_name: &'a str, byte_offset: usize, highlighter: &'a mut Highlighter, injection_callback: F, @@ -199,6 +202,7 @@ impl Highlighter { ) -> Result> + 'a, Error> { let layers = HighlightIterLayer::new( source, + None, self, cancellation_flag, &mut injection_callback, @@ -214,6 +218,7 @@ impl Highlighter { assert_ne!(layers.len(), 0); let mut result = HighlightIter { source, + language_name: &config.language_name, byte_offset: 0, injection_callback, cancellation_flag, @@ -310,6 +315,7 @@ impl HighlightConfiguration { // Store the numeric ids for all of the special captures. let mut injection_content_capture_index = None; let mut injection_language_capture_index = None; + let mut injection_parent_capture_index = None; let mut injection_self_capture_index = None; let mut local_def_capture_index = None; let mut local_def_value_capture_index = None; @@ -320,6 +326,7 @@ impl HighlightConfiguration { match name.as_str() { "injection.content" => injection_content_capture_index = i, "injection.language" => injection_language_capture_index = i, + "injection.parent" => injection_parent_capture_index = i, "injection.self" => injection_self_capture_index = i, "local.definition" => local_def_capture_index = i, "local.definition-value" => local_def_value_capture_index = i, @@ -342,6 +349,7 @@ impl HighlightConfiguration { non_local_variable_patterns, injection_content_capture_index, injection_language_capture_index, + injection_parent_capture_index, injection_self_capture_index, local_def_capture_index, local_def_value_capture_index, @@ -418,6 +426,7 @@ impl<'a> HighlightIterLayer<'a> { /// added to the returned vector. fn new Option<&'a HighlightConfiguration> + 'a>( source: &'a [u8], + parent_name: Option<&str>, highlighter: &mut Highlighter, cancellation_flag: Option<&'a AtomicUsize>, injection_callback: &mut F, @@ -450,8 +459,13 @@ impl<'a> HighlightIterLayer<'a> { cursor.matches(combined_injections_query, tree.root_node(), source); for mat in matches { let entry = &mut injections_by_pattern_index[mat.pattern_index]; - let (language_name, content_node, include_children) = - injection_for_match(config, combined_injections_query, &mat, source); + let (language_name, content_node, include_children) = injection_for_match( + config, + parent_name, + combined_injections_query, + &mat, + source, + ); if language_name.is_some() { entry.0 = language_name; } @@ -772,8 +786,13 @@ where // If this capture represents an injection, then process the injection. if match_.pattern_index < layer.config.locals_pattern_index { - let (language_name, content_node, include_children) = - injection_for_match(&layer.config, &layer.config.query, &match_, &self.source); + let (language_name, content_node, include_children) = injection_for_match( + layer.config, + Some(self.language_name), + &layer.config.query, + &match_, + self.source, + ); // Explicitly remove this match so that none of its other captures will remain // in the stream of captures. @@ -791,6 +810,7 @@ where if !ranges.is_empty() { match HighlightIterLayer::new( self.source, + Some(self.language_name), self.highlighter, self.cancellation_flag, &mut self.injection_callback, @@ -1118,22 +1138,29 @@ impl HtmlRenderer { fn injection_for_match<'a>( config: &'a HighlightConfiguration, + parent_name: Option<&'a str>, query: &'a Query, query_match: &QueryMatch<'a, 'a>, source: &'a [u8], ) -> (Option<&'a str>, Option>, bool) { let content_capture_index = config.injection_content_capture_index; let language_capture_index = config.injection_language_capture_index; + let parent_capture_index = config.injection_parent_capture_index; let self_capture_index = config.injection_self_capture_index; let mut language_name = None; let mut content_node = None; + let parent_name = parent_name.unwrap_or_default(); + for capture in query_match.captures { let index = Some(capture.index); if index == language_capture_index { language_name = capture.node.utf8_text(source).ok(); } else if index == content_capture_index { content_node = Some(capture.node); + } else if index == parent_capture_index && !parent_name.is_empty() { + language_name = Some(parent_name); + content_node = Some(capture.node); } else if index == self_capture_index { if let Ok(name) = capture.node.utf8_text(source) { language_name = Some(name); @@ -1150,7 +1177,7 @@ fn injection_for_match<'a>( // that sets the injection.language key. "injection.language" => { if language_name.is_none() { - language_name = prop.value.as_ref().map(|s| s.as_ref()) + language_name = prop.value.as_ref().map(|s| s.as_ref()); } }