Add "shift-r" and "g ." support for helix mode (#35468)
Related #4642 Compatible with #34136 Release Notes: - Helix: `Shift+R` works as Paste instead of taking you to ReplaceMode - Helix: `g .` goes to last modification place (similar to `. in vim)
This commit is contained in:
parent
633ce23ae9
commit
bb5cfe118f
2 changed files with 89 additions and 0 deletions
|
@ -428,11 +428,13 @@
|
||||||
"g h": "vim::StartOfLine",
|
"g h": "vim::StartOfLine",
|
||||||
"g s": "vim::FirstNonWhitespace", // "g s" default behavior is "space s"
|
"g s": "vim::FirstNonWhitespace", // "g s" default behavior is "space s"
|
||||||
"g e": "vim::EndOfDocument",
|
"g e": "vim::EndOfDocument",
|
||||||
|
"g .": "vim::HelixGotoLastModification", // go to last modification
|
||||||
"g r": "editor::FindAllReferences", // zed specific
|
"g r": "editor::FindAllReferences", // zed specific
|
||||||
"g t": "vim::WindowTop",
|
"g t": "vim::WindowTop",
|
||||||
"g c": "vim::WindowMiddle",
|
"g c": "vim::WindowMiddle",
|
||||||
"g b": "vim::WindowBottom",
|
"g b": "vim::WindowBottom",
|
||||||
|
|
||||||
|
"shift-r": "editor::Paste",
|
||||||
"x": "editor::SelectLine",
|
"x": "editor::SelectLine",
|
||||||
"shift-x": "editor::SelectLine",
|
"shift-x": "editor::SelectLine",
|
||||||
"%": "editor::SelectAll",
|
"%": "editor::SelectAll",
|
||||||
|
|
|
@ -23,6 +23,8 @@ actions!(
|
||||||
HelixInsert,
|
HelixInsert,
|
||||||
/// Appends at the end of the selection.
|
/// Appends at the end of the selection.
|
||||||
HelixAppend,
|
HelixAppend,
|
||||||
|
/// Goes to the location of the last modification.
|
||||||
|
HelixGotoLastModification,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -31,6 +33,7 @@ pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
|
||||||
Vim::action(editor, cx, Vim::helix_insert);
|
Vim::action(editor, cx, Vim::helix_insert);
|
||||||
Vim::action(editor, cx, Vim::helix_append);
|
Vim::action(editor, cx, Vim::helix_append);
|
||||||
Vim::action(editor, cx, Vim::helix_yank);
|
Vim::action(editor, cx, Vim::helix_yank);
|
||||||
|
Vim::action(editor, cx, Vim::helix_goto_last_modification);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vim {
|
impl Vim {
|
||||||
|
@ -430,6 +433,15 @@ impl Vim {
|
||||||
});
|
});
|
||||||
self.switch_mode(Mode::HelixNormal, true, window, cx);
|
self.switch_mode(Mode::HelixNormal, true, window, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn helix_goto_last_modification(
|
||||||
|
&mut self,
|
||||||
|
_: &HelixGotoLastModification,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) {
|
||||||
|
self.jump(".".into(), false, false, window, cx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -441,6 +453,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_word_motions(cx: &mut gpui::TestAppContext) {
|
async fn test_word_motions(cx: &mut gpui::TestAppContext) {
|
||||||
let mut cx = VimTestContext::new(cx, true).await;
|
let mut cx = VimTestContext::new(cx, true).await;
|
||||||
|
cx.enable_helix();
|
||||||
// «
|
// «
|
||||||
// ˇ
|
// ˇ
|
||||||
// »
|
// »
|
||||||
|
@ -502,6 +515,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_delete(cx: &mut gpui::TestAppContext) {
|
async fn test_delete(cx: &mut gpui::TestAppContext) {
|
||||||
let mut cx = VimTestContext::new(cx, true).await;
|
let mut cx = VimTestContext::new(cx, true).await;
|
||||||
|
cx.enable_helix();
|
||||||
|
|
||||||
// test delete a selection
|
// test delete a selection
|
||||||
cx.set_state(
|
cx.set_state(
|
||||||
|
@ -582,6 +596,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_f_and_t(cx: &mut gpui::TestAppContext) {
|
async fn test_f_and_t(cx: &mut gpui::TestAppContext) {
|
||||||
let mut cx = VimTestContext::new(cx, true).await;
|
let mut cx = VimTestContext::new(cx, true).await;
|
||||||
|
cx.enable_helix();
|
||||||
|
|
||||||
cx.set_state(
|
cx.set_state(
|
||||||
indoc! {"
|
indoc! {"
|
||||||
|
@ -635,6 +650,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_newline_char(cx: &mut gpui::TestAppContext) {
|
async fn test_newline_char(cx: &mut gpui::TestAppContext) {
|
||||||
let mut cx = VimTestContext::new(cx, true).await;
|
let mut cx = VimTestContext::new(cx, true).await;
|
||||||
|
cx.enable_helix();
|
||||||
|
|
||||||
cx.set_state("aa«\nˇ»bb cc", Mode::HelixNormal);
|
cx.set_state("aa«\nˇ»bb cc", Mode::HelixNormal);
|
||||||
|
|
||||||
|
@ -652,6 +668,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_insert_selected(cx: &mut gpui::TestAppContext) {
|
async fn test_insert_selected(cx: &mut gpui::TestAppContext) {
|
||||||
let mut cx = VimTestContext::new(cx, true).await;
|
let mut cx = VimTestContext::new(cx, true).await;
|
||||||
|
cx.enable_helix();
|
||||||
cx.set_state(
|
cx.set_state(
|
||||||
indoc! {"
|
indoc! {"
|
||||||
«The ˇ»quick brown
|
«The ˇ»quick brown
|
||||||
|
@ -674,6 +691,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_append(cx: &mut gpui::TestAppContext) {
|
async fn test_append(cx: &mut gpui::TestAppContext) {
|
||||||
let mut cx = VimTestContext::new(cx, true).await;
|
let mut cx = VimTestContext::new(cx, true).await;
|
||||||
|
cx.enable_helix();
|
||||||
// test from the end of the selection
|
// test from the end of the selection
|
||||||
cx.set_state(
|
cx.set_state(
|
||||||
indoc! {"
|
indoc! {"
|
||||||
|
@ -716,6 +734,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_replace(cx: &mut gpui::TestAppContext) {
|
async fn test_replace(cx: &mut gpui::TestAppContext) {
|
||||||
let mut cx = VimTestContext::new(cx, true).await;
|
let mut cx = VimTestContext::new(cx, true).await;
|
||||||
|
cx.enable_helix();
|
||||||
|
|
||||||
// No selection (single character)
|
// No selection (single character)
|
||||||
cx.set_state("ˇaa", Mode::HelixNormal);
|
cx.set_state("ˇaa", Mode::HelixNormal);
|
||||||
|
@ -763,4 +782,72 @@ mod test {
|
||||||
cx.shared_clipboard().assert_eq("worl");
|
cx.shared_clipboard().assert_eq("worl");
|
||||||
cx.assert_state("hello «worlˇ»d", Mode::HelixNormal);
|
cx.assert_state("hello «worlˇ»d", Mode::HelixNormal);
|
||||||
}
|
}
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_shift_r_paste(cx: &mut gpui::TestAppContext) {
|
||||||
|
let mut cx = VimTestContext::new(cx, true).await;
|
||||||
|
cx.enable_helix();
|
||||||
|
|
||||||
|
// First copy some text to clipboard
|
||||||
|
cx.set_state("«hello worldˇ»", Mode::HelixNormal);
|
||||||
|
cx.simulate_keystrokes("y");
|
||||||
|
|
||||||
|
// Test paste with shift-r on single cursor
|
||||||
|
cx.set_state("foo ˇbar", Mode::HelixNormal);
|
||||||
|
cx.simulate_keystrokes("shift-r");
|
||||||
|
|
||||||
|
cx.assert_state("foo hello worldˇbar", Mode::HelixNormal);
|
||||||
|
|
||||||
|
// Test paste with shift-r on selection
|
||||||
|
cx.set_state("foo «barˇ» baz", Mode::HelixNormal);
|
||||||
|
cx.simulate_keystrokes("shift-r");
|
||||||
|
|
||||||
|
cx.assert_state("foo hello worldˇ baz", Mode::HelixNormal);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_insert_mode_stickiness(cx: &mut gpui::TestAppContext) {
|
||||||
|
let mut cx = VimTestContext::new(cx, true).await;
|
||||||
|
cx.enable_helix();
|
||||||
|
|
||||||
|
// Make a modification at a specific location
|
||||||
|
cx.set_state("ˇhello", Mode::HelixNormal);
|
||||||
|
assert_eq!(cx.mode(), Mode::HelixNormal);
|
||||||
|
cx.simulate_keystrokes("i");
|
||||||
|
assert_eq!(cx.mode(), Mode::Insert);
|
||||||
|
cx.simulate_keystrokes("escape");
|
||||||
|
assert_eq!(cx.mode(), Mode::HelixNormal);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_goto_last_modification(cx: &mut gpui::TestAppContext) {
|
||||||
|
let mut cx = VimTestContext::new(cx, true).await;
|
||||||
|
cx.enable_helix();
|
||||||
|
|
||||||
|
// Make a modification at a specific location
|
||||||
|
cx.set_state("line one\nline ˇtwo\nline three", Mode::HelixNormal);
|
||||||
|
cx.assert_state("line one\nline ˇtwo\nline three", Mode::HelixNormal);
|
||||||
|
cx.simulate_keystrokes("i");
|
||||||
|
cx.simulate_keystrokes("escape");
|
||||||
|
cx.simulate_keystrokes("i");
|
||||||
|
cx.simulate_keystrokes("m o d i f i e d space");
|
||||||
|
cx.simulate_keystrokes("escape");
|
||||||
|
|
||||||
|
// TODO: this fails, because state is no longer helix
|
||||||
|
cx.assert_state(
|
||||||
|
"line one\nline modified ˇtwo\nline three",
|
||||||
|
Mode::HelixNormal,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Move cursor away from the modification
|
||||||
|
cx.simulate_keystrokes("up");
|
||||||
|
|
||||||
|
// Use "g ." to go back to last modification
|
||||||
|
cx.simulate_keystrokes("g .");
|
||||||
|
|
||||||
|
// Verify we're back at the modification location and still in HelixNormal mode
|
||||||
|
cx.assert_state(
|
||||||
|
"line one\nline modifiedˇ two\nline three",
|
||||||
|
Mode::HelixNormal,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue