vim: Move to opening html tag from / in closing tag (#42513)

Pranav Joglekar created

Closes #41582

Release Notes:

- Improves the '%' vim motion for html by moving the cursor to the
opening tag when its positioned on the `/` ( slash ) of the closing tag

Change summary

crates/vim/src/motion.rs                     | 31 +++++++++++++++++++--
crates/vim/test_data/test_matching_tags.json |  5 +++
2 files changed, 32 insertions(+), 4 deletions(-)

Detailed changes

crates/vim/src/motion.rs 🔗

@@ -2388,10 +2388,16 @@ fn matching(map: &DisplaySnapshot, display_point: DisplayPoint) -> DisplayPoint
         .or_else(|| snapshot.innermost_enclosing_bracket_ranges(offset..offset, None));
 
     if let Some((opening_range, closing_range)) = bracket_ranges {
-        if opening_range.contains(&offset) {
-            return closing_range.start.to_display_point(map);
-        } else if closing_range.contains(&offset) {
-            return opening_range.start.to_display_point(map);
+        let mut chars = map.buffer_snapshot().chars_at(offset);
+        match chars.next() {
+            Some('/') => {}
+            _ => {
+                if opening_range.contains(&offset) {
+                    return closing_range.start.to_display_point(map);
+                } else if closing_range.contains(&offset) {
+                    return opening_range.start.to_display_point(map);
+                }
+            }
         }
     }
 
@@ -3443,6 +3449,23 @@ mod test {
                 test = "test"
             />
         </a>"#});
+
+        // test nested closing tag
+        cx.set_shared_state(indoc! {r#"<html>
+            <bˇody>
+            </body>
+        </html>"#})
+            .await;
+        cx.simulate_shared_keystrokes("%").await;
+        cx.shared_state().await.assert_eq(indoc! {r#"<html>
+            <body>
+            <ˇ/body>
+        </html>"#});
+        cx.simulate_shared_keystrokes("%").await;
+        cx.shared_state().await.assert_eq(indoc! {r#"<html>
+            <ˇbody>
+            </body>
+        </html>"#});
     }
 
     #[gpui::test]

crates/vim/test_data/test_matching_tags.json 🔗

@@ -13,3 +13,8 @@
 {"Put":{"state":"<a>\n    <br\n        test = \"test\"\n    /ˇ>\n</a>"}}
 {"Key":"%"}
 {"Get":{"state":"<a>\n    ˇ<br\n        test = \"test\"\n    />\n</a>","mode":"Normal"}}
+{"Put":{"state":"<html>\n    <bˇody>\n    </body>\n</html>"}}
+{"Key":"%"}
+{"Get":{"state":"<html>\n    <body>\n    <ˇ/body>\n</html>","mode":"Normal"}}
+{"Key":"%"}
+{"Get":{"state":"<html>\n    <ˇbody>\n    </body>\n</html>","mode":"Normal"}}