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
A: MapAccess<'de>,
{
use serde::de::Error;
use toml::Value;
let mut bindings = FxHashMap::default();
while let Some((key_str, action)) =
map.next_entry::<String, Action>()?
while let Some((key_str, raw_value)) =
map.next_entry::<String, Value>()?
{
let key =
parse_key(&key_str).map_err(serde::de::Error::custom)?;
bindings.insert(key, action);
let key = parse_key(&key_str).map_err(Error::custom)?;
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)
}
@ -738,4 +755,33 @@ mod tests {
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 =
tester.spawn_command_tui(tv_local_config_and_cable_with_args(&[
"--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)
// tester.send(ESC);
// 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 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
tester.send("'a'");
@ -66,14 +64,12 @@ fn test_multiple_keybindings_override() {
let mut child =
tester.spawn_command_tui(tv_local_config_and_cable_with_args(&[
"--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);
// tester.assert_tui_running(&mut child);
// Verify ESC doesn't quit (default overridden)
tester.send(ESC);
tester.assert_tui_running(&mut child);
// Test that Ctrl+T opens remote control panel (custom keybinding works)
tester.send(&ctrl('t'));