Exclude only named children without injection.include-children (#3129)

* Exclude only named children without injection.include-children

* Add injection.include-unnamed-children parameter
This commit is contained in:
Matthias Deiml 2022-08-03 12:18:17 +02:00 committed by GitHub
parent 08b442f4cc
commit 6b244e2fef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -752,7 +752,7 @@ impl Syntax {
); );
let mut injections = Vec::new(); let mut injections = Vec::new();
for mat in matches { for mat in matches {
let (language_name, content_node, include_children) = injection_for_match( let (language_name, content_node, included_children) = injection_for_match(
&layer.config, &layer.config,
&layer.config.injections_query, &layer.config.injections_query,
&mat, &mat,
@ -769,7 +769,7 @@ impl Syntax {
{ {
if let Some(config) = (injection_callback)(&language_name) { if let Some(config) = (injection_callback)(&language_name) {
let ranges = let ranges =
intersect_ranges(&layer.ranges, &[content_node], include_children); intersect_ranges(&layer.ranges, &[content_node], included_children);
if !ranges.is_empty() { if !ranges.is_empty() {
injections.push((config, ranges)); injections.push((config, ranges));
@ -781,7 +781,10 @@ impl Syntax {
// Process combined injections. // Process combined injections.
if let Some(combined_injections_query) = &layer.config.combined_injections_query { if let Some(combined_injections_query) = &layer.config.combined_injections_query {
let mut injections_by_pattern_index = let mut injections_by_pattern_index =
vec![(None, Vec::new(), false); combined_injections_query.pattern_count()]; vec![
(None, Vec::new(), IncludedChildren::default());
combined_injections_query.pattern_count()
];
let matches = cursor.matches( let matches = cursor.matches(
combined_injections_query, combined_injections_query,
layer.tree().root_node(), layer.tree().root_node(),
@ -789,7 +792,7 @@ impl Syntax {
); );
for mat in matches { for mat in matches {
let entry = &mut injections_by_pattern_index[mat.pattern_index]; let entry = &mut injections_by_pattern_index[mat.pattern_index];
let (language_name, content_node, include_children) = injection_for_match( let (language_name, content_node, included_children) = injection_for_match(
&layer.config, &layer.config,
combined_injections_query, combined_injections_query,
&mat, &mat,
@ -801,16 +804,16 @@ impl Syntax {
if let Some(content_node) = content_node { if let Some(content_node) = content_node {
entry.1.push(content_node); entry.1.push(content_node);
} }
entry.2 = include_children; entry.2 = included_children;
} }
for (lang_name, content_nodes, includes_children) in injections_by_pattern_index for (lang_name, content_nodes, included_children) in injections_by_pattern_index
{ {
if let (Some(lang_name), false) = (lang_name, content_nodes.is_empty()) { if let (Some(lang_name), false) = (lang_name, content_nodes.is_empty()) {
if let Some(config) = (injection_callback)(&lang_name) { if let Some(config) = (injection_callback)(&lang_name) {
let ranges = intersect_ranges( let ranges = intersect_ranges(
&layer.ranges, &layer.ranges,
&content_nodes, &content_nodes,
includes_children, included_children,
); );
if !ranges.is_empty() { if !ranges.is_empty() {
injections.push((config, ranges)); injections.push((config, ranges));
@ -1408,6 +1411,19 @@ impl<'a> HighlightIterLayer<'a> {
} }
} }
#[derive(Clone)]
enum IncludedChildren {
None,
All,
Unnamed,
}
impl Default for IncludedChildren {
fn default() -> Self {
Self::None
}
}
// Compute the ranges that should be included when parsing an injection. // Compute the ranges that should be included when parsing an injection.
// This takes into account three things: // This takes into account three things:
// * `parent_ranges` - The ranges must all fall within the *current* layer's ranges. // * `parent_ranges` - The ranges must all fall within the *current* layer's ranges.
@ -1420,7 +1436,7 @@ impl<'a> HighlightIterLayer<'a> {
fn intersect_ranges( fn intersect_ranges(
parent_ranges: &[Range], parent_ranges: &[Range],
nodes: &[Node], nodes: &[Node],
includes_children: bool, included_children: IncludedChildren,
) -> Vec<Range> { ) -> Vec<Range> {
let mut cursor = nodes[0].walk(); let mut cursor = nodes[0].walk();
let mut result = Vec::new(); let mut result = Vec::new();
@ -1444,11 +1460,15 @@ fn intersect_ranges(
for excluded_range in node for excluded_range in node
.children(&mut cursor) .children(&mut cursor)
.filter_map(|child| { .filter_map(|child| match included_children {
if includes_children { IncludedChildren::None => Some(child.range()),
None IncludedChildren::All => None,
} else { IncludedChildren::Unnamed => {
Some(child.range()) if child.is_named() {
Some(child.range())
} else {
None
}
} }
}) })
.chain([following_range].iter().cloned()) .chain([following_range].iter().cloned())
@ -1777,7 +1797,7 @@ fn injection_for_match<'a>(
query: &'a Query, query: &'a Query,
query_match: &QueryMatch<'a, 'a>, query_match: &QueryMatch<'a, 'a>,
source: RopeSlice<'a>, source: RopeSlice<'a>,
) -> (Option<Cow<'a, str>>, Option<Node<'a>>, bool) { ) -> (Option<Cow<'a, str>>, Option<Node<'a>>, IncludedChildren) {
let content_capture_index = config.injection_content_capture_index; let content_capture_index = config.injection_content_capture_index;
let language_capture_index = config.injection_language_capture_index; let language_capture_index = config.injection_language_capture_index;
@ -1793,7 +1813,7 @@ fn injection_for_match<'a>(
} }
} }
let mut include_children = false; let mut included_children = IncludedChildren::default();
for prop in query.property_settings(query_match.pattern_index) { for prop in query.property_settings(query_match.pattern_index) {
match prop.key.as_ref() { match prop.key.as_ref() {
// In addition to specifying the language name via the text of a // In addition to specifying the language name via the text of a
@ -1809,12 +1829,17 @@ fn injection_for_match<'a>(
// `injection.content` node - only the ranges that belong to the // `injection.content` node - only the ranges that belong to the
// node itself. This can be changed using a `#set!` predicate that // node itself. This can be changed using a `#set!` predicate that
// sets the `injection.include-children` key. // sets the `injection.include-children` key.
"injection.include-children" => include_children = true, "injection.include-children" => included_children = IncludedChildren::All,
// Some queries might only exclude named children but include unnamed
// children in their `injection.content` node. This can be enabled using
// a `#set!` predicate that sets the `injection.include-unnamed-children` key.
"injection.include-unnamed-children" => included_children = IncludedChildren::Unnamed,
_ => {} _ => {}
} }
} }
(language_name, content_node, include_children) (language_name, content_node, included_children)
} }
pub struct Merge<I> { pub struct Merge<I> {