vim: Add some forced motion support (#27991)

Closes https://github.com/zed-industries/zed/issues/20971

Added `v` input to yank and delete to override default motion. The
global vim state tracking if the forced motion flag was passed handled
the same way that the count is. [The main chunk of code maps the motion
kind from the default to the overridden
kind](https://github.com/zed-industries/zed/pull/27991/files#diff-2dca6b7d1673c912d14e4edc74e415abbe3a4e6d6b37e0e2006d30828bf4bb9cR1249-R1254).
To handle the case of deleting a single character (dv0) at the start of
a row I had to modify the control flow
[here](https://github.com/zed-industries/zed/pull/27991/files#diff-2dca6b7d1673c912d14e4edc74e415abbe3a4e6d6b37e0e2006d30828bf4bb9cR1240-R1244).
Then to handle an exclusive delete till the end of the row (dv$) I
[saturated the endpoint with a left
bias](https://github.com/zed-industries/zed/pull/27991/files#diff-2dca6b7d1673c912d14e4edc74e415abbe3a4e6d6b37e0e2006d30828bf4bb9cR1281-R1286).

Test case: dv0


https://github.com/user-attachments/assets/613cf9fb-9732-425c-9179-025f3e107584

Test case: yvjp


https://github.com/user-attachments/assets/550b7c77-1eb8-41c3-894b-117eb50b7a5d

Release Notes:

- Added some forced motion support for delete and yank
This commit is contained in:
Peter Finn 2025-04-11 10:12:30 -07:00 committed by GitHub
parent 1df01eabfe
commit 08ce230bae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 485 additions and 58 deletions

View file

@ -85,6 +85,7 @@ pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
Vim::action(editor, cx, |vim, _: &SelectLargerSyntaxNode, window, cx| {
let count = Vim::take_count(cx).unwrap_or(1);
Vim::take_forced_motion(cx);
for _ in 0..count {
vim.update_editor(window, cx, |_, editor, window, cx| {
editor.select_larger_syntax_node(&Default::default(), window, cx);
@ -97,6 +98,7 @@ pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
cx,
|vim, _: &SelectSmallerSyntaxNode, window, cx| {
let count = Vim::take_count(cx).unwrap_or(1);
Vim::take_forced_motion(cx);
for _ in 0..count {
vim.update_editor(window, cx, |_, editor, window, cx| {
editor.select_smaller_syntax_node(&Default::default(), window, cx);
@ -682,6 +684,7 @@ impl Vim {
}
pub fn select_next(&mut self, _: &SelectNext, window: &mut Window, cx: &mut Context<Self>) {
Vim::take_forced_motion(cx);
let count =
Vim::take_count(cx).unwrap_or_else(|| if self.mode.is_visual() { 1 } else { 2 });
self.update_editor(window, cx, |_, editor, window, cx| {
@ -704,6 +707,7 @@ impl Vim {
window: &mut Window,
cx: &mut Context<Self>,
) {
Vim::take_forced_motion(cx);
let count =
Vim::take_count(cx).unwrap_or_else(|| if self.mode.is_visual() { 1 } else { 2 });
self.update_editor(window, cx, |_, editor, window, cx| {
@ -725,6 +729,7 @@ impl Vim {
window: &mut Window,
cx: &mut Context<Self>,
) {
Vim::take_forced_motion(cx);
let count = Vim::take_count(cx).unwrap_or(1);
let Some(pane) = self.pane(window, cx) else {
return;