vim: Add sneak motion (#22793)

A (re)continuation of https://github.com/zed-industries/zed/pull/21067. 

This takes the original implementation in
https://github.com/zed-industries/zed/pull/15572 and adds the test in
https://github.com/zed-industries/zed/pull/21067. Then, as requested in
https://github.com/zed-industries/zed/pull/21067#issuecomment-2515469185,
it documents how to map a keybinding instead of having a setting.

Closes #13858

Release Notes:

- Added support for the popular
[vim_sneak](https://github.com/justinmk/vim-sneak) plugin. This is
disabled by default and can be enabled by binding a key to the `Sneak`
and `SneakBackward` operators.

Reference:
https://github.com/justinmk/vim-sneak

---------

Co-authored-by: Kajetan Puchalski <kajetan.puchalski@tuta.io>
Co-authored-by: Aidan Grant <mraidangrant@gmail.com>
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
Nico Lehmann 2025-01-10 04:07:32 -03:00 committed by GitHub
parent 0d6a549950
commit 0b105ba8b7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 301 additions and 5 deletions

View file

@ -80,9 +80,11 @@ actions!(
InnerObject,
FindForward,
FindBackward,
OpenDefaultKeymap,
MaximizePane,
OpenDefaultKeymap,
ResetPaneSizes,
Sneak,
SneakBackward,
]
);
@ -1093,6 +1095,40 @@ impl Vim {
Vim::globals(cx).last_find = Some(find.clone());
self.motion(find, cx)
}
Some(Operator::Sneak { first_char }) => {
if let Some(first_char) = first_char {
if let Some(second_char) = text.chars().next() {
let sneak = Motion::Sneak {
first_char,
second_char,
smartcase: VimSettings::get_global(cx).use_smartcase_find,
};
Vim::globals(cx).last_find = Some((&sneak).clone());
self.motion(sneak, cx)
}
} else {
let first_char = text.chars().next();
self.pop_operator(cx);
self.push_operator(Operator::Sneak { first_char }, cx);
}
}
Some(Operator::SneakBackward { first_char }) => {
if let Some(first_char) = first_char {
if let Some(second_char) = text.chars().next() {
let sneak = Motion::SneakBackward {
first_char,
second_char,
smartcase: VimSettings::get_global(cx).use_smartcase_find,
};
Vim::globals(cx).last_find = Some((&sneak).clone());
self.motion(sneak, cx)
}
} else {
let first_char = text.chars().next();
self.pop_operator(cx);
self.push_operator(Operator::SneakBackward { first_char }, cx);
}
}
Some(Operator::Replace) => match self.mode {
Mode::Normal => self.normal_replace(text, cx),
Mode::Visual | Mode::VisualLine | Mode::VisualBlock => {