Merge pull request #2035 from zed-industries/always-auto-indent-block-on-paste
Always auto-indent in block-wise mode when pasting
This commit is contained in:
commit
1a6a807db5
3 changed files with 108 additions and 21 deletions
|
@ -2020,7 +2020,9 @@ impl Editor {
|
||||||
old_selections
|
old_selections
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| (s.start..s.end, text.clone())),
|
.map(|s| (s.start..s.end, text.clone())),
|
||||||
Some(AutoindentMode::EachLine),
|
Some(AutoindentMode::Block {
|
||||||
|
original_indent_columns: Vec::new(),
|
||||||
|
}),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
anchors
|
anchors
|
||||||
|
|
|
@ -1349,13 +1349,6 @@ impl Buffer {
|
||||||
let edit_id = edit_operation.local_timestamp();
|
let edit_id = edit_operation.local_timestamp();
|
||||||
|
|
||||||
if let Some((before_edit, mode)) = autoindent_request {
|
if let Some((before_edit, mode)) = autoindent_request {
|
||||||
let (start_columns, is_block_mode) = match mode {
|
|
||||||
AutoindentMode::Block {
|
|
||||||
original_indent_columns: start_columns,
|
|
||||||
} => (start_columns, true),
|
|
||||||
AutoindentMode::EachLine => (Default::default(), false),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut delta = 0isize;
|
let mut delta = 0isize;
|
||||||
let entries = edits
|
let entries = edits
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -1369,7 +1362,7 @@ impl Buffer {
|
||||||
|
|
||||||
let mut range_of_insertion_to_indent = 0..new_text_len;
|
let mut range_of_insertion_to_indent = 0..new_text_len;
|
||||||
let mut first_line_is_new = false;
|
let mut first_line_is_new = false;
|
||||||
let mut start_column = None;
|
let mut original_indent_column = None;
|
||||||
|
|
||||||
// When inserting an entire line at the beginning of an existing line,
|
// When inserting an entire line at the beginning of an existing line,
|
||||||
// treat the insertion as new.
|
// treat the insertion as new.
|
||||||
|
@ -1381,14 +1374,23 @@ impl Buffer {
|
||||||
|
|
||||||
// When inserting text starting with a newline, avoid auto-indenting the
|
// When inserting text starting with a newline, avoid auto-indenting the
|
||||||
// previous line.
|
// previous line.
|
||||||
if new_text[range_of_insertion_to_indent.clone()].starts_with('\n') {
|
if new_text.starts_with('\n') {
|
||||||
range_of_insertion_to_indent.start += 1;
|
range_of_insertion_to_indent.start += 1;
|
||||||
first_line_is_new = true;
|
first_line_is_new = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid auto-indenting after the insertion.
|
// Avoid auto-indenting after the insertion.
|
||||||
if is_block_mode {
|
if let AutoindentMode::Block {
|
||||||
start_column = start_columns.get(ix).copied();
|
original_indent_columns,
|
||||||
|
} = &mode
|
||||||
|
{
|
||||||
|
original_indent_column =
|
||||||
|
Some(original_indent_columns.get(ix).copied().unwrap_or_else(|| {
|
||||||
|
indent_size_for_text(
|
||||||
|
new_text[range_of_insertion_to_indent.clone()].chars(),
|
||||||
|
)
|
||||||
|
.len
|
||||||
|
}));
|
||||||
if new_text[range_of_insertion_to_indent.clone()].ends_with('\n') {
|
if new_text[range_of_insertion_to_indent.clone()].ends_with('\n') {
|
||||||
range_of_insertion_to_indent.end -= 1;
|
range_of_insertion_to_indent.end -= 1;
|
||||||
}
|
}
|
||||||
|
@ -1396,7 +1398,7 @@ impl Buffer {
|
||||||
|
|
||||||
AutoindentRequestEntry {
|
AutoindentRequestEntry {
|
||||||
first_line_is_new,
|
first_line_is_new,
|
||||||
original_indent_column: start_column,
|
original_indent_column,
|
||||||
indent_size: before_edit.language_indent_size_at(range.start, cx),
|
indent_size: before_edit.language_indent_size_at(range.start, cx),
|
||||||
range: self.anchor_before(new_start + range_of_insertion_to_indent.start)
|
range: self.anchor_before(new_start + range_of_insertion_to_indent.start)
|
||||||
..self.anchor_after(new_start + range_of_insertion_to_indent.end),
|
..self.anchor_after(new_start + range_of_insertion_to_indent.end),
|
||||||
|
@ -1407,7 +1409,7 @@ impl Buffer {
|
||||||
self.autoindent_requests.push(Arc::new(AutoindentRequest {
|
self.autoindent_requests.push(Arc::new(AutoindentRequest {
|
||||||
before_edit,
|
before_edit,
|
||||||
entries,
|
entries,
|
||||||
is_block_mode,
|
is_block_mode: matches!(mode, AutoindentMode::Block { .. }),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2414,7 +2416,7 @@ impl BufferSnapshot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn indent_size_for_line(text: &text::BufferSnapshot, row: u32) -> IndentSize {
|
fn indent_size_for_line(text: &text::BufferSnapshot, row: u32) -> IndentSize {
|
||||||
indent_size_for_text(text.chars_at(Point::new(row, 0)))
|
indent_size_for_text(text.chars_at(Point::new(row, 0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -995,6 +995,11 @@ fn test_autoindent_block_mode(cx: &mut MutableAppContext) {
|
||||||
.unindent();
|
.unindent();
|
||||||
let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
|
let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
|
||||||
|
|
||||||
|
// When this text was copied, both of the quotation marks were at the same
|
||||||
|
// indent level, but the indentation of the first line was not included in
|
||||||
|
// the copied text. This information is retained in the
|
||||||
|
// 'original_indent_columns' vector.
|
||||||
|
let original_indent_columns = vec![4];
|
||||||
let inserted_text = r#"
|
let inserted_text = r#"
|
||||||
"
|
"
|
||||||
c
|
c
|
||||||
|
@ -1009,7 +1014,7 @@ fn test_autoindent_block_mode(cx: &mut MutableAppContext) {
|
||||||
buffer.edit(
|
buffer.edit(
|
||||||
[(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
|
[(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
|
||||||
Some(AutoindentMode::Block {
|
Some(AutoindentMode::Block {
|
||||||
original_indent_columns: vec![0],
|
original_indent_columns: original_indent_columns.clone(),
|
||||||
}),
|
}),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
@ -1037,7 +1042,7 @@ fn test_autoindent_block_mode(cx: &mut MutableAppContext) {
|
||||||
buffer.edit(
|
buffer.edit(
|
||||||
[(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
|
[(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
|
||||||
Some(AutoindentMode::Block {
|
Some(AutoindentMode::Block {
|
||||||
original_indent_columns: vec![0],
|
original_indent_columns: original_indent_columns.clone(),
|
||||||
}),
|
}),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
@ -1060,6 +1065,84 @@ fn test_autoindent_block_mode(cx: &mut MutableAppContext) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut MutableAppContext) {
|
||||||
|
cx.set_global(Settings::test(cx));
|
||||||
|
cx.add_model(|cx| {
|
||||||
|
let text = r#"
|
||||||
|
fn a() {
|
||||||
|
if b() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
.unindent();
|
||||||
|
let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
|
||||||
|
|
||||||
|
// The original indent columns are not known, so this text is
|
||||||
|
// auto-indented in a block as if the first line was copied in
|
||||||
|
// its entirety.
|
||||||
|
let original_indent_columns = Vec::new();
|
||||||
|
let inserted_text = " c\n .d()\n .e();";
|
||||||
|
|
||||||
|
// Insert the block at column zero. The entire block is indented
|
||||||
|
// so that the first line matches the previous line's indentation.
|
||||||
|
buffer.edit(
|
||||||
|
[(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
|
||||||
|
Some(AutoindentMode::Block {
|
||||||
|
original_indent_columns: original_indent_columns.clone(),
|
||||||
|
}),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
buffer.text(),
|
||||||
|
r#"
|
||||||
|
fn a() {
|
||||||
|
if b() {
|
||||||
|
c
|
||||||
|
.d()
|
||||||
|
.e();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
.unindent()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Grouping is disabled in tests, so we need 2 undos
|
||||||
|
buffer.undo(cx); // Undo the auto-indent
|
||||||
|
buffer.undo(cx); // Undo the original edit
|
||||||
|
|
||||||
|
// Insert the block at a deeper indent level. The entire block is outdented.
|
||||||
|
buffer.edit(
|
||||||
|
[(Point::new(2, 0)..Point::new(2, 0), " ".repeat(12))],
|
||||||
|
None,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
buffer.edit(
|
||||||
|
[(Point::new(2, 12)..Point::new(2, 12), inserted_text)],
|
||||||
|
Some(AutoindentMode::Block {
|
||||||
|
original_indent_columns: Vec::new(),
|
||||||
|
}),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
buffer.text(),
|
||||||
|
r#"
|
||||||
|
fn a() {
|
||||||
|
if b() {
|
||||||
|
c
|
||||||
|
.d()
|
||||||
|
.e();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
.unindent()
|
||||||
|
);
|
||||||
|
|
||||||
|
buffer
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
fn test_autoindent_language_without_indents_query(cx: &mut MutableAppContext) {
|
fn test_autoindent_language_without_indents_query(cx: &mut MutableAppContext) {
|
||||||
cx.set_global(Settings::test(cx));
|
cx.set_global(Settings::test(cx));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue