Attempt to fix go to the end of the line when using helix mode (#41575)

Closes #41550

Release Notes:

- Fixed `<g-l>` behavior in helix mode which will now correctly go to the last charactor of the line.
- Fixed not switching to helix normal mode when in default vim context and pressing escape.

---------

Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
This commit is contained in:
HuaGu-Dragon
2025-11-24 17:32:30 +01:00
committed by GitHub
co-authored by Jakub Konka
parent ea7568ceb3
commit 47e8946581
2 changed files with 82 additions and 1 deletions
+2 -1
View File
@@ -414,8 +414,9 @@
}
},
{
"context": "vim_mode == helix_normal && !menu",
"context": "VimControl && vim_mode == helix_normal && !menu",
"bindings": {
"escape": "vim::SwitchToHelixNormalMode",
"i": "vim::HelixInsert",
"a": "vim::HelixAppend",
"ctrl-[": "editor::Cancel"
+80
View File
@@ -263,6 +263,31 @@ impl Vim {
cx: &mut Context<Self>,
) {
match motion {
Motion::EndOfLine { .. } => {
// In Helix mode, EndOfLine should position cursor ON the last character,
// not after it. We therefore need special handling for it.
self.update_editor(cx, |_, editor, cx| {
let text_layout_details = editor.text_layout_details(window);
editor.change_selections(Default::default(), window, cx, |s| {
s.move_with(|map, selection| {
let goal = selection.goal;
let cursor = if selection.is_empty() || selection.reversed {
selection.head()
} else {
movement::left(map, selection.head())
};
let (point, _goal) = motion
.move_point(map, cursor, goal, times, &text_layout_details)
.unwrap_or((cursor, goal));
// Move left by one character to position on the last character
let adjusted_point = movement::saturating_left(map, point);
selection.collapse_to(adjusted_point, SelectionGoal::None)
})
});
});
}
Motion::NextWordStart { ignore_punctuation } => {
self.helix_find_range_forward(times, window, cx, |left, right, classifier| {
let left_kind = classifier.kind_with(left, ignore_punctuation);
@@ -1493,4 +1518,59 @@ mod test {
Mode::Insert,
);
}
#[gpui::test]
async fn test_g_l_end_of_line(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await;
cx.enable_helix();
// Test g l moves to last character, not after it
cx.set_state("hello ˇworld!", Mode::HelixNormal);
cx.simulate_keystrokes("g l");
cx.assert_state("hello worldˇ!", Mode::HelixNormal);
// Test with Chinese characters, test if work with UTF-8?
cx.set_state("ˇ你好世界", Mode::HelixNormal);
cx.simulate_keystrokes("g l");
cx.assert_state("你好世ˇ界", Mode::HelixNormal);
// Test with end of line
cx.set_state("endˇ", Mode::HelixNormal);
cx.simulate_keystrokes("g l");
cx.assert_state("enˇd", Mode::HelixNormal);
// Test with empty line
cx.set_state(
indoc! {"
hello
ˇ
world"},
Mode::HelixNormal,
);
cx.simulate_keystrokes("g l");
cx.assert_state(
indoc! {"
hello
ˇ
world"},
Mode::HelixNormal,
);
// Test with multiple lines
cx.set_state(
indoc! {"
ˇfirst line
second line
third line"},
Mode::HelixNormal,
);
cx.simulate_keystrokes("g l");
cx.assert_state(
indoc! {"
first linˇe
second line
third line"},
Mode::HelixNormal,
);
}
}