Introduce AutoindentMode parameter to Buffer::edit

This controls whether or not we preserve the relative indentation
of inserted text blocks.

Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
This commit is contained in:
Max Brunsfeld
2022-07-28 14:03:31 -07:00
co-authored by Mikayla Maki
parent cdf6ae25bb
commit fa5af4383d
18 changed files with 308 additions and 236 deletions
+2 -1
View File
@@ -897,7 +897,7 @@ pub mod tests {
let ix = snapshot.buffer_snapshot.text().find("seven").unwrap();
buffer.update(cx, |buffer, cx| {
buffer.edit([(ix..ix, "and ")], cx);
buffer.edit([(ix..ix, "and ")], None, cx);
});
let snapshot = map.update(cx, |map, cx| map.snapshot(cx));
@@ -936,6 +936,7 @@ pub mod tests {
(Point::new(1, 1)..Point::new(1, 1), "\t"),
(Point::new(2, 1)..Point::new(2, 1), "\t"),
],
None,
cx,
)
});
+1 -1
View File
@@ -1164,7 +1164,7 @@ mod tests {
// Insert a line break, separating two block decorations into separate lines.
let buffer_snapshot = buffer.update(cx, |buffer, cx| {
buffer.edit([(Point::new(1, 1)..Point::new(1, 1), "!!!\n")], cx);
buffer.edit([(Point::new(1, 1)..Point::new(1, 1), "!!!\n")], None, cx);
buffer.snapshot(cx)
});
+4 -3
View File
@@ -1240,6 +1240,7 @@ mod tests {
(Point::new(0, 0)..Point::new(0, 1), "123"),
(Point::new(2, 3)..Point::new(2, 3), "123"),
],
None,
cx,
);
buffer.snapshot(cx)
@@ -1262,7 +1263,7 @@ mod tests {
);
let buffer_snapshot = buffer.update(cx, |buffer, cx| {
buffer.edit([(Point::new(2, 6)..Point::new(4, 3), "456")], cx);
buffer.edit([(Point::new(2, 6)..Point::new(4, 3), "456")], None, cx);
buffer.snapshot(cx)
});
let (snapshot4, _) = map.read(buffer_snapshot.clone(), subscription.consume().into_inner());
@@ -1318,7 +1319,7 @@ mod tests {
// Edit within one of the folds.
let buffer_snapshot = buffer.update(cx, |buffer, cx| {
buffer.edit([(0..1, "12345")], cx);
buffer.edit([(0..1, "12345")], None, cx);
buffer.snapshot(cx)
});
let (snapshot, _) =
@@ -1360,7 +1361,7 @@ mod tests {
assert_eq!(snapshot.text(), "aa…cccc\nd…eeeee");
let buffer_snapshot = buffer.update(cx, |buffer, cx| {
buffer.edit([(Point::new(2, 2)..Point::new(3, 1), "")], cx);
buffer.edit([(Point::new(2, 2)..Point::new(3, 1), "")], None, cx);
buffer.snapshot(cx)
});
let (snapshot, _) = map.read(buffer_snapshot.clone(), subscription.consume().into_inner());
+44 -26
View File
@@ -38,9 +38,9 @@ use hover_popover::{hide_hover, HoverState};
pub use items::MAX_TAB_TITLE_LEN;
pub use language::{char_kind, CharKind};
use language::{
BracketPair, Buffer, CodeAction, CodeLabel, Completion, Diagnostic, DiagnosticSeverity,
IndentKind, IndentSize, Language, OffsetRangeExt, OffsetUtf16, Point, Selection, SelectionGoal,
TransactionId,
AutoindentMode, BracketPair, Buffer, CodeAction, CodeLabel, Completion, Diagnostic,
DiagnosticSeverity, IndentKind, IndentSize, Language, OffsetRangeExt, OffsetUtf16, Point,
Selection, SelectionGoal, TransactionId,
};
use link_go_to_definition::LinkGoToDefinitionState;
pub use multi_buffer::{
@@ -1464,7 +1464,8 @@ impl Editor {
S: ToOffset,
T: Into<Arc<str>>,
{
self.buffer.update(cx, |buffer, cx| buffer.edit(edits, cx));
self.buffer
.update(cx, |buffer, cx| buffer.edit(edits, None, cx));
}
pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
@@ -1473,8 +1474,9 @@ impl Editor {
S: ToOffset,
T: Into<Arc<str>>,
{
self.buffer
.update(cx, |buffer, cx| buffer.edit_with_autoindent(edits, cx));
self.buffer.update(cx, |buffer, cx| {
buffer.edit(edits, Some(AutoindentMode::Independent), cx)
});
}
fn select(&mut self, Select(phase): &Select, cx: &mut ViewContext<Self>) {
@@ -1887,9 +1889,7 @@ impl Editor {
.unzip()
};
this.buffer.update(cx, |buffer, cx| {
buffer.edit_with_autoindent(edits, cx);
});
this.edit_with_autoindent(edits, cx);
let buffer = this.buffer.read(cx).snapshot(cx);
let new_selections = selection_fixup_info
.into_iter()
@@ -1922,10 +1922,11 @@ impl Editor {
})
.collect::<Vec<_>>()
};
buffer.edit_with_autoindent(
buffer.edit(
old_selections
.iter()
.map(|s| (s.start..s.end, text.clone())),
Some(AutoindentMode::Block),
cx,
);
anchors
@@ -1986,6 +1987,7 @@ impl Editor {
(s.end.clone()..s.end.clone(), pair_end.clone()),
]
}),
None,
cx,
);
});
@@ -2061,6 +2063,7 @@ impl Editor {
selection_ranges
.iter()
.map(|range| (range.clone(), pair_end.clone())),
None,
cx,
);
snapshot = buffer.snapshot(cx);
@@ -2363,8 +2366,11 @@ impl Editor {
this.insert_snippet(&ranges, snippet, cx).log_err();
} else {
this.buffer.update(cx, |buffer, cx| {
buffer
.edit_with_autoindent(ranges.iter().map(|range| (range.clone(), text)), cx);
buffer.edit(
ranges.iter().map(|range| (range.clone(), text)),
Some(AutoindentMode::Block),
cx,
);
});
}
});
@@ -2725,11 +2731,12 @@ impl Editor {
) -> Result<()> {
let tabstops = self.buffer.update(cx, |buffer, cx| {
let snippet_text: Arc<str> = snippet.text.clone().into();
buffer.edit_with_autoindent(
buffer.edit(
insertion_ranges
.iter()
.cloned()
.map(|range| (range, snippet_text.clone())),
Some(AutoindentMode::Independent),
cx,
);
@@ -2933,7 +2940,11 @@ impl Editor {
let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
IndentSize::spaces(chars_to_next_tab_stop)
};
buffer.edit([(cursor..cursor, tab_size.chars().collect::<String>())], cx);
buffer.edit(
[(cursor..cursor, tab_size.chars().collect::<String>())],
None,
cx,
);
cursor.column += tab_size.len;
selection.start = cursor;
selection.end = cursor;
@@ -3006,6 +3017,7 @@ impl Editor {
row_start..row_start,
indent_delta.chars().collect::<String>(),
)],
None,
cx,
);
@@ -3080,6 +3092,7 @@ impl Editor {
deletion_ranges
.into_iter()
.map(|range| (range, empty_str.clone())),
None,
cx,
);
});
@@ -3145,6 +3158,7 @@ impl Editor {
edit_ranges
.into_iter()
.map(|range| (range, empty_str.clone())),
None,
cx,
);
buffer.snapshot(cx)
@@ -3202,7 +3216,7 @@ impl Editor {
self.transact(cx, |this, cx| {
this.buffer.update(cx, |buffer, cx| {
buffer.edit(edits, cx);
buffer.edit(edits, None, cx);
});
this.request_autoscroll(Autoscroll::Fit, cx);
@@ -3311,7 +3325,7 @@ impl Editor {
this.unfold_ranges(unfold_ranges, true, cx);
this.buffer.update(cx, |buffer, cx| {
for (range, text) in edits {
buffer.edit([(range, text)], cx);
buffer.edit([(range, text)], None, cx);
}
});
this.fold_ranges(refold_ranges, cx);
@@ -3416,7 +3430,7 @@ impl Editor {
this.unfold_ranges(unfold_ranges, true, cx);
this.buffer.update(cx, |buffer, cx| {
for (range, text) in edits {
buffer.edit([(range, text)], cx);
buffer.edit([(range, text)], None, cx);
}
});
this.fold_ranges(refold_ranges, cx);
@@ -3467,7 +3481,8 @@ impl Editor {
});
edits
});
this.buffer.update(cx, |buffer, cx| buffer.edit(edits, cx));
this.buffer
.update(cx, |buffer, cx| buffer.edit(edits, None, cx));
let selections = this.selections.all::<usize>(cx);
this.change_selections(Some(Autoscroll::Fit), cx, |s| {
s.select(selections);
@@ -3597,7 +3612,7 @@ impl Editor {
edits.push((range, to_insert));
}
drop(snapshot);
buffer.edit_with_autoindent(edits, cx);
buffer.edit(edits, Some(AutoindentMode::Block), cx);
});
let selections = this.selections.all::<usize>(cx);
@@ -4432,6 +4447,7 @@ impl Editor {
.iter()
.cloned()
.map(|range| (range, empty_str.clone())),
None,
cx,
);
} else {
@@ -4441,7 +4457,7 @@ impl Editor {
let position = Point::new(range.start.row, min_column);
(position..position, full_comment_prefix.clone())
});
buffer.edit(edits, cx);
buffer.edit(edits, None, cx);
}
}
}
@@ -4875,9 +4891,9 @@ impl Editor {
editor.override_text_style =
Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
}
editor
.buffer
.update(cx, |buffer, cx| buffer.edit([(0..0, old_name.clone())], cx));
editor.buffer.update(cx, |buffer, cx| {
buffer.edit([(0..0, old_name.clone())], None, cx)
});
editor.select_all(&SelectAll, cx);
editor
});
@@ -6658,8 +6674,8 @@ mod tests {
// Simulate an edit in another editor
buffer.update(cx, |buffer, cx| {
buffer.start_transaction_at(now, cx);
buffer.edit([(0..1, "a")], cx);
buffer.edit([(1..1, "b")], cx);
buffer.edit([(0..1, "a")], None, cx);
buffer.edit([(1..1, "b")], None, cx);
buffer.end_transaction_at(now, cx);
});
@@ -7200,6 +7216,7 @@ mod tests {
(Point::new(1, 0)..Point::new(1, 0), "\t"),
(Point::new(1, 1)..Point::new(1, 1), "\t"),
],
None,
cx,
);
});
@@ -7836,6 +7853,7 @@ mod tests {
(Point::new(1, 2)..Point::new(3, 0), ""),
(Point::new(4, 2)..Point::new(6, 0), ""),
],
None,
cx,
);
assert_eq!(
@@ -7894,7 +7912,7 @@ mod tests {
// Edit the buffer directly, deleting ranges surrounding the editor's selections
buffer.update(cx, |buffer, cx| {
buffer.edit([(2..5, ""), (10..13, ""), (18..21, "")], cx);
buffer.edit([(2..5, ""), (10..13, ""), (18..21, "")], None, cx);
assert_eq!(buffer.read(cx).text(), "a(), b(), c()".unindent());
});
+26 -50
View File
@@ -7,9 +7,9 @@ use collections::{Bound, HashMap, HashSet};
use gpui::{AppContext, Entity, ModelContext, ModelHandle, Task};
pub use language::Completion;
use language::{
char_kind, Buffer, BufferChunks, BufferSnapshot, CharKind, Chunk, DiagnosticEntry, Event, File,
IndentSize, Language, OffsetRangeExt, Outline, OutlineItem, Selection, ToOffset as _,
ToOffsetUtf16 as _, ToPoint as _, ToPointUtf16 as _, TransactionId,
char_kind, AutoindentMode, Buffer, BufferChunks, BufferSnapshot, CharKind, Chunk,
DiagnosticEntry, Event, File, IndentSize, Language, OffsetRangeExt, Outline, OutlineItem,
Selection, ToOffset as _, ToOffsetUtf16 as _, ToPoint as _, ToPointUtf16 as _, TransactionId,
};
use smallvec::SmallVec;
use std::{
@@ -302,28 +302,10 @@ impl MultiBuffer {
self.read(cx).symbols_containing(offset, theme)
}
pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut ModelContext<Self>)
where
I: IntoIterator<Item = (Range<S>, T)>,
S: ToOffset,
T: Into<Arc<str>>,
{
self.edit_internal(edits, false, cx)
}
pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ModelContext<Self>)
where
I: IntoIterator<Item = (Range<S>, T)>,
S: ToOffset,
T: Into<Arc<str>>,
{
self.edit_internal(edits, true, cx)
}
pub fn edit_internal<I, S, T>(
pub fn edit<I, S, T>(
&mut self,
edits: I,
autoindent: bool,
autoindent_mode: Option<AutoindentMode>,
cx: &mut ModelContext<Self>,
) where
I: IntoIterator<Item = (Range<S>, T)>,
@@ -345,11 +327,7 @@ impl MultiBuffer {
if let Some(buffer) = self.as_singleton() {
return buffer.update(cx, |buffer, cx| {
if autoindent {
buffer.edit_with_autoindent(edits, cx);
} else {
buffer.edit(edits, cx);
}
buffer.edit(edits, autoindent_mode, cx);
});
}
@@ -464,13 +442,8 @@ impl MultiBuffer {
}
}
if autoindent {
buffer.edit_with_autoindent(deletions, cx);
buffer.edit_with_autoindent(insertions, cx);
} else {
buffer.edit(deletions, cx);
buffer.edit(insertions, cx);
}
buffer.edit(deletions, autoindent_mode, cx);
buffer.edit(insertions, autoindent_mode, cx);
})
}
}
@@ -1386,7 +1359,7 @@ impl MultiBuffer {
log::info!("mutating multi-buffer with {:?}", edits);
drop(snapshot);
self.edit(edits, cx);
self.edit(edits, None, cx);
}
pub fn randomly_edit_excerpts(
@@ -3224,7 +3197,7 @@ mod tests {
.collect::<Vec<_>>()
);
buffer.update(cx, |buffer, cx| buffer.edit([(1..3, "XXX\n")], cx));
buffer.update(cx, |buffer, cx| buffer.edit([(1..3, "XXX\n")], None, cx));
let snapshot = multibuffer.read(cx).snapshot(cx);
assert_eq!(snapshot.text(), buffer.read(cx).text());
@@ -3247,11 +3220,11 @@ mod tests {
let snapshot = multibuffer.read(cx).snapshot(cx);
assert_eq!(snapshot.text(), "a");
guest_buffer.update(cx, |buffer, cx| buffer.edit([(1..1, "b")], cx));
guest_buffer.update(cx, |buffer, cx| buffer.edit([(1..1, "b")], None, cx));
let snapshot = multibuffer.read(cx).snapshot(cx);
assert_eq!(snapshot.text(), "ab");
guest_buffer.update(cx, |buffer, cx| buffer.edit([(2..2, "c")], cx));
guest_buffer.update(cx, |buffer, cx| buffer.edit([(2..2, "c")], None, cx));
let snapshot = multibuffer.read(cx).snapshot(cx);
assert_eq!(snapshot.text(), "abc");
}
@@ -3392,6 +3365,7 @@ mod tests {
(Point::new(0, 0)..Point::new(0, 0), text),
(Point::new(2, 1)..Point::new(2, 3), text),
],
None,
cx,
);
});
@@ -3529,8 +3503,8 @@ mod tests {
let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
let old_snapshot = multibuffer.read(cx).snapshot(cx);
buffer.update(cx, |buffer, cx| {
buffer.edit([(0..0, "X")], cx);
buffer.edit([(5..5, "Y")], cx);
buffer.edit([(0..0, "X")], None, cx);
buffer.edit([(5..5, "Y")], None, cx);
});
let new_snapshot = multibuffer.read(cx).snapshot(cx);
@@ -3577,12 +3551,12 @@ mod tests {
assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
buffer_1.update(cx, |buffer, cx| {
buffer.edit([(0..0, "W")], cx);
buffer.edit([(5..5, "X")], cx);
buffer.edit([(0..0, "W")], None, cx);
buffer.edit([(5..5, "X")], None, cx);
});
buffer_2.update(cx, |buffer, cx| {
buffer.edit([(0..0, "Y")], cx);
buffer.edit([(6..6, "Z")], cx);
buffer.edit([(0..0, "Y")], None, cx);
buffer.edit([(6..6, "Z")], None, cx);
});
let new_snapshot = multibuffer.read(cx).snapshot(cx);
@@ -3611,7 +3585,7 @@ mod tests {
// Create an insertion id in buffer 1 that doesn't exist in buffer 2.
// Add an excerpt from buffer 1 that spans this new insertion.
buffer_1.update(cx, |buffer, cx| buffer.edit([(4..4, "123")], cx));
buffer_1.update(cx, |buffer, cx| buffer.edit([(4..4, "123")], None, cx));
let excerpt_id_1 = multibuffer.update(cx, |multibuffer, cx| {
multibuffer
.push_excerpts(
@@ -4184,6 +4158,7 @@ mod tests {
(Point::new(0, 0)..Point::new(0, 0), "A"),
(Point::new(1, 0)..Point::new(1, 0), "A"),
],
None,
cx,
);
multibuffer.edit(
@@ -4191,6 +4166,7 @@ mod tests {
(Point::new(0, 1)..Point::new(0, 1), "B"),
(Point::new(1, 1)..Point::new(1, 1), "B"),
],
None,
cx,
);
multibuffer.end_transaction_at(now, cx);
@@ -4199,19 +4175,19 @@ mod tests {
// Edit buffer 1 through the multibuffer
now += 2 * group_interval;
multibuffer.start_transaction_at(now, cx);
multibuffer.edit([(2..2, "C")], cx);
multibuffer.edit([(2..2, "C")], None, cx);
multibuffer.end_transaction_at(now, cx);
assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
// Edit buffer 1 independently
buffer_1.update(cx, |buffer_1, cx| {
buffer_1.start_transaction_at(now);
buffer_1.edit([(3..3, "D")], cx);
buffer_1.edit([(3..3, "D")], None, cx);
buffer_1.end_transaction_at(now, cx);
now += 2 * group_interval;
buffer_1.start_transaction_at(now);
buffer_1.edit([(4..4, "E")], cx);
buffer_1.edit([(4..4, "E")], None, cx);
buffer_1.end_transaction_at(now, cx);
});
assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678");
@@ -4252,7 +4228,7 @@ mod tests {
// Redo stack gets cleared after an edit.
now += 2 * group_interval;
multibuffer.start_transaction_at(now, cx);
multibuffer.edit([(0..0, "X")], cx);
multibuffer.edit([(0..0, "X")], None, cx);
multibuffer.end_transaction_at(now, cx);
assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
multibuffer.redo(cx);