use keymap_core::{
BreakReason, Key, KeyInput, Keymap, LegacyForm, Modifiers, RebindVerdict, resolve_layered,
validate_rebind,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Action {
Save,
Quit,
}
fn plain(c: char) -> KeyInput {
KeyInput::new(Key::Char(c), Modifiers::NONE)
}
fn ctrl(c: char) -> KeyInput {
KeyInput::new(Key::Char(c), Modifiers::CTRL)
}
fn esc() -> KeyInput {
KeyInput::new(Key::Esc, Modifiers::NONE)
}
fn would_break_escape<A: Clone + PartialEq>(
layers: &[&Keymap<A>],
target: usize,
proposed: KeyInput,
action: A,
reserved: &[KeyInput],
) -> bool {
if let LegacyForm::CollapsesTo(byte_twin) = proposed.legacy_form() {
if reserved.contains(&byte_twin) {
return true;
}
}
let mut simulated: Vec<Keymap<A>> = layers.iter().map(|l| (*l).clone()).collect();
simulated[target].bind(proposed, action);
reserved.iter().any(|&r| {
resolve_layered(layers.iter().copied(), &r) != resolve_layered(simulated.iter(), &r)
})
}
#[test]
fn direct_theft_of_a_reserved_key_is_refused() {
let global: Keymap<Action> = Keymap::new();
let reserved = [esc()];
assert!(would_break_escape(
&[&global],
0,
esc(),
Action::Save,
&reserved
));
}
#[test]
fn an_upper_layer_shadowing_a_reserved_key_is_refused() {
let mut base = Keymap::new();
base.bind(esc(), Action::Quit); let overlay: Keymap<Action> = Keymap::new();
let reserved = [esc()];
assert!(would_break_escape(
&[&overlay, &base],
0, esc(),
Action::Save,
&reserved
));
}
#[test]
fn rebinding_a_reserved_key_in_a_shadowed_lower_layer_is_allowed() {
let mut overlay = Keymap::new();
overlay.bind(esc(), Action::Quit);
let base: Keymap<Action> = Keymap::new();
let reserved = [esc()];
assert!(!would_break_escape(
&[&overlay, &base],
1, esc(),
Action::Save,
&reserved
));
}
#[test]
fn rebinding_a_reserved_key_to_its_own_current_action_is_allowed() {
let mut global = Keymap::new();
global.bind(esc(), Action::Quit);
let reserved = [esc()];
assert!(!would_break_escape(
&[&global],
0,
esc(),
Action::Quit, &reserved
));
}
#[test]
fn a_legacy_collapse_onto_a_reserved_key_is_refused() {
let global: Keymap<Action> = Keymap::new();
let reserved = [KeyInput::new(Key::Tab, Modifiers::NONE)];
assert!(would_break_escape(
&[&global],
0,
ctrl('i'),
Action::Save,
&reserved
));
}
#[test]
fn an_ordinary_rebind_is_allowed() {
let mut global = Keymap::new();
global.bind(ctrl('s'), Action::Quit);
let reserved = [esc()];
assert!(!would_break_escape(
&[&global],
0,
ctrl('s'),
Action::Save,
&reserved
));
}
#[test]
fn validation_does_not_mutate_the_live_keymap() {
let global: Keymap<Action> = Keymap::new();
let reserved = [esc()];
assert!(would_break_escape(
&[&global],
0,
esc(),
Action::Save,
&reserved
));
assert_eq!(global.get(&esc()), None);
assert!(global.is_empty());
}
#[test]
fn validate_rebind_and_clone_simulate_agree_on_distinct_action_matrix() {
let proposed_ordinary = ctrl('s');
let proposed_reserved = esc();
let proposed_collapse = KeyInput::new(Key::Char('i'), Modifiers::CTRL);
let reserved_esc: &[KeyInput] = &[esc()];
let reserved_esc_tab: &[KeyInput] = &[esc(), KeyInput::new(Key::Tab, Modifiers::NONE)];
let assert_agree = |layers: &[&Keymap<Action>],
target: usize,
proposed: KeyInput,
reserved: &[KeyInput]| {
let clone_result = would_break_escape(layers, target, proposed, Action::Save, reserved);
let vr = validate_rebind(layers, target, proposed, reserved);
let vr_blocks = matches!(
vr,
RebindVerdict::BreaksReserved {
reason: BreakReason::DirectSteal,
..
} | RebindVerdict::BreaksReserved {
reason: BreakReason::LegacyCollapse,
..
}
);
assert_eq!(
clone_result, vr_blocks,
"disagreement: proposed={proposed}, reserved={reserved:?}, clone={clone_result}, validate={vr_blocks}"
);
};
let empty: Keymap<Action> = Keymap::new();
assert_agree(&[&empty], 0, proposed_ordinary, reserved_esc);
assert_agree(&[&empty], 0, proposed_reserved, reserved_esc);
assert_agree(&[&empty], 0, proposed_collapse, reserved_esc_tab);
let mut with_esc = Keymap::new();
with_esc.bind(esc(), Action::Quit);
assert_agree(&[&with_esc], 0, proposed_ordinary, reserved_esc);
assert_agree(&[&with_esc], 0, proposed_reserved, reserved_esc);
assert_agree(&[&with_esc], 0, proposed_collapse, reserved_esc_tab);
let overlay: Keymap<Action> = Keymap::new();
let mut base = Keymap::new();
base.bind(esc(), Action::Quit);
assert_agree(&[&overlay, &base], 0, proposed_ordinary, reserved_esc);
assert_agree(&[&overlay, &base], 0, proposed_reserved, reserved_esc);
assert_agree(&[&overlay, &base], 0, proposed_collapse, reserved_esc_tab);
let mut overlay2 = Keymap::new();
overlay2.bind(esc(), Action::Quit);
let base2: Keymap<Action> = Keymap::new();
assert_agree(&[&overlay2, &base2], 1, proposed_ordinary, reserved_esc);
assert_agree(&[&overlay2, &base2], 1, proposed_reserved, reserved_esc);
assert_agree(&[&overlay2, &base2], 1, proposed_collapse, reserved_esc_tab);
}
#[test]
fn validate_rebind_and_clone_simulate_diverge_on_same_action_rebind() {
let mut global: Keymap<Action> = Keymap::new();
global.bind(esc(), Action::Quit);
let reserved = [esc()];
let clone_result = would_break_escape(&[&global], 0, esc(), Action::Quit, &reserved);
assert!(!clone_result, "clone-simulate permits same-action rebind");
let vr = validate_rebind(&[&global], 0, esc(), &reserved);
assert!(
matches!(vr, RebindVerdict::BreaksReserved { .. }),
"validate_rebind refuses same-action rebind onto reserved"
);
}
#[test]
fn multiple_reserved_keys_are_all_protected() {
let global: Keymap<Action> = Keymap::new();
let reserved = [esc(), ctrl('c'), plain('q')];
assert!(would_break_escape(
&[&global],
0,
plain('q'),
Action::Save,
&reserved
));
}