diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index c11a474c68f0b5fe7b43648149abea20881d3f0d..6228f6def68fd46902a1bf9394bcf6eff3ec61ad 100644 --- a/assets/keymaps/vim.json +++ b/assets/keymaps/vim.json @@ -197,6 +197,7 @@ "d": ["vim::PushOperator", "Delete"], "shift-d": "vim::DeleteToEndOfLine", "shift-j": "vim::JoinLines", + "g shift-j": "vim::JoinLinesNoWhitespace", "y": ["vim::PushOperator", "Yank"], "shift-y": "vim::YankLine", "i": "vim::InsertBefore", @@ -278,6 +279,7 @@ "g shift-i": "vim::VisualInsertFirstNonWhiteSpace", "g shift-a": "vim::VisualInsertEndOfLine", "shift-j": "vim::JoinLines", + "g shift-j": "vim::JoinLinesNoWhitespace", "r": ["vim::PushOperator", "Replace"], "ctrl-c": ["vim::SwitchMode", "Normal"], "escape": ["vim::SwitchMode", "Normal"], diff --git a/crates/editor/src/actions.rs b/crates/editor/src/actions.rs index a2bc64c4b55e4a736c02156ccafafc153b93a236..ede5916b06fa6a74e8f9d7459701955319c30812 100644 --- a/crates/editor/src/actions.rs +++ b/crates/editor/src/actions.rs @@ -204,7 +204,7 @@ impl_actions!( ToggleCodeActions, ToggleComments, UnfoldAt, - FoldAtLevel + FoldAtLevel, ] ); diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index a217cda0f131ed21f0dbb7a4e3b24f39e6bc96c0..b11832e1b180046859d370eb7b686f9735e31919 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -5851,7 +5851,7 @@ impl Editor { }); } - pub fn join_lines(&mut self, _: &JoinLines, cx: &mut ViewContext) { + pub fn join_lines_impl(&mut self, insert_whitespace: bool, cx: &mut ViewContext) { if self.read_only(cx) { return; } @@ -5893,11 +5893,12 @@ impl Editor { let indent = snapshot.indent_size_for_line(next_line_row); let start_of_next_line = Point::new(next_line_row.0, indent.len); - let replace = if snapshot.line_len(next_line_row) > indent.len { - " " - } else { - "" - }; + let replace = + if snapshot.line_len(next_line_row) > indent.len && insert_whitespace { + " " + } else { + "" + }; this.buffer.update(cx, |buffer, cx| { buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx) @@ -5911,6 +5912,10 @@ impl Editor { }); } + pub fn join_lines(&mut self, _: &JoinLines, cx: &mut ViewContext) { + self.join_lines_impl(true, cx); + } + pub fn sort_lines_case_sensitive( &mut self, _: &SortLinesCaseSensitive, diff --git a/crates/vim/src/normal.rs b/crates/vim/src/normal.rs index bde3c12027482f6a8cf369a249623c1aad6880db..df01f2affc203882f6c8ed24db083cbb1910b50e 100644 --- a/crates/vim/src/normal.rs +++ b/crates/vim/src/normal.rs @@ -44,6 +44,8 @@ actions!( InsertLineAbove, InsertLineBelow, InsertAtPrevious, + JoinLines, + JoinLinesNoWhitespace, DeleteLeft, DeleteRight, ChangeToEndOfLine, @@ -53,7 +55,6 @@ actions!( ChangeCase, ConvertToUpperCase, ConvertToLowerCase, - JoinLines, ToggleComments, Undo, Redo, @@ -108,25 +109,11 @@ pub(crate) fn register(editor: &mut Editor, cx: &mut ViewContext) { ); }); Vim::action(editor, cx, |vim, _: &JoinLines, cx| { - vim.record_current_action(cx); - let mut times = Vim::take_count(cx).unwrap_or(1); - if vim.mode.is_visual() { - times = 1; - } else if times > 1 { - // 2J joins two lines together (same as J or 1J) - times -= 1; - } + vim.join_lines_impl(true, cx); + }); - vim.update_editor(cx, |_, editor, cx| { - editor.transact(cx, |editor, cx| { - for _ in 0..times { - editor.join_lines(&Default::default(), cx) - } - }) - }); - if vim.mode.is_visual() { - vim.switch_mode(Mode::Normal, true, cx) - } + Vim::action(editor, cx, |vim, _: &JoinLinesNoWhitespace, cx| { + vim.join_lines_impl(false, cx); }); Vim::action(editor, cx, |vim, _: &Undo, cx| { @@ -401,6 +388,28 @@ impl Vim { }); } + fn join_lines_impl(&mut self, insert_whitespace: bool, cx: &mut ViewContext) { + self.record_current_action(cx); + let mut times = Vim::take_count(cx).unwrap_or(1); + if self.mode.is_visual() { + times = 1; + } else if times > 1 { + // 2J joins two lines together (same as J or 1J) + times -= 1; + } + + self.update_editor(cx, |_, editor, cx| { + editor.transact(cx, |editor, cx| { + for _ in 0..times { + editor.join_lines_impl(insert_whitespace, cx) + } + }) + }); + if self.mode.is_visual() { + self.switch_mode(Mode::Normal, true, cx) + } + } + fn yank_line(&mut self, _: &YankLine, cx: &mut ViewContext) { let count = Vim::take_count(cx); self.yank_motion(motion::Motion::CurrentLine, count, cx) diff --git a/crates/vim/src/test.rs b/crates/vim/src/test.rs index 947353e2d302d1d03db300f41c57d006c21c295c..25488c9146caa0d1bcf54d2024b16bd803445280 100644 --- a/crates/vim/src/test.rs +++ b/crates/vim/src/test.rs @@ -367,6 +367,46 @@ async fn test_join_lines(cx: &mut gpui::TestAppContext) { two three fourˇ five six "}); + + cx.set_shared_state(indoc! {" + ˇone + two + three + four + five + six + "}) + .await; + cx.simulate_shared_keystrokes("g shift-j").await; + cx.shared_state().await.assert_eq(indoc! {" + oneˇtwo + three + four + five + six + "}); + cx.simulate_shared_keystrokes("3 g shift-j").await; + cx.shared_state().await.assert_eq(indoc! {" + onetwothreeˇfour + five + six + "}); + + cx.set_shared_state(indoc! {" + ˇone + two + three + four + five + six + "}) + .await; + cx.simulate_shared_keystrokes("j v 3 j g shift-j").await; + cx.shared_state().await.assert_eq(indoc! {" + one + twothreefourˇfive + six + "}); } #[cfg(target_os = "macos")] diff --git a/crates/vim/test_data/test_join_lines.json b/crates/vim/test_data/test_join_lines.json index b4bc5c30e1ce7a96e2fa9ada59efa48e0aa83a0e..55aa8b1dcb5ef17761e2d8b75ec0abfd3a8b10cf 100644 --- a/crates/vim/test_data/test_join_lines.json +++ b/crates/vim/test_data/test_join_lines.json @@ -11,3 +11,19 @@ {"Key":"j"} {"Key":"shift-j"} {"Get":{"state":"one\ntwo three fourˇ five\nsix\n","mode":"Normal"}} +{"Put":{"state":"ˇone\ntwo\nthree\nfour\nfive\nsix\n"}} +{"Key":"g"} +{"Key":"shift-j"} +{"Get":{"state":"oneˇtwo\nthree\nfour\nfive\nsix\n","mode":"Normal"}} +{"Key":"3"} +{"Key":"g"} +{"Key":"shift-j"} +{"Get":{"state":"onetwothreeˇfour\nfive\nsix\n","mode":"Normal"}} +{"Put":{"state":"ˇone\ntwo\nthree\nfour\nfive\nsix\n"}} +{"Key":"j"} +{"Key":"v"} +{"Key":"3"} +{"Key":"j"} +{"Key":"g"} +{"Key":"shift-j"} +{"Get":{"state":"one\ntwothreefourˇfive\nsix\n","mode":"Normal"}}