From 2276d25bdfcf5e31f4996f84695c82b25cb61e4e Mon Sep 17 00:00:00 2001 From: Kay Simmons Date: Thu, 23 Feb 2023 13:40:31 -0800 Subject: [PATCH] Fix enter in normal mode acting incorrectly --- assets/keymaps/vim.json | 1 + crates/vim/src/motion.rs | 50 ++++++++++++++++++++++++---- crates/vim/src/normal.rs | 21 ++++++------ crates/vim/test_data/test_enter.json | 1 + 4 files changed, 57 insertions(+), 16 deletions(-) create mode 100644 crates/vim/test_data/test_enter.json diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index 824fb63c0f..a24c4aff69 100644 --- a/assets/keymaps/vim.json +++ b/assets/keymaps/vim.json @@ -27,6 +27,7 @@ "h": "vim::Left", "backspace": "vim::Backspace", "j": "vim::Down", + "enter": "vim::NextLineStart", "k": "vim::Up", "l": "vim::Right", "$": "vim::EndOfLine", diff --git a/crates/vim/src/motion.rs b/crates/vim/src/motion.rs index 25188a466c..1794e999a2 100644 --- a/crates/vim/src/motion.rs +++ b/crates/vim/src/motion.rs @@ -36,6 +36,7 @@ pub enum Motion { Matching, FindForward { before: bool, text: Arc }, FindBackward { after: bool, text: Arc }, + NextLineStart, } #[derive(Clone, Deserialize, PartialEq)] @@ -74,6 +75,7 @@ actions!( StartOfDocument, EndOfDocument, Matching, + NextLineStart, ] ); impl_actions!(vim, [NextWordStart, NextWordEnd, PreviousWordStart]); @@ -111,6 +113,7 @@ pub fn init(cx: &mut MutableAppContext) { &PreviousWordStart { ignore_punctuation }: &PreviousWordStart, cx: _| { motion(Motion::PreviousWordStart { ignore_punctuation }, cx) }, ); + cx.add_action(|_: &mut Workspace, &NextLineStart, cx: _| motion(Motion::NextLineStart, cx)) } pub(crate) fn motion(motion: Motion, cx: &mut MutableAppContext) { @@ -138,15 +141,43 @@ pub(crate) fn motion(motion: Motion, cx: &mut MutableAppContext) { impl Motion { pub fn linewise(&self) -> bool { use Motion::*; - matches!( - self, - Down | Up | StartOfDocument | EndOfDocument | CurrentLine - ) + match self { + Down | Up | StartOfDocument | EndOfDocument | CurrentLine | NextLineStart => true, + EndOfLine + | NextWordEnd { .. } + | Matching + | FindForward { .. } + | Left + | Backspace + | Right + | StartOfLine + | NextWordStart { .. } + | PreviousWordStart { .. } + | FirstNonWhitespace + | FindBackward { .. } => false, + } } pub fn infallible(&self) -> bool { use Motion::*; - matches!(self, StartOfDocument | CurrentLine | EndOfDocument) + match self { + StartOfDocument | EndOfDocument | CurrentLine => true, + Down + | Up + | EndOfLine + | NextWordEnd { .. } + | Matching + | FindForward { .. } + | Left + | Backspace + | Right + | StartOfLine + | NextWordStart { .. } + | PreviousWordStart { .. } + | FirstNonWhitespace + | FindBackward { .. } + | NextLineStart => false, + } } pub fn inclusive(&self) -> bool { @@ -160,7 +191,8 @@ impl Motion { | EndOfLine | NextWordEnd { .. } | Matching - | FindForward { .. } => true, + | FindForward { .. } + | NextLineStart => true, Left | Backspace | Right @@ -214,6 +246,7 @@ impl Motion { find_backward(map, point, *after, text.clone(), times), SelectionGoal::None, ), + NextLineStart => (next_line_start(map, point, times), SelectionGoal::None), }; (new_point != point || infallible).then_some((new_point, goal)) @@ -543,3 +576,8 @@ fn find_backward( }) .unwrap_or(from) } + +fn next_line_start(map: &DisplaySnapshot, point: DisplayPoint, times: usize) -> DisplayPoint { + let new_row = (point.row() + times as u32).min(map.max_buffer_row()); + map.clip_point(DisplayPoint::new(new_row, 0), Bias::Left) +} diff --git a/crates/vim/src/normal.rs b/crates/vim/src/normal.rs index 0cac45fd18..55134e2149 100644 --- a/crates/vim/src/normal.rs +++ b/crates/vim/src/normal.rs @@ -473,6 +473,7 @@ pub(crate) fn normal_replace(text: Arc, cx: &mut MutableAppContext) { #[cfg(test)] mod test { + use gpui::TestAppContext; use indoc::indoc; use crate::{ @@ -515,15 +516,15 @@ mod test { .await; } - // #[gpui::test] - // async fn test_enter(cx: &mut gpui::TestAppContext) { - // let mut cx = NeovimBackedTestContext::new(cx).await.binding(["enter"]); - // cx.assert_all(indoc! {" - // ˇThe qˇuick broˇwn - // ˇfox jumps" - // }) - // .await; - // } + #[gpui::test] + async fn test_enter(cx: &mut gpui::TestAppContext) { + let mut cx = NeovimBackedTestContext::new(cx).await.binding(["enter"]); + cx.assert_all(indoc! {" + ˇThe qˇuick broˇwn + ˇfox jumps" + }) + .await; + } #[gpui::test] async fn test_k(cx: &mut gpui::TestAppContext) { @@ -1030,7 +1031,7 @@ mod test { } #[gpui::test] - async fn test_percent(cx: &mut gpui::TestAppContext) { + async fn test_percent(cx: &mut TestAppContext) { let mut cx = NeovimBackedTestContext::new(cx).await.binding(["%"]); cx.assert_all("ˇconsole.logˇ(ˇvaˇrˇ)ˇ;").await; cx.assert_all("ˇconsole.logˇ(ˇ'var', ˇ[ˇ1, ˇ2, 3ˇ]ˇ)ˇ;") diff --git a/crates/vim/test_data/test_enter.json b/crates/vim/test_data/test_enter.json new file mode 100644 index 0000000000..1bbc077812 --- /dev/null +++ b/crates/vim/test_data/test_enter.json @@ -0,0 +1 @@ +[{"Text":"The quick brown\nfox jumps"},{"Mode":"Normal"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Normal"},{"Text":"The quick brown\nfox jumps"},{"Mode":"Normal"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Normal"},{"Text":"The quick brown\nfox jumps"},{"Mode":"Normal"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Normal"},{"Text":"The quick brown\nfox jumps"},{"Mode":"Normal"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Normal"}] \ No newline at end of file