fix: distinguish Ctrl+I from Tab in comparisons

This commit is contained in:
Valdemar Lorenzen
2026-10-16 12:48:13 +02:00
parent 92e1e6e8fd
commit 930735c537
8 changed files with 104 additions and 39 deletions
+12 -29
View File
@@ -1224,9 +1224,8 @@ fn parse_key(key: &str) -> Result<Input, String> {
}
fn control_key(ch: char) -> Input {
// Terminals encode these controls as named keys.
// Preserve distinguishable control keys; Ctrl+M retains its Enter alias.
match ch.to_ascii_lowercase() {
'i' => Input::Char('\t'),
'm' => Input::Enter,
ch => Input::Ctrl(ch),
}
@@ -1299,6 +1298,7 @@ fn default_bindings() -> HashMap<Mode, HashMap<Input, Binding>> {
(Input::Ctrl('o'), JumpBack),
(Input::Ctrl('b'), DiffModeToggle),
(Input::Char('\t'), JumpForward),
(Input::Ctrl('i'), JumpForward),
(Input::Alt('h'), PaneFocusLeft),
(Input::Alt('j'), PaneFocusDown),
(Input::Alt('k'), PaneFocusUp),
@@ -1403,6 +1403,7 @@ fn default_bindings() -> HashMap<Mode, HashMap<Input, Binding>> {
.insert(Input::Ctrl('n'), Binding::Action(LspCompletion));
for (key, action) in [
(Input::Char('\t'), SnippetNext),
(Input::Ctrl('i'), SnippetNext),
(Input::BackTab, SnippetPrevious),
] {
bindings
@@ -5139,7 +5140,11 @@ impl Editor {
| Action::Plugins
| Action::Buffers
)
)
) || (input != Input::Char('\t')
&& matches!(
binding,
Binding::Action(Action::JumpBack | Action::JumpForward)
))
})
{
return self.handle_input(input);
@@ -18172,7 +18177,7 @@ mod tests {
}
#[test]
fn jump_keys_honor_control_aliases_custom_bindings_and_normal_mode_eligibility() {
fn jump_keys_honor_independent_tab_bindings_and_normal_mode_eligibility() {
let directory = Directory::new();
let path = directory.path("text.txt");
fs::write(&path, "zero\none\ntwo").unwrap();
@@ -18193,12 +18198,9 @@ mod tests {
editor
.bind("normal", "ctrl+i", Some("core.right".into()))
.unwrap();
editor.handle(Input::Char('\t'));
assert_eq!(editor.cursor().column, 1);
editor
.bind("normal", "tab", Some("core.jump_forward".into()))
.unwrap();
editor.handle(Input::Ctrl('I'));
assert_eq!(editor.cursor().column, 1);
editor.handle(Input::Char('\t'));
assert_eq!(editor.cursor(), Cursor { row: 1, column: 1 });
for mode in ["insert", "visual", "command", "search"] {
for action in ["core.jump_back", "core.jump_forward"] {
@@ -20425,11 +20427,7 @@ mod tests {
#[test]
fn ctrl_j_is_distinct_from_enter_and_preserves_editor_defaults() {
assert_eq!(parse_key("CTRL+J").unwrap(), Input::Ctrl('j'));
for (key, input) in [
("ctrl+m", Input::Enter),
("ctrl+h", Input::Ctrl('h')),
("ctrl+i", Input::Char('\t')),
] {
for (key, input) in [("ctrl+m", Input::Enter), ("ctrl+h", Input::Ctrl('h'))] {
assert_eq!(parse_key(key).unwrap(), input);
}
let mut editor = editor();
@@ -24537,12 +24535,6 @@ mod tests {
editor
.bind("normal", "ctrl+j", Some("core.insert".into()))
.unwrap();
assert_eq!(
palette_entry(&editor, "core.insert").bindings,
vec![
"Ctrl+h", "Ctrl+j", "Ctrl+r", "Enter", "I", "Space", "Tab", "界"
]
);
assert!(
palette_entry(&editor, "core.insert_first_nonblank")
.bindings
@@ -25817,15 +25809,6 @@ mod tests {
editor.handle(Input::Char('+'));
assert_eq!(editor.lines(), &["界", ""]);
editor.bind("insert", "CTRL+I", None).unwrap();
editor.handle(Input::Char('\t'));
assert_eq!(editor.lines(), &["界", ""]);
editor
.bind("insert", "TAB", Some("core.newline".into()))
.unwrap();
editor.handle(Input::Ctrl('i'));
assert_eq!(editor.lines(), &["界", "", ""]);
editor
.bind("insert", "shift+j", Some("core.normal".into()))
.unwrap();