@@ -151,8 +151,6 @@ impl Drop for QueryCursorHandle {
QUERY_CURSORS.lock().push(cursor)
}
}
-const SPACES: &'static str = " ";
-
pub struct Buffer {
fragments: SumTree<Fragment>,
visible_text: Rope,
@@ -972,8 +970,8 @@ impl Buffer {
language: Arc<Language>,
cx: &mut ModelContext<Self>,
) {
- let mut autoindent_requests_by_row = BTreeMap::<u32, AutoindentRequest>::default();
let mut autoindent_requests = mem::take(&mut self.autoindent_requests);
+ let mut autoindent_requests_by_row = BTreeMap::<u32, AutoindentRequest>::default();
for request in autoindent_requests.drain(..) {
let row = request.position.to_point(&*self).row;
autoindent_requests_by_row
@@ -986,10 +984,9 @@ impl Buffer {
}
self.autoindent_requests = autoindent_requests;
+ let mut row_range = None;
let mut cursor = QueryCursorHandle::new();
-
self.start_transaction(None).unwrap();
- let mut row_range = None;
for row in autoindent_requests_by_row.keys().copied() {
match &mut row_range {
None => row_range = Some(row..(row + 1)),
@@ -1038,7 +1035,6 @@ impl Buffer {
cursor: &mut QueryCursor,
cx: &mut ModelContext<Self>,
) {
- let max_row = self.row_count() - 1;
let prev_non_blank_row = self.prev_non_blank_row(row_range.start);
// Get the "indentation ranges" that intersect this row range.
@@ -1048,107 +1044,77 @@ impl Buffer {
Point::new(prev_non_blank_row.unwrap_or(row_range.start), 0).into()
..Point::new(row_range.end, 0).into(),
);
- let mut indentation_ranges = Vec::<Range<u32>>::new();
+ let mut indentation_ranges = Vec::<(Range<Point>, &'static str)>::new();
for mat in cursor.matches(
&language.indents_query,
new_tree.root_node(),
TextProvider(&self.visible_text),
) {
- let mut start_row = None;
- let mut end_row = None;
+ let mut node_kind = "";
+ let mut start: Option<Point> = None;
+ let mut end: Option<Point> = None;
for capture in mat.captures {
if Some(capture.index) == indent_capture_ix {
- start_row.get_or_insert(capture.node.start_position().row as u32);
- end_row.get_or_insert(max_row.min(capture.node.end_position().row as u32 + 1));
+ node_kind = capture.node.kind();
+ start.get_or_insert(capture.node.start_position().into());
+ end.get_or_insert(capture.node.end_position().into());
} else if Some(capture.index) == end_capture_ix {
- end_row = Some(capture.node.start_position().row as u32);
+ end = Some(capture.node.start_position().into());
}
}
- if let Some((start_row, end_row)) = start_row.zip(end_row) {
- let range = start_row..end_row;
- match indentation_ranges.binary_search_by_key(&range.start, |r| r.start) {
- Err(ix) => indentation_ranges.insert(ix, range),
+
+ if let Some((start, end)) = start.zip(end) {
+ if start.row == end.row {
+ continue;
+ }
+
+ let range = start..end;
+ match indentation_ranges.binary_search_by_key(&range.start, |r| r.0.start) {
+ Err(ix) => indentation_ranges.insert(ix, (range, node_kind)),
Ok(ix) => {
let prev_range = &mut indentation_ranges[ix];
- prev_range.end = prev_range.end.max(range.end);
+ prev_range.0.end = prev_range.0.end.max(range.end);
}
}
}
}
- #[derive(Debug)]
- struct Adjustment {
- row: u32,
- indent: bool,
- outdent: bool,
- }
+ let mut prev_row = prev_non_blank_row.unwrap_or(0);
+ let mut prev_indent_column =
+ prev_non_blank_row.map_or(0, |prev_row| self.indent_column_for_line(prev_row, cx));
+ for row in row_range {
+ let request = autoindent_requests.get(&row).unwrap();
+ let row_start = Point::new(row, self.indent_column_for_line(row, cx));
- let mut adjustments = Vec::<Adjustment>::new();
- 'outer: for range in &indentation_ranges {
- let mut indent_row = range.start;
- loop {
- indent_row += 1;
- if indent_row > max_row {
- continue 'outer;
- }
- if row_range.contains(&indent_row) || !self.is_line_blank(indent_row) {
- break;
- }
- }
+ eprintln!("autoindent row: {:?}", row);
- let mut outdent_row = range.end;
- loop {
- outdent_row += 1;
- if outdent_row > max_row {
+ let mut increase_from_prev_row = false;
+ let mut dedent_to_row = u32::MAX;
+ for (range, node_kind) in &indentation_ranges {
+ if range.start.row == prev_row && prev_row < row && range.end > row_start {
+ eprintln!(" indent because of {} {:?}", node_kind, range);
+ increase_from_prev_row = true;
break;
}
- if row_range.contains(&outdent_row) || !self.is_line_blank(outdent_row) {
- break;
+
+ if range.start.row < prev_row
+ && (Point::new(prev_row, 0)..=row_start).contains(&range.end)
+ {
+ eprintln!(" outdent because of {} {:?}", node_kind, range);
+ dedent_to_row = dedent_to_row.min(range.start.row);
}
}
- match adjustments.binary_search_by_key(&indent_row, |a| a.row) {
- Ok(ix) => adjustments[ix].indent = true,
- Err(ix) => adjustments.insert(
- ix,
- Adjustment {
- row: indent_row,
- indent: true,
- outdent: false,
- },
- ),
+ let mut indent_column = prev_indent_column;
+ if increase_from_prev_row {
+ indent_column += request.indent_size as u32;
+ } else if dedent_to_row < row {
+ indent_column = self.indent_column_for_line(dedent_to_row, cx);
}
- match adjustments.binary_search_by_key(&outdent_row, |a| a.row) {
- Ok(ix) => adjustments[ix].outdent = true,
- Err(ix) => adjustments.insert(
- ix,
- Adjustment {
- row: outdent_row,
- indent: false,
- outdent: true,
- },
- ),
- }
- }
- let mut adjustments = adjustments.iter().peekable();
- for row in row_range {
- if let Some(request) = autoindent_requests.get(&row) {
- while let Some(adjustment) = adjustments.peek() {
- if adjustment.row < row {
- adjustments.next();
- } else {
- if adjustment.row == row {
- match (adjustment.indent, adjustment.outdent) {
- (true, false) => self.indent_line(row, request.indent_size, cx),
- (false, true) => self.outdent_line(row, request.indent_size, cx),
- _ => {}
- }
- }
- break;
- }
- }
- }
+ self.set_indent_column_for_line(row, indent_column, cx);
+ prev_indent_column = indent_column;
+ prev_row = row;
}
}
@@ -1162,39 +1128,46 @@ impl Buffer {
None
}
- fn next_non_blank_row(&self, mut row: u32) -> Option<u32> {
- let row_count = self.row_count();
- row += 1;
- while row < row_count {
- if !self.is_line_blank(row) {
- return Some(row);
+ fn indent_column_for_line(&mut self, row: u32, cx: &mut ModelContext<Self>) -> u32 {
+ let mut result = 0;
+ for c in self.chars_at(Point::new(row, 0)) {
+ if c == ' ' {
+ result += 1;
+ } else {
+ break;
}
- row += 1;
}
- None
- }
-
- fn indent_line(&mut self, row: u32, size: u8, cx: &mut ModelContext<Self>) {
- self.edit(
- [Point::new(row, 0)..Point::new(row, 0)],
- &SPACES[..(size as usize)],
- cx,
- )
+ result
}
- fn outdent_line(&mut self, row: u32, size: u8, cx: &mut ModelContext<Self>) {
- let mut end_column = 0;
- for c in self.chars_at(Point::new(row, 0)) {
- if c == ' ' {
- end_column += 1;
- if end_column == size as u32 {
- break;
- }
+ fn set_indent_column_for_line(&mut self, row: u32, column: u32, cx: &mut ModelContext<Self>) {
+ let current_column = self.indent_column_for_line(row, cx);
+ if column > current_column {
+ let offset = self.visible_text.to_offset(Point::new(row, 0));
+
+ // TODO: do this differently. By replacing the preceding newline,
+ // we force the new indentation to come before any left-biased anchors
+ // on the line.
+ let delta = (column - current_column) as usize;
+ if offset > 0 {
+ let mut prefix = String::with_capacity(1 + delta);
+ prefix.push('\n');
+ prefix.extend(std::iter::repeat(' ').take(delta));
+ self.edit([(offset - 1)..offset], prefix, cx);
} else {
- break;
+ self.edit(
+ [offset..offset],
+ std::iter::repeat(' ').take(delta).collect::<String>(),
+ cx,
+ );
}
+ } else if column < current_column {
+ self.edit(
+ [Point::new(row, 0)..Point::new(row, current_column - column)],
+ "",
+ cx,
+ );
}
- self.edit([Point::new(row, 0)..Point::new(row, end_column)], "", cx);
}
fn is_line_blank(&self, row: u32) -> bool {