diff --git a/helix-core/src/indent.rs b/helix-core/src/indent.rs index 2a0a3876c768..ca72fc3a24fb 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) -> Vec { - 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) -> 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.