aboutsummaryrefslogtreecommitdiffstats
path: root/src/common/input
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 /src/common/input
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 'src/common/input')
-rw-r--r--src/common/input/actions.rs64
-rw-r--r--src/common/input/config.rs218
-rw-r--r--src/common/input/handler.rs268
-rw-r--r--src/common/input/keybinds.rs301
-rw-r--r--src/common/input/mod.rs7
-rw-r--r--src/common/input/options.rs45
-rw-r--r--src/common/input/unit/keybinds_test.rs801
7 files changed, 0 insertions, 1704 deletions
diff --git a/src/common/input/actions.rs b/src/common/input/actions.rs
deleted file mode 100644
index b806aa3f..00000000
--- a/src/common/input/actions.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-//! Definition of the actions that can be bound to keys.
-
-use serde::{Deserialize, Serialize};
-use zellij_tile::data::InputMode;
-
-/// The four directions (left, right, up, down).
-#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
-pub enum Direction {
- Left,
- Right,
- Up,
- Down,
-}
-
-/// Actions that can be bound to keys.
-#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
-pub enum Action {
- /// Quit Zellij.
- Quit,
- /// Write to the terminal.
- Write(Vec<u8>),
- /// Switch to the specified input mode.
- SwitchToMode(InputMode),
- /// Resize focus pane in specified direction.
- Resize(Direction),
- /// Switch focus to next pane in specified direction.
- FocusNextPane,
- FocusPreviousPane,
- /// Move the focus pane in specified direction.
- SwitchFocus,
- MoveFocus(Direction),
- /// Tries to move the focus pane in specified direction.
- /// If there is no pane in the direction, move to previous/next Tab.
- MoveFocusOrTab(Direction),
- /// Scroll up in focus pane.
- ScrollUp,
- /// Scroll down in focus pane.
- ScrollDown,
- /// Scroll up one page in focus pane.
- PageScrollUp,
- /// Scroll down one page in focus pane.
- PageScrollDown,
- /// Toggle between fullscreen focus pane and normal layout.
- ToggleFocusFullscreen,
- /// Toggle between sending text commands to all panes on the current tab and normal mode.
- ToggleActiveSyncTab,
- /// Open a new pane in the specified direction (relative to focus).
- /// If no direction is specified, will try to use the biggest available space.
- NewPane(Option<Direction>),
- /// Close the focus pane.
- CloseFocus,
- /// Create a new tab.
- NewTab,
- /// Do nothing.
- NoOp,
- /// Go to the next tab.
- GoToNextTab,
- /// Go to the previous tab.
- GoToPreviousTab,
- /// Close the current tab.
- CloseTab,
- GoToTab(u32),
- TabNameInput(Vec<u8>),
-}
diff --git a/src/common/input/config.rs b/src/common/input/config.rs
deleted file mode 100644
index 3dffe71c..00000000
--- a/src/common/input/config.rs
+++ /dev/null
@@ -1,218 +0,0 @@
-//! Deserializes configuration options.
-use std::error;
-use std::fmt::{self, Display};
-use std::fs::File;
-use std::io::{self, Read};
-use std::path::{Path, PathBuf};
-
-use super::keybinds::{Keybinds, KeybindsFromYaml};
-use super::options::Options;
-use crate::cli::{CliArgs, ConfigCli};
-use crate::common::setup;
-
-use serde::{Deserialize, Serialize};
-use std::convert::TryFrom;
-
-const DEFAULT_CONFIG_FILE_NAME: &str = "config.yaml";
-
-type ConfigResult = Result<Config, ConfigError>;
-
-/// Intermediate deserialization config struct
-#[derive(Debug, Deserialize)]
-pub struct ConfigFromYaml {
- #[serde(flatten)]
- pub options: Option<Options>,
- pub keybinds: Option<KeybindsFromYaml>,
-}
-
-/// Main configuration.
-#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
-pub struct Config {
- pub keybinds: Keybinds,
- pub options: Options,
-}
-
-#[derive(Debug)]
-pub enum ConfigError {
- // Deserialization error
- Serde(serde_yaml::Error),
- // Io error
- Io(io::Error),
- // Io error with path context
- IoPath(io::Error, PathBuf),
- // Internal Deserialization Error
- FromUtf8(std::string::FromUtf8Error),
-}
-
-impl Default for Config {
- fn default() -> Self {
- let keybinds = Keybinds::default();
- let options = Options::default();
- Config { keybinds, options }
- }
-}
-
-impl TryFrom<&CliArgs> for Config {
- type Error = ConfigError;
-
- fn try_from(opts: &CliArgs) -> ConfigResult {
- if let Some(ref path) = opts.config {
- return Config::new(&path);
- }
-
- if let Some(ConfigCli::Setup(setup)) = opts.option.clone() {
- if setup.clean {
- return Config::from_default_assets();
- }
- }
-
- let config_dir = opts
- .config_dir
- .clone()
- .or_else(setup::find_default_config_dir);
-
- if let Some(ref config) = config_dir {
- let path = config.join(DEFAULT_CONFIG_FILE_NAME);
- if path.exists() {
- Config::new(&path)
- } else {
- Config::from_default_assets()
- }
- } else {
- Config::from_default_assets()
- }
- }
-}
-
-impl Config {
- /// Uses defaults, but lets config override them.
- pub fn from_yaml(yaml_config: &str) -> ConfigResult {
- let config_from_yaml: ConfigFromYaml = serde_yaml::from_str(&yaml_config)?;
- let keybinds = Keybinds::get_default_keybinds_with_config(config_from_yaml.keybinds);
- let options = Options::from_yaml(config_from_yaml.options);
- Ok(Config { keybinds, options })
- }
-
- /// Deserializes from given path.
- pub fn new(path: &Path) -> ConfigResult {
- match File::open(path) {
- Ok(mut file) => {
- let mut yaml_config = String::new();
- file.read_to_string(&mut yaml_config)
- .map_err(|e| ConfigError::IoPath(e, path.to_path_buf()))?;
- Ok(Config::from_yaml(&yaml_config)?)
- }
- Err(e) => Err(ConfigError::IoPath(e, path.into())),
- }
- }
-
- /// Gets default configuration from assets
- // TODO Deserialize the Configuration from bytes &[u8],
- // once serde-yaml supports zero-copy
- pub fn from_default_assets() -> ConfigResult {
- Self::from_yaml(String::from_utf8(setup::DEFAULT_CONFIG.to_vec())?.as_str())
- }
-}
-
-impl Display for ConfigError {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- match self {
- ConfigError::Io(ref err) => write!(formatter, "IoError: {}", err),
- ConfigError::IoPath(ref err, ref path) => {
- write!(formatter, "IoError: {}, File: {}", err, path.display(),)
- }
- ConfigError::Serde(ref err) => write!(formatter, "Deserialization error: {}", err),
- ConfigError::FromUtf8(ref err) => write!(formatter, "FromUtf8Error: {}", err),
- }
- }
-}
-
-impl std::error::Error for ConfigError {
- fn cause(&self) -> Option<&dyn error::Error> {
- match *self {
- ConfigError::Io(ref err) => Some(err),
- ConfigError::IoPath(ref err, _) => Some(err),
- ConfigError::Serde(ref err) => Some(err),
- ConfigError::FromUtf8(ref err) => Some(err),
- }
- }
-}
-
-impl From<io::Error> for ConfigError {
- fn from(err: io::Error) -> ConfigError {
- ConfigError::Io(err)
- }
-}
-
-impl From<serde_yaml::Error> for ConfigError {
- fn from(err: serde_yaml::Error) -> ConfigError {
- ConfigError::Serde(err)
- }
-}
-
-impl From<std::string::FromUtf8Error> for ConfigError {
- fn from(err: std::string::FromUtf8Error) -> ConfigError {
- ConfigError::FromUtf8(err)
- }
-}
-
-// The unit test location.
-#[cfg(test)]
-mod config_test {
- use std::io::Write;
-
- use tempfile::tempdir;
-
- use super::*;
-
- #[test]
- fn try_from_cli_args_with_config() {
- let arbitrary_config = PathBuf::from("nonexistent.yaml");
- let mut opts = CliArgs::default();
- opts.config = Some(arbitrary_config);
- println!("OPTS= {:?}", opts);
- let result = Config::try_from(&opts);
- assert!(result.is_err());
- }
-
- #[test]
- fn try_from_cli_args_with_option_clean() {
- use crate::common::setup::Setup;
- let mut opts = CliArgs::default();
- opts.option = Some(ConfigCli::Setup(Setup {
- clean: true,
- ..Setup::default()
- }));
- let result = Config::try_from(&opts);
- assert!(result.is_ok());
- }
-
- #[test]
- fn try_from_cli_args_with_config_dir() {
- let mut opts = CliArgs::default();
- let tmp = tempdir().unwrap();
- File::create(tmp.path().join(DEFAULT_CONFIG_FILE_NAME))
- .unwrap()
- .write_all(b"keybinds: invalid\n")
- .unwrap();
- opts.config_dir = Some(tmp.path().to_path_buf());
- let result = Config::try_from(&opts);
- assert!(result.is_err());
- }
-
- #[test]
- fn try_from_cli_args_with_config_dir_without_config() {
- let mut opts = CliArgs::default();
- let tmp = tempdir().unwrap();
- opts.config_dir = Some(tmp.path().to_path_buf());
- let result = Config::try_from(&opts);
- assert_eq!(result.unwrap(), Config::default());
- }
-
- #[test]
- fn try_from_cli_args_default() {
- let opts = CliArgs::default();
- let result = Config::try_from(&opts);
- assert_eq!(result.unwrap(), Config::default());
- }
-}
diff --git a/src/common/input/handler.rs b/src/common/input/handler.rs
deleted file mode 100644
index 4ac2cf83..00000000
--- a/src/common/input/handler.rs
+++ /dev/null
@@ -1,268 +0,0 @@
-//! Main input logic.
-
-use super::actions::Action;
-use super::keybinds::Keybinds;
-use crate::client::ClientInstruction;
-use crate::common::input::config::Config;
-use crate::common::ipc::ClientToServerMsg;
-use crate::common::thread_bus::{SenderWithContext, OPENCALLS};
-use crate::errors::ContextType;
-use crate::os_input_output::ClientOsApi;
-use crate::CommandIsExecuting;
-
-use termion::input::{TermRead, TermReadEventsAndRaw};
-use zellij_tile::data::{InputMode, Key, ModeInfo, Palette, PluginCapabilities};
-
-/// Handles the dispatching of [`Action`]s according to the current
-/// [`InputMode`], and keep tracks of the current [`InputMode`].
-struct InputHandler {
- /// The current input mode
- mode: InputMode,
- os_input: Box<dyn ClientOsApi>,
- config: Config,
- command_is_executing: CommandIsExecuting,
- send_client_instructions: SenderWithContext<ClientInstruction>,
- should_exit: bool,
- pasting: bool,
-}
-
-impl InputHandler {
- /// Returns a new [`InputHandler`] with the attributes specified as arguments.
- fn new(
- os_input: Box<dyn ClientOsApi>,
- command_is_executing: CommandIsExecuting,
- config: Config,
- send_client_instructions: SenderWithContext<ClientInstruction>,
- ) -> Self {
- InputHandler {
- mode: InputMode::Normal,
- os_input,
- config,
- command_is_executing,
- send_client_instructions,
- should_exit: false,
- pasting: false,
- }
- }
-
- /// Main input event loop. Interprets the terminal [`Event`](termion::event::Event)s
- /// as [`Action`]s according to the current [`InputMode`], and dispatches those actions.
- fn handle_input(&mut self) {
- let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow());
- err_ctx.add_call(ContextType::StdinHandler);
- let alt_left_bracket = vec![27, 91];
- let bracketed_paste_start = vec![27, 91, 50, 48, 48, 126]; // \u{1b}[200~
- let bracketed_paste_end = vec![27, 91, 50, 48, 49, 126]; // \u{1b}[201
- loop {
- if self.should_exit {
- break;
- }
- let stdin_buffer = self.os_input.read_from_stdin();
- for key_result in stdin_buffer.events_and_raw() {
- match key_result {
- Ok((event, raw_bytes)) => match event {
- termion::event::Event::Key(key) => {
- let key = cast_termion_key(key);
- self.handle_key(&key, raw_bytes);
- }
- termion::event::Event::Unsupported(unsupported_key) => {
- // we have to do this because of a bug in termion
- // this should be a key event and not an unsupported event
- if unsupported_key == alt_left_bracket {
- let key = Key::Alt('[');
- self.handle_key(&key, raw_bytes);
- } else if unsupported_key == bracketed_paste_start {
- self.pasting = true;
- } else if unsupported_key == bracketed_paste_end {
- self.pasting = false;
- } else {
- // this is a hack because termion doesn't recognize certain keys
- // in this case we just forward it to the terminal
- self.handle_unknown_key(raw_bytes);
- }
- }
- termion::event::Event::Mouse(_) => {
- // Mouse events aren't implemented yet,
- // use a NoOp untill then.
- }
- },
- Err(err) => panic!("Encountered read error: {:?}", err),
- }
- }
- }
- }
- fn handle_unknown_key(&mut self, raw_bytes: Vec<u8>) {
- if self.mode == InputMode::Normal || self.mode == InputMode::Locked {
- let action = Action::Write(raw_bytes);
- self.dispatch_action(action);
- }
- }
- fn handle_key(&mut self, key: &Key, raw_bytes: Vec<u8>) {
- let keybinds = &self.config.keybinds;
- if self.pasting {
- // we're inside a paste block, if we're in a mode that allows sending text to the
- // terminal, send all text directly without interpreting it
- // otherwise, just discard the input
- if self.mode == InputMode::Normal || self.mode == InputMode::Locked {
- let action = Action::Write(raw_bytes);
- self.dispatch_action(action);
- }
- } else {
- for action in Keybinds::key_to_actions(&key, raw_bytes, &self.mode, keybinds) {
- let should_exit = self.dispatch_action(action);
- if should_exit {
- self.should_exit = true;
- }
- }
- }
- }
-
- /// Dispatches an [`Action`].
- ///
- /// This function's body dictates what each [`Action`] actually does when
- /// dispatched.
- ///
- /// # Return value
- /// Currently, this function returns a boolean that indicates whether
- /// [`Self::handle_input()`] should break after this action is dispatched.
- /// This is a temporary measure that is only necessary due to the way that the
- /// framework works, and shouldn't be necessary anymore once the test framework
- /// is revised. See [issue#183](https://github.com/zellij-org/zellij/issues/183).
- fn dispatch_action(&mut self, action: Action) -> bool {
- let mut should_break = false;
-
- match action {
- Action::Quit => {
- self.exit();
- should_break = true;
- }
- Action::SwitchToMode(mode) => {
- self.mode = mode;
- self.os_input
- .send_to_server(ClientToServerMsg::Action(action));
- }
- Action::CloseFocus
- | Action::NewPane(_)
- | Action::NewTab
- | Action::GoToNextTab
- | Action::GoToPreviousTab
- | Action::CloseTab
- | Action::GoToTab(_)
- | Action::MoveFocusOrTab(_) => {
- self.command_is_executing.blocking_input_thread();
- self.os_input
- .send_to_server(ClientToServerMsg::Action(action));
- self.command_is_executing
- .wait_until_input_thread_is_unblocked();
- }
- _ => self
- .os_input
- .send_to_server(ClientToServerMsg::Action(action)),
- }
-
- should_break
- }
-
- /// Routine to be called when the input handler exits (at the moment this is the
- /// same as quitting Zellij).
- fn exit(&mut self) {
- self.send_client_instructions
- .send(ClientInstruction::Exit)
- .unwrap();
- }
-}
-
-/// Creates a [`Help`] struct indicating the current [`InputMode`] and its keybinds
-/// (as pairs of [`String`]s).
-// TODO this should probably be automatically generated in some way
-pub fn get_mode_info(
- mode: InputMode,
- palette: Palette,
- capabilities: PluginCapabilities,
-) -> ModeInfo {
- let mut keybinds: Vec<(String, String)> = vec![];
- match mode {
- InputMode::Normal | InputMode::Locked => {}
- InputMode::Resize => {
- keybinds.push(("←↓↑→".to_string(), "Resize".to_string()));
- }
- InputMode::Pane => {
- keybinds.push(("←↓↑→".to_string(), "Move focus".to_string()));
- keybinds.push(("p".to_string(), "Next".to_string()));
- keybinds.push(("n".to_string(), "New".to_string()));
- keybinds.push(("d".to_string(), "Down split".to_string()));
- keybinds.push(("r".to_string(), "Right split".to_string()));
- keybinds.push(("x".to_string(), "Close".to_string()));
- keybinds.push(("f".to_string(), "Fullscreen".to_string()));
- }
- InputMode::Tab => {
- keybinds.push(("←↓↑→".to_string(), "Move focus".to_string()));
- keybinds.push(("n".to_string(), "New".to_string()));
- keybinds.push(("x".to_string(), "Close".to_string()));
- keybinds.push(("r".to_string(), "Rename".to_string()));
- keybinds.push(("s".to_string(), "Sync".to_string()));
- }
- InputMode::Scroll => {
- keybinds.push(("↓↑".to_string(), "Scroll".to_string()));
- keybinds.push(("PgUp/PgDn".to_string(), "Scroll Page".to_string()));
- }
- InputMode::RenameTab => {
- keybinds.push(("Enter".to_string(), "when done".to_string()));
- }
- }
- ModeInfo {
- mode,
- keybinds,
- palette,
- capabilities,
- }
-}
-
-/// Entry point to the module. Instantiates an [`InputHandler`] and starts
-/// its [`InputHandler::handle_input()`] loop.
-pub fn input_loop(
- os_input: Box<dyn ClientOsApi>,
- config: Config,
- command_is_executing: CommandIsExecuting,
- send_client_instructions: SenderWithContext<ClientInstruction>,
-) {
- let _handler = InputHandler::new(
- os_input,
- command_is_executing,
- config,
- send_client_instructions,
- )
- .handle_input();
-}
-
-pub fn parse_keys(input_bytes: &[u8]) -> Vec<Key> {
- input_bytes.keys().flatten().map(cast_termion_key).collect()
-}
-
-// FIXME: This is an absolutely cursed function that should be destroyed as soon
-// as an alternative that doesn't touch zellij-tile can be developed...
-fn cast_termion_key(event: termion::event::Key) -> Key {
- match event {
- termion::event::Key::Backspace => Key::Backspace,
- termion::event::Key::Left => Key::Left,
- termion::event::Key::Right => Key::Right,
- termion::event::Key::Up => Key::Up,
- termion::event::Key::Down => Key::Down,
- termion::event::Key::Home => Key::Home,
- termion::event::Key::End => Key::End,
- termion::event::Key::PageUp => Key::PageUp,
- termion::event::Key::PageDown => Key::PageDown,
- termion::event::Key::BackTab => Key::BackTab,
- termion::event::Key::Delete => Key::Delete,
- termion::event::Key::Insert => Key::Insert,
- termion::event::Key::F(n) => Key::F(n),
- termion::event::Key::Char(c) => Key::Char(c),
- termion::event::Key::Alt(c) => Key::Alt(c),
- termion::event::Key::Ctrl(c) => Key::Ctrl(c),
- termion::event::Key::Null => Key::Null,
- termion::event::Key::Esc => Key::Esc,
- _ => {
- unimplemented!("Encountered an unknown key!")
- }
- }
-}
diff --git a/src/common/input/keybinds.rs b/src/common/input/keybinds.rs
deleted file mode 100644
index 8bef47fd..00000000
--- a/src/common/input/keybinds.rs
+++ /dev/null
@@ -1,301 +0,0 @@
-//! 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;
diff --git a/src/common/input/mod.rs b/src/common/input/mod.rs
deleted file mode 100644
index f30ccf23..00000000
--- a/src/common/input/mod.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//! The way terminal input is handled.
-
-pub mod actions;
-pub mod config;
-pub mod handler;
-pub mod keybinds;
-pub mod options;
diff --git a/src/common/input/options.rs b/src/common/input/options.rs
deleted file mode 100644
index 33625b65..00000000
--- a/src/common/input/options.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-//! Handles cli and configuration options
-use crate::cli::ConfigCli;
-use serde::{Deserialize, Serialize};
-use structopt::StructOpt;
-
-#[derive(Clone, Default, Debug, PartialEq, Deserialize, Serialize, StructOpt)]
-/// Options that can be set either through the config file,
-/// or cli flags
-pub struct Options {
- /// Allow plugins to use a more simplified layout
- /// that is compatible with more fonts
- #[structopt(long)]
- pub simplified_ui: bool,
-}
-
-impl Options {
- pub fn from_yaml(from_yaml: Option<Options>) -> Options {
- if let Some(opts) = from_yaml {
- opts
- } else {
- Options::default()
- }
- }
-
- /// Merges two [`Options`] structs, a `Some` in `other`
- /// will supercede a `Some` in `self`
- // TODO: Maybe a good candidate for a macro?
- pub fn merge(&self, other: Options) -> Options {
- let simplified_ui = if other.simplified_ui {
- true
- } else {
- self.simplified_ui
- };
-
- Options { simplified_ui }
- }
-
- pub fn from_cli(&self, other: Option<ConfigCli>) -> Options {
- if let Some(ConfigCli::Options(options)) = other {
- Options::merge(&self, options)
- } else {
- self.to_owned()
- }
- }
-}
diff --git a/src/common/input/unit/keybinds_test.rs b/src/common/input/unit/keybinds_test.rs
deleted file mode 100644
index 4767fc15..00000000
--- a/src/common/input/unit/keybinds_test.rs
+++ /dev/null
@@ -1,801 +0,0 @@
-use super::super::actions::*;
-use super::super::keybinds::*;
-use zellij_tile::data::Key;
-
-#[test]
-fn merge_keybinds_merges_different_keys() {
- let mut mode_keybinds_self = ModeKeybinds::new();
- mode_keybinds_self.0.insert(Key::F(1), vec![Action::NoOp]);
- let mut mode_keybinds_other = ModeKeybinds::new();
- mode_keybinds_other
- .0
- .insert(Key::Backspace, vec![Action::NoOp]);
-
- let mut mode_keybinds_expected = ModeKeybinds::new();
- mode_keybinds_expected
- .0
- .insert(Key::F(1), vec![Action::NoOp]);
- mode_keybinds_expected
- .0
- .insert(Key::Backspace, vec![Action::NoOp]);
-
- let mode_keybinds_merged = mode_keybinds_self.merge(mode_keybinds_other);
-
- assert_eq!(mode_keybinds_expected, mode_keybinds_merged);
-}
-
-#[test]
-fn merge_mode_keybinds_overwrites_same_keys() {
- let mut mode_keybinds_self = ModeKeybinds::new();
- mode_keybinds_self.0.insert(Key::F(1), vec![Action::NoOp]);
- let mut mode_keybinds_other = ModeKeybinds::new();
- mode_keybinds_other
- .0
- .insert(Key::F(1), vec![Action::GoToTab(1)]);
-
- let mut mode_keybinds_expected = ModeKeybinds::new();
- mode_keybinds_expected
- .0
- .insert(Key::F(1), vec![Action::GoToTab(1)]);
-
- let mode_keybinds_merged = mode_keybinds_self.merge(mode_keybinds_other);
-
- assert_eq!(mode_keybinds_expected, mode_keybinds_merged);
-}
-
-#[test]
-fn merge_keybinds_merges() {
- let mut mode_keybinds_self = ModeKeybinds::new();
- mode_keybinds_self.0.insert(Key::F(1), vec![Action::NoOp]);
- let mut mode_keybinds_other = ModeKeybinds::new();
- mode_keybinds_other
- .0
- .insert(Key::Backspace, vec![Action::NoOp]);
- let mut keybinds_self = Keybinds::new();
- keybinds_self
- .0
- .insert(InputMode::Normal, mode_keybinds_self.clone());
- let mut keybinds_other = Keybinds::new();
- keybinds_other
- .0
- .insert(InputMode::Resize, mode_keybinds_other.clone());
- let mut keybinds_expected = Keybinds::new();
- keybinds_expected
- .0
- .insert(InputMode::Normal, mode_keybinds_self);
- keybinds_expected
- .0
- .insert(InputMode::Resize, mode_keybinds_other);
-
- assert_eq!(
- keybinds_expected,
- keybinds_self.merge_keybinds(keybinds_other)
- )
-}
-
-#[test]
-fn merge_keybinds_overwrites_same_keys() {
- let mut mode_keybinds_self = ModeKeybinds::new();
- mode_keybinds_self.0.insert(Key::F(1), vec![Action::NoOp]);
- mode_keybinds_self.0.insert(Key::F(2), vec![Action::NoOp]);
- mode_keybinds_self.0.insert(Key::F(3), vec![Action::NoOp]);
- let mut mode_keybinds_other = ModeKeybinds::new();
- mode_keybinds_other
- .0
- .insert(Key::F(1), vec![Action::GoToTab(1)]);
- mode_keybinds_other
- .0
- .insert(Key::F(2), vec![Action::GoToTab(2)]);
- mode_keybinds_other
- .0
- .insert(Key::F(3), vec![Action::GoToTab(3)]);
- let mut keybinds_self = Keybinds::new();
- keybinds_self
- .0
- .insert(InputMode::Normal, mode_keybinds_self.clone());
- let mut keybinds_other = Keybinds::new();
- keybinds_other
- .0
- .insert(InputMode::Normal, mode_keybinds_other.clone());
- let mut keybinds_expected = Keybinds::new();
- keybinds_expected
- .0
- .insert(InputMode::Normal, mode_keybinds_other);
-
- assert_eq!(
- keybinds_expected,
- keybinds_self.merge_keybinds(keybinds_other)
- )
-}
-
-#[test]
-fn from_keyaction_from_yaml_to_mode_keybindings() {
- let actions = vec![Action::NoOp, Action::GoToTab(1)];
- let keyaction = KeyActionFromYaml {
- action: actions.clone(),
- key: vec![Key::F(1), Key::Backspace, Key::Char('t')],
- };
-
- let mut expected = ModeKeybinds::new();
- expected.0.insert(Key::F(1), actions.clone());
- expected.0.insert(Key::Backspace, actions.clone());
- expected.0.insert(Key::Char('t'), actions);
-
- assert_eq!(expected, ModeKeybinds::from(keyaction));
-}
-
-#[test]
-fn toplevel_unbind_unbinds_all() {
- let from_yaml = KeybindsFromYaml {
- unbind: Unbind::All(true),
- keybinds: HashMap::new(),
- };
-
- let keybinds_from_yaml = Keybinds::get_default_keybinds_with_config(Some(from_yaml));
-
- assert_eq!(keybinds_from_yaml, Keybinds::new());
-}
-
-#[test]
-fn no_unbind_unbinds_none() {
- let from_yaml = KeybindsFromYaml {
- unbind: Unbind::All(false),
- keybinds: HashMap::new(),
- };
-
- 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());
-}