vim: Fix `g _` not having the expected behavior (#12607)

CharlesChen0823 and Conrad Irwin created

Release Notes:

- N/A

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>

Change summary

crates/vim/src/motion.rs                            | 12 ++++++++++++
crates/vim/test_data/test_end_of_line_downward.json |  4 ++++
2 files changed, 16 insertions(+)

Detailed changes

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");