@@ -172,6 +172,13 @@ pub(crate) fn repeat(cx: &mut WindowContext, from_insert_mode: bool) {
editor.show_local_selections = false;
})?;
for action in actions {
+ if !matches!(
+ cx.update(|cx| Vim::read(cx).workspace_state.replaying),
+ Ok(true)
+ ) {
+ break;
+ }
+
match action {
ReplayableAction::Action(action) => {
if should_replay(&action) {
@@ -341,6 +341,10 @@ impl Vim {
}
}
+ pub fn stop_replaying(&mut self) {
+ self.workspace_state.replaying = false;
+ }
+
/// When finishing an action that modifies the buffer, stop recording.
/// as you usually call this within a keystroke handler we also ensure that
/// the current action is recorded.
@@ -499,6 +503,7 @@ impl Vim {
self.sync_vim_settings(cx);
popped_operator
}
+
fn clear_operator(&mut self, cx: &mut WindowContext) {
self.take_count(cx);
self.update_state(|state| state.operator_stack.clear());
@@ -509,7 +509,6 @@ pub fn select_match(
vim.update_active_editor(cx, |_, editor, _| {
editor.set_collapse_matches(false);
});
-
if vim_is_normal {
pane.update(cx, |pane, cx| {
if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<BufferSearchBar>() {
@@ -521,21 +520,27 @@ pub fn select_match(
}
});
}
-
vim.update_active_editor(cx, |_, editor, cx| {
let latest = editor.selections.newest::<usize>(cx);
start_selection = latest.start;
end_selection = latest.end;
});
+ let mut match_exists = false;
pane.update(cx, |pane, cx| {
if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<BufferSearchBar>() {
search_bar.update(cx, |search_bar, cx| {
search_bar.update_match_index(cx);
search_bar.select_match(direction, count, cx);
+ match_exists = search_bar.match_exists(cx);
});
}
});
+ if !match_exists {
+ vim.clear_operator(cx);
+ vim.stop_replaying();
+ return;
+ }
vim.update_active_editor(cx, |_, editor, cx| {
let latest = editor.selections.newest::<usize>(cx);
if vim_is_normal {
@@ -553,6 +558,7 @@ pub fn select_match(
});
editor.set_collapse_matches(true);
});
+
match vim.maybe_pop_operator() {
Some(Operator::Change) => substitute(vim, None, false, cx),
Some(Operator::Delete) => {
@@ -561,7 +567,7 @@ pub fn select_match(
}
Some(Operator::Yank) => yank(vim, cx),
_ => {} // Ignoring other operators
- };
+ }
}
#[cfg(test)]
@@ -1195,4 +1201,29 @@ mod test {
cx.simulate_shared_keystrokes(["."]).await;
cx.assert_shared_state("aa x ˇx aa aa").await;
}
+
+ #[gpui::test]
+ async fn test_cgn_nomatch(cx: &mut gpui::TestAppContext) {
+ let mut cx = NeovimBackedTestContext::new(cx).await;
+
+ cx.set_shared_state("aaˇ aa aa aa aa").await;
+ cx.simulate_shared_keystrokes(["/", "b", "b", "enter"])
+ .await;
+ cx.assert_shared_state("aaˇ aa aa aa aa").await;
+ cx.simulate_shared_keystrokes(["c", "g", "n", "x", "escape"])
+ .await;
+ cx.assert_shared_state("aaˇaa aa aa aa").await;
+ cx.simulate_shared_keystrokes(["."]).await;
+ cx.assert_shared_state("aaˇa aa aa aa").await;
+
+ cx.set_shared_state("aaˇ bb aa aa aa").await;
+ cx.simulate_shared_keystrokes(["/", "b", "b", "enter"])
+ .await;
+ cx.assert_shared_state("aa ˇbb aa aa aa").await;
+ cx.simulate_shared_keystrokes(["c", "g", "n", "x", "escape"])
+ .await;
+ cx.assert_shared_state("aa ˇx aa aa aa").await;
+ cx.simulate_shared_keystrokes(["."]).await;
+ cx.assert_shared_state("aa ˇx aa aa aa").await;
+ }
}
@@ -0,0 +1,28 @@
+{"Put":{"state":"aaˇ aa aa aa aa"}}
+{"Key":"/"}
+{"Key":"b"}
+{"Key":"b"}
+{"Key":"enter"}
+{"Get":{"state":"aaˇ aa aa aa aa","mode":"Normal"}}
+{"Key":"c"}
+{"Key":"g"}
+{"Key":"n"}
+{"Key":"x"}
+{"Key":"escape"}
+{"Get":{"state":"aaˇaa aa aa aa","mode":"Normal"}}
+{"Key":"."}
+{"Get":{"state":"aaˇa aa aa aa","mode":"Normal"}}
+{"Put":{"state":"aaˇ bb aa aa aa"}}
+{"Key":"/"}
+{"Key":"b"}
+{"Key":"b"}
+{"Key":"enter"}
+{"Get":{"state":"aa ˇbb aa aa aa","mode":"Normal"}}
+{"Key":"c"}
+{"Key":"g"}
+{"Key":"n"}
+{"Key":"x"}
+{"Key":"escape"}
+{"Get":{"state":"aa ˇx aa aa aa","mode":"Normal"}}
+{"Key":"."}
+{"Get":{"state":"aa ˇx aa aa aa","mode":"Normal"}}