Skip to content

Commit

Permalink
Share sort_layers function between query iterators
Browse files Browse the repository at this point in the history
The code in the `sort_layers` function was fully duplicated between
the HighlightIter and the QueryIter. This change adds a common
`sort_layers` function that accepts a layer Vec from both.
  • Loading branch information
the-mikedavis committed Jan 11, 2024
1 parent 480590a commit 276ba75
Showing 1 changed file with 66 additions and 87 deletions.
153 changes: 66 additions & 87 deletions helix-core/src/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1327,7 +1327,7 @@ impl Syntax {
range: Option<std::ops::Range<usize>>,
cancellation_flag: Option<&'a AtomicUsize>,
) -> impl Iterator<Item = Result<HighlightEvent, Error>> + 'a {
let mut layers = self
let mut layers: Vec<_> = self
.layers
.iter()
.filter_map(|(_, layer)| {
Expand Down Expand Up @@ -1374,21 +1374,21 @@ impl Syntax {
depth: layer.depth, // TODO: just reuse `layer`
})
})
.collect::<Vec<_>>();
.collect();

layers.sort_unstable_by_key(|layer| layer.sort_key());

let mut result = HighlightIter {
sort_layers(&mut layers);

HighlightIter {
source,
byte_offset: range.map_or(0, |r| r.start),
cancellation_flag,
iter_count: 0,
layers,
next_event: None,
last_highlight_range: None,
};
result.sort_layers();
result
}
}

// Commenting
Expand Down Expand Up @@ -2015,6 +2015,58 @@ impl<'a> IterLayer for QueryIterLayer<'a> {
self.cursor
}
}

/// Re-sort the given layers so that the next capture for the `layers[0]` is
/// the earliest capture in the document for all layers.
///
/// This function assumes that `layers` is already sorted except for the
/// first layer in the `Vec`. This function shifts the first layer later in
/// the `Vec` after any layers with earlier captures.
///
/// This is quicker than a regular full sort: it can only take as many
/// iterations as the number of layers and usually takes many fewer than
/// the full number of layers. The case when `layers[0]` is already the
/// layer with the earliest capture and the sort is a no-op is a fast-lane
/// which only takes one comparison operation.
///
/// This function also removes any layers which have no more query captures
/// to emit.
fn sort_layers<L: IterLayer>(layers: &mut Vec<L>) {
while !layers.is_empty() {
// If `Layer::sort_key` returns `None`, the layer has no more captures
// to emit and can be removed.
if let Some(sort_key) = layers[0].sort_key() {
let mut i = 0;
while i + 1 < layers.len() {
if let Some(next_offset) = layers[i + 1].sort_key() {
// Compare `0`'s sort key to `i + 1`'s. If `i + 1` comes
// before `0`, shift the `0` layer so it comes after the
// `i + 1` layers.
if next_offset < sort_key {
i += 1;
continue;
}
} else {
let layer = layers.remove(i + 1);
PARSER.with(|ts_parser| {
let highlighter = &mut ts_parser.borrow_mut();
highlighter.cursors.push(layer.cursor());
});
}
break;
}
if i > 0 {
layers[0..(i + 1)].rotate_left(1);
}
break;
} else {
let layer = layers.remove(0);
PARSER.with(|ts_parser| {
let highlighter = &mut ts_parser.borrow_mut();
highlighter.cursors.push(layer.cursor());
});
}
}
}

#[derive(Clone)]
Expand Down Expand Up @@ -2145,42 +2197,9 @@ impl<'a> HighlightIter<'a> {
} else {
result = event.map(Ok);
}
self.sort_layers();
sort_layers(&mut self.layers);
result
}

fn sort_layers(&mut self) {
while !self.layers.is_empty() {
if let Some(sort_key) = self.layers[0].sort_key() {
let mut i = 0;
while i + 1 < self.layers.len() {
if let Some(next_offset) = self.layers[i + 1].sort_key() {
if next_offset < sort_key {
i += 1;
continue;
}
} else {
let layer = self.layers.remove(i + 1);
PARSER.with(|ts_parser| {
let highlighter = &mut ts_parser.borrow_mut();
highlighter.cursors.push(layer.cursor);
});
}
break;
}
if i > 0 {
self.layers[0..(i + 1)].rotate_left(1);
}
break;
} else {
let layer = self.layers.remove(0);
PARSER.with(|ts_parser| {
let highlighter = &mut ts_parser.borrow_mut();
highlighter.cursors.push(layer.cursor);
});
}
}
}
}

