@@ -36,6 +36,8 @@ actions!(
HelixInsert,
/// Appends at the end of the selection.
HelixAppend,
+ /// Inserts at the end of the current Helix cursor line.
+ HelixInsertEndOfLine,
/// Goes to the location of the last modification.
HelixGotoLastModification,
/// Select entire line or multiple lines, extending downwards.
@@ -64,6 +66,7 @@ pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
Vim::action(editor, cx, Vim::helix_select_lines);
Vim::action(editor, cx, Vim::helix_insert);
Vim::action(editor, cx, Vim::helix_append);
+ Vim::action(editor, cx, Vim::helix_insert_end_of_line);
Vim::action(editor, cx, Vim::helix_yank);
Vim::action(editor, cx, Vim::helix_goto_last_modification);
Vim::action(editor, cx, Vim::helix_paste);
@@ -600,6 +603,34 @@ impl Vim {
});
}
+ /// Helix-specific implementation of `shift-a` that accounts for Helix's
+ /// selection model, where selecting a line with `x` creates a selection
+ /// from column 0 of the current row to column 0 of the next row, so the
+ /// default [`vim::normal::InsertEndOfLine`] would move the cursor to the
+ /// end of the wrong line.
+ fn helix_insert_end_of_line(
+ &mut self,
+ _: &HelixInsertEndOfLine,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ self.start_recording(cx);
+ self.switch_mode(Mode::Insert, false, window, cx);
+ self.update_editor(cx, |_, editor, cx| {
+ editor.change_selections(Default::default(), window, cx, |s| {
+ s.move_with(&mut |map, selection| {
+ let cursor = if !selection.is_empty() && !selection.reversed {
+ movement::left(map, selection.head())
+ } else {
+ selection.head()
+ };
+ selection
+ .collapse_to(motion::next_line_end(map, cursor, 1), SelectionGoal::None);
+ });
+ });
+ });
+ }
+
pub fn helix_replace(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
self.update_editor(cx, |_, editor, cx| {
editor.transact(window, cx, |editor, window, cx| {
@@ -1447,6 +1478,47 @@ mod test {
ˇ»line five"},
Mode::HelixNormal,
);
+
+ // Test selecting with an empty line below the current line
+ cx.set_state(
+ indoc! {"
+ line one
+ line twoˇ
+
+ line four
+ line five"},
+ Mode::HelixNormal,
+ );
+ cx.simulate_keystrokes("x");
+ cx.assert_state(
+ indoc! {"
+ line one
+ «line two
+ ˇ»
+ line four
+ line five"},
+ Mode::HelixNormal,
+ );
+ cx.simulate_keystrokes("x");
+ cx.assert_state(
+ indoc! {"
+ line one
+ «line two
+
+ ˇ»line four
+ line five"},
+ Mode::HelixNormal,
+ );
+ cx.simulate_keystrokes("x");
+ cx.assert_state(
+ indoc! {"
+ line one
+ «line two
+
+ line four
+ ˇ»line five"},
+ Mode::HelixNormal,
+ );
}
#[gpui::test]
@@ -1848,4 +1920,51 @@ mod test {
Mode::HelixSelect,
);
}
+
+ #[gpui::test]
+ async fn test_helix_insert_end_of_line(cx: &mut gpui::TestAppContext) {
+ let mut cx = VimTestContext::new(cx, true).await;
+ cx.enable_helix();
+
+ // Ensure that, when lines are selected using `x`, pressing `shift-a`
+ // actually puts the cursor at the end of the selected lines and not at
+ // the end of the line below.
+ cx.set_state(
+ indoc! {"
+ line oˇne
+ line two"},
+ Mode::HelixNormal,
+ );
+
+ cx.simulate_keystrokes("x");
+ cx.assert_state(
+ indoc! {"
+ «line one
+ ˇ»line two"},
+ Mode::HelixNormal,
+ );
+
+ cx.simulate_keystrokes("shift-a");
+ cx.assert_state(
+ indoc! {"
+ line oneˇ
+ line two"},
+ Mode::Insert,
+ );
+
+ cx.set_state(
+ indoc! {"
+ line «one
+ lineˇ» two"},
+ Mode::HelixNormal,
+ );
+
+ cx.simulate_keystrokes("shift-a");
+ cx.assert_state(
+ indoc! {"
+ line one
+ line twoˇ"},
+ Mode::Insert,
+ );
+ }
}