From c42df413327bdd4d999e43237e915f87fcfa4f92 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Mon, 16 Sep 2019 17:02:29 +0200 Subject: [PATCH] Fix bindings incorrectly getting replaced Fixes #2794. --- alacritty_terminal/src/input.rs | 121 +++++++++++++++++++++++++------- 1 file changed, 95 insertions(+), 26 deletions(-) diff --git a/alacritty_terminal/src/input.rs b/alacritty_terminal/src/input.rs index 02d8576..e87a70a 100644 --- a/alacritty_terminal/src/input.rs +++ b/alacritty_terminal/src/input.rs @@ -198,10 +198,21 @@ impl Binding { #[inline] pub fn triggers_match(&self, binding: &Binding) -> bool { - self.trigger == binding.trigger - && self.mods == binding.mods - && (self.mode.contains(binding.mode) || binding.mode.contains(self.mode)) - && (self.notmode.contains(binding.notmode) || binding.notmode.contains(self.notmode)) + // Check the binding's key and modifiers + if self.trigger != binding.trigger || self.mods != binding.mods { + return false; + } + + // Completely empty modes match all modes + if (self.mode.is_empty() && self.notmode.is_empty()) + || (binding.mode.is_empty() && binding.notmode.is_empty()) + { + return true; + } + + // Check for intersection (equality is required since empty does not intersect itself) + (self.mode == binding.mode || self.mode.intersects(binding.mode)) + && (self.notmode == binding.notmode || self.notmode.intersects(binding.notmode)) } } @@ -1074,28 +1085,6 @@ mod tests { assert!(different_action.triggers_match(&binding)); } - #[test] - fn subset_mode_binding_matches_superset() { - let mut superset_mode = MockBinding::default(); - superset_mode.mode = TermMode::ALT_SCREEN | TermMode::INSERT | TermMode::ORIGIN; - let mut subset_mode = MockBinding::default(); - subset_mode.mode = TermMode::ALT_SCREEN | TermMode::ORIGIN; - - assert!(superset_mode.triggers_match(&subset_mode)); - assert!(subset_mode.triggers_match(&superset_mode)); - } - - #[test] - fn subset_notmode_binding_matches_superset() { - let mut superset_notmode = MockBinding::default(); - superset_notmode.notmode = TermMode::ALT_SCREEN | TermMode::INSERT | TermMode::ORIGIN; - let mut subset_notmode = MockBinding::default(); - subset_notmode.notmode = TermMode::ALT_SCREEN | TermMode::ORIGIN; - - assert!(superset_notmode.triggers_match(&subset_notmode)); - assert!(subset_notmode.triggers_match(&superset_notmode)); - } - #[test] fn mods_binding_requires_strict_match() { let mut superset_mods = MockBinding::default(); @@ -1107,6 +1096,86 @@ mod tests { assert!(!subset_mods.triggers_match(&superset_mods)); } + #[test] + fn binding_matches_identical_mode() { + let mut b1 = MockBinding::default(); + b1.mode = TermMode::ALT_SCREEN; + let mut b2 = MockBinding::default(); + b2.mode = TermMode::ALT_SCREEN; + + assert!(b1.triggers_match(&b2)); + } + + #[test] + fn binding_without_mode_matches_any_mode() { + let b1 = MockBinding::default(); + let mut b2 = MockBinding::default(); + b2.mode = TermMode::APP_KEYPAD; + b2.notmode = TermMode::ALT_SCREEN; + + assert!(b1.triggers_match(&b2)); + } + + #[test] + fn binding_with_mode_matches_empty_mode() { + let mut b1 = MockBinding::default(); + b1.mode = TermMode::APP_KEYPAD; + b1.notmode = TermMode::ALT_SCREEN; + let b2 = MockBinding::default(); + + assert!(b1.triggers_match(&b2)); + } + + #[test] + fn binding_matches_superset_mode() { + let mut b1 = MockBinding::default(); + b1.mode = TermMode::APP_KEYPAD; + let mut b2 = MockBinding::default(); + b2.mode = TermMode::ALT_SCREEN | TermMode::APP_KEYPAD; + + assert!(b1.triggers_match(&b2)); + } + + #[test] + fn binding_matches_subset_mode() { + let mut b1 = MockBinding::default(); + b1.mode = TermMode::ALT_SCREEN | TermMode::APP_KEYPAD; + let mut b2 = MockBinding::default(); + b2.mode = TermMode::APP_KEYPAD; + + assert!(b1.triggers_match(&b2)); + } + + #[test] + fn binding_matches_partial_intersection() { + let mut b1 = MockBinding::default(); + b1.mode = TermMode::ALT_SCREEN | TermMode::APP_KEYPAD; + let mut b2 = MockBinding::default(); + b2.mode = TermMode::APP_KEYPAD | TermMode::APP_CURSOR; + + assert!(b1.triggers_match(&b2)); + } + + #[test] + fn binding_mismatches_notmode() { + let mut b1 = MockBinding::default(); + b1.mode = TermMode::ALT_SCREEN; + let mut b2 = MockBinding::default(); + b2.notmode = TermMode::ALT_SCREEN; + + assert!(!b1.triggers_match(&b2)); + } + + #[test] + fn binding_mismatches_unrelated() { + let mut b1 = MockBinding::default(); + b1.mode = TermMode::ALT_SCREEN; + let mut b2 = MockBinding::default(); + b2.mode = TermMode::APP_KEYPAD; + + assert!(!b1.triggers_match(&b2)); + } + #[test] fn binding_trigger_input() { let mut binding = MockBinding::default();