Improve Helix insert (#34765)
Closes #34763 Release Notes: - Improved insert in `helix_mode` when a selection exists to better match helix's behavior: collapse selection to avoid replacing it - Improved append (`insert_after`) to better match helix's behavior: move cursor to end of selection if it exists
This commit is contained in:
parent
8b0ec287a5
commit
a6956eebcb
2 changed files with 112 additions and 4 deletions
|
@ -220,6 +220,8 @@
|
|||
{
|
||||
"context": "vim_mode == normal",
|
||||
"bindings": {
|
||||
"i": "vim::InsertBefore",
|
||||
"a": "vim::InsertAfter",
|
||||
"ctrl-[": "editor::Cancel",
|
||||
":": "command_palette::Toggle",
|
||||
"c": "vim::PushChange",
|
||||
|
@ -353,9 +355,7 @@
|
|||
"shift-d": "vim::DeleteToEndOfLine",
|
||||
"shift-j": "vim::JoinLines",
|
||||
"shift-y": "vim::YankLine",
|
||||
"i": "vim::InsertBefore",
|
||||
"shift-i": "vim::InsertFirstNonWhitespace",
|
||||
"a": "vim::InsertAfter",
|
||||
"shift-a": "vim::InsertEndOfLine",
|
||||
"o": "vim::InsertLineBelow",
|
||||
"shift-o": "vim::InsertLineAbove",
|
||||
|
@ -377,6 +377,8 @@
|
|||
{
|
||||
"context": "vim_mode == helix_normal && !menu",
|
||||
"bindings": {
|
||||
"i": "vim::HelixInsert",
|
||||
"a": "vim::HelixAppend",
|
||||
"ctrl-[": "editor::Cancel",
|
||||
";": "vim::HelixCollapseSelection",
|
||||
":": "command_palette::Toggle",
|
||||
|
|
|
@ -4,18 +4,28 @@ use gpui::{Context, Window};
|
|||
use language::{CharClassifier, CharKind};
|
||||
use text::SelectionGoal;
|
||||
|
||||
use crate::{Vim, motion::Motion, state::Mode};
|
||||
use crate::{
|
||||
Vim,
|
||||
motion::{Motion, right},
|
||||
state::Mode,
|
||||
};
|
||||
|
||||
actions!(
|
||||
vim,
|
||||
[
|
||||
/// Switches to normal mode after the cursor (Helix-style).
|
||||
HelixNormalAfter
|
||||
HelixNormalAfter,
|
||||
/// Inserts at the beginning of the selection.
|
||||
HelixInsert,
|
||||
/// Appends at the end of the selection.
|
||||
HelixAppend,
|
||||
]
|
||||
);
|
||||
|
||||
pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
|
||||
Vim::action(editor, cx, Vim::helix_normal_after);
|
||||
Vim::action(editor, cx, Vim::helix_insert);
|
||||
Vim::action(editor, cx, Vim::helix_append);
|
||||
}
|
||||
|
||||
impl Vim {
|
||||
|
@ -299,6 +309,38 @@ impl Vim {
|
|||
_ => self.helix_move_and_collapse(motion, times, window, cx),
|
||||
}
|
||||
}
|
||||
|
||||
fn helix_insert(&mut self, _: &HelixInsert, window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.start_recording(cx);
|
||||
self.update_editor(window, cx, |_, editor, window, cx| {
|
||||
editor.change_selections(Default::default(), window, cx, |s| {
|
||||
s.move_with(|_map, selection| {
|
||||
// In helix normal mode, move cursor to start of selection and collapse
|
||||
if !selection.is_empty() {
|
||||
selection.collapse_to(selection.start, SelectionGoal::None);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
self.switch_mode(Mode::Insert, false, window, cx);
|
||||
}
|
||||
|
||||
fn helix_append(&mut self, _: &HelixAppend, window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.start_recording(cx);
|
||||
self.switch_mode(Mode::Insert, false, window, cx);
|
||||
self.update_editor(window, cx, |_, editor, window, cx| {
|
||||
editor.change_selections(Default::default(), window, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
let point = if selection.is_empty() {
|
||||
right(map, selection.head(), 1)
|
||||
} else {
|
||||
selection.end
|
||||
};
|
||||
selection.collapse_to(point, SelectionGoal::None);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -497,4 +539,68 @@ mod test {
|
|||
|
||||
cx.assert_state("«ˇaa»\n", Mode::HelixNormal);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_insert_selected(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("i");
|
||||
|
||||
cx.assert_state(
|
||||
indoc! {"
|
||||
ˇThe quick brown
|
||||
fox jumps over
|
||||
the lazy dog."},
|
||||
Mode::Insert,
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_append(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
// test from the end of the selection
|
||||
cx.set_state(
|
||||
indoc! {"
|
||||
«Theˇ» quick brown
|
||||
fox jumps over
|
||||
the lazy dog."},
|
||||
Mode::HelixNormal,
|
||||
);
|
||||
|
||||
cx.simulate_keystrokes("a");
|
||||
|
||||
cx.assert_state(
|
||||
indoc! {"
|
||||
Theˇ quick brown
|
||||
fox jumps over
|
||||
the lazy dog."},
|
||||
Mode::Insert,
|
||||
);
|
||||
|
||||
// test from the beginning of the selection
|
||||
cx.set_state(
|
||||
indoc! {"
|
||||
«ˇThe» quick brown
|
||||
fox jumps over
|
||||
the lazy dog."},
|
||||
Mode::HelixNormal,
|
||||
);
|
||||
|
||||
cx.simulate_keystrokes("a");
|
||||
|
||||
cx.assert_state(
|
||||
indoc! {"
|
||||
Theˇ quick brown
|
||||
fox jumps over
|
||||
the lazy dog."},
|
||||
Mode::Insert,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue