Unnamed repository; edit this file 'description' to name the repository.
Simplify first-in-line computation for indent queries. (#10527)
Triton171 2024-04-21
parent 35b6aef · commit efae85e
-rw-r--r--helix-core/src/indent.rs49
1 files changed, 11 insertions, 38 deletions
diff --git a/helix-core/src/indent.rs b/helix-core/src/indent.rs
index 2a0a3876..ca72fc3a 100644
--- a/helix-core/src/indent.rs
+++ b/helix-core/src/indent.rs
@@ -247,41 +247,18 @@ fn add_indent_level(
}
}
-/// Computes for node and all ancestors whether they are the first node on their line.
-/// The first entry in the return value represents the root node, the last one the node itself
-fn get_first_in_line(mut node: Node, new_line_byte_pos: Option<usize>) -> Vec<bool> {
- let mut first_in_line = Vec::new();
- loop {
- if let Some(prev) = node.prev_sibling() {
- // If we insert a new line, the first node at/after the cursor is considered to be the first in its line
- let first = prev.end_position().row != node.start_position().row
- || new_line_byte_pos.map_or(false, |byte_pos| {
- node.start_byte() >= byte_pos && prev.start_byte() < byte_pos
- });
- first_in_line.push(Some(first));
- } else {
- // Nodes that have no previous siblings are first in their line if and only if their parent is
- // (which we don't know yet)
- first_in_line.push(None);
- }
- if let Some(parent) = node.parent() {
- node = parent;
- } else {
- break;
- }
- }
-
- let mut result = Vec::with_capacity(first_in_line.len());
- let mut parent_is_first = true; // The root node is by definition the first node in its line
- for first in first_in_line.into_iter().rev() {
- if let Some(first) = first {
- result.push(first);
- parent_is_first = first;
- } else {
- result.push(parent_is_first);
+/// Return true if only whitespace comes before the node on its line.
+/// If given, new_line_byte_pos is treated the same way as any existing newline.
+fn is_first_in_line(node: Node, text: RopeSlice, new_line_byte_pos: Option<usize>) -> bool {
+ let mut line_start_byte_pos = text.line_to_byte(node.start_position().row);
+ if let Some(pos) = new_line_byte_pos {
+ if line_start_byte_pos < pos && pos <= node.start_byte() {
+ line_start_byte_pos = pos;
}
}
- result
+ text.byte_slice(line_start_byte_pos..node.start_byte())
+ .chars()
+ .all(|c| c.is_whitespace())
}
/// The total indent for some line of code.
@@ -852,7 +829,6 @@ pub fn treesitter_indent_for_pos<'a>(
byte_pos,
new_line_byte_pos,
)?;
- let mut first_in_line = get_first_in_line(node, new_line.then_some(byte_pos));
let mut result = Indentation::default();
// We always keep track of all the indent changes on one line, in order to only indent once
@@ -861,9 +837,7 @@ pub fn treesitter_indent_for_pos<'a>(
let mut indent_for_line_below = Indentation::default();
loop {
- // This can safely be unwrapped because `first_in_line` contains
- // one entry for each ancestor of the node (which is what we iterate over)
- let is_first = *first_in_line.last().unwrap();
+ let is_first = is_first_in_line(node, text, new_line_byte_pos);
// Apply all indent definitions for this node.
// Since we only iterate over each node once, we can remove the
@@ -906,7 +880,6 @@ pub fn treesitter_indent_for_pos<'a>(
}
node = parent;
- first_in_line.pop();
} else {
// Only add the indentation for the line below if that line
// is not after the line that the indentation is calculated for.