on master help sign in
Exclude only named children without injection.include-children (#3129)

* Exclude only named children without injection.include-children * Add injection.include-unnamed-children parameter

commit6b244e2fefc33ce4e66c8cbd21e2b15f7ba6f179 authorMatthias Deiml <matthias@deiml.net> dateWed 3 Aug 2022, 12:18 (4 years ago) parent08b442f
1 file changed+42−17
helix-core/src/syntax.rs+42−17
helix-core/src/syntax.rs+42−17
@@ -752,7 +752,7 @@ impl Syntax {
752752 );
753753 let mut injections = Vec::new();
754754 for mat in matches {
755− let (language_name, content_node, include_children) = injection_for_match(
755+ let (language_name, content_node, included_children) = injection_for_match(
756756 &layer.config,
757757 &layer.config.injections_query,
758758 &mat,
@@ -769,7 +769,7 @@ impl Syntax {
769769 {
770770 if let Some(config) = (injection_callback)(&language_name) {
771771 let ranges =
772− intersect_ranges(&layer.ranges, &[content_node], include_children);
772+ intersect_ranges(&layer.ranges, &[content_node], included_children);
773773
774774 if !ranges.is_empty() {
775775 injections.push((config, ranges));
@@ -781,7 +781,10 @@ impl Syntax {
781781 // Process combined injections.
782782 if let Some(combined_injections_query) = &layer.config.combined_injections_query {
783783 let mut injections_by_pattern_index =
784− vec![(None, Vec::new(), false); combined_injections_query.pattern_count()];
784+ vec![
785+ (None, Vec::new(), IncludedChildren::default());
786+ combined_injections_query.pattern_count()
787+ ];
785788 let matches = cursor.matches(
786789 combined_injections_query,
787790 layer.tree().root_node(),
@@ -789,7 +792,7 @@ impl Syntax {
789792 );
790793 for mat in matches {
791794 let entry = &mut injections_by_pattern_index[mat.pattern_index];
792− let (language_name, content_node, include_children) = injection_for_match(
795+ let (language_name, content_node, included_children) = injection_for_match(
793796 &layer.config,
794797 combined_injections_query,
795798 &mat,
@@ -801,16 +804,16 @@ impl Syntax {
801804 if let Some(content_node) = content_node {
802805 entry.1.push(content_node);
803806 }
804− entry.2 = include_children;
807+ entry.2 = included_children;
805808 }
806− for (lang_name, content_nodes, includes_children) in injections_by_pattern_index
809+ for (lang_name, content_nodes, included_children) in injections_by_pattern_index
807810 {
808811 if let (Some(lang_name), false) = (lang_name, content_nodes.is_empty()) {
809812 if let Some(config) = (injection_callback)(&lang_name) {
810813 let ranges = intersect_ranges(
811814 &layer.ranges,
812815 &content_nodes,
813− includes_children,
816+ included_children,
814817 );
815818 if !ranges.is_empty() {
816819 injections.push((config, ranges));
@@ -1408,6 +1411,19 @@ impl<'a> HighlightIterLayer<'a> {
14081411 }
14091412}
14101413
1414+#[derive(Clone)]
1415+enum IncludedChildren {
1416+ None,
1417+ All,
1418+ Unnamed,
1419+}
1420+
1421+impl Default for IncludedChildren {
1422+ fn default() -> Self {
1423+ Self::None
1424+ }
1425+}
1426+
14111427// Compute the ranges that should be included when parsing an injection.
14121428// This takes into account three things:
14131429// * `parent_ranges` - The ranges must all fall within the *current* layer's ranges.
@@ -1420,7 +1436,7 @@ impl<'a> HighlightIterLayer<'a> {
14201436fn intersect_ranges(
14211437 parent_ranges: &[Range],
14221438 nodes: &[Node],
1423− includes_children: bool,
1439+ included_children: IncludedChildren,
14241440) -> Vec<Range> {
14251441 let mut cursor = nodes[0].walk();
14261442 let mut result = Vec::new();
@@ -1444,11 +1460,15 @@ fn intersect_ranges(
14441460
14451461 for excluded_range in node
14461462 .children(&mut cursor)
1447− .filter_map(|child| {
1448− if includes_children {
1449− None
1450− } else {
1451− Some(child.range())
1463+ .filter_map(|child| match included_children {
1464+ IncludedChildren::None => Some(child.range()),
1465+ IncludedChildren::All => None,
1466+ IncludedChildren::Unnamed => {
1467+ if child.is_named() {
1468+ Some(child.range())
1469+ } else {
1470+ None
1471+ }
14521472 }
14531473 })
14541474 .chain([following_range].iter().cloned())
@@ -1777,7 +1797,7 @@ fn injection_for_match<'a>(
17771797 query: &'a Query,
17781798 query_match: &QueryMatch<'a, 'a>,
17791799 source: RopeSlice<'a>,
1780−) -> (Option<Cow<'a, str>>, Option<Node<'a>>, bool) {
1800+) -> (Option<Cow<'a, str>>, Option<Node<'a>>, IncludedChildren) {
17811801 let content_capture_index = config.injection_content_capture_index;
17821802 let language_capture_index = config.injection_language_capture_index;
17831803
@@ -1793,7 +1813,7 @@ fn injection_for_match<'a>(
17931813 }
17941814 }
17951815
1796− let mut include_children = false;
1816+ let mut included_children = IncludedChildren::default();
17971817 for prop in query.property_settings(query_match.pattern_index) {
17981818 match prop.key.as_ref() {
17991819 // In addition to specifying the language name via the text of a
@@ -1809,12 +1829,17 @@ fn injection_for_match<'a>(
18091829 // `injection.content` node - only the ranges that belong to the
18101830 // node itself. This can be changed using a `#set!` predicate that
18111831 // sets the `injection.include-children` key.
1812− "injection.include-children" => include_children = true,
1832+ "injection.include-children" => included_children = IncludedChildren::All,
1833+
1834+ // Some queries might only exclude named children but include unnamed
1835+ // children in their `injection.content` node. This can be enabled using
1836+ // a `#set!` predicate that sets the `injection.include-unnamed-children` key.
1837+ "injection.include-unnamed-children" => included_children = IncludedChildren::Unnamed,
18131838 _ => {}
18141839 }
18151840 }
18161841
1817− (language_name, content_node, include_children)
1842+ (language_name, content_node, included_children)
18181843}
18191844
18201845pub struct Merge<I> {