impl<'a> Iterator for HighlightIter<'a> {
Expand Down Expand Up @@ -2332,7 +2351,7 @@ impl<'a> Iterator for HighlightIter<'a> {
}
}

self.sort_layers();
sort_layers(&mut self.layers);
continue 'main;
}

Expand All @@ -2341,7 +2360,7 @@ impl<'a> Iterator for HighlightIter<'a> {
// a different layer, then skip over this one.
if let Some((last_start, last_end, last_depth)) = self.last_highlight_range {
if range.start == last_start && range.end == last_end && layer.depth < last_depth {
self.sort_layers();
sort_layers(&mut self.layers);
continue 'main;
}
}
Expand All @@ -2359,7 +2378,7 @@ impl<'a> Iterator for HighlightIter<'a> {
}
}

self.sort_layers();
sort_layers(&mut self.layers);
continue 'main;
}
}
Expand Down Expand Up @@ -2394,7 +2413,7 @@ impl<'a> Iterator for HighlightIter<'a> {
.emit_event(range.start, Some(HighlightEvent::HighlightStart(highlight)));
}

self.sort_layers();
sort_layers(&mut self.layers);
}
}
}
Expand Down Expand Up @@ -2606,7 +2625,7 @@ fn pretty_print_tree_impl<W: fmt::Write>(

struct QueryIterLayer<'a> {
cursor: QueryCursor,
captures: iter::Peekable<QueryCaptures<'a, 'a, RopeProvider<'a>, &'a [u8]>>,
captures: RefCell<iter::Peekable<QueryCaptures<'a, 'a, RopeProvider<'a>, &'a [u8]>>>,
layer: &'a LanguageLayer,
}

Expand All @@ -2616,16 +2635,6 @@ impl<'a> fmt::Debug for QueryIterLayer<'a> {
}
}

impl<'a> QueryIterLayer<'a> {
fn sort_key(&mut self) -> Option<(usize, isize)> {
let depth = -(self.layer.depth as isize);
let (match_, capture_index) = self.captures.peek()?;
let start = match_.captures[*capture_index].node.start_byte();

Some((start, depth))
}
}

#[derive(Debug)]
pub struct QueryIter<'a> {
layers: Vec<QueryIterLayer<'a>>,
Expand All @@ -2635,38 +2644,8 @@ impl<'a> Iterator for QueryIter<'a> {
type Item = (&'a LanguageLayer, QueryMatch<'a, 'a>, usize);

fn next(&mut self) -> Option<Self::Item> {
// Sort the layers so that the first layer in the Vec has the next
// capture ordered by start byte and depth (descending).
while !self.layers.is_empty() {
if let Some(sort_key) = self.layers[0].sort_key() {
let mut i = 0;
while i + 1 < self.layers.len() {
if let Some(next_sort_key) = self.layers[i + 1].sort_key() {
if next_sort_key < sort_key {
i += 1;
continue;
}
} else {
let layer = self.layers.remove(i + 1);
PARSER.with(|ts_parser| {
let parser = &mut ts_parser.borrow_mut();
parser.cursors.push(layer.cursor);
});
}
break;
}
if i > 0 {
self.layers[0..(i + 1)].rotate_left(1);
}
break;
} else {
let layer = self.layers.remove(0);
PARSER.with(|ts_parser| {
let parser = &mut ts_parser.borrow_mut();
parser.cursors.push(layer.cursor);
})
}
}
// Sort the layers so that the first layer contains the next capture.
sort_layers(&mut self.layers);

// Emit the next capture from the lowest layer. If there are no more
// layers, terminate.
Expand Down

0 comments on commit 276ba75

Please sign in to comment.