Skip to content

Commit

Permalink
use a single query for injections
Browse files Browse the repository at this point in the history
In the past we used two separate queries for combined and normal injections. There was no real reason for this (except historical/slightly easier implementation). Instead, we now use a single query and simply check if an injection corresponds to a combined injection or not.
  • Loading branch information
pascalkuthe committed Jul 13, 2023
1 parent 0957a54 commit 89596f9
Showing 1 changed file with 44 additions and 59 deletions.
103 changes: 44 additions & 59 deletions helix-core/src/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1135,13 +1135,39 @@ impl Syntax {
layer.tree().root_node(),
RopeProvider(source_slice),
);
let mut combined_injections = vec![
(None, Vec::new(), IncludedChildren::default());
layer.config.combined_injections_patterns.len()
];
let mut injections = Vec::new();
let mut last_injection_end = 0;
for mat in matches {
let (injection_capture, content_node, included_children) = layer
.config
.injection_for_match(&layer.config.injections_query, &mat, source_slice);

// in case this is a combined injection save it for more processing later
if let Some(combined_injection_idx) = layer
.config
.combined_injections_patterns
.iter()
.position(|&pattern| pattern == mat.pattern_index)
{
let entry = &mut combined_injections[combined_injection_idx];
if injection_capture.is_some() {
entry.0 = injection_capture;
}
if let Some(content_node) = content_node {
if content_node.start_byte() >= last_injection_end {
entry.2 = included_children;
} else {
last_injection_end = content_node.end_byte();
}
entry.1.push(content_node);
}
continue;
}

// Explicitly remove this match so that none of its other captures will remain
// in the stream of captures.
mat.remove();
Expand All @@ -1167,43 +1193,13 @@ 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(), IncludedChildren::default());
combined_injections_query.pattern_count()
];
let matches = cursor.matches(
combined_injections_query,
layer.tree().root_node(),
RopeProvider(source_slice),
);
for mat in matches {
let entry = &mut injections_by_pattern_index[mat.pattern_index];
let (injection_capture, content_node, included_children) = layer
.config
.injection_for_match(combined_injections_query, &mat, source_slice);
if injection_capture.is_some() {
entry.0 = injection_capture;
}
if let Some(content_node) = content_node {
entry.1.push(content_node);
}
entry.2 = included_children;
}
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,
included_children,
);
if !ranges.is_empty() {
injections.push((config, ranges));
}
for (lang_name, content_nodes, included_children) in combined_injections {
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, included_children);
if !ranges.is_empty() {
injections.push((config, ranges));
}
}
}
Expand Down Expand Up @@ -1566,7 +1562,7 @@ pub struct HighlightConfiguration {
pub language: Grammar,
pub query: Query,
injections_query: Query,
combined_injections_query: Option<Query>,
combined_injections_patterns: Vec<usize>,
highlights_pattern_index: usize,
highlight_indices: ArcSwap<Vec<Option<Highlight>>>,
non_local_variable_patterns: Vec<bool>,
Expand Down Expand Up @@ -1682,26 +1678,15 @@ impl HighlightConfiguration {
}
}

let mut injections_query = Query::new(language, injection_query)?;

// Construct a separate query just for dealing with the 'combined injections'.
// Disable the combined injection patterns in the main query.
let mut combined_injections_query = Query::new(language, injection_query)?;
let mut has_combined_queries = false;
for pattern_index in 0..injections_query.pattern_count() {
let settings = injections_query.property_settings(pattern_index);
if settings.iter().any(|s| &*s.key == "injection.combined") {
has_combined_queries = true;
injections_query.disable_pattern(pattern_index);
} else {
combined_injections_query.disable_pattern(pattern_index);
}
}
let combined_injections_query = if has_combined_queries {
Some(combined_injections_query)
} else {
None
};
let injections_query = Query::new(language, injection_query)?;
let combined_injections_patterns = (0..injections_query.pattern_count())
.filter(|&i| {
injections_query
.property_settings(i)
.iter()
.any(|s| &*s.key == "injection.combined")
})
.collect();

// Find all of the highlighting patterns that are disabled for nodes that
// have been identified as local variables.
Expand Down Expand Up @@ -1750,7 +1735,7 @@ impl HighlightConfiguration {
language,
query,
injections_query,
combined_injections_query,
combined_injections_patterns,
highlights_pattern_index,
highlight_indices,
non_local_variable_patterns,
Expand Down

0 comments on commit 89596f9

Please sign in to comment.