vim: Allow count and repeat for "r" and "shift-r" action (#13287)

Fixing the "r" action just involved adapting `normal_replace` to replace
multiple characters.

Fixing the "shift-r" command was less straightforward. The bindings for
`vim::BeforeNormal` in replace mode were being overwritten and several
other steps required for action repetition were not performed. Finally,
the cursor adjustment after re-entering normal mode was duplicated
(`vim::BeforeNormal` was now triggered correctly) so I removed the
special case for replace mode.

Release Notes:

- Fixed vim "r" action to accept a count argument
- Fixed vim "shift-r" action to accept a count argument and allow
repetition

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
Benjamin Davies 2024-06-25 03:41:33 +12:00 committed by GitHub
parent 77b2da2b42
commit dea928b00c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 109 additions and 10 deletions

View file

@ -484,6 +484,7 @@ fn restore_selection_cursors(
pub(crate) fn normal_replace(text: Arc<str>, cx: &mut WindowContext) {
Vim::update(cx, |vim, cx| {
let count = vim.take_count(cx).unwrap_or(1);
vim.stop_recording();
vim.update_active_editor(cx, |_, editor, cx| {
editor.transact(cx, |editor, cx| {
@ -506,13 +507,13 @@ pub(crate) fn normal_replace(text: Arc<str>, cx: &mut WindowContext) {
.into_iter()
.map(|selection| {
let mut range = selection.range();
*range.end.column_mut() += 1;
range.end = map.clip_point(range.end, Bias::Right);
range.end = right(&map, range.end, count);
let repeated_text = text.repeat(count);
(
range.start.to_offset(&map, Bias::Left)
..range.end.to_offset(&map, Bias::Left),
text.clone(),
repeated_text,
)
})
.collect::<Vec<_>>();
@ -523,6 +524,11 @@ pub(crate) fn normal_replace(text: Arc<str>, cx: &mut WindowContext) {
editor.set_clip_at_line_ends(true, cx);
editor.change_selections(None, cx, |s| {
s.select_anchor_ranges(stable_anchors);
if count > 1 {
s.move_cursors_with(|map, point, _| {
(right(map, point, count - 1), SelectionGoal::None)
});
}
});
});
});
@ -1415,4 +1421,25 @@ mod test {
indoc! {"asserˇt_binding"},
);
}
#[gpui::test]
async fn test_r(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("ˇhello\n").await;
cx.simulate_shared_keystrokes("r -").await;
cx.shared_state().await.assert_eq("ˇ-ello\n");
cx.set_shared_state("ˇhello\n").await;
cx.simulate_shared_keystrokes("3 r -").await;
cx.shared_state().await.assert_eq("--ˇ-lo\n");
cx.set_shared_state("ˇhello\n").await;
cx.simulate_shared_keystrokes("r - 2 l .").await;
cx.shared_state().await.assert_eq("-eˇ-lo\n");
cx.set_shared_state("ˇhello world\n").await;
cx.simulate_shared_keystrokes("2 r - f w .").await;
cx.shared_state().await.assert_eq("--llo -ˇ-rld\n");
}
}