Fix single column vim selections

Conrad Irwin created

Change summary

crates/editor/src/editor_tests.rs              | 15 +++++++++++++--
crates/editor/src/movement.rs                  |  2 ++
crates/gpui/src/text_layout.rs                 |  6 +++++-
crates/vim/src/normal/increment.rs             | 12 +++++++++++-
crates/vim/src/visual.rs                       |  8 ++++++--
crates/vim/test_data/test_increment_steps.json |  1 +
6 files changed, 38 insertions(+), 6 deletions(-)

Detailed changes

crates/editor/src/editor_tests.rs 🔗

@@ -851,7 +851,7 @@ fn test_move_cursor_multibyte(cx: &mut TestAppContext) {
 
     let view = cx
         .add_window(|cx| {
-            let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcde\nαβγδε\n", cx);
+            let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcde\nαβγδε", cx);
             build_editor(buffer.clone(), cx)
         })
         .root(cx);
@@ -869,7 +869,7 @@ fn test_move_cursor_multibyte(cx: &mut TestAppContext) {
             true,
             cx,
         );
-        assert_eq!(view.display_text(cx), "ⓐⓑ⋯ⓔ\nab⋯e\nαβ⋯ε\n");
+        assert_eq!(view.display_text(cx), "ⓐⓑ⋯ⓔ\nab⋯e\nαβ⋯ε");
 
         view.move_right(&MoveRight, cx);
         assert_eq!(
@@ -934,6 +934,17 @@ fn test_move_cursor_multibyte(cx: &mut TestAppContext) {
             view.selections.display_ranges(cx),
             &[empty_range(1, "ab⋯e".len())]
         );
+        view.move_down(&MoveDown, cx);
+        assert_eq!(
+            view.selections.display_ranges(cx),
+            &[empty_range(2, "αβ⋯ε".len())]
+        );
+        view.move_up(&MoveUp, cx);
+        assert_eq!(
+            view.selections.display_ranges(cx),
+            &[empty_range(1, "ab⋯e".len())]
+        );
+
         view.move_up(&MoveUp, cx);
         assert_eq!(
             view.selections.display_ranges(cx),

crates/editor/src/movement.rs 🔗

@@ -147,7 +147,9 @@ pub fn down_by_rows(
         goal_x = map.x_for_point(point, text_layout_details)
     }
 
+    dbg!(point);
     let mut clipped_point = map.clip_point(point, Bias::Right);
+    dbg!(clipped_point);
     if clipped_point.row() > point.row() {
         clipped_point = map.clip_point(point, Bias::Left);
     }

crates/gpui/src/text_layout.rs 🔗

@@ -302,7 +302,11 @@ impl Line {
                 prev_x = glyph.position.x();
             }
         }
-        prev_index
+        if self.width() - x < x - prev_x {
+            prev_index + 1
+        } else {
+            prev_index
+        }
     }
 
     pub fn paint(

crates/vim/src/normal/increment.rs 🔗

@@ -255,8 +255,18 @@ mod test {
             4
             5"})
             .await;
-        cx.simulate_shared_keystrokes(["shift-g", "ctrl-v", "g", "g", "g", "ctrl-x"])
+
+        cx.simulate_shared_keystrokes(["shift-g", "ctrl-v", "g", "g"])
+            .await;
+        cx.assert_shared_state(indoc! {"
+            «1ˇ»
+            «2ˇ»
+            «3ˇ»  2
+            «4ˇ»
+            «5ˇ»"})
             .await;
+
+        cx.simulate_shared_keystrokes(["g", "ctrl-x"]).await;
         cx.assert_shared_state(indoc! {"
             ˇ0
             0

crates/vim/src/visual.rs 🔗

@@ -169,10 +169,10 @@ pub fn visual_block_motion(
 
         let is_reversed = tail_x > head_x;
         if was_reversed && !is_reversed {
-            tail = movement::left(map, tail);
+            tail = movement::saturating_left(map, tail);
             tail_x = map.x_for_point(tail, &text_layout_details);
         } else if !was_reversed && is_reversed {
-            tail = movement::right(map, tail);
+            tail = movement::saturating_right(map, tail);
             tail_x = map.x_for_point(tail, &text_layout_details);
         }
         if !is_reversed && !preserve_goal {
@@ -180,8 +180,12 @@ pub fn visual_block_motion(
             head_x = map.x_for_point(head, &text_layout_details);
         }
 
+        dbg!(head, head_x, tail, tail_x);
+
         let positions = if is_reversed {
             head_x..tail_x
+        } else if head_x == tail_x {
+            map.x_for_point(movement::saturating_left(map, tail), &text_layout_details)..head_x
         } else {
             tail_x..head_x
         };

crates/vim/test_data/test_increment_steps.json 🔗

@@ -9,6 +9,7 @@
 {"Key":"ctrl-v"}
 {"Key":"g"}
 {"Key":"g"}
+{"Get":{"state":"«1ˇ»\n«2ˇ»\n«3ˇ»  2\n«4ˇ»\n«5ˇ»","mode":"VisualBlock"}}
 {"Key":"g"}
 {"Key":"ctrl-x"}
 {"Get":{"state":"ˇ0\n0\n0  2\n0\n0","mode":"Normal"}}