feat(bindings): add support for unbinding keys

This commit is contained in:
lalvarezt 2025-07-22 13:37:03 +02:00
parent 064e156271
commit f7d0963d6f
2 changed files with 62 additions and 20 deletions

View File

@ -470,13 +470,30 @@ where
where where
A: MapAccess<'de>, A: MapAccess<'de>,
{ {
use serde::de::Error;
use toml::Value;
let mut bindings = FxHashMap::default(); let mut bindings = FxHashMap::default();
while let Some((key_str, action)) = while let Some((key_str, raw_value)) =
map.next_entry::<String, Action>()? map.next_entry::<String, Value>()?
{ {
let key = let key = parse_key(&key_str).map_err(Error::custom)?;
parse_key(&key_str).map_err(serde::de::Error::custom)?;
bindings.insert(key, action); match raw_value {
Value::Boolean(false) => {
// Explicitly unbind key
bindings.insert(key, Action::NoOp);
}
Value::Boolean(true) => {
// True means do nothing (keep current binding or ignore)
}
action => {
// Try to deserialize as Action
let action = Action::deserialize(action)
.map_err(Error::custom)?;
bindings.insert(key, action);
}
}
} }
Ok(bindings) Ok(bindings)
} }
@ -738,4 +755,33 @@ mod tests {
Some(&Action::SelectNextPage) Some(&Action::SelectNextPage)
); );
} }
#[test]
fn test_deserialize_unbinding() {
let keybindings: KeyBindings = toml::from_str(
r#"
"esc" = "quit"
"ctrl-c" = false
"down" = "select_next_entry"
"up" = true
"#,
)
.unwrap();
// Normal action binding should work
assert_eq!(keybindings.bindings.get(&Key::Esc), Some(&Action::Quit));
assert_eq!(
keybindings.bindings.get(&Key::Down),
Some(&Action::SelectNextEntry)
);
// false should bind to NoOp (unbinding)
assert_eq!(
keybindings.bindings.get(&Key::Ctrl('c')),
Some(&Action::NoOp)
);
// true should be ignored (no binding created)
assert_eq!(keybindings.bindings.get(&Key::Up), None);
}
} }

View File

@ -39,18 +39,16 @@ fn test_keybindings_override_default() {
let mut child = let mut child =
tester.spawn_command_tui(tv_local_config_and_cable_with_args(&[ tester.spawn_command_tui(tv_local_config_and_cable_with_args(&[
"--keybindings", "--keybindings",
"a=\"quit\"", "a=\"quit\";ctrl-c=false;esc=false",
])); ]));
// TODO: add back when unbinding is implemented // Test that ESC no longer quits (default behavior is overridden)
tester.send(ESC);
tester.assert_tui_running(&mut child);
// // Test that ESC no longer quits (default behavior is overridden) // Test that Ctrl+C no longer quits (default behavior is overridden)
// tester.send(ESC); tester.send(&ctrl('c'));
// tester.assert_tui_running(&mut child); tester.assert_tui_running(&mut child);
//
// // Test that Ctrl+C no longer quits (default behavior is overridden)
// tester.send(&ctrl('c'));
// tester.assert_tui_running(&mut child);
// Test that our custom "a" key now quits the application // Test that our custom "a" key now quits the application
tester.send("'a'"); tester.send("'a'");
@ -66,14 +64,12 @@ fn test_multiple_keybindings_override() {
let mut child = let mut child =
tester.spawn_command_tui(tv_local_config_and_cable_with_args(&[ tester.spawn_command_tui(tv_local_config_and_cable_with_args(&[
"--keybindings", "--keybindings",
"a=\"quit\";ctrl-t=\"toggle_remote_control\"", "a=\"quit\";ctrl-t=\"toggle_remote_control\";esc=false",
])); ]));
// TODO: add back when unbinding is implemented // Verify ESC doesn't quit (default overridden)
tester.send(ESC);
// // Verify ESC doesn't quit (default overridden) tester.assert_tui_running(&mut child);
// tester.send(ESC);
// tester.assert_tui_running(&mut child);
// Test that Ctrl+T opens remote control panel (custom keybinding works) // Test that Ctrl+T opens remote control panel (custom keybinding works)
tester.send(&ctrl('t')); tester.send(&ctrl('t'));