Add AutoIndent action and '=' vim operator (#21427)

Release Notes:

- vim: Added the `=` operator, for auto-indent

Co-authored-by: Conrad <conrad@zed.dev>
This commit is contained in:
Max Brunsfeld 2024-12-02 15:00:04 -08:00 committed by GitHub
parent f3140f54d8
commit 7c994cd4a5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 481 additions and 186 deletions

View file

@ -467,6 +467,7 @@ struct AutoindentRequest {
before_edit: BufferSnapshot,
entries: Vec<AutoindentRequestEntry>,
is_block_mode: bool,
ignore_empty_lines: bool,
}
#[derive(Debug, Clone)]
@ -1381,7 +1382,7 @@ impl Buffer {
let autoindent_requests = self.autoindent_requests.clone();
Some(async move {
let mut indent_sizes = BTreeMap::new();
let mut indent_sizes = BTreeMap::<u32, (IndentSize, bool)>::new();
for request in autoindent_requests {
// Resolve each edited range to its row in the current buffer and in the
// buffer before this batch of edits.
@ -1475,10 +1476,12 @@ impl Buffer {
let suggested_indent = indent_sizes
.get(&suggestion.basis_row)
.copied()
.map(|e| e.0)
.unwrap_or_else(|| {
snapshot.indent_size_for_line(suggestion.basis_row)
})
.with_delta(suggestion.delta, language_indent_size);
if old_suggestions.get(&new_row).map_or(
true,
|(old_indentation, was_within_error)| {
@ -1486,7 +1489,10 @@ impl Buffer {
&& (!suggestion.within_error || *was_within_error)
},
) {
indent_sizes.insert(new_row, suggested_indent);
indent_sizes.insert(
new_row,
(suggested_indent, request.ignore_empty_lines),
);
}
}
}
@ -1494,10 +1500,12 @@ impl Buffer {
if let (true, Some(original_indent_column)) =
(request.is_block_mode, original_indent_column)
{
let new_indent = indent_sizes
.get(&row_range.start)
.copied()
.unwrap_or_else(|| snapshot.indent_size_for_line(row_range.start));
let new_indent =
if let Some((indent, _)) = indent_sizes.get(&row_range.start) {
*indent
} else {
snapshot.indent_size_for_line(row_range.start)
};
let delta = new_indent.len as i64 - original_indent_column as i64;
if delta != 0 {
for row in row_range.skip(1) {
@ -1512,7 +1520,7 @@ impl Buffer {
Ordering::Equal => {}
}
}
size
(size, request.ignore_empty_lines)
});
}
}
@ -1523,6 +1531,15 @@ impl Buffer {
}
indent_sizes
.into_iter()
.filter_map(|(row, (indent, ignore_empty_lines))| {
if ignore_empty_lines && snapshot.line_len(row) == 0 {
None
} else {
Some((row, indent))
}
})
.collect()
})
}
@ -2067,6 +2084,7 @@ impl Buffer {
before_edit,
entries,
is_block_mode: matches!(mode, AutoindentMode::Block { .. }),
ignore_empty_lines: false,
}));
}
@ -2094,6 +2112,30 @@ impl Buffer {
cx.notify();
}
pub fn autoindent_ranges<I, T>(&mut self, ranges: I, cx: &mut ModelContext<Self>)
where
I: IntoIterator<Item = Range<T>>,
T: ToOffset + Copy,
{
let before_edit = self.snapshot();
let entries = ranges
.into_iter()
.map(|range| AutoindentRequestEntry {
range: before_edit.anchor_before(range.start)..before_edit.anchor_after(range.end),
first_line_is_new: true,
indent_size: before_edit.language_indent_size_at(range.start, cx),
original_indent_column: None,
})
.collect();
self.autoindent_requests.push(Arc::new(AutoindentRequest {
before_edit,
entries,
is_block_mode: false,
ignore_empty_lines: true,
}));
self.request_autoindent(cx);
}
// Inserts newlines at the given position to create an empty line, returning the start of the new line.
// You can also request the insertion of empty lines above and below the line starting at the returned point.
pub fn insert_empty_line(