vim: Fix visual object expands (#28301)

0x2CA created

Closes #28198

Release Notes:

- Fixed visual object expands

Change summary

crates/vim/src/visual.rs                             | 72 +++++++++++++
crates/vim/test_data/test_visual_object_expands.json | 10 +
2 files changed, 80 insertions(+), 2 deletions(-)

Detailed changes

crates/vim/src/visual.rs 🔗

@@ -386,8 +386,20 @@ impl Vim {
                                     || movement::right(map, selection.start) == selection.end;
 
                                 if expand_both_ways {
-                                    selection.start = range.start;
-                                    selection.end = range.end;
+                                    if selection.start == range.start
+                                        && selection.end == range.end
+                                        && object.always_expands_both_ways()
+                                    {
+                                        if let Some(range) =
+                                            object.range(map, selection.clone(), around)
+                                        {
+                                            selection.start = range.start;
+                                            selection.end = range.end;
+                                        }
+                                    } else {
+                                        selection.start = range.start;
+                                        selection.end = range.end;
+                                    }
                                 } else if selection.reversed {
                                     selection.start = range.start;
                                 } else {
@@ -1419,6 +1431,62 @@ mod test {
             .assert_eq("«ˇhello in a word» again.");
     }
 
+    #[gpui::test]
+    async fn test_visual_object_expands(cx: &mut gpui::TestAppContext) {
+        let mut cx = NeovimBackedTestContext::new(cx).await;
+
+        cx.set_shared_state(indoc! {
+            "{
+                {
+               ˇ }
+            }
+            {
+            }
+            "
+        })
+        .await;
+        cx.simulate_shared_keystrokes("v l").await;
+        cx.shared_state().await.assert_eq(indoc! {
+            "{
+                {
+               « }ˇ»
+            }
+            {
+            }
+            "
+        });
+        cx.simulate_shared_keystrokes("a {").await;
+        cx.shared_state().await.assert_eq(indoc! {
+            "{
+                «{
+                }ˇ»
+            }
+            {
+            }
+            "
+        });
+        cx.simulate_shared_keystrokes("a {").await;
+        cx.shared_state().await.assert_eq(indoc! {
+            "«{
+                {
+                }
+            }ˇ»
+            {
+            }
+            "
+        });
+        // cx.simulate_shared_keystrokes("a {").await;
+        // cx.shared_state().await.assert_eq(indoc! {
+        //     "{
+        //         «{
+        //         }ˇ»
+        //     }
+        //     {
+        //     }
+        //     "
+        // });
+    }
+
     #[gpui::test]
     async fn test_mode_across_command(cx: &mut gpui::TestAppContext) {
         let mut cx = VimTestContext::new(cx, true).await;

crates/vim/test_data/test_visual_object_expands.json 🔗

@@ -0,0 +1,10 @@
+{"Put":{"state":"{\n    {\n   ˇ }\n}\n{\n}\n"}}
+{"Key":"v"}
+{"Key":"l"}
+{"Get":{"state":"{\n    {\n   « }ˇ»\n}\n{\n}\n","mode":"Visual"}}
+{"Key":"a"}
+{"Key":"{"}
+{"Get":{"state":"{\n    «{\n    }ˇ»\n}\n{\n}\n","mode":"Visual"}}
+{"Key":"a"}
+{"Key":"{"}
+{"Get":{"state":"«{\n    {\n    }\n}ˇ»\n{\n}\n","mode":"Visual"}}