Merge pull request #2544 from amaanq/injection-parent

`@injection.parent`
This commit is contained in:
Amaan Qureshi 2023-08-21 17:31:45 -04:00 committed by GitHub
commit e716e2e45a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 5 deletions

View file

@ -24,6 +24,7 @@ lazy_static! {
get_highlight_config("rust", Some("injections.scm"), &HIGHLIGHT_NAMES);
static ref HIGHLIGHT_NAMES: Vec<String> = [
"attribute",
"boolean",
"carriage-return",
"comment",
"constant",

View file

@ -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,8 @@ pub struct HighlightConfiguration {
non_local_variable_patterns: Vec<bool>,
injection_content_capture_index: Option<u32>,
injection_language_capture_index: Option<u32>,
injection_parent_capture_index: Option<u32>,
injection_self_capture_index: Option<u32>,
local_scope_capture_index: Option<u32>,
local_def_capture_index: Option<u32>,
local_def_value_capture_index: Option<u32>,
@ -154,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,
@ -198,6 +202,7 @@ impl Highlighter {
) -> Result<impl Iterator<Item = Result<HighlightEvent, Error>> + 'a, Error> {
let layers = HighlightIterLayer::new(
source,
None,
self,
cancellation_flag,
&mut injection_callback,
@ -213,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,
@ -309,6 +315,8 @@ 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;
let mut local_ref_capture_index = None;
@ -318,6 +326,8 @@ 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,
"local.reference" => local_ref_capture_index = i,
@ -339,6 +349,8 @@ 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,
local_ref_capture_index,
@ -414,6 +426,7 @@ impl<'a> HighlightIterLayer<'a> {
/// added to the returned vector.
fn new<F: FnMut(&str) -> Option<&'a HighlightConfiguration> + 'a>(
source: &'a [u8],
parent_name: Option<&str>,
highlighter: &mut Highlighter,
cancellation_flag: Option<&'a AtomicUsize>,
injection_callback: &mut F,
@ -446,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;
}
@ -768,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.
@ -787,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,
@ -1114,21 +1138,34 @@ 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<Node<'a>>, 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);
content_node = Some(capture.node);
}
}
}
@ -1140,10 +1177,13 @@ 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());
}
}
// 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());