Skip to content

Commit 63ad4b0

Browse files
committed
feat(vim): Add delete action to HelixNormal mode
Related issue: #4642
1 parent 196fd65 commit 63ad4b0

File tree

2 files changed

+104
-1
lines changed

2 files changed

+104
-1
lines changed

assets/keymaps/vim.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@
331331
"bindings": {
332332
"i": "vim::InsertBefore",
333333
"a": "vim::InsertAfter",
334+
"d": "vim::HelixDelete",
334335
"w": "vim::NextWordStart",
335336
"e": "vim::NextWordEnd",
336337
"b": "vim::PreviousWordStart",

crates/vim/src/helix.rs

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ use ui::ViewContext;
55

66
use crate::{motion::Motion, state::Mode, Vim};
77

8-
actions!(vim, [HelixNormalAfter]);
8+
actions!(vim, [HelixNormalAfter, HelixDelete]);
99

1010
pub fn register(editor: &mut Editor, cx: &mut ViewContext<Vim>) {
1111
Vim::action(editor, cx, Vim::helix_normal_after);
12+
Vim::action(editor, cx, Vim::helix_delete);
1213
}
1314

1415
impl Vim {
@@ -226,6 +227,27 @@ impl Vim {
226227
_ => self.helix_move_and_collapse(motion, times, cx),
227228
}
228229
}
230+
231+
pub fn helix_delete(&mut self, _: &HelixDelete, cx: &mut ViewContext<Self>) {
232+
self.store_visual_marks(cx);
233+
self.update_editor(cx, |vim, editor, cx| {
234+
// Fixup selections so they have helix's semantics.
235+
// Specifically:
236+
// - Make sure that each cursor acts as a 1 character wide selection
237+
editor.transact(cx, |editor, cx| {
238+
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
239+
s.move_with(|map, selection| {
240+
if selection.is_empty() && !selection.reversed {
241+
selection.end = movement::right(map, selection.end);
242+
}
243+
});
244+
});
245+
});
246+
247+
vim.copy_selections_content(editor, false, cx);
248+
editor.insert("", cx);
249+
});
250+
}
229251
}
230252

231253
#[cfg(test)]
@@ -268,4 +290,84 @@ mod test {
268290
Mode::HelixNormal,
269291
);
270292
}
293+
294+
#[gpui::test]
295+
async fn test_delete(cx: &mut gpui::TestAppContext) {
296+
let mut cx = VimTestContext::new(cx, true).await;
297+
298+
// test delete a selection
299+
cx.set_state(
300+
indoc! {"
301+
The qu«ick ˇ»brown
302+
fox jumps over
303+
the lazy dog."},
304+
Mode::HelixNormal,
305+
);
306+
307+
cx.simulate_keystrokes("d");
308+
309+
cx.assert_state(
310+
indoc! {"
311+
The quˇbrown
312+
fox jumps over
313+
the lazy dog."},
314+
Mode::HelixNormal,
315+
);
316+
317+
// test deleting a single character
318+
cx.simulate_keystrokes("d");
319+
320+
cx.assert_state(
321+
indoc! {"
322+
The quˇrown
323+
fox jumps over
324+
the lazy dog."},
325+
Mode::HelixNormal,
326+
);
327+
}
328+
329+
#[gpui::test]
330+
async fn test_delete_character_end_of_line(cx: &mut gpui::TestAppContext) {
331+
let mut cx = VimTestContext::new(cx, true).await;
332+
333+
cx.set_state(
334+
indoc! {"
335+
The quick brownˇ
336+
fox jumps over
337+
the lazy dog."},
338+
Mode::HelixNormal,
339+
);
340+
341+
cx.simulate_keystrokes("d");
342+
343+
cx.assert_state(
344+
indoc! {"
345+
The quick brownˇfox jumps over
346+
the lazy dog."},
347+
Mode::HelixNormal,
348+
);
349+
}
350+
351+
#[gpui::test]
352+
async fn test_delete_character_end_of_buffer(cx: &mut gpui::TestAppContext) {
353+
let mut cx = VimTestContext::new(cx, true).await;
354+
355+
cx.set_state(
356+
indoc! {"
357+
The quick brown
358+
fox jumps over
359+
the lazy dog.ˇ"},
360+
Mode::HelixNormal,
361+
);
362+
363+
cx.simulate_keystrokes("d");
364+
365+
cx.assert_state(
366+
indoc! {"
367+
The quick brown
368+
fox jumps over
369+
the lazy dog.ˇ"},
370+
Mode::HelixNormal,
371+
);
372+
}
271373
}

0 commit comments

Comments
 (0)