summaryrefslogtreecommitdiff
path: root/helix-core/src/syntax.rs
diff options
context:
space:
mode:
authorMatthias Deiml2022-08-03 10:18:17 +0000
committerGitHub2022-08-03 10:18:17 +0000
commit6b244e2fefc33ce4e66c8cbd21e2b15f7ba6f179 (patch)
treec550cadfef81617c4e9be562c561204c3d69ef0a /helix-core/src/syntax.rs
parent08b442f4cc962fd83a41754aba41f742acd1e8dc (diff)
Exclude only named children without injection.include-children (#3129)
* Exclude only named children without injection.include-children * Add injection.include-unnamed-children parameter
Diffstat (limited to 'helix-core/src/syntax.rs')
-rw-r--r--helix-core/src/syntax.rs59
1 files changed, 42 insertions, 17 deletions
diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs
index 9011f835..79570faa 100644
--- a/helix-core/src/syntax.rs
+++ b/helix-core/src/syntax.rs
@@ -752,7 +752,7 @@ impl Syntax {
);
let mut injections = Vec::new();
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.injections_query,
&mat,
@@ -769,7 +769,7 @@ impl Syntax {
{
if let Some(config) = (injection_callback)(&language_name) {
let ranges =
- intersect_ranges(&layer.ranges, &[content_node], include_children);
+ intersect_ranges(&layer.ranges, &[content_node], included_children);
if !ranges.is_empty() {
injections.push((config, ranges));
@@ -781,7 +781,10 @@ impl Syntax {
// Process combined injections.
if let Some(combined_injections_query) = &layer.config.combined_injections_query {
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(
combined_injections_query,
layer.tree().root_node(),
@@ -789,7 +792,7 @@ impl Syntax {
);
for mat in matches {
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,
combined_injections_query,
&mat,
@@ -801,16 +804,16 @@ impl Syntax {
if let Some(content_node) = 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(config) = (injection_callback)(&lang_name) {
let ranges = intersect_ranges(
&layer.ranges,
&content_nodes,
- includes_children,
+ included_children,
);
if !ranges.is_empty() {
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.
// This takes into account three things:
// * `parent_ranges` - The ranges must all fall within the *current* layer's ranges.
@@ -1420,7 +1436,7 @@ impl<'a> HighlightIterLayer<'a> {
fn intersect_ranges(
parent_ranges: &[Range],
nodes: &[Node],
- includes_children: bool,
+ included_children: IncludedChildren,
) -> Vec<Range> {
let mut cursor = nodes[0].walk();
let mut result = Vec::new();
@@ -1444,11 +1460,15 @@ fn intersect_ranges(
for excluded_range in node
.children(&mut cursor)
- .filter_map(|child| {
- if includes_children {
- None
- } else {
- Some(child.range())
+ .filter_map(|child| match included_children {
+ IncludedChildren::None => Some(child.range()),
+ IncludedChildren::All => None,
+ IncludedChildren::Unnamed => {
+ if child.is_named() {
+ Some(child.range())
+ } else {
+ None
+ }
}
})
.chain([following_range].iter().cloned())
@@ -1777,7 +1797,7 @@ fn injection_for_match<'a>(
query: &'a Query,
query_match: &QueryMatch<'a, '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 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) {
match prop.key.as_ref() {
// 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
// node itself. This can be changed using a `#set!` predicate that
// 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> {