diff --git a/crates/vim/src/motion.rs b/crates/vim/src/motion.rs index 626ee3a5c1..295112e881 100644 --- a/crates/vim/src/motion.rs +++ b/crates/vim/src/motion.rs @@ -1440,6 +1440,14 @@ pub(crate) fn last_non_whitespace( ) -> DisplayPoint { let mut end_of_line = end_of_line(map, false, from, count).to_offset(map, Bias::Left); let scope = map.buffer_snapshot.language_scope_at(from.to_point(map)); + + // NOTE: depending on clip_at_line_end we may already be one char back from the end. + if let Some((ch, _)) = map.buffer_chars_at(end_of_line).next() { + if char_kind(&scope, ch) != CharKind::Whitespace { + return end_of_line.to_display_point(map); + } + } + for (ch, offset) in map.reverse_buffer_chars_at(end_of_line) { if ch == '\n' { break; @@ -1935,6 +1943,10 @@ mod test { #[gpui::test] async fn test_end_of_line_downward(cx: &mut gpui::TestAppContext) { let mut cx = NeovimBackedTestContext::new(cx).await; + cx.set_shared_state("ˇ one\n two \nthree").await; + cx.simulate_shared_keystrokes("g _").await; + cx.shared_state().await.assert_eq(" onˇe\n two \nthree"); + cx.set_shared_state("ˇ one \n two \nthree").await; cx.simulate_shared_keystrokes("g _").await; cx.shared_state().await.assert_eq(" onˇe \n two \nthree"); diff --git a/crates/vim/test_data/test_end_of_line_downward.json b/crates/vim/test_data/test_end_of_line_downward.json index be73805cdc..e3563f6b3f 100644 --- a/crates/vim/test_data/test_end_of_line_downward.json +++ b/crates/vim/test_data/test_end_of_line_downward.json @@ -1,3 +1,7 @@ +{"Put":{"state":"ˇ one\n two \nthree"}} +{"Key":"g"} +{"Key":"_"} +{"Get":{"state":" onˇe\n two \nthree","mode":"Normal"}} {"Put":{"state":"ˇ one \n two \nthree"}} {"Key":"g"} {"Key":"_"}