mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-19 02:17:35 +03:00
vim: fix t
not being repeatable with ,
(#7007)
This fixes `t` not being repeatable with `,` and `;` in normal mode. Release Notes: - Fixed `t` in Vim mode not being repeatable with `,` or `;`. --------- Co-authored-by: Conrad <conrad@zed.dev>
This commit is contained in:
parent
843916d585
commit
cddc0fbf92
@ -330,12 +330,7 @@
|
|||||||
"*": "vim::MoveToNext",
|
"*": "vim::MoveToNext",
|
||||||
"#": "vim::MoveToPrev",
|
"#": "vim::MoveToPrev",
|
||||||
";": "vim::RepeatFind",
|
";": "vim::RepeatFind",
|
||||||
",": [
|
",": "vim::RepeatFindReversed",
|
||||||
"vim::RepeatFind",
|
|
||||||
{
|
|
||||||
"backwards": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"r": ["vim::PushOperator", "Replace"],
|
"r": ["vim::PushOperator", "Replace"],
|
||||||
"s": "vim::Substitute",
|
"s": "vim::Substitute",
|
||||||
"shift-s": "vim::SubstituteLine",
|
"shift-s": "vim::SubstituteLine",
|
||||||
|
@ -37,6 +37,8 @@ pub enum Motion {
|
|||||||
Matching,
|
Matching,
|
||||||
FindForward { before: bool, char: char },
|
FindForward { before: bool, char: char },
|
||||||
FindBackward { after: bool, char: char },
|
FindBackward { after: bool, char: char },
|
||||||
|
RepeatFind { last_find: Box<Motion> },
|
||||||
|
RepeatFindReversed { last_find: Box<Motion> },
|
||||||
NextLineStart,
|
NextLineStart,
|
||||||
StartOfLineDownward,
|
StartOfLineDownward,
|
||||||
EndOfLineDownward,
|
EndOfLineDownward,
|
||||||
@ -102,16 +104,9 @@ pub struct StartOfLine {
|
|||||||
pub(crate) display_lines: bool,
|
pub(crate) display_lines: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, PartialEq)]
|
|
||||||
struct RepeatFind {
|
|
||||||
#[serde(default)]
|
|
||||||
backwards: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_actions!(
|
impl_actions!(
|
||||||
vim,
|
vim,
|
||||||
[
|
[
|
||||||
RepeatFind,
|
|
||||||
StartOfLine,
|
StartOfLine,
|
||||||
EndOfLine,
|
EndOfLine,
|
||||||
FirstNonWhitespace,
|
FirstNonWhitespace,
|
||||||
@ -139,6 +134,8 @@ actions!(
|
|||||||
StartOfLineDownward,
|
StartOfLineDownward,
|
||||||
EndOfLineDownward,
|
EndOfLineDownward,
|
||||||
GoToColumn,
|
GoToColumn,
|
||||||
|
RepeatFind,
|
||||||
|
RepeatFindReversed,
|
||||||
WindowTop,
|
WindowTop,
|
||||||
WindowMiddle,
|
WindowMiddle,
|
||||||
WindowBottom,
|
WindowBottom,
|
||||||
@ -234,8 +231,27 @@ pub fn register(workspace: &mut Workspace, _: &mut ViewContext<Workspace>) {
|
|||||||
});
|
});
|
||||||
workspace
|
workspace
|
||||||
.register_action(|_: &mut Workspace, &GoToColumn, cx: _| motion(Motion::GoToColumn, cx));
|
.register_action(|_: &mut Workspace, &GoToColumn, cx: _| motion(Motion::GoToColumn, cx));
|
||||||
workspace.register_action(|_: &mut Workspace, action: &RepeatFind, cx: _| {
|
|
||||||
repeat_motion(action.backwards, cx)
|
workspace.register_action(|_: &mut Workspace, _: &RepeatFind, cx: _| {
|
||||||
|
if let Some(last_find) = Vim::read(cx)
|
||||||
|
.workspace_state
|
||||||
|
.last_find
|
||||||
|
.clone()
|
||||||
|
.map(Box::new)
|
||||||
|
{
|
||||||
|
motion(Motion::RepeatFind { last_find }, cx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
workspace.register_action(|_: &mut Workspace, _: &RepeatFindReversed, cx: _| {
|
||||||
|
if let Some(last_find) = Vim::read(cx)
|
||||||
|
.workspace_state
|
||||||
|
.last_find
|
||||||
|
.clone()
|
||||||
|
.map(Box::new)
|
||||||
|
{
|
||||||
|
motion(Motion::RepeatFindReversed { last_find }, cx);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
workspace.register_action(|_: &mut Workspace, &WindowTop, cx: _| motion(Motion::WindowTop, cx));
|
workspace.register_action(|_: &mut Workspace, &WindowTop, cx: _| motion(Motion::WindowTop, cx));
|
||||||
workspace.register_action(|_: &mut Workspace, &WindowMiddle, cx: _| {
|
workspace.register_action(|_: &mut Workspace, &WindowMiddle, cx: _| {
|
||||||
@ -265,35 +281,6 @@ pub(crate) fn motion(motion: Motion, cx: &mut WindowContext) {
|
|||||||
Vim::update(cx, |vim, cx| vim.clear_operator(cx));
|
Vim::update(cx, |vim, cx| vim.clear_operator(cx));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn repeat_motion(backwards: bool, cx: &mut WindowContext) {
|
|
||||||
let find = match Vim::read(cx).workspace_state.last_find.clone() {
|
|
||||||
Some(Motion::FindForward { before, char }) => {
|
|
||||||
if backwards {
|
|
||||||
Motion::FindBackward {
|
|
||||||
after: before,
|
|
||||||
char,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Motion::FindForward { before, char }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(Motion::FindBackward { after, char }) => {
|
|
||||||
if backwards {
|
|
||||||
Motion::FindForward {
|
|
||||||
before: after,
|
|
||||||
char,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Motion::FindBackward { after, char }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
motion(find, cx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Motion handling is specified here:
|
// Motion handling is specified here:
|
||||||
// https://github.com/vim/vim/blob/master/runtime/doc/motion.txt
|
// https://github.com/vim/vim/blob/master/runtime/doc/motion.txt
|
||||||
impl Motion {
|
impl Motion {
|
||||||
@ -325,7 +312,9 @@ impl Motion {
|
|||||||
| NextWordStart { .. }
|
| NextWordStart { .. }
|
||||||
| PreviousWordStart { .. }
|
| PreviousWordStart { .. }
|
||||||
| FirstNonWhitespace { .. }
|
| FirstNonWhitespace { .. }
|
||||||
| FindBackward { .. } => false,
|
| FindBackward { .. }
|
||||||
|
| RepeatFind { .. }
|
||||||
|
| RepeatFindReversed { .. } => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,6 +328,7 @@ impl Motion {
|
|||||||
| NextWordEnd { .. }
|
| NextWordEnd { .. }
|
||||||
| Matching
|
| Matching
|
||||||
| FindForward { .. }
|
| FindForward { .. }
|
||||||
|
| RepeatFind { .. }
|
||||||
| Left
|
| Left
|
||||||
| Backspace
|
| Backspace
|
||||||
| Right
|
| Right
|
||||||
@ -352,6 +342,7 @@ impl Motion {
|
|||||||
| PreviousWordStart { .. }
|
| PreviousWordStart { .. }
|
||||||
| FirstNonWhitespace { .. }
|
| FirstNonWhitespace { .. }
|
||||||
| FindBackward { .. }
|
| FindBackward { .. }
|
||||||
|
| RepeatFindReversed { .. }
|
||||||
| WindowTop
|
| WindowTop
|
||||||
| WindowMiddle
|
| WindowMiddle
|
||||||
| WindowBottom
|
| WindowBottom
|
||||||
@ -388,6 +379,9 @@ impl Motion {
|
|||||||
| PreviousWordStart { .. }
|
| PreviousWordStart { .. }
|
||||||
| FirstNonWhitespace { .. }
|
| FirstNonWhitespace { .. }
|
||||||
| FindBackward { .. } => false,
|
| FindBackward { .. } => false,
|
||||||
|
RepeatFind { last_find: motion } | RepeatFindReversed { last_find: motion } => {
|
||||||
|
motion.inclusive()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,17 +450,58 @@ impl Motion {
|
|||||||
SelectionGoal::None,
|
SelectionGoal::None,
|
||||||
),
|
),
|
||||||
Matching => (matching(map, point), SelectionGoal::None),
|
Matching => (matching(map, point), SelectionGoal::None),
|
||||||
|
// t f
|
||||||
FindForward { before, char } => {
|
FindForward { before, char } => {
|
||||||
if let Some(new_point) = find_forward(map, point, *before, *char, times) {
|
return find_forward(map, point, *before, *char, times)
|
||||||
return Some((new_point, SelectionGoal::None));
|
.map(|new_point| (new_point, SelectionGoal::None))
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// T F
|
||||||
FindBackward { after, char } => (
|
FindBackward { after, char } => (
|
||||||
find_backward(map, point, *after, *char, times),
|
find_backward(map, point, *after, *char, times),
|
||||||
SelectionGoal::None,
|
SelectionGoal::None,
|
||||||
),
|
),
|
||||||
|
// ; -- repeat the last find done with t, f, T, F
|
||||||
|
RepeatFind { last_find } => match **last_find {
|
||||||
|
Motion::FindForward { before, char } => {
|
||||||
|
let mut new_point = find_forward(map, point, before, char, times);
|
||||||
|
if new_point == Some(point) {
|
||||||
|
new_point = find_forward(map, point, before, char, times + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_point.map(|new_point| (new_point, SelectionGoal::None));
|
||||||
|
}
|
||||||
|
|
||||||
|
Motion::FindBackward { after, char } => {
|
||||||
|
let mut new_point = find_backward(map, point, after, char, times);
|
||||||
|
if new_point == point {
|
||||||
|
new_point = find_backward(map, point, after, char, times + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
(new_point, SelectionGoal::None)
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
},
|
||||||
|
// , -- repeat the last find done with t, f, T, F, in opposite direction
|
||||||
|
RepeatFindReversed { last_find } => match **last_find {
|
||||||
|
Motion::FindForward { before, char } => {
|
||||||
|
let mut new_point = find_backward(map, point, before, char, times);
|
||||||
|
if new_point == point {
|
||||||
|
new_point = find_backward(map, point, before, char, times + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
(new_point, SelectionGoal::None)
|
||||||
|
}
|
||||||
|
|
||||||
|
Motion::FindBackward { after, char } => {
|
||||||
|
let mut new_point = find_forward(map, point, after, char, times);
|
||||||
|
if new_point == Some(point) {
|
||||||
|
new_point = find_forward(map, point, after, char, times + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_point.map(|new_point| (new_point, SelectionGoal::None));
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
},
|
||||||
NextLineStart => (next_line_start(map, point, times), SelectionGoal::None),
|
NextLineStart => (next_line_start(map, point, times), SelectionGoal::None),
|
||||||
StartOfLineDownward => (next_line_start(map, point, times - 1), SelectionGoal::None),
|
StartOfLineDownward => (next_line_start(map, point, times - 1), SelectionGoal::None),
|
||||||
EndOfLineDownward => (next_line_end(map, point, times), SelectionGoal::None),
|
EndOfLineDownward => (next_line_end(map, point, times), SelectionGoal::None),
|
||||||
@ -1155,6 +1190,7 @@ mod test {
|
|||||||
async fn test_comma_semicolon(cx: &mut gpui::TestAppContext) {
|
async fn test_comma_semicolon(cx: &mut gpui::TestAppContext) {
|
||||||
let mut cx = NeovimBackedTestContext::new(cx).await;
|
let mut cx = NeovimBackedTestContext::new(cx).await;
|
||||||
|
|
||||||
|
// f and F
|
||||||
cx.set_shared_state("ˇone two three four").await;
|
cx.set_shared_state("ˇone two three four").await;
|
||||||
cx.simulate_shared_keystrokes(["f", "o"]).await;
|
cx.simulate_shared_keystrokes(["f", "o"]).await;
|
||||||
cx.assert_shared_state("one twˇo three four").await;
|
cx.assert_shared_state("one twˇo three four").await;
|
||||||
@ -1162,6 +1198,21 @@ mod test {
|
|||||||
cx.assert_shared_state("ˇone two three four").await;
|
cx.assert_shared_state("ˇone two three four").await;
|
||||||
cx.simulate_shared_keystrokes(["2", ";"]).await;
|
cx.simulate_shared_keystrokes(["2", ";"]).await;
|
||||||
cx.assert_shared_state("one two three fˇour").await;
|
cx.assert_shared_state("one two three fˇour").await;
|
||||||
|
cx.simulate_shared_keystrokes(["shift-f", "e"]).await;
|
||||||
|
cx.assert_shared_state("one two threˇe four").await;
|
||||||
|
cx.simulate_shared_keystrokes(["2", ";"]).await;
|
||||||
|
cx.assert_shared_state("onˇe two three four").await;
|
||||||
|
cx.simulate_shared_keystrokes([","]).await;
|
||||||
|
cx.assert_shared_state("one two thrˇee four").await;
|
||||||
|
|
||||||
|
// t and T
|
||||||
|
cx.set_shared_state("ˇone two three four").await;
|
||||||
|
cx.simulate_shared_keystrokes(["t", "o"]).await;
|
||||||
|
cx.assert_shared_state("one tˇwo three four").await;
|
||||||
|
cx.simulate_shared_keystrokes([","]).await;
|
||||||
|
cx.assert_shared_state("oˇne two three four").await;
|
||||||
|
cx.simulate_shared_keystrokes(["2", ";"]).await;
|
||||||
|
cx.assert_shared_state("one two three ˇfour").await;
|
||||||
cx.simulate_shared_keystrokes(["shift-t", "e"]).await;
|
cx.simulate_shared_keystrokes(["shift-t", "e"]).await;
|
||||||
cx.assert_shared_state("one two threeˇ four").await;
|
cx.assert_shared_state("one two threeˇ four").await;
|
||||||
cx.simulate_shared_keystrokes(["3", ";"]).await;
|
cx.simulate_shared_keystrokes(["3", ";"]).await;
|
||||||
|
@ -7,6 +7,23 @@
|
|||||||
{"Key":"2"}
|
{"Key":"2"}
|
||||||
{"Key":";"}
|
{"Key":";"}
|
||||||
{"Get":{"state":"one two three fˇour","mode":"Normal"}}
|
{"Get":{"state":"one two three fˇour","mode":"Normal"}}
|
||||||
|
{"Key":"shift-f"}
|
||||||
|
{"Key":"e"}
|
||||||
|
{"Get":{"state":"one two threˇe four","mode":"Normal"}}
|
||||||
|
{"Key":"2"}
|
||||||
|
{"Key":";"}
|
||||||
|
{"Get":{"state":"onˇe two three four","mode":"Normal"}}
|
||||||
|
{"Key":","}
|
||||||
|
{"Get":{"state":"one two thrˇee four","mode":"Normal"}}
|
||||||
|
{"Put":{"state":"ˇone two three four"}}
|
||||||
|
{"Key":"t"}
|
||||||
|
{"Key":"o"}
|
||||||
|
{"Get":{"state":"one tˇwo three four","mode":"Normal"}}
|
||||||
|
{"Key":","}
|
||||||
|
{"Get":{"state":"oˇne two three four","mode":"Normal"}}
|
||||||
|
{"Key":"2"}
|
||||||
|
{"Key":";"}
|
||||||
|
{"Get":{"state":"one two three ˇfour","mode":"Normal"}}
|
||||||
{"Key":"shift-t"}
|
{"Key":"shift-t"}
|
||||||
{"Key":"e"}
|
{"Key":"e"}
|
||||||
{"Get":{"state":"one two threeˇ four","mode":"Normal"}}
|
{"Get":{"state":"one two threeˇ four","mode":"Normal"}}
|
||||||
|
Loading…
Reference in New Issue
Block a user