Improve code style for tree-sitter indentation.
Split extend logic into a separate file.
This commit is contained in:
parent
05832f90cb
commit
2b02785f19
1 changed files with 102 additions and 87 deletions
|
@ -456,6 +456,67 @@ fn query_indents(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handle extend queries. deepest_preceding is the deepest descendant of node that directly precedes the cursor position.
|
||||||
|
/// Any ancestor of deepest_preceding which is also a descendant of node may be "extended". In that case, node will be updated,
|
||||||
|
/// so that the indent computation starts with the correct syntax node.
|
||||||
|
fn extend_nodes<'a>(
|
||||||
|
node: &mut Node<'a>,
|
||||||
|
deepest_preceding: Option<Node<'a>>,
|
||||||
|
extend_captures: &HashMap<usize, Vec<ExtendCapture>>,
|
||||||
|
text: RopeSlice,
|
||||||
|
line: usize,
|
||||||
|
tab_width: usize,
|
||||||
|
) {
|
||||||
|
if let Some(mut deepest_preceding) = deepest_preceding {
|
||||||
|
let mut stop_extend = false;
|
||||||
|
while deepest_preceding != *node {
|
||||||
|
let mut extend_node = false;
|
||||||
|
if let Some(captures) = extend_captures.get(&deepest_preceding.id()) {
|
||||||
|
for capture in captures {
|
||||||
|
match capture {
|
||||||
|
ExtendCapture::StopExtend => {
|
||||||
|
stop_extend = true;
|
||||||
|
}
|
||||||
|
ExtendCapture::ExtendIndented => {
|
||||||
|
// We extend the node if
|
||||||
|
// - the cursor is on the same line as the end of the node OR
|
||||||
|
// - the line that the cursor is on is more indented than the
|
||||||
|
// first line of the node
|
||||||
|
if deepest_preceding.end_position().row == line {
|
||||||
|
extend_node = true;
|
||||||
|
} else {
|
||||||
|
let cursor_indent =
|
||||||
|
indent_level_for_line(text.line(line), tab_width);
|
||||||
|
let node_indent = indent_level_for_line(
|
||||||
|
text.line(deepest_preceding.start_position().row),
|
||||||
|
tab_width,
|
||||||
|
);
|
||||||
|
if cursor_indent > node_indent {
|
||||||
|
extend_node = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we encountered some `StopExtend` capture before, we don't
|
||||||
|
// extend the node even if we otherwise would
|
||||||
|
match (extend_node, stop_extend) {
|
||||||
|
(true, true) => {
|
||||||
|
stop_extend = false;
|
||||||
|
}
|
||||||
|
(true, false) => {
|
||||||
|
*node = deepest_preceding;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
// This parent always exists since node is an ancestor of deepest_preceding
|
||||||
|
deepest_preceding = deepest_preceding.parent().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Use the syntax tree to determine the indentation for a given position.
|
/// Use the syntax tree to determine the indentation for a given position.
|
||||||
/// This can be used in 2 ways:
|
/// This can be used in 2 ways:
|
||||||
///
|
///
|
||||||
|
@ -510,100 +571,54 @@ pub fn treesitter_indent_for_pos(
|
||||||
.tree()
|
.tree()
|
||||||
.root_node()
|
.root_node()
|
||||||
.descendant_for_byte_range(byte_pos, byte_pos)?;
|
.descendant_for_byte_range(byte_pos, byte_pos)?;
|
||||||
let (query_result, prev_child) = crate::syntax::PARSER.with(|ts_parser| {
|
let (query_result, deepest_preceding) = {
|
||||||
let mut ts_parser = ts_parser.borrow_mut();
|
|
||||||
let mut cursor = ts_parser.cursors.pop().unwrap_or_else(QueryCursor::new);
|
|
||||||
// The query range should intersect with all nodes directly preceding
|
// The query range should intersect with all nodes directly preceding
|
||||||
// the cursor in case one of them is extended.
|
// the cursor in case one of them is extended.
|
||||||
// prev_child is the deepest such node.
|
let mut deepest_preceding = None; // The deepest node preceding the cursor
|
||||||
let (query_range, prev_child) = {
|
let mut tree_cursor = node.walk();
|
||||||
// TODO Is there some way we can reuse this cursor?
|
for child in node.children(&mut tree_cursor) {
|
||||||
let mut tree_cursor = node.walk();
|
if child.byte_range().end <= byte_pos {
|
||||||
let mut prev_child = None;
|
deepest_preceding = Some(child);
|
||||||
for child in node.children(&mut tree_cursor) {
|
|
||||||
if child.byte_range().end <= byte_pos {
|
|
||||||
prev_child = Some(child);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
match prev_child {
|
}
|
||||||
Some(mut prev_child) => {
|
deepest_preceding = deepest_preceding.map(|mut prec| {
|
||||||
// Get the deepest directly preceding node
|
// Get the deepest directly preceding node
|
||||||
while prev_child.child_count() > 0 {
|
while prec.child_count() > 0 {
|
||||||
prev_child = prev_child.child(prev_child.child_count() - 1).unwrap();
|
prec = prec.child(prec.child_count() - 1).unwrap();
|
||||||
}
|
|
||||||
(
|
|
||||||
prev_child.byte_range().end - 1..byte_pos + 1,
|
|
||||||
Some(prev_child),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
None => (byte_pos..byte_pos + 1, None),
|
|
||||||
}
|
}
|
||||||
};
|
prec
|
||||||
let query_result = query_indents(
|
});
|
||||||
query,
|
let query_range = deepest_preceding
|
||||||
syntax,
|
.map(|prec| prec.byte_range().end - 1..byte_pos + 1)
|
||||||
&mut cursor,
|
.unwrap_or(byte_pos..byte_pos + 1);
|
||||||
text,
|
|
||||||
query_range,
|
crate::syntax::PARSER.with(|ts_parser| {
|
||||||
new_line.then(|| (line, byte_pos)),
|
let mut ts_parser = ts_parser.borrow_mut();
|
||||||
);
|
let mut cursor = ts_parser.cursors.pop().unwrap_or_else(QueryCursor::new);
|
||||||
ts_parser.cursors.push(cursor);
|
let query_result = query_indents(
|
||||||
(query_result, prev_child)
|
query,
|
||||||
});
|
syntax,
|
||||||
|
&mut cursor,
|
||||||
|
text,
|
||||||
|
query_range,
|
||||||
|
new_line.then(|| (line, byte_pos)),
|
||||||
|
);
|
||||||
|
ts_parser.cursors.push(cursor);
|
||||||
|
(query_result, deepest_preceding)
|
||||||
|
})
|
||||||
|
};
|
||||||
let indent_captures = query_result.indent_captures;
|
let indent_captures = query_result.indent_captures;
|
||||||
let extend_captures = query_result.extend_captures;
|
let extend_captures = query_result.extend_captures;
|
||||||
|
|
||||||
// Check for extend captures (starting with the deepest
|
// Check for extend captures, potentially changing the node that the indent calculation starts with
|
||||||
// candidate node and then going up the syntax tree).
|
extend_nodes(
|
||||||
if let Some(mut prev_child) = prev_child {
|
&mut node,
|
||||||
let mut stop_extend = false;
|
deepest_preceding,
|
||||||
while prev_child != node {
|
&extend_captures,
|
||||||
let mut extend_node = false;
|
text,
|
||||||
if let Some(captures) = extend_captures.get(&prev_child.id()) {
|
line,
|
||||||
for capture in captures {
|
tab_width,
|
||||||
match capture {
|
);
|
||||||
ExtendCapture::StopExtend => {
|
|
||||||
stop_extend = true;
|
|
||||||
}
|
|
||||||
ExtendCapture::ExtendIndented => {
|
|
||||||
// We extend the node if
|
|
||||||
// - the cursor is on the same line as the end of the node OR
|
|
||||||
// - the line that the cursor is on is more indented than the
|
|
||||||
// first line of the node
|
|
||||||
if prev_child.end_position().row == line {
|
|
||||||
extend_node = true;
|
|
||||||
} else {
|
|
||||||
let cursor_indent =
|
|
||||||
indent_level_for_line(text.line(line), tab_width);
|
|
||||||
let node_indent = indent_level_for_line(
|
|
||||||
text.line(prev_child.start_position().row),
|
|
||||||
tab_width,
|
|
||||||
);
|
|
||||||
if cursor_indent > node_indent {
|
|
||||||
extend_node = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If we encountered some `StopExtend` capture before, we don't
|
|
||||||
// extend the node even if we otherwise would
|
|
||||||
match (extend_node, stop_extend) {
|
|
||||||
(true, true) => {
|
|
||||||
stop_extend = false;
|
|
||||||
}
|
|
||||||
(true, false) => {
|
|
||||||
node = prev_child;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
// This parent always exists since node is an ancestor of prev_child
|
|
||||||
prev_child = prev_child.parent().unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut first_in_line = get_first_in_line(node, new_line.then(|| byte_pos));
|
let mut first_in_line = get_first_in_line(node, new_line.then(|| byte_pos));
|
||||||
|
|
||||||
let mut result = Indentation::default();
|
let mut result = Indentation::default();
|
||||||
|
|
Loading…
Add table
Reference in a new issue