Start on joining lines

Nathan Sobo and Conrad Irwin created

Co-Authored-By: Conrad Irwin <conrad.irwin@gmail.com>

Change summary

crates/editor/src/editor.rs       | 13 +++++++++++
crates/editor/src/editor_tests.rs | 36 ++++++++++++++++++++++++++++++--
2 files changed, 46 insertions(+), 3 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -206,6 +206,7 @@ actions!(
         DuplicateLine,
         MoveLineUp,
         MoveLineDown,
+        JoinLines,
         Transpose,
         Cut,
         Copy,
@@ -321,6 +322,7 @@ pub fn init(cx: &mut AppContext) {
     cx.add_action(Editor::indent);
     cx.add_action(Editor::outdent);
     cx.add_action(Editor::delete_line);
+    cx.add_action(Editor::join_lines);
     cx.add_action(Editor::delete_to_previous_word_start);
     cx.add_action(Editor::delete_to_previous_subword_start);
     cx.add_action(Editor::delete_to_next_word_end);
@@ -3952,6 +3954,17 @@ impl Editor {
         });
     }
 
+    pub fn join_lines(&mut self, _: &JoinLines, cx: &mut ViewContext<Self>) {
+        let cursor_position = self.selections.newest::<Point>(cx).head();
+        let snapshot = self.buffer.read(cx).snapshot(cx);
+        let end_of_line = Point::new(cursor_position.row, snapshot.line_len(cursor_position.row));
+        let start_of_next_line = end_of_line + Point::new(1, 0);
+
+        self.buffer.update(cx, |buffer, cx| {
+            buffer.edit([(end_of_line..start_of_next_line, " ")], None, cx)
+        });
+    }
+
     pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
         let buffer = &display_map.buffer_snapshot;

crates/editor/src/editor_tests.rs 🔗

@@ -1,7 +1,10 @@
 use super::*;
-use crate::test::{
-    assert_text_with_selections, build_editor, editor_lsp_test_context::EditorLspTestContext,
-    editor_test_context::EditorTestContext, select_ranges,
+use crate::{
+    test::{
+        assert_text_with_selections, build_editor, editor_lsp_test_context::EditorLspTestContext,
+        editor_test_context::EditorTestContext, select_ranges,
+    },
+    JoinLines,
 };
 use drag_and_drop::DragAndDrop;
 use futures::StreamExt;
@@ -2325,6 +2328,33 @@ fn test_delete_line(cx: &mut TestAppContext) {
     });
 }
 
+#[gpui::test]
+fn test_join_lines(cx: &mut TestAppContext) {
+    init_test(cx, |_| {});
+
+    let (_, editor) = cx.add_window(|cx| {
+        let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx);
+        let mut editor = build_editor(buffer.clone(), cx);
+        let buffer = buffer.read(cx).as_singleton().unwrap();
+
+        assert_eq!(
+            editor.selections.ranges::<Point>(cx),
+            &[Point::new(0, 0)..Point::new(0, 0)]
+        );
+
+        editor.join_lines(&JoinLines, cx);
+
+        // assert_eq!(
+        //     editor.selections.ranges::<Point>(cx),
+        //     &[Point::new(0, 0), Point::new(0, 0)]
+        // );
+
+        assert_eq!(buffer.read(cx).text(), "abc def\nghi\n");
+
+        editor
+    });
+}
+
 #[gpui::test]
 fn test_duplicate_line(cx: &mut TestAppContext) {
     init_test(cx, |_| {});