Merge pull request #301 from zed-industries/move-lines-in-multibuffer

Support moving lines up and down in multi-buffers
This commit is contained in:
Nathan Sobo 2021-12-30 01:13:31 -08:00 committed by GitHub
commit f499a1dfc2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 35 deletions

View file

@ -123,14 +123,11 @@ impl DisplayMap {
self.block_map.read(snapshot, edits); self.block_map.read(snapshot, edits);
} }
pub fn insert_blocks<P>( pub fn insert_blocks(
&mut self, &mut self,
blocks: impl IntoIterator<Item = BlockProperties<P>>, blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) -> Vec<BlockId> ) -> Vec<BlockId> {
where
P: ToOffset + Clone,
{
let snapshot = self.buffer.read(cx).snapshot(cx); let snapshot = self.buffer.read(cx).snapshot(cx);
let edits = self.buffer_subscription.consume().into_inner(); let edits = self.buffer_subscription.consume().into_inner();
let (snapshot, edits) = self.fold_map.read(snapshot, edits); let (snapshot, edits) = self.fold_map.read(snapshot, edits);

View file

@ -1,5 +1,5 @@
use super::wrap_map::{self, WrapEdit, WrapPoint, WrapSnapshot}; use super::wrap_map::{self, WrapEdit, WrapPoint, WrapSnapshot};
use crate::{Anchor, ToOffset, ToPoint as _}; use crate::{Anchor, ToPoint as _};
use collections::{HashMap, HashSet}; use collections::{HashMap, HashSet};
use gpui::{AppContext, ElementBox}; use gpui::{AppContext, ElementBox};
use language::Chunk; use language::Chunk;
@ -362,13 +362,10 @@ impl std::ops::DerefMut for BlockPoint {
} }
impl<'a> BlockMapWriter<'a> { impl<'a> BlockMapWriter<'a> {
pub fn insert<P>( pub fn insert(
&mut self, &mut self,
blocks: impl IntoIterator<Item = BlockProperties<P>>, blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
) -> Vec<BlockId> ) -> Vec<BlockId> {
where
P: ToOffset + Clone,
{
let mut ids = Vec::new(); let mut ids = Vec::new();
let mut edits = Vec::<Edit<u32>>::new(); let mut edits = Vec::<Edit<u32>>::new();
let wrap_snapshot = &*self.0.wrap_snapshot.lock(); let wrap_snapshot = &*self.0.wrap_snapshot.lock();
@ -378,7 +375,7 @@ impl<'a> BlockMapWriter<'a> {
let id = BlockId(self.0.next_block_id.fetch_add(1, SeqCst)); let id = BlockId(self.0.next_block_id.fetch_add(1, SeqCst));
ids.push(id); ids.push(id);
let position = buffer.anchor_after(block.position); let position = block.position;
let point = position.to_point(&buffer); let point = position.to_point(&buffer);
let wrap_row = wrap_snapshot let wrap_row = wrap_snapshot
.from_point(Point::new(point.row, 0), Bias::Left) .from_point(Point::new(point.row, 0), Bias::Left)
@ -903,8 +900,9 @@ mod tests {
let text = "aaa\nbbb\nccc\nddd"; let text = "aaa\nbbb\nccc\nddd";
let buffer = MultiBuffer::build_simple(text, cx); let buffer = MultiBuffer::build_simple(text, cx);
let buffer_snapshot = buffer.read(cx).snapshot(cx);
let subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
let (fold_map, folds_snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx)); let (fold_map, folds_snapshot) = FoldMap::new(buffer_snapshot.clone());
let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), 1); let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), 1);
let (wrap_map, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, None, cx); let (wrap_map, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, None, cx);
let mut block_map = BlockMap::new(wraps_snapshot.clone()); let mut block_map = BlockMap::new(wraps_snapshot.clone());
@ -912,19 +910,19 @@ mod tests {
let mut writer = block_map.write(wraps_snapshot.clone(), vec![]); let mut writer = block_map.write(wraps_snapshot.clone(), vec![]);
writer.insert(vec![ writer.insert(vec![
BlockProperties { BlockProperties {
position: Point::new(1, 0), position: buffer_snapshot.anchor_after(Point::new(1, 0)),
height: 1, height: 1,
disposition: BlockDisposition::Above, disposition: BlockDisposition::Above,
render: Arc::new(|_| Empty::new().named("block 1")), render: Arc::new(|_| Empty::new().named("block 1")),
}, },
BlockProperties { BlockProperties {
position: Point::new(1, 2), position: buffer_snapshot.anchor_after(Point::new(1, 2)),
height: 2, height: 2,
disposition: BlockDisposition::Above, disposition: BlockDisposition::Above,
render: Arc::new(|_| Empty::new().named("block 2")), render: Arc::new(|_| Empty::new().named("block 2")),
}, },
BlockProperties { BlockProperties {
position: Point::new(3, 3), position: buffer_snapshot.anchor_after(Point::new(3, 3)),
height: 3, height: 3,
disposition: BlockDisposition::Below, disposition: BlockDisposition::Below,
render: Arc::new(|_| Empty::new().named("block 3")), render: Arc::new(|_| Empty::new().named("block 3")),
@ -1071,7 +1069,8 @@ mod tests {
let text = "one two three\nfour five six\nseven eight"; let text = "one two three\nfour five six\nseven eight";
let buffer = MultiBuffer::build_simple(text, cx); let buffer = MultiBuffer::build_simple(text, cx);
let (_, folds_snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx)); let buffer_snapshot = buffer.read(cx).snapshot(cx);
let (_, folds_snapshot) = FoldMap::new(buffer_snapshot.clone());
let (_, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), 1); let (_, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), 1);
let (_, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, Some(60.), cx); let (_, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, Some(60.), cx);
let mut block_map = BlockMap::new(wraps_snapshot.clone()); let mut block_map = BlockMap::new(wraps_snapshot.clone());
@ -1079,13 +1078,13 @@ mod tests {
let mut writer = block_map.write(wraps_snapshot.clone(), vec![]); let mut writer = block_map.write(wraps_snapshot.clone(), vec![]);
writer.insert(vec![ writer.insert(vec![
BlockProperties { BlockProperties {
position: Point::new(1, 12), position: buffer_snapshot.anchor_after(Point::new(1, 12)),
disposition: BlockDisposition::Above, disposition: BlockDisposition::Above,
render: Arc::new(|_| Empty::new().named("block 1")), render: Arc::new(|_| Empty::new().named("block 1")),
height: 1, height: 1,
}, },
BlockProperties { BlockProperties {
position: Point::new(1, 1), position: buffer_snapshot.anchor_after(Point::new(1, 1)),
disposition: BlockDisposition::Below, disposition: BlockDisposition::Below,
render: Arc::new(|_| Empty::new().named("block 2")), render: Arc::new(|_| Empty::new().named("block 2")),
height: 1, height: 1,

View file

@ -1737,8 +1737,13 @@ impl Editor {
.chain(['\n']) .chain(['\n'])
.collect::<String>(); .collect::<String>();
edits.push((insertion_point..insertion_point, text)); edits.push((
edits.push((range_to_move.clone(), String::new())); buffer.anchor_after(range_to_move.start)
..buffer.anchor_before(range_to_move.end),
String::new(),
));
let insertion_anchor = buffer.anchor_after(insertion_point);
edits.push((insertion_anchor.clone()..insertion_anchor, text));
let row_delta = range_to_move.start.row - insertion_point.row + 1; let row_delta = range_to_move.start.row - insertion_point.row + 1;
@ -1773,7 +1778,7 @@ impl Editor {
self.start_transaction(cx); self.start_transaction(cx);
self.unfold_ranges(unfold_ranges, cx); self.unfold_ranges(unfold_ranges, cx);
self.buffer.update(cx, |buffer, cx| { self.buffer.update(cx, |buffer, cx| {
for (range, text) in edits.into_iter().rev() { for (range, text) in edits {
buffer.edit([range], text, cx); buffer.edit([range], text, cx);
} }
}); });
@ -1828,8 +1833,13 @@ impl Editor {
let mut text = String::from("\n"); let mut text = String::from("\n");
text.extend(buffer.text_for_range(range_to_move.clone())); text.extend(buffer.text_for_range(range_to_move.clone()));
text.pop(); // Drop trailing newline text.pop(); // Drop trailing newline
edits.push((range_to_move.clone(), String::new())); edits.push((
edits.push((insertion_point..insertion_point, text)); buffer.anchor_after(range_to_move.start)
..buffer.anchor_before(range_to_move.end),
String::new(),
));
let insertion_anchor = buffer.anchor_after(insertion_point);
edits.push((insertion_anchor.clone()..insertion_anchor, text));
let row_delta = insertion_point.row - range_to_move.end.row + 1; let row_delta = insertion_point.row - range_to_move.end.row + 1;
@ -1864,7 +1874,7 @@ impl Editor {
self.start_transaction(cx); self.start_transaction(cx);
self.unfold_ranges(unfold_ranges, cx); self.unfold_ranges(unfold_ranges, cx);
self.buffer.update(cx, |buffer, cx| { self.buffer.update(cx, |buffer, cx| {
for (range, text) in edits.into_iter().rev() { for (range, text) in edits {
buffer.edit([range], text, cx); buffer.edit([range], text, cx);
} }
}); });
@ -2962,7 +2972,7 @@ impl Editor {
let message_height = diagnostic.message.lines().count() as u8; let message_height = diagnostic.message.lines().count() as u8;
BlockProperties { BlockProperties {
position: entry.range.start, position: buffer.anchor_after(entry.range.start),
height: message_height, height: message_height,
render: diagnostic_block_renderer(diagnostic, true, build_settings), render: diagnostic_block_renderer(diagnostic, true, build_settings),
disposition: BlockDisposition::Below, disposition: BlockDisposition::Below,
@ -3421,14 +3431,11 @@ impl Editor {
} }
} }
pub fn insert_blocks<P>( pub fn insert_blocks(
&mut self, &mut self,
blocks: impl IntoIterator<Item = BlockProperties<P>>, blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Vec<BlockId> ) -> Vec<BlockId> {
where
P: ToOffset + Clone,
{
let blocks = self let blocks = self
.display_map .display_map
.update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx)); .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
@ -5130,12 +5137,13 @@ mod tests {
fn test_move_line_up_down_with_blocks(cx: &mut gpui::MutableAppContext) { fn test_move_line_up_down_with_blocks(cx: &mut gpui::MutableAppContext) {
let settings = EditorSettings::test(&cx); let settings = EditorSettings::test(&cx);
let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx); let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx);
let snapshot = buffer.read(cx).snapshot(cx);
let (_, editor) = let (_, editor) =
cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
editor.insert_blocks( editor.insert_blocks(
[BlockProperties { [BlockProperties {
position: Point::new(2, 0), position: snapshot.anchor_after(Point::new(2, 0)),
disposition: BlockDisposition::Below, disposition: BlockDisposition::Below,
height: 1, height: 1,
render: Arc::new(|_| Empty::new().boxed()), render: Arc::new(|_| Empty::new().boxed()),