Skip to content

Commit

Permalink
feat(vim): Add delete action to HelixNormal mode
Browse files Browse the repository at this point in the history
Related issue: zed-industries#4642
  • Loading branch information
leroycep committed Dec 4, 2024
1 parent 196fd65 commit 9263d98
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 1 deletion.
1 change: 1 addition & 0 deletions assets/keymaps/vim.json
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@
"bindings": {
"i": "vim::InsertBefore",
"a": "vim::InsertAfter",
"d": "vim::HelixDelete",
"w": "vim::NextWordStart",
"e": "vim::NextWordEnd",
"b": "vim::PreviousWordStart",
Expand Down
110 changes: 109 additions & 1 deletion crates/vim/src/helix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ use ui::ViewContext;

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

actions!(vim, [HelixNormalAfter]);
actions!(vim, [HelixNormalAfter, HelixDelete]);

pub fn register(editor: &mut Editor, cx: &mut ViewContext<Vim>) {
Vim::action(editor, cx, Vim::helix_normal_after);
Vim::action(editor, cx, Vim::helix_delete);
}

impl Vim {
Expand Down Expand Up @@ -226,6 +227,33 @@ impl Vim {
_ => self.helix_move_and_collapse(motion, times, cx),
}
}

pub fn helix_delete(&mut self, _: &HelixDelete, cx: &mut ViewContext<Self>) {
self.store_visual_marks(cx);
self.update_editor(cx, |vim, editor, cx| {
// Fixup selections so they have helix's semantics.
// Specifically:
// - Make sure that each cursor acts as a 1 character wide selection
editor.transact(cx, |editor, cx| {
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.move_with(|map, selection| {
if selection.is_empty() && !selection.reversed {
*selection.end.column_mut() += 1;

// if we're at the end of the line, select the newline for deletion
if selection.end.column() > map.line_len(selection.end.row()) {
*selection.end.row_mut() += 1;
*selection.end.column_mut() = 0;
}
}
});
});
});

vim.copy_selections_content(editor, false, cx);
editor.insert("", cx);
});
}
}

#[cfg(test)]
Expand Down Expand Up @@ -268,4 +296,84 @@ mod test {
Mode::HelixNormal,
);
}

#[gpui::test]
async fn test_delete(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await;

// test delete a selection
cx.set_state(
indoc! {"
The qu«ick ˇ»brown
fox jumps over
the lazy dog."},
Mode::HelixNormal,
);

cx.simulate_keystrokes("d");

cx.assert_state(
indoc! {"
The quˇbrown
fox jumps over
the lazy dog."},
Mode::HelixNormal,
);

// test deleting a single character
cx.simulate_keystrokes("d");

cx.assert_state(
indoc! {"
The quˇrown
fox jumps over
the lazy dog."},
Mode::HelixNormal,
);
}

#[gpui::test]
async fn test_delete_character_end_of_line(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await;

cx.set_state(
indoc! {"
The quick brownˇ
fox jumps over
the lazy dog."},
Mode::HelixNormal,
);

cx.simulate_keystrokes("d");

cx.assert_state(
indoc! {"
The quick brownˇfox jumps over
the lazy dog."},
Mode::HelixNormal,
);
}

#[gpui::test]
async fn test_delete_character_end_of_buffer(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await;

cx.set_state(
indoc! {"
The quick brown
fox jumps over
the lazy dog.ˇ"},
Mode::HelixNormal,
);

cx.simulate_keystrokes("d");

cx.assert_state(
indoc! {"
The quick brown
fox jumps over
the lazy dog.ˇ"},
Mode::HelixNormal,
);
}
}

0 comments on commit 9263d98

Please sign in to comment.