WIP - new approach to autoindent

- Indent one row at a time.
- Consider only the innermost match.
This commit is contained in:
Max Brunsfeld 2021-05-27 15:05:19 -07:00
parent fc8758c619
commit 79878f20cc
4 changed files with 80 additions and 87 deletions

View file

@ -1,4 +1,12 @@
name = "Rust" name = "Rust"
path_suffixes = ["rs"] path_suffixes = ["rs"]
indent = 4 indent = 4
indent_nodes = ["declaration_list", "block"]
idents = [
{ inside = "let_declaration" },
{ inside = "field_declaration" },
{ start = "where_clause", end = ["block", "field_declaration_list"] },
{ after = "{", before = "}" },
{ start = "(", end = ")" },
{ start = "[", end = "]" },
]

View file

@ -1,7 +1,8 @@
(where_clause) @indent (field_expression) @inside
(let_declaration) @inside
(field_expression) @indent ((_ . "where" @after) _ @until)
(_ "(" ")" @outdent) @indent (_ "{" @after "}" @until)
(_ "[" "]" @outdent) @indent (_ "[" @after "]" @until)
(_ "{" "}" @outdent) @indent (_ "(" @after ")" @until)

View file

@ -654,6 +654,7 @@ impl Buffer {
} }
fn parse_text(text: &Rope, old_tree: Option<Tree>, language: &Language) -> Tree { fn parse_text(text: &Rope, old_tree: Option<Tree>, language: &Language) -> Tree {
let t0 = std::time::Instant::now();
PARSER.with(|parser| { PARSER.with(|parser| {
let mut parser = parser.borrow_mut(); let mut parser = parser.borrow_mut();
parser parser
@ -669,6 +670,7 @@ impl Buffer {
old_tree.as_ref(), old_tree.as_ref(),
) )
.unwrap(); .unwrap();
eprintln!("parsed in {:?}", t0.elapsed());
tree tree
}) })
} }
@ -689,9 +691,9 @@ impl Buffer {
(indent, is_whitespace) (indent, is_whitespace)
} }
pub fn autoindent_for_rows(&self, rows: Range<u32>) -> Vec<usize> { pub fn autoindent_for_row(&self, row: u32) -> usize {
// Find the indentation level of the previous non-whitespace row. // Find the indentation level of the previous non-whitespace row.
let mut prev_row = rows.start; let mut prev_row = row;
let prev_indent = loop { let prev_indent = loop {
if prev_row == 0 { if prev_row == 0 {
break 0; break 0;
@ -705,87 +707,73 @@ impl Buffer {
let (language, syntax_tree) = match self.language.as_ref().zip(self.syntax_tree()) { let (language, syntax_tree) = match self.language.as_ref().zip(self.syntax_tree()) {
Some(e) => e, Some(e) => e,
None => return vec![prev_indent; rows.len()], None => return prev_indent,
}; };
// Find the capture indices in the language's indent query that represent increased // Find the capture indices in the language's indent query.
// and decreased indentation. let mut indent_inside_capture_ix = u32::MAX;
let mut indent_capture_ix = u32::MAX; let mut indent_after_capture_ix = u32::MAX;
let mut outdent_capture_ix = u32::MAX; let mut indent_until_capture_ix = u32::MAX;
for (ix, name) in language.indent_query.capture_names().iter().enumerate() { for (ix, name) in language.indent_query.capture_names().iter().enumerate() {
match name.as_ref() { *match name.as_ref() {
"indent" => indent_capture_ix = ix as u32, "inside" => &mut indent_inside_capture_ix,
"outdent" => outdent_capture_ix = ix as u32, "after" => &mut indent_after_capture_ix,
"until" => &mut indent_until_capture_ix,
_ => continue, _ => continue,
} } = ix as u32;
} }
let start_row = rows.start as usize; eprintln!("autoindent for row: {}", row);
let mut indents = vec![prev_indent; rows.len()];
// Find all of the indent and outdent nodes in the given row range. // Find all of the indentation nodes intersecting the previous and current row.
let mut does_start_indent = false;
let mut start_row_of_most_recent_ending_indent = None;
let mut cursor = acquire_query_cursor(); let mut cursor = acquire_query_cursor();
cursor.set_point_range( cursor.set_point_range(
Point::new(prev_row, 0).into(), Point::new(prev_row, 0).into(),
Point::new(rows.end + 1, 0).into(), Point::new(row + 1, 0).into(),
); );
for mat in cursor.matches( for mat in cursor.matches(
&language.indent_query, &language.indent_query,
syntax_tree.root_node(), syntax_tree.root_node(),
TextProvider(&self.visible_text), TextProvider(&self.visible_text),
) { ) {
let mut row_range = 0..self.row_count();
eprintln!(" match: {:?}", mat);
for capture in mat.captures { for capture in mat.captures {
if capture.index == indent_capture_ix { let node_start_row = capture.node.start_position().row as u32;
let node_start_row = capture.node.start_position().row; let node_end_row = capture.node.end_position().row as u32;
let node_end_row = capture.node.end_position().row; if capture.index == indent_inside_capture_ix {
let start_ix = (node_start_row + 1).saturating_sub(start_row); row_range.start = row_range.start.max(node_start_row + 1);
let end_ix = (node_end_row + 1).saturating_sub(start_row); row_range.end = row_range.end.min(node_end_row + 1);
for ix in start_ix..cmp::min(end_ix, indents.len()) { } else if capture.index == indent_after_capture_ix {
indents[ix] += language.config.indent; row_range.start = row_range.start.max(node_end_row + 1);
} } else if capture.index == indent_until_capture_ix {
row_range.end = row_range.end.min(node_start_row);
} }
} }
for capture in mat.captures {
if capture.index == outdent_capture_ix { eprintln!(" row_range: {:?}", row_range);
let node_start_row = capture.node.start_position().row;
let node_end_row = capture.node.end_position().row; if row_range.contains(&row) {
let start_ix = node_start_row.saturating_sub(start_row); does_start_indent = true;
let end_ix = (node_end_row + 1).saturating_sub(start_row); } else if !row_range.is_empty() && row_range.end == row {
for ix in start_ix..cmp::min(end_ix, indents.len()) { start_row_of_most_recent_ending_indent = Some(
indents[ix] = indents[ix].saturating_sub(language.config.indent); start_row_of_most_recent_ending_indent
} .unwrap_or(0)
} .max(row_range.start),
);
} }
} }
// Post-process indents to fix doubly-indented lines. if does_start_indent {
struct Indent { prev_indent + language.config.indent
initial: usize, } else if let Some(start_row) = start_row_of_most_recent_ending_indent {
adjusted: usize, self.indent_for_row(start_row).0
} else {
prev_indent
} }
let mut indent_stack = vec![Indent {
initial: prev_indent,
adjusted: prev_indent,
}];
for indent in indents.iter_mut() {
while *indent < indent_stack.last().unwrap().initial {
indent_stack.pop();
}
let cur_indent = indent_stack.last().unwrap();
if *indent > cur_indent.initial {
let adjusted_indent = cur_indent.adjusted + language.config.indent;
indent_stack.push(Indent {
initial: *indent,
adjusted: adjusted_indent,
});
*indent = adjusted_indent;
} else {
*indent = cur_indent.adjusted;
}
}
indents
} }
fn diff(&self, new_text: Arc<str>, ctx: &AppContext) -> Task<Diff> { fn diff(&self, new_text: Arc<str>, ctx: &AppContext) -> Task<Diff> {
@ -3771,9 +3759,11 @@ mod tests {
indent_query: tree_sitter::Query::new( indent_query: tree_sitter::Query::new(
grammar, grammar,
r#" r#"
(block "}" @outdent) @indent (field_expression) @inside
(_ ")" @outdent) @indent (let_declaration) @inside
(where_clause) @indent ((_ . "where" @after) _ @until)
(_ "{" @after "}" @until)
(_ "(" @after ")" @until)
"#, "#,
) )
.unwrap(), .unwrap(),
@ -3806,7 +3796,10 @@ mod tests {
B: E, B: E,
C: F C: F
{ {
a
.b
.c
.d
} }
" "
.unindent(), .unindent(),
@ -3819,26 +3812,14 @@ mod tests {
buffer.condition(&ctx, |buf, _| !buf.is_parsing()).await; buffer.condition(&ctx, |buf, _| !buf.is_parsing()).await;
buffer.read_with(&ctx, |buffer, _| { buffer.read_with(&ctx, |buffer, _| {
let row_range = 0..buffer.row_count(); for row in 0..buffer.row_count() {
let current_indents = row_range
.clone()
.map(|row| buffer.indent_for_row(row).0)
.collect::<Vec<_>>();
let autoindents = buffer.autoindent_for_rows(row_range);
assert_eq!(
autoindents.len(),
current_indents.len(),
"wrong number of autoindents returned for example {}",
example_ix
);
for (row, indent) in autoindents.into_iter().enumerate() {
assert_eq!( assert_eq!(
indent, buffer.autoindent_for_row(row),
current_indents[row], buffer.indent_for_row(row).0,
"wrong autoindent for example {}, row {}, line {:?}", "wrong autoindent for example {}, row {}, line {:?}",
example_ix, example_ix,
row, row,
buffer.text().split('\n').skip(row).next().unwrap(), buffer.text().split('\n').skip(row as usize).next().unwrap(),
); );
} }
}); });

View file

@ -641,7 +641,10 @@ impl BufferView {
pub fn print_autoindents(&mut self, _: &(), ctx: &mut ViewContext<Self>) { pub fn print_autoindents(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
let buf = self.buffer.read(ctx); let buf = self.buffer.read(ctx);
dbg!(buf.autoindent_for_rows(0..buf.row_count())); eprintln!("autoindents:");
for row in 0..buf.row_count() {
eprintln!(" {}: {}", row, buf.autoindent_for_row(row));
}
} }
pub fn insert(&mut self, text: &String, ctx: &mut ViewContext<Self>) { pub fn insert(&mut self, text: &String, ctx: &mut ViewContext<Self>) {