From b3de19a6bd19f769a732f52d70e4bd16a9bd0d8d Mon Sep 17 00:00:00 2001 From: CharlesChen0823 Date: Fri, 13 Dec 2024 09:57:24 +0800 Subject: [PATCH] editor: Add duplicate selection command (#21154) Closes #4890 Release Notes: - Add duplicate selection command for editor --- crates/editor/src/actions.rs | 1 + crates/editor/src/editor.rs | 22 ++++++++++++++++++++++ crates/editor/src/editor_tests.rs | 22 ++++++++++++++++++++++ crates/editor/src/element.rs | 1 + 4 files changed, 46 insertions(+) diff --git a/crates/editor/src/actions.rs b/crates/editor/src/actions.rs index eb0fcaa1e5002829753e8f0f3ae831d2f86bd2ef..721b71ddecb595026754a8057d979c4fce1e5ed1 100644 --- a/crates/editor/src/actions.rs +++ b/crates/editor/src/actions.rs @@ -251,6 +251,7 @@ gpui::actions!( DisplayCursorNames, DuplicateLineDown, DuplicateLineUp, + DuplicateSelection, ExpandAllHunkDiffs, ExpandMacroRecursively, FindAllReferences, diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index f86acc72b7f55f3738499ee2d27cf2519dca6411..38b34892323e3e141f55bac43285fa9e85c266d9 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -6119,6 +6119,28 @@ impl Editor { }); } + pub fn duplicate_selection(&mut self, _: &DuplicateSelection, cx: &mut ViewContext) { + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + let buffer = &display_map.buffer_snapshot; + let selections = self.selections.all::(cx); + + let mut edits = Vec::new(); + for selection in selections.iter() { + let start = selection.start; + let end = selection.end; + let text = buffer.text_for_range(start..end).collect::(); + edits.push((selection.end..selection.end, text)); + } + + self.transact(cx, |this, cx| { + this.buffer.update(cx, |buffer, cx| { + buffer.edit(edits, None, cx); + }); + + this.request_autoscroll(Autoscroll::fit(), cx); + }); + } + pub fn duplicate_line(&mut self, upwards: bool, cx: &mut ViewContext) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = &display_map.buffer_snapshot; diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 65c5347d368dd49ce1d7946b789b5847e3cd3707..ce020c8ca812a993be2580ab848118e88c70f94d 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -3895,6 +3895,28 @@ fn test_duplicate_line(cx: &mut TestAppContext) { ] ); }); + + let view = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); + build_editor(buffer, cx) + }); + _ = view.update(cx, |view, cx| { + view.change_selections(None, cx, |s| { + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(1), 1), + DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(2), 1), + ]) + }); + view.duplicate_selection(&DuplicateSelection, cx); + assert_eq!(view.display_text(cx), "abc\ndbc\ndef\ngf\nghi\n"); + assert_eq!( + view.selections.display_ranges(cx), + vec![ + DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(1), 1), + DisplayPoint::new(DisplayRow(2), 2)..DisplayPoint::new(DisplayRow(3), 1), + ] + ); + }); } #[gpui::test] diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 25c419fa62eca2e696bae816219cbd0bd8608d31..26b5cae32dc7d6060dda1870051f422b333e6d89 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -218,6 +218,7 @@ impl EditorElement { register_action(view, cx, Editor::cut_to_end_of_line); register_action(view, cx, Editor::duplicate_line_up); register_action(view, cx, Editor::duplicate_line_down); + register_action(view, cx, Editor::duplicate_selection); register_action(view, cx, Editor::move_line_up); register_action(view, cx, Editor::move_line_down); register_action(view, cx, Editor::transpose);