aboutsummaryrefslogtreecommitdiffstats
path: root/zellij-utils/src/input/keybinds.rs
diff options
context:
space:
mode:
authorKunal Mohan <kunalmohan99@gmail.com>2021-05-16 16:42:50 +0530
committerKunal Mohan <kunalmohan99@gmail.com>2021-05-16 21:41:56 +0530
commit2038947a14d32d89da2bdbcaa1381c3015ac9c7a (patch)
tree5a332470e32b380816098594a89d3c3db1f6eb53 /zellij-utils/src/input/keybinds.rs
parenthandle error on termios initialization (#511) (diff)
downloadsl0ppij-2038947a14d32d89da2bdbcaa1381c3015ac9c7a.tar.gz
sl0ppij-2038947a14d32d89da2bdbcaa1381c3015ac9c7a.tar.xz
sl0ppij-2038947a14d32d89da2bdbcaa1381c3015ac9c7a.zip
Big refactor: separate crates for client, server and utilities
Diffstat (limited to 'zellij-utils/src/input/keybinds.rs')
-rw-r--r--zellij-utils/src/input/keybinds.rs301
1 files changed, 301 insertions, 0 deletions
diff --git a/zellij-utils/src/input/keybinds.rs b/zellij-utils/src/input/keybinds.rs
new file mode 100644
index 00000000..8bef47fd
--- /dev/null
+++ b/zellij-utils/src/input/keybinds.rs
@@ -0,0 +1,301 @@
+//! Mapping of inputs to sequences of actions.
+use std::collections::HashMap;
+
+use super::actions::Action;
+use super::config;
+
+use serde::{Deserialize, Serialize};
+use strum::IntoEnumIterator;
+use zellij_tile::data::*;
+
+/// Used in the config struct
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct Keybinds(HashMap<InputMode, ModeKeybinds>);
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct ModeKeybinds(HashMap<Key, Vec<Action>>);
+
+/// Intermediate struct used for deserialisation
+/// Used in the config file.
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+pub struct KeybindsFromYaml {
+ #[serde(flatten)]
+ keybinds: HashMap<InputMode, Vec<KeyActionUnbind>>,
+ #[serde(default)]
+ unbind: Unbind,
+}
+
+/// Intermediate enum used for deserialisation
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+#[serde(untagged)]
+enum KeyActionUnbind {
+ KeyAction(KeyActionFromYaml),
+ Unbind(UnbindFromYaml),
+}
+
+/// Intermediate struct used for deserialisation
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+struct KeyActionUnbindFromYaml {
+ keybinds: Vec<KeyActionFromYaml>,
+ unbind: Unbind,
+}
+
+/// Intermediate struct used for deserialisation
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+pub struct KeyActionFromYaml {
+ action: Vec<Action>,
+ key: Vec<Key>,
+}
+
+/// Intermediate struct used for deserialisation
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+struct UnbindFromYaml {
+ unbind: Unbind,
+}
+
+/// List of keys, for which to disable their respective default actions
+/// `All` is a catch all, and will disable the default actions for all keys.
+#[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),
+}
+
+impl Default for Keybinds {
+ // Use once per codepath
+ // TODO investigate why
+ fn default() -> Keybinds {
+ Self::from_default_assets()
+ }
+}
+
+impl Keybinds {
+ pub fn new() -> 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) | Unbind::Keys(_) => Keybinds::unbind(keybinds),
+ },
+ None => Keybinds::default(),
+ };
+
+ if let Some(keybinds) = from_yaml {
+ default_keybinds.merge_keybinds(Keybinds::from(keybinds))
+ } else {
+ default_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 {
+ let mut keybinds = Keybinds::new();
+
+ for mode in InputMode::iter() {
+ let mut mode_keybinds = ModeKeybinds::new();
+ if let Some(keybind) = self.0.get(&mode) {
+ mode_keybinds.0.extend(keybind.0.clone());
+ };
+ if let Some(keybind) = other.0.get(&mode) {
+ mode_keybinds.0.extend(keybind.0.clone());
+ }
+ if !mode_keybinds.0.is_empty() {
+ keybinds.0.insert(mode, mode_keybinds);
+ }
+ }
+ keybinds
+ }
+
+ /// Converts a [`Key`] terminal event to a sequence of [`Action`]s according to the current
+ /// [`InputMode`] and [`Keybinds`].
+ pub fn key_to_actions(
+ key: &Key,
+ input: Vec<u8>,
+ mode: &InputMode,
+ keybinds: &Keybinds,
+ ) -> Vec<Action> {
+ let mode_keybind_or_action = |action: Action| {
+ keybinds
+ .0
+ .get(mode)
+ .unwrap_or_else(|| unreachable!("Unrecognized mode: {:?}", mode))
+ .0
+ .get(key)
+ .cloned()
+ .unwrap_or_else(|| vec![action])
+ };
+ match *mode {
+ InputMode::Normal | InputMode::Locked => mode_keybind_or_action(Action::Write(input)),
+ InputMode::RenameTab => mode_keybind_or_action(Action::TabNameInput(input)),
+ _ => mode_keybind_or_action(Action::NoOp),
+ }
+ }
+}
+
+impl ModeKeybinds {
+ fn new() -> ModeKeybinds {
+ ModeKeybinds(HashMap::<Key, Vec<Action>>::new())
+ }
+
+ /// Merges `self` with `other`, if keys are the same, `other` overwrites.
+ fn merge(self, other: ModeKeybinds) -> ModeKeybinds {
+ let mut merged = self;
+ 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 {
+ fn from(keybinds_from_yaml: KeybindsFromYaml) -> Keybinds {
+ let mut keybinds = Keybinds::new();
+
+ for mode in InputMode::iter() {
+ let mut mode_keybinds = ModeKeybinds::new();
+ for key_action in keybinds_from_yaml.keybinds.get(&mode).iter() {
+ for keybind in key_action.iter() {
+ mode_keybinds = mode_keybinds.merge(ModeKeybinds::from(keybind.clone()));
+ }
+ }
+ keybinds.0.insert(mode, mode_keybinds);
+ }
+ keybinds
+ }
+}
+
+/// 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 actions = key_action.action;
+
+ ModeKeybinds(
+ key_action
+ .key
+ .into_iter()
+ .map(|k| (k, actions.clone()))
+ .collect::<HashMap<Key, Vec<Action>>>(),
+ )
+ }
+}
+
+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
+ }
+}
+
+impl Default for Unbind {
+ fn default() -> Unbind {
+ Unbind::All(false)
+ }
+}
+
+// The unit test location.
+#[cfg(test)]
+#[path = "./unit/keybinds_test.rs"]
+mod keybinds_test;