From 79878f20ccfac68bcd264af515ee10cc46e8f0db Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 27 May 2021 15:05:19 -0700 Subject: [PATCH] WIP - new approach to autoindent - Indent one row at a time. - Consider only the innermost match. --- zed/languages/rust/config.toml | 10 ++- zed/languages/rust/indents.scm | 11 +-- zed/src/editor/buffer/mod.rs | 139 ++++++++++++++------------------- zed/src/editor/buffer_view.rs | 5 +- 4 files changed, 79 insertions(+), 86 deletions(-) diff --git a/zed/languages/rust/config.toml b/zed/languages/rust/config.toml index 66e21d4dfa978510073acdbbdf08408ce619d73b..67dda1b7d3c826b5aed62dbe329c34b2d33a2fb4 100644 --- a/zed/languages/rust/config.toml +++ b/zed/languages/rust/config.toml @@ -1,4 +1,12 @@ name = "Rust" path_suffixes = ["rs"] 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 = "]" }, +] diff --git a/zed/languages/rust/indents.scm b/zed/languages/rust/indents.scm index 709897be4d71709dd40685fa38ab5f675e100d5e..f9791c007c23a628164a23f0fd4a8ac4397d2d3c 100644 --- a/zed/languages/rust/indents.scm +++ b/zed/languages/rust/indents.scm @@ -1,7 +1,8 @@ -(where_clause) @indent +(field_expression) @inside +(let_declaration) @inside -(field_expression) @indent +((_ . "where" @after) _ @until) -(_ "(" ")" @outdent) @indent -(_ "[" "]" @outdent) @indent -(_ "{" "}" @outdent) @indent +(_ "{" @after "}" @until) +(_ "[" @after "]" @until) +(_ "(" @after ")" @until) \ No newline at end of file diff --git a/zed/src/editor/buffer/mod.rs b/zed/src/editor/buffer/mod.rs index 826e9b07eb36601f23313948b58c682c433c927a..ec47c6abe14de770eb207d84005545892aa7c8c1 100644 --- a/zed/src/editor/buffer/mod.rs +++ b/zed/src/editor/buffer/mod.rs @@ -654,6 +654,7 @@ impl Buffer { } fn parse_text(text: &Rope, old_tree: Option, language: &Language) -> Tree { + let t0 = std::time::Instant::now(); PARSER.with(|parser| { let mut parser = parser.borrow_mut(); parser @@ -669,6 +670,7 @@ impl Buffer { old_tree.as_ref(), ) .unwrap(); + eprintln!("parsed in {:?}", t0.elapsed()); tree }) } @@ -689,9 +691,9 @@ impl Buffer { (indent, is_whitespace) } - pub fn autoindent_for_rows(&self, rows: Range) -> Vec { + pub fn autoindent_for_row(&self, row: u32) -> usize { // 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 { if prev_row == 0 { break 0; @@ -705,87 +707,73 @@ impl Buffer { let (language, syntax_tree) = match self.language.as_ref().zip(self.syntax_tree()) { 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 - // and decreased indentation. - let mut indent_capture_ix = u32::MAX; - let mut outdent_capture_ix = u32::MAX; + // Find the capture indices in the language's indent query. + let mut indent_inside_capture_ix = u32::MAX; + let mut indent_after_capture_ix = u32::MAX; + let mut indent_until_capture_ix = u32::MAX; for (ix, name) in language.indent_query.capture_names().iter().enumerate() { - match name.as_ref() { - "indent" => indent_capture_ix = ix as u32, - "outdent" => outdent_capture_ix = ix as u32, + *match name.as_ref() { + "inside" => &mut indent_inside_capture_ix, + "after" => &mut indent_after_capture_ix, + "until" => &mut indent_until_capture_ix, _ => continue, - } + } = ix as u32; } - let start_row = rows.start as usize; - let mut indents = vec![prev_indent; rows.len()]; + eprintln!("autoindent for row: {}", row); - // 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(); cursor.set_point_range( Point::new(prev_row, 0).into(), - Point::new(rows.end + 1, 0).into(), + Point::new(row + 1, 0).into(), ); for mat in cursor.matches( &language.indent_query, syntax_tree.root_node(), TextProvider(&self.visible_text), ) { + let mut row_range = 0..self.row_count(); + eprintln!(" match: {:?}", mat); + for capture in mat.captures { - if capture.index == indent_capture_ix { - let node_start_row = capture.node.start_position().row; - let node_end_row = capture.node.end_position().row; - let start_ix = (node_start_row + 1).saturating_sub(start_row); - let end_ix = (node_end_row + 1).saturating_sub(start_row); - for ix in start_ix..cmp::min(end_ix, indents.len()) { - indents[ix] += language.config.indent; - } - } - } - for capture in mat.captures { - if capture.index == outdent_capture_ix { - let node_start_row = capture.node.start_position().row; - let node_end_row = capture.node.end_position().row; - let start_ix = node_start_row.saturating_sub(start_row); - let end_ix = (node_end_row + 1).saturating_sub(start_row); - for ix in start_ix..cmp::min(end_ix, indents.len()) { - indents[ix] = indents[ix].saturating_sub(language.config.indent); - } + let node_start_row = capture.node.start_position().row as u32; + let node_end_row = capture.node.end_position().row as u32; + if capture.index == indent_inside_capture_ix { + row_range.start = row_range.start.max(node_start_row + 1); + row_range.end = row_range.end.min(node_end_row + 1); + } else if capture.index == indent_after_capture_ix { + 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); } } - } - // Post-process indents to fix doubly-indented lines. - struct Indent { - initial: usize, - adjusted: usize, - } - 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(); - } + eprintln!(" row_range: {:?}", row_range); - 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; + if row_range.contains(&row) { + does_start_indent = true; + } else if !row_range.is_empty() && row_range.end == row { + start_row_of_most_recent_ending_indent = Some( + start_row_of_most_recent_ending_indent + .unwrap_or(0) + .max(row_range.start), + ); } } - indents + if does_start_indent { + prev_indent + language.config.indent + } else if let Some(start_row) = start_row_of_most_recent_ending_indent { + self.indent_for_row(start_row).0 + } else { + prev_indent + } } fn diff(&self, new_text: Arc, ctx: &AppContext) -> Task { @@ -3771,9 +3759,11 @@ mod tests { indent_query: tree_sitter::Query::new( grammar, r#" - (block "}" @outdent) @indent - (_ ")" @outdent) @indent - (where_clause) @indent + (field_expression) @inside + (let_declaration) @inside + ((_ . "where" @after) _ @until) + (_ "{" @after "}" @until) + (_ "(" @after ")" @until) "#, ) .unwrap(), @@ -3806,7 +3796,10 @@ mod tests { B: E, C: F { - + a + .b + .c + .d } " .unindent(), @@ -3819,26 +3812,14 @@ mod tests { buffer.condition(&ctx, |buf, _| !buf.is_parsing()).await; buffer.read_with(&ctx, |buffer, _| { - let row_range = 0..buffer.row_count(); - let current_indents = row_range - .clone() - .map(|row| buffer.indent_for_row(row).0) - .collect::>(); - 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() { + for row in 0..buffer.row_count() { assert_eq!( - indent, - current_indents[row], + buffer.autoindent_for_row(row), + buffer.indent_for_row(row).0, "wrong autoindent for example {}, row {}, line {:?}", example_ix, row, - buffer.text().split('\n').skip(row).next().unwrap(), + buffer.text().split('\n').skip(row as usize).next().unwrap(), ); } }); diff --git a/zed/src/editor/buffer_view.rs b/zed/src/editor/buffer_view.rs index b741f271cc512b5090fc9e5c2d2bbb98eecd3d4a..f8425b03697edeb922d2d680a7de18ec71b7bd8e 100644 --- a/zed/src/editor/buffer_view.rs +++ b/zed/src/editor/buffer_view.rs @@ -641,7 +641,10 @@ impl BufferView { pub fn print_autoindents(&mut self, _: &(), ctx: &mut ViewContext) { 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) {