aboutsummaryrefslogtreecommitdiffstats
path: root/src/common/input
diff options
context:
space:
mode:
authora-kenji <aks.kenji@protonmail.com>2021-05-07 15:07:23 +0200
committerGitHub <noreply@github.com>2021-05-07 15:07:23 +0200
commitc6ec5b22c9bdbc877d8ccd2c90f927b0e17c9b87 (patch)
treebe3c795d96d836e290ac39ab0bf8731c1d1d20df /src/common/input
parentchore(version): bump development version (diff)
parent!fixup Add more Functionality to Unbind (diff)
downloadsl0ppij-c6ec5b22c9bdbc877d8ccd2c90f927b0e17c9b87.tar.gz
sl0ppij-c6ec5b22c9bdbc877d8ccd2c90f927b0e17c9b87.tar.xz
sl0ppij-c6ec5b22c9bdbc877d8ccd2c90f927b0e17c9b87.zip
Merge pull request #468 from a-kenji/partial-unbind-modes
Add more Functionality to Unbind
Diffstat (limited to 'src/common/input')
-rw-r--r--src/common/input/keybinds.rs132
-rw-r--r--src/common/input/unit/keybinds_test.rs653
2 files changed, 771 insertions, 14 deletions
diff --git a/src/common/input/keybinds.rs b/src/common/input/keybinds.rs
index 9842fbe2..823ca264 100644
--- a/src/common/input/keybinds.rs
+++ b/src/common/input/keybinds.rs
@@ -29,8 +29,14 @@ pub struct KeybindsFromYaml {
#[serde(untagged)]
enum KeyActionUnbind {
KeyAction(KeyActionFromYaml),
- // TODO: use the enum
- //Unbind(UnbindFromYaml),
+ Unbind(UnbindFromYaml),
+}
+
+/// Intermediate struct used for deserialisation
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+struct KeyActionUnbindFromYaml {
+ keybinds: Vec<KeyActionFromYaml>,
+ unbind: Unbind,
}
/// Intermediate struct used for deserialisation
@@ -41,7 +47,7 @@ pub struct KeyActionFromYaml {
}
/// Intermediate struct used for deserialisation
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize)]
+#[derive(Clone, Debug, PartialEq, Deserialize)]
struct UnbindFromYaml {
unbind: Unbind,
}
@@ -51,16 +57,19 @@ struct UnbindFromYaml {
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize)]
#[serde(untagged)]
enum Unbind {
+ // This is the correct order, don't rearrange!
+ // Suspected Bug in the untagged macro.
+ // 1. Keys
+ Keys(Vec<Key>),
+ // 2. All
All(bool),
- // TODO@a-kenji: use the enum
- //Keys(Vec<Key>),
}
impl Default for Keybinds {
+ // Use once per codepath
+ // TODO investigate why
fn default() -> Keybinds {
- config::Config::from_default_assets()
- .expect("Keybinds from default assets Error")
- .keybinds
+ Self::from_default_assets()
}
}
@@ -69,11 +78,18 @@ impl Keybinds {
Keybinds(HashMap::<InputMode, ModeKeybinds>::new())
}
+ fn from_default_assets() -> Keybinds {
+ config::Config::from_default_assets()
+ .expect("Keybinds from default assets Error!")
+ .keybinds
+ }
+
+ /// Entrypoint from the config module
pub fn get_default_keybinds_with_config(from_yaml: Option<KeybindsFromYaml>) -> Keybinds {
let default_keybinds = match from_yaml.clone() {
Some(keybinds) => match keybinds.unbind {
Unbind::All(true) => Keybinds::new(),
- Unbind::All(false) => Keybinds::default(),
+ Unbind::All(false) | Unbind::Keys(_) => Keybinds::unbind(keybinds),
},
None => Keybinds::default(),
};
@@ -85,6 +101,71 @@ impl Keybinds {
}
}
+ /// Unbinds the default keybindings in relation to their mode
+ fn unbind(from_yaml: KeybindsFromYaml) -> Keybinds {
+ let mut keybind_config = Self::new();
+ let mut unbind_config: HashMap<InputMode, Unbind> = HashMap::new();
+ let keybinds_from_yaml = from_yaml.keybinds;
+
+ for mode in InputMode::iter() {
+ if let Some(keybinds) = keybinds_from_yaml.get(&mode) {
+ for keybind in keybinds.iter() {
+ match keybind {
+ KeyActionUnbind::Unbind(unbind) => {
+ unbind_config.insert(mode, unbind.unbind.clone());
+ }
+ KeyActionUnbind::KeyAction(key_action_from_yaml) => {
+ keybind_config
+ .0
+ .insert(mode, ModeKeybinds::from(key_action_from_yaml.clone()));
+ }
+ }
+ }
+ }
+ }
+
+ let mut default = Self::default().unbind_mode(unbind_config);
+
+ // Toplevel Unbinds
+ if let Unbind::Keys(_) = from_yaml.unbind {
+ let mut unbind_config: HashMap<InputMode, Unbind> = HashMap::new();
+ for mode in InputMode::iter() {
+ unbind_config.insert(mode, from_yaml.unbind.clone());
+ }
+ default = default.unbind_mode(unbind_config);
+ };
+
+ default.merge_keybinds(keybind_config)
+ }
+
+ /// Unbind [`Key`] bindings respective to their mode
+ fn unbind_mode(&self, unbind: HashMap<InputMode, Unbind>) -> Keybinds {
+ let mut keybinds = Keybinds::new();
+
+ for mode in InputMode::iter() {
+ if let Some(unbind) = unbind.get(&mode) {
+ match unbind {
+ Unbind::All(true) => {}
+ Unbind::Keys(keys) => {
+ if let Some(defaults) = self.0.get(&mode) {
+ keybinds
+ .0
+ .insert(mode, defaults.clone().unbind_keys(keys.to_vec()));
+ }
+ }
+ Unbind::All(false) => {
+ if let Some(defaults) = self.0.get(&mode) {
+ keybinds.0.insert(mode, defaults.clone());
+ }
+ }
+ }
+ } else if let Some(defaults) = self.0.get(&mode) {
+ keybinds.0.insert(mode, defaults.clone());
+ }
+ }
+ keybinds
+ }
+
/// Merges two Keybinds structs into one Keybinds struct
/// `other` overrides the ModeKeybinds of `self`.
fn merge_keybinds(&self, other: Keybinds) -> Keybinds {
@@ -142,6 +223,15 @@ impl ModeKeybinds {
merged.0.extend(other.0);
merged
}
+
+ /// Remove [`Key`]'s from [`ModeKeybinds`]
+ fn unbind_keys(self, unbind: Vec<Key>) -> Self {
+ let mut keymap = self;
+ for key in unbind {
+ keymap.0.remove(&key);
+ }
+ keymap
+ }
}
impl From<KeybindsFromYaml> for Keybinds {
@@ -161,27 +251,41 @@ impl From<KeybindsFromYaml> for Keybinds {
}
}
-/// For each `Key` assigned to `Action`s,
-/// map the `Action`s to the key
+/// For each [`Key`] assigned to [`Action`]s,
+/// map the [`Action`]s to the [`Key`]
impl From<KeyActionFromYaml> for ModeKeybinds {
fn from(key_action: KeyActionFromYaml) -> ModeKeybinds {
- let keys = key_action.key;
let actions = key_action.action;
ModeKeybinds(
- keys.into_iter()
+ key_action
+ .key
+ .into_iter()
.map(|k| (k, actions.clone()))
.collect::<HashMap<Key, Vec<Action>>>(),
)
}
}
-// Currently an enum for future use
impl From<KeyActionUnbind> for ModeKeybinds {
fn from(key_action_unbind: KeyActionUnbind) -> ModeKeybinds {
match key_action_unbind {
KeyActionUnbind::KeyAction(key_action) => ModeKeybinds::from(key_action),
+ KeyActionUnbind::Unbind(_) => ModeKeybinds::new(),
+ }
+ }
+}
+
+impl From<Vec<KeyActionFromYaml>> for ModeKeybinds {
+ fn from(key_action_from_yaml: Vec<KeyActionFromYaml>) -> ModeKeybinds {
+ let mut mode_keybinds = ModeKeybinds::new();
+
+ for keybind in key_action_from_yaml {
+ for key in keybind.key {
+ mode_keybinds.0.insert(key, keybind.action.clone());
+ }
}
+ mode_keybinds
}
}
diff --git a/src/common/input/unit/keybinds_test.rs b/src/common/input/unit/keybinds_test.rs
index e0d78b62..4767fc15 100644
--- a/src/common/input/unit/keybinds_test.rs
+++ b/src/common/input/unit/keybinds_test.rs
@@ -136,6 +136,7 @@ fn toplevel_unbind_unbinds_all() {
assert_eq!(keybinds_from_yaml, Keybinds::new());
}
+#[test]
fn no_unbind_unbinds_none() {
let from_yaml = KeybindsFromYaml {
unbind: Unbind::All(false),
@@ -144,5 +145,657 @@ fn no_unbind_unbinds_none() {
let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml));
+ assert_eq!(keybinds_from_yaml, Keybinds::default());
+}
+
+#[test]
+fn last_keybind_is_taken() {
+ let actions_1 = vec![Action::NoOp, Action::NewTab];
+ let keyaction_1 = KeyActionFromYaml {
+ action: actions_1.clone(),
+ key: vec![Key::F(1), Key::Backspace, Key::Char('t')],
+ };
+ let actions_2 = vec![Action::GoToTab(1)];
+ let keyaction_2 = KeyActionFromYaml {
+ action: actions_2.clone(),
+ key: vec![Key::F(1), Key::Backspace, Key::Char('t')],
+ };
+
+ let mut expected = ModeKeybinds::new();
+ expected.0.insert(Key::F(1), actions_2.clone());
+ expected.0.insert(Key::Backspace, actions_2.clone());
+ expected.0.insert(Key::Char('t'), actions_2);
+
+ assert_eq!(expected, ModeKeybinds::from(vec![keyaction_1, keyaction_2]));
+}
+
+#[test]
+fn last_keybind_overwrites() {
+ let actions_1 = vec![Action::NoOp, Action::NewTab];
+ let keyaction_1 = KeyActionFromYaml {
+ action: actions_1.clone(),
+ key: vec![Key::F(1), Key::Backspace, Key::Char('t')],
+ };
+ let actions_2 = vec![Action::GoToTab(1)];
+ let keyaction_2 = KeyActionFromYaml {
+ action: actions_2.clone(),
+ key: vec![Key::F(1), Key::Char('t')],
+ };
+
+ let mut expected = ModeKeybinds::new();
+ expected.0.insert(Key::F(1), actions_2.clone());
+ expected.0.insert(Key::Backspace, actions_1.clone());
+ expected.0.insert(Key::Char('t'), actions_2);
+
+ assert_eq!(expected, ModeKeybinds::from(vec![keyaction_1, keyaction_2]));
+}
+
+#[test]
+fn unbind_single_mode() {
+ let unbind = Unbind::All(true);
+ let unbind_from_yaml = UnbindFromYaml { unbind };
+ let key_action_unbinds = vec![KeyActionUnbind::Unbind(unbind_from_yaml)];
+
+ let mut keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ keys.insert(InputMode::Normal, key_action_unbinds);
+
+ let keybinds_from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::All(false),
+ };
+
+ let keybinds = Keybinds::unbind(keybinds_from_yaml);
+ let result = keybinds.0.get(&InputMode::Normal);
+ assert!(result.is_none());
+}
+
+#[test]
+fn unbind_multiple_modes() {
+ let unbind = Unbind::All(true);
+ let unbind_from_yaml = UnbindFromYaml { unbind };
+ let key_action_unbinds = vec![KeyActionUnbind::Unbind(unbind_from_yaml)];
+
+ let mut keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ keys.insert(InputMode::Normal, key_action_unbinds.clone());
+ keys.insert(InputMode::Pane, key_action_unbinds);
+
+ let keybinds_from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::All(false),
+ };
+
+ let keybinds = Keybinds::unbind(keybinds_from_yaml);
+ let normal = keybinds.0.get(&InputMode::Normal);
+ let pane = keybinds.0.get(&InputMode::Pane);
+ assert!(normal.is_none());
+ assert!(pane.is_none());
+}
+
+#[test]
+fn unbind_single_keybind_single_mode() {
+ let unbind = Unbind::Keys(vec![Key::Alt('n')]);
+ let unbind_from_yaml = UnbindFromYaml { unbind };
+ let key_action_unbinds = vec![KeyActionUnbind::Unbind(unbind_from_yaml)];
+
+ let mut keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ keys.insert(InputMode::Normal, key_action_unbinds);
+
+ let keybinds_from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::All(false),
+ };
+
+ let keybinds = Keybinds::unbind(keybinds_from_yaml);
+ let mode_keybinds = keybinds.0.get(&InputMode::Normal);
+ let result = mode_keybinds
+ .expect("Mode shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ assert!(result.is_none());
+}
+
+#[test]
+fn unbind_single_keybind_multiple_modes() {
+ let unbind_n = Unbind::Keys(vec![Key::Alt('n')]);
+ let unbind_h = Unbind::Keys(vec![Key::Alt('h')]);
+ let unbind_from_yaml_n = UnbindFromYaml { unbind: unbind_n };
+ let unbind_from_yaml_h = UnbindFromYaml { unbind: unbind_h };
+ let key_action_unbinds_n = vec![KeyActionUnbind::Unbind(unbind_from_yaml_n)];
+ let key_action_unbinds_h = vec![KeyActionUnbind::Unbind(unbind_from_yaml_h)];
+
+ let mut keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ keys.insert(InputMode::Normal, key_action_unbinds_n);
+ keys.insert(InputMode::Pane, key_action_unbinds_h);
+
+ let keybinds_from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::All(false),
+ };
+
+ let keybinds = Keybinds::unbind(keybinds_from_yaml);
+ let normal = keybinds.0.get(&InputMode::Normal);
+ let pane = keybinds.0.get(&InputMode::Pane);
+ let result_normal = normal
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_pane = pane.expect("Mode shouldn't be empty").0.get(&Key::Alt('h'));
+ assert!(result_normal.is_none());
+ assert!(result_pane.is_none());
+}
+
+#[test]
+fn unbind_multiple_keybinds_single_mode() {
+ let unbind = Unbind::Keys(vec![Key::Alt('n'), Key::Ctrl('p')]);
+ let unbind_from_yaml = UnbindFromYaml { unbind };
+ let key_action_unbinds = vec![KeyActionUnbind::Unbind(unbind_from_yaml)];
+
+ let mut keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ keys.insert(InputMode::Normal, key_action_unbinds);
+
+ let keybinds_from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::All(false),
+ };
+
+ let keybinds = Keybinds::unbind(keybinds_from_yaml);
+ let mode_keybinds = keybinds.0.get(&InputMode::Normal);
+ let result_n = mode_keybinds
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_p = mode_keybinds
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Ctrl('p'));
+ assert!(result_n.is_none());
+ assert!(result_p.is_none());
+}
+
+#[test]
+fn unbind_multiple_keybinds_multiple_modes() {
+ let unbind_normal = Unbind::Keys(vec![Key::Alt('n'), Key::Ctrl('p')]);
+ let unbind_resize = Unbind::Keys(vec![Key::Char('h'), Key::Ctrl('r')]);
+ let unbind_from_yaml_normal = UnbindFromYaml {
+ unbind: unbind_normal,
+ };
+ let unbind_from_yaml_resize = UnbindFromYaml {
+ unbind: unbind_resize,
+ };
+ let key_action_unbinds_normal = vec![KeyActionUnbind::Unbind(unbind_from_yaml_normal)];
+ let key_action_unbinds_resize = vec![KeyActionUnbind::Unbind(unbind_from_yaml_resize)];
+
+ let mut keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ keys.insert(InputMode::Normal, key_action_unbinds_normal);
+ keys.insert(InputMode::Resize, key_action_unbinds_resize);
+
+ let keybinds_from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::All(false),
+ };
+
+ let keybinds = Keybinds::unbind(keybinds_from_yaml);
+ let mode_keybinds_normal = keybinds.0.get(&InputMode::Normal);
+ let mode_keybinds_resize = keybinds.0.get(&InputMode::Resize);
+ let result_normal_1 = mode_keybinds_normal
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_normal_2 = mode_keybinds_normal
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Ctrl('p'));
+ let result_resize_1 = mode_keybinds_resize
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Char('h'));
+ let result_resize_2 = mode_keybinds_resize
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Ctrl('r'));
+ assert!(result_normal_1.is_none());
+ assert!(result_resize_1.is_none());
+ assert!(result_normal_2.is_none());
+ assert!(result_resize_2.is_none());
+}
+
+#[test]
+fn unbind_multiple_keybinds_all_modes() {
+ let unbind = Unbind::Keys(vec![Key::Alt('n'), Key::Alt('h')]);
+ let keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ let keybinds_from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind,
+ };
+
+ let keybinds = Keybinds::unbind(keybinds_from_yaml);
+ let mode_keybinds_normal = keybinds.0.get(&InputMode::Normal);
+ let mode_keybinds_resize = keybinds.0.get(&InputMode::Resize);
+ let result_normal_1 = mode_keybinds_normal
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_normal_2 = mode_keybinds_normal
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Ctrl('h'));
+ let result_resize_1 = mode_keybinds_resize
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Char('n'));
+ let result_resize_2 = mode_keybinds_resize
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Ctrl('h'));
+ assert!(result_normal_1.is_none());
+ assert!(result_resize_1.is_none());
+ assert!(result_normal_2.is_none());
+ assert!(result_resize_2.is_none());
+}
+
+#[test]
+fn unbind_all_toplevel_single_key_single_mode() {
+ let unbind = Unbind::Keys(vec![Key::Alt('h')]);
+ let unbind_from_yaml = UnbindFromYaml { unbind };
+ let key_action_unbinds_normal = vec![KeyActionUnbind::Unbind(unbind_from_yaml)];
+ let mut keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ keys.insert(InputMode::Normal, key_action_unbinds_normal);
+ let from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::All(true),
+ };
+
+ let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml));
+ assert_eq!(keybinds_from_yaml, Keybinds::new());
+}
+
+#[test]
+fn unbind_all_toplevel_single_key_multiple_modes() {
+ let unbind_n = Unbind::Keys(vec![Key::Alt('n')]);
+ let unbind_h = Unbind::Keys(vec![Key::Alt('h')]);
+ let unbind_from_yaml_n = UnbindFromYaml { unbind: unbind_n };
+ let unbind_from_yaml_h = UnbindFromYaml { unbind: unbind_h };
+ let key_action_unbinds_normal = vec![KeyActionUnbind::Unbind(unbind_from_yaml_n)];
+ let key_action_unbinds_pane = vec![KeyActionUnbind::Unbind(unbind_from_yaml_h)];
+ let mut keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ keys.insert(InputMode::Normal, key_action_unbinds_normal);
+ keys.insert(InputMode::Pane, key_action_unbinds_pane);
+ let from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::All(true),
+ };
+
+ let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml));
+ assert_eq!(keybinds_from_yaml, Keybinds::new());
+}
+
+#[test]
+fn unbind_all_toplevel_multiple_key_multiple_modes() {
+ let unbind_n = Unbind::Keys(vec![Key::Alt('n'), Key::Ctrl('p')]);
+ let unbind_h = Unbind::Keys(vec![Key::Alt('h'), Key::Ctrl('t')]);
+ let unbind_from_yaml_n = UnbindFromYaml { unbind: unbind_n };
+ let unbind_from_yaml_h = UnbindFromYaml { unbind: unbind_h };
+ let key_action_unbinds_normal = vec![KeyActionUnbind::Unbind(unbind_from_yaml_n)];
+ let key_action_unbinds_pane = vec![KeyActionUnbind::Unbind(unbind_from_yaml_h)];
+ let mut keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ keys.insert(InputMode::Normal, key_action_unbinds_normal);
+ keys.insert(InputMode::Pane, key_action_unbinds_pane);
+ let from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::All(true),
+ };
+
+ let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml));
assert_eq!(keybinds_from_yaml, Keybinds::new());
}
+
+#[test]
+fn unbind_all_toplevel_all_key_multiple_modes() {
+ let unbind = Unbind::All(true);
+ let unbind_from_yaml = UnbindFromYaml { unbind };
+ let key_action_unbinds_normal = vec![KeyActionUnbind::Unbind(unbind_from_yaml.clone())];
+ let key_action_unbinds_pane = vec![KeyActionUnbind::Unbind(unbind_from_yaml)];
+ let mut keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ keys.insert(InputMode::Normal, key_action_unbinds_normal);
+ keys.insert(InputMode::Pane, key_action_unbinds_pane);
+ let from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::All(true),
+ };
+
+ let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml));
+ assert_eq!(keybinds_from_yaml, Keybinds::new());
+}
+
+#[test]
+fn unbind_single_keybind_all_modes() {
+ let keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ let from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::Keys(vec![Key::Alt('n')]),
+ };
+
+ let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml));
+
+ let result_normal = keybinds_from_yaml
+ .0
+ .get(&InputMode::Normal)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_pane = keybinds_from_yaml
+ .0
+ .get(&InputMode::Pane)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_resize = keybinds_from_yaml
+ .0
+ .get(&InputMode::Resize)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_tab = keybinds_from_yaml
+ .0
+ .get(&InputMode::Tab)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+
+ assert!(result_normal.is_none());
+ assert!(result_pane.is_none());
+ assert!(result_resize.is_none());
+ assert!(result_tab.is_none());
+}
+
+#[test]
+fn unbind_single_toplevel_single_key_single_mode_identical() {
+ let unbind = Unbind::Keys(vec![Key::Alt('n')]);
+ let unbind_from_yaml = UnbindFromYaml { unbind };
+ let key_action_unbind = vec![KeyActionUnbind::Unbind(unbind_from_yaml)];
+ let mut keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ keys.insert(InputMode::Normal, key_action_unbind);
+ let from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::Keys(vec![Key::Alt('n')]),
+ };
+
+ let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml));
+
+ let result_normal = keybinds_from_yaml
+ .0
+ .get(&InputMode::Normal)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_pane = keybinds_from_yaml
+ .0
+ .get(&InputMode::Pane)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_resize = keybinds_from_yaml
+ .0
+ .get(&InputMode::Resize)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_tab = keybinds_from_yaml
+ .0
+ .get(&InputMode::Tab)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+
+ assert!(result_normal.is_none());
+ assert!(result_pane.is_none());
+ assert!(result_resize.is_none());
+ assert!(result_tab.is_none());
+}
+
+#[test]
+fn unbind_single_toplevel_single_key_single_mode_differing() {
+ let unbind = Unbind::Keys(vec![Key::Alt('l')]);
+ let unbind_from_yaml = UnbindFromYaml { unbind };
+ let key_action_unbind = vec![KeyActionUnbind::Unbind(unbind_from_yaml)];
+ let mut keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ keys.insert(InputMode::Normal, key_action_unbind);
+ let from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::Keys(vec![Key::Alt('n')]),
+ };
+
+ let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml));
+
+ let result_normal_n = keybinds_from_yaml
+ .0
+ .get(&InputMode::Normal)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_normal_l = keybinds_from_yaml
+ .0
+ .get(&InputMode::Normal)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('l'));
+ let result_resize_n = keybinds_from_yaml
+ .0
+ .get(&InputMode::Resize)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_resize_l = keybinds_from_yaml
+ .0
+ .get(&InputMode::Resize)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('l'));
+
+ assert!(result_normal_n.is_none());
+ assert!(result_normal_l.is_none());
+ assert!(result_resize_n.is_none());
+ assert!(result_resize_l.is_some());
+}
+
+#[test]
+fn unbind_single_toplevel_single_key_multiple_modes() {
+ let unbind = Unbind::Keys(vec![Key::Alt('l')]);
+ let unbind_from_yaml = UnbindFromYaml { unbind };
+ let key_action_unbind = vec![KeyActionUnbind::Unbind(unbind_from_yaml)];
+ let mut keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ keys.insert(InputMode::Normal, key_action_unbind.clone());
+ keys.insert(InputMode::Pane, key_action_unbind);
+ let from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::Keys(vec![Key::Alt('n')]),
+ };
+
+ let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml));
+
+ let result_normal_n = keybinds_from_yaml
+ .0
+ .get(&InputMode::Normal)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_normal_l = keybinds_from_yaml
+ .0
+ .get(&InputMode::Normal)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('l'));
+ let result_pane_n = keybinds_from_yaml
+ .0
+ .get(&InputMode::Pane)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_pane_l = keybinds_from_yaml
+ .0
+ .get(&InputMode::Pane)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('l'));
+
+ assert!(result_normal_n.is_none());
+ assert!(result_normal_l.is_none());
+ assert!(result_pane_n.is_none());
+ assert!(result_pane_l.is_none());
+}
+
+#[test]
+fn unbind_single_toplevel_multiple_keys_single_mode() {
+ let unbind = Unbind::Keys(vec![
+ Key::Alt('l'),
+ Key::Alt('h'),
+ Key::Alt('j'),
+ Key::Alt('k'),
+ ]);
+ let unbind_from_yaml = UnbindFromYaml { unbind };
+ let key_action_unbind = vec![KeyActionUnbind::Unbind(unbind_from_yaml)];
+ let mut keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ keys.insert(InputMode::Normal, key_action_unbind.clone());
+ keys.insert(InputMode::Pane, key_action_unbind);
+ let from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::Keys(vec![Key::Alt('n')]),
+ };
+
+ let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml));
+
+ let result_normal_n = keybinds_from_yaml
+ .0
+ .get(&InputMode::Normal)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_normal_l = keybinds_from_yaml
+ .0
+ .get(&InputMode::Normal)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('l'));
+ let result_normal_k = keybinds_from_yaml
+ .0
+ .get(&InputMode::Pane)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('k'));
+ let result_normal_h = keybinds_from_yaml
+ .0
+ .get(&InputMode::Pane)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('h'));
+
+ assert!(result_normal_n.is_none());
+ assert!(result_normal_l.is_none());
+ assert!(result_normal_h.is_none());
+ assert!(result_normal_k.is_none());
+}
+
+#[test]
+fn unbind_single_toplevel_multiple_keys_multiple_modes() {
+ let unbind_normal = Unbind::Keys(vec![Key::Alt('l'), Key::Ctrl('p')]);
+ let unbind_from_yaml_normal = UnbindFromYaml {
+ unbind: unbind_normal,
+ };
+ let key_action_unbind_normal = vec![KeyActionUnbind::Unbind(unbind_from_yaml_normal)];
+ let unbind = Unbind::Keys(vec![Key::Alt('l'), Key::Alt('k')]);
+ let unbind_from_yaml = UnbindFromYaml { unbind };
+ let key_action_unbind = vec![KeyActionUnbind::Unbind(unbind_from_yaml)];
+ let mut keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ keys.insert(InputMode::Normal, key_action_unbind_normal);
+ keys.insert(InputMode::Pane, key_action_unbind);
+ let from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::Keys(vec![Key::Alt('n')]),
+ };
+
+ let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml));
+
+ let result_normal_n = keybinds_from_yaml
+ .0
+ .get(&InputMode::Normal)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_normal_p = keybinds_from_yaml
+ .0
+ .get(&InputMode::Normal)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Ctrl('p'));
+ let result_normal_l = keybinds_from_yaml
+ .0
+ .get(&InputMode::Normal)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('l'));
+ let result_pane_p = keybinds_from_yaml
+ .0
+ .get(&InputMode::Pane)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Ctrl('p'));
+ let result_pane_n = keybinds_from_yaml
+ .0
+ .get(&InputMode::Pane)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('n'));
+ let result_pane_l = keybinds_from_yaml
+ .0
+ .get(&InputMode::Pane)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Alt('l'));
+
+ assert!(result_normal_n.is_none());
+ assert!(result_normal_l.is_none());
+ assert!(result_normal_p.is_none());
+ assert!(result_pane_n.is_none());
+ assert!(result_pane_p.is_some());
+ assert!(result_pane_l.is_none());
+}
+
+#[test]
+fn uppercase_and_lowercase_are_distinct() {
+ let key_action_n = KeyActionFromYaml {
+ key: vec![Key::Char('n')],
+ action: vec![Action::NewTab],
+ };
+ let key_action_large_n = KeyActionFromYaml {
+ key: vec![Key::Char('N')],
+ action: vec![Action::NewPane(None)],
+ };
+
+ let key_action_unbind = vec![
+ KeyActionUnbind::KeyAction(key_action_n),
+ KeyActionUnbind::KeyAction(key_action_large_n),
+ ];
+ let mut keys = HashMap::<InputMode, Vec<KeyActionUnbind>>::new();
+ keys.insert(InputMode::Normal, key_action_unbind);
+ let from_yaml = KeybindsFromYaml {
+ keybinds: keys,
+ unbind: Unbind::All(false),
+ };
+
+ let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml));
+ let result_n = keybinds_from_yaml
+ .0
+ .get(&InputMode::Normal)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Char('n'));
+ let result_large_n = keybinds_from_yaml
+ .0
+ .get(&InputMode::Normal)
+ .expect("ModeKeybinds shouldn't be empty")
+ .0
+ .get(&Key::Char('N'));
+
+ assert!(result_n.is_some());
+ assert!(result_large_n.is_some());
+}