When using `$` to move to the end of line (`vim::EndOfLine`), the
`vim::motion::Motion.move_point` method checks whether the new point,
that is, the point after the motion is applied is different from the
point that was passed as a method argument. If the point is not
different, the point and selection goals are only updated if
`vim::motion::Motion.infallible` returns true for the motion in
question.
In short, this means that, if the cursor was already at the end of the
line, and it got there using `vim::Right`, for example, the selection
goal wouldn't actually be set to
`SelectionGoal::HorizontalPosition(f64::INFINITY)`, so when the cursor
was moved to a shorter line, it wouldn't be set at the end of that line,
even though `$` had been used.
This commit updates `vim::motion::Motion.infallible` to ensure that, for
`vim::motion::Motion::EndOfLine`, it returns `true`, so that the
selection goal is always updated, regardless of whether the cursor is
already at the end of the line.
Closes #48855
- [X] Tests or screenshots needed?
- [X] Code Reviewed
- [X] Manual QA
Release Notes:
- vim: Fixed `$` not sticking to end-of-line on vertical motions
(`j`/`k`) when the cursor was already at the end of the line via `l` or
arrow keys
@@ -899,10 +899,9 @@ impl Motion {
pub fn infallible(&self) -> bool {
use Motion::*;
match self {
- StartOfDocument | EndOfDocument | CurrentLine => true,
+ StartOfDocument | EndOfDocument | CurrentLine | EndOfLine { .. } => true,
Down { .. }
| Up { .. }
- | EndOfLine { .. }
| MiddleOfLine { .. }
| Matching { .. }
| UnmatchedForward { .. }
@@ -3901,6 +3900,29 @@ mod test {
jumps over the
lazy dog
"});
+
+ // Test that, when the cursor is moved to the end of the line using `l`,
+ // if `$` is used, the cursor stays at the end of the line when moving
+ // to a longer line, ensuring that the selection goal was correctly
+ // updated.
+ cx.set_shared_state(indoc! {"
+ The quick brown fox
+ jumps over the
+ lazy dˇog
+ "})
+ .await;
+ cx.simulate_shared_keystrokes("l").await;
+ cx.shared_state().await.assert_eq(indoc! {"
+ The quick brown fox
+ jumps over the
+ lazy doˇg
+ "});
+ cx.simulate_shared_keystrokes("$ k").await;
+ cx.shared_state().await.assert_eq(indoc! {"
+ The quick brown fox
+ jumps over thˇe
+ lazy dog
+ "});
}
#[gpui::test]
@@ -14,3 +14,9 @@
{"Get":{"state":"The quick brown fox\njumps ˇover the\nlazy dog\n","mode":"Normal"}}
{"Key":"k"}
{"Get":{"state":"The quˇick brown fox\njumps over the\nlazy dog\n","mode":"Normal"}}
+{"Put":{"state":"The quick brown fox\njumps over the\nlazy dˇog\n"}}
+{"Key":"l"}
+{"Get":{"state":"The quick brown fox\njumps over the\nlazy doˇg\n","mode":"Normal"}}
+{"Key":"$"}
+{"Key":"k"}
+{"Get":{"state":"The quick brown fox\njumps over thˇe\nlazy dog\n","mode":"Normal"}}