From 2b2b7325e7e6b6c3db6376cc0031148a3af1c086 Mon Sep 17 00:00:00 2001 From: a-kenji Date: Thu, 11 Mar 2021 13:58:58 +0100 Subject: [PATCH] Poking around --- assets/completions/_zellij | 1 - assets/completions/zellij.bash | 6 +- assets/completions/zellij.fish | 2 +- config.yaml | 23 +++--- src/cli.rs | 2 +- src/common/config.rs | 11 ++- src/common/input/handler.rs | 72 ++++++++---------- src/common/input/keybinds.rs | 109 ++++++++++----------------- src/common/input/ut/config_test.rs | 43 ++++++----- src/common/input/ut/keybinds_test.rs | 76 +++++++++++++++++++ src/common/mod.rs | 2 +- 11 files changed, 193 insertions(+), 154 deletions(-) diff --git a/assets/completions/_zellij b/assets/completions/_zellij index cd8dce56e..f292d5604 100644 --- a/assets/completions/_zellij +++ b/assets/completions/_zellij @@ -22,7 +22,6 @@ _zellij() { '--max-panes=[Maximum panes on screen, caution: opening more panes will close old ones]' \ '-l+[Path to a layout yaml file]' \ '--layout=[Path to a layout yaml file]' \ -'-c+[Path to the configuration yaml file]' \ '--config=[Path to the configuration yaml file]' \ '-m[Send "move focused pane" to active zellij session]' \ '--move-focus[Send "move focused pane" to active zellij session]' \ diff --git a/assets/completions/zellij.bash b/assets/completions/zellij.bash index 0ede5cce0..17afd610e 100644 --- a/assets/completions/zellij.bash +++ b/assets/completions/zellij.bash @@ -20,7 +20,7 @@ _zellij() { case "${cmd}" in zellij) - opts=" -m -d -h -V -s -o -l -c --move-focus --debug --help --version --split --open-file --max-panes --layout --config " + opts=" -m -d -h -V -s -o -l --move-focus --debug --help --version --split --open-file --max-panes --layout --config " if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -59,10 +59,6 @@ _zellij() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -c) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; *) COMPREPLY=() ;; diff --git a/assets/completions/zellij.fish b/assets/completions/zellij.fish index eaba9fa4b..36425a255 100644 --- a/assets/completions/zellij.fish +++ b/assets/completions/zellij.fish @@ -2,7 +2,7 @@ complete -c zellij -n "__fish_use_subcommand" -s s -l split -d 'Send "split (dir complete -c zellij -n "__fish_use_subcommand" -s o -l open-file -d 'Send "open file in new pane" to active zellij session' complete -c zellij -n "__fish_use_subcommand" -l max-panes -d 'Maximum panes on screen, caution: opening more panes will close old ones' complete -c zellij -n "__fish_use_subcommand" -s l -l layout -d 'Path to a layout yaml file' -complete -c zellij -n "__fish_use_subcommand" -s c -l config -d 'Path to the configuration yaml file' +complete -c zellij -n "__fish_use_subcommand" -l config -d 'Path to the configuration yaml file' complete -c zellij -n "__fish_use_subcommand" -s m -l move-focus -d 'Send "move focused pane" to active zellij session' complete -c zellij -n "__fish_use_subcommand" -s d -l debug complete -c zellij -n "__fish_use_subcommand" -s h -l help -d 'Prints help information' diff --git a/config.yaml b/config.yaml index 719d15a2c..eb227d4ed 100644 --- a/config.yaml +++ b/config.yaml @@ -1,12 +1,17 @@ --- keybinds: Normal: - - {F: 1}: [GoToTab: 1,] - - {F: 2}: [GoToTab: 2,] - - {F: 3}: [GoToTab: 3,] - - {F: 4}: [GoToTab: 4,] - - {F: 5}: [NewTab: ,] - - ? - F: 6 - - F: 7 - : - {GoToTab: 5} - - Backspace: [NewPane: Right, NewPane: Right,] + - action: [GoToTab: 1,] + key: [F: 1,] + - action: [GoToTab: 2,] + key: [F: 2,] + - action: [GoToTab: 3,] + key: [F: 3,] + - action: [GoToTab: 4,] + key: [F: 3,] + - action: [NewTab,] + key: [F: 5,] + - action: [NewPane: Right, NewPane: Right,] + key: [F: 6,] + - action: [NewPane: Right, NewPane: Right,] + key: [F: 6,] diff --git a/src/cli.rs b/src/cli.rs index 67a92196e..d6d3057e1 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -25,7 +25,7 @@ pub struct CliArgs { pub layout: Option, /// Path to the configuration yaml file - #[structopt(short, long)] + #[structopt(long)] pub config: Option, #[structopt(short, long)] diff --git a/src/common/config.rs b/src/common/config.rs index bf8a9a9fd..4a66acb07 100644 --- a/src/common/config.rs +++ b/src/common/config.rs @@ -1,12 +1,11 @@ //! Deserializes configuration options. -use std; use std::error; use std::fmt::{self, Display}; use std::fs::File; use std::io::{self, Read}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; -use super::input::keybinds::{Keybinds, MultipleKeybinds}; +use super::input::keybinds::{Keybinds, KeybindsFromYaml}; use crate::utils::logging::*; use directories_next::ProjectDirs; @@ -15,7 +14,7 @@ use serde::Deserialize; /// Intermediate deserialisation config struct #[derive(Debug, Deserialize)] pub struct ConfigFromYaml { - pub keybinds: Option, + pub keybinds: Option, } /// Main configuration. @@ -53,7 +52,7 @@ impl Config { /// The allow is here, because rust assumes there is no /// error handling when logging the error to the log file. #[allow(unused_must_use)] - pub fn new(path: &PathBuf) -> Result { + pub fn new(path: &Path) -> Result { match File::open(path) { Ok(mut file) => { let mut yaml_config = String::new(); @@ -81,7 +80,7 @@ impl Config { Ok(Config::new(&config_path)?) } else { let project_dirs = ProjectDirs::from("org", "Zellij Contributors", "Zellij").unwrap(); - let mut config_path: PathBuf = project_dirs.config_dir().to_owned().into(); + let mut config_path: PathBuf = project_dirs.config_dir().to_owned(); config_path.push("config.yaml"); Ok(Config::new(&config_path)?) } diff --git a/src/common/input/handler.rs b/src/common/input/handler.rs index 9b08491b8..3438bba80 100644 --- a/src/common/input/handler.rs +++ b/src/common/input/handler.rs @@ -60,49 +60,43 @@ impl InputHandler { self.send_pty_instructions.update(err_ctx); self.send_app_instructions.update(err_ctx); self.send_screen_instructions.update(err_ctx); - if let Ok(_keybinds) = Keybinds::get_default_keybinds() { - let keybinds = self.config.keybinds.clone(); - 'input_loop: loop { - //@@@ I think this should actually just iterate over stdin directly - let stdin_buffer = self.os_input.read_from_stdin(); - drop( - self.send_plugin_instructions - .send(PluginInstruction::GlobalInput(stdin_buffer.clone())), - ); - for key_result in stdin_buffer.events_and_raw() { - match key_result { - Ok((event, raw_bytes)) => match event { - termion::event::Event::Key(key) => { - // FIXME this explicit break is needed because the current test - // framework relies on it to not create dead threads that loop - // and eat up CPUs. Do not remove until the test framework has - // been revised. Sorry about this (@categorille) - if { - let mut should_break = false; - // Hacked on way to have a means of testing Macros, needs to - // get properly integrated - for action in Keybinds::key_to_actions( - &key, raw_bytes, &self.mode, &keybinds, - ) { - should_break |= self.dispatch_action(action); - } - should_break - } { - break 'input_loop; + let keybinds = self.config.keybinds.clone(); + 'input_loop: loop { + //@@@ I think this should actually just iterate over stdin directly + let stdin_buffer = self.os_input.read_from_stdin(); + drop( + self.send_plugin_instructions + .send(PluginInstruction::GlobalInput(stdin_buffer.clone())), + ); + for key_result in stdin_buffer.events_and_raw() { + match key_result { + Ok((event, raw_bytes)) => match event { + termion::event::Event::Key(key) => { + // FIXME this explicit break is needed because the current test + // framework relies on it to not create dead threads that loop + // and eat up CPUs. Do not remove until the test framework has + // been revised. Sorry about this (@categorille) + if { + let mut should_break = false; + // Hacked on way to have a means of testing Macros, needs to + // get properly integrated + for action in + Keybinds::key_to_actions(&key, raw_bytes, &self.mode, &keybinds) + { + should_break |= self.dispatch_action(action); } + should_break + } { + break 'input_loop; } - termion::event::Event::Mouse(_) - | termion::event::Event::Unsupported(_) => { - unimplemented!("Mouse and unsupported events aren't supported!"); - } - }, - Err(err) => panic!("Encountered read error: {:?}", err), - } + } + termion::event::Event::Mouse(_) | termion::event::Event::Unsupported(_) => { + unimplemented!("Mouse and unsupported events aren't supported!"); + } + }, + Err(err) => panic!("Encountered read error: {:?}", err), } } - } else { - //@@@ Error handling? - self.exit(); } } diff --git a/src/common/input/keybinds.rs b/src/common/input/keybinds.rs index 8b089ecf3..2c395d376 100644 --- a/src/common/input/keybinds.rs +++ b/src/common/input/keybinds.rs @@ -8,50 +8,41 @@ use serde::Deserialize; use strum::IntoEnumIterator; use termion::event::Key; -#[derive(Clone, Debug, PartialEq, Deserialize)] +#[derive(Clone, Debug, PartialEq)] pub struct Keybinds(HashMap); -#[derive(Clone, Debug, Default, PartialEq, Deserialize)] +#[derive(Clone, Debug, Default, PartialEq)] pub struct ModeKeybinds(HashMap>); -/// Intermediate struct for configuration. -#[derive(Clone, Debug, Default, PartialEq, Deserialize)] -pub struct MultipleKeybinds(HashMap>); -/// Intermediate struct for configuration. -#[derive(Clone, Debug, Default, PartialEq, Deserialize)] -struct MultipleModeKeybinds(HashMap, Vec>); +/// Intermediate struct used for deserialisation +#[derive(Clone, Debug, PartialEq, Deserialize)] +pub struct KeybindsFromYaml(HashMap>); -/// Intermediate enum for configuration. -#[derive(Debug, Clone, PartialEq, Deserialize)] -#[serde(untagged)] -enum ModeKeybind { - ModeKeybinds(ModeKeybinds), - MultipleModeKeybinds(MultipleModeKeybinds), +/// Intermediate struct used for deserialisation +#[derive(Clone, Debug, PartialEq, Deserialize)] +pub struct KeyActionFromYaml { + action: Vec, + key: Vec, } impl Default for Keybinds { fn default() -> Keybinds { - Keybinds::get_default_keybinds().expect("Something is wrong with the default Keybinds") - } -} - -impl Keybinds { - pub fn new() -> Keybinds { - Keybinds::from(HashMap::::new()) - } - - pub fn get_default_keybinds() -> Result { let mut defaults = Keybinds::new(); for mode in InputMode::iter() { defaults .0 - .insert(mode, Keybinds::get_defaults_for_mode(&mode)?); + .insert(mode, Keybinds::get_defaults_for_mode(&mode)); } + defaults + } +} - Ok(defaults) +impl Keybinds { + pub fn new() -> Keybinds { + Keybinds(HashMap::::new()) } - pub fn get_default_keybinds_with_config(keybinds: Option) -> Keybinds { + pub fn get_default_keybinds_with_config(keybinds: Option) -> Keybinds { let default_keybinds = Keybinds::default(); if let Some(keybinds) = keybinds { default_keybinds.merge_keybinds(Keybinds::from(keybinds)) @@ -80,7 +71,7 @@ impl Keybinds { } /// Returns the default keybinds for a given [`InputMode`]. - fn get_defaults_for_mode(mode: &InputMode) -> Result { + fn get_defaults_for_mode(mode: &InputMode) -> ModeKeybinds { let mut defaults = HashMap::new(); match *mode { @@ -212,8 +203,7 @@ impl Keybinds { defaults.insert(Key::Esc, vec![Action::SwitchToMode(InputMode::Command)]); } } - - Ok(ModeKeybinds::from(defaults)) + ModeKeybinds(defaults) } /// Converts a [`Key`] terminal event to a sequence of [`Action`]s according to the current @@ -242,39 +232,27 @@ impl Keybinds { } impl ModeKeybinds { - pub fn new() -> ModeKeybinds { - ModeKeybinds::from(HashMap::>::new()) + fn new() -> ModeKeybinds { + ModeKeybinds(HashMap::>::new()) } /// Merges `self` with `other`, if keys are the same, `other` overwrites. - pub fn merge(self, other: ModeKeybinds) -> ModeKeybinds { + fn merge(self, other: ModeKeybinds) -> ModeKeybinds { let mut merged = self; - merged.0.extend(other.0.clone()); + merged.0.extend(other.0); merged } } -/// Converts from the `MultipleKeybinds` struct to a `Keybinds` struct. -/// TODO @a-kenji Error on conflicting keybinds? -/// Atm the Lower Keybind will take precedence and will overwrite the -/// one further up. -impl From for Keybinds { - fn from(multiple: MultipleKeybinds) -> Keybinds { +impl From 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 mode_keybind in multiple.0.get(&mode).iter() { - for keybind in mode_keybind.iter() { - match keybind { - ModeKeybind::ModeKeybinds(k) => { - mode_keybinds = mode_keybinds.clone().merge(k.clone()); - } - ModeKeybind::MultipleModeKeybinds(k) => { - mode_keybinds = - mode_keybinds.clone().merge(ModeKeybinds::from(k.clone())); - } - } + for key_action in keybinds_from_yaml.0.get(&mode).iter() { + for keybind in key_action.iter() { + mode_keybinds = mode_keybinds.merge(ModeKeybinds::from(keybind.clone())); } } keybinds.0.insert(mode, mode_keybinds); @@ -283,25 +261,18 @@ impl From for Keybinds { } } -impl From> for Keybinds { - fn from(map: HashMap) -> Keybinds { - Keybinds(map) - } -} -impl From>> for ModeKeybinds { - fn from(map: HashMap>) -> ModeKeybinds { - ModeKeybinds(map) - } -} +/// For each `Key` assigned to `Action`s, +/// map the `Action`s to the key +impl From for ModeKeybinds { + fn from(key_action: KeyActionFromYaml) -> ModeKeybinds { + let keys = key_action.key; + let actions = key_action.action; -impl From for ModeKeybinds { - fn from(multiple: MultipleModeKeybinds) -> ModeKeybinds { - let single: HashMap> = multiple - .0 - .into_iter() - .flat_map(|(k, v)| (k.into_iter().map(move |k| (k, v.clone())))) - .collect(); - ModeKeybinds::from(single) + ModeKeybinds( + keys.into_iter() + .map(|k| (k, actions.clone())) + .collect::>>(), + ) } } diff --git a/src/common/input/ut/config_test.rs b/src/common/input/ut/config_test.rs index 001aab154..17649d14d 100644 --- a/src/common/input/ut/config_test.rs +++ b/src/common/input/ut/config_test.rs @@ -1,13 +1,12 @@ //! For Configuration Options use super::super::config::*; -use crate::common::input::keybinds::*; use crate::common::input::actions::*; +use crate::common::input::keybinds::*; use std::path::PathBuf; use termion::event::Key; - #[test] fn no_config_file_equals_default_config() { let no_file = PathBuf::from(r"../fixtures/config/config.yamlll"); @@ -23,29 +22,29 @@ fn no_config_option_file_equals_default_config() { assert_eq!(config, default); } -#[test] -fn multiple_keys_mapped_to_one_action() { - let options = r" - --- -keybindings: - Normal: - - ? - F: 6 - - F: 7 - - F: 8 - : - {GoToTab: 5} - "; +//#[test] +//fn multiple_keys_mapped_to_one_action() { +//let options = r" +//--- +//keybindings: +//Normal: +//- ? - F: 6 +//- F: 7 +//- F: 8 +//: - {GoToTab: 5} +//"; - let config_options = Config::from_yaml(&options).unwrap(); +//let config_options = Config::from_yaml(&options).unwrap(); - assert_eq!(config_options, config_options) -} +//assert_eq!(config_options, config_options) +//} //#[test] //fn merge_keybinds_merges(){ - //let mut self_keybinds = Keybinds::new(); - //let mut self_mode_keybinds = ModeKeybinds::new(); - //self_mode_keybinds.0.insert(Key::F(1), vec![Action::GoToTab(5)]); - //let mut other_keybinds = Keybinds::new(); - //let mut self_mode_keybinds = ModeKeybinds::new(); - //let mut expected = Keybinds::new(); +//let mut self_keybinds = Keybinds::new(); +//let mut self_mode_keybinds = ModeKeybinds::new(); +//self_mode_keybinds.0.insert(Key::F(1), vec![Action::GoToTab(5)]); +//let mut other_keybinds = Keybinds::new(); +//let mut self_mode_keybinds = ModeKeybinds::new(); +//let mut expected = Keybinds::new(); //} diff --git a/src/common/input/ut/keybinds_test.rs b/src/common/input/ut/keybinds_test.rs index e69de29bb..444729858 100644 --- a/src/common/input/ut/keybinds_test.rs +++ b/src/common/input/ut/keybinds_test.rs @@ -0,0 +1,76 @@ +use super::super::actions::*; +use super::super::keybinds::*; +use termion::event::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) + ) +} diff --git a/src/common/mod.rs b/src/common/mod.rs index fdd666492..3e2f370a3 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -656,7 +656,7 @@ pub fn start(mut os_input: Box, opts: CliArgs) { let send_pty_instructions = send_pty_instructions.clone(); let send_plugin_instructions = send_plugin_instructions.clone(); let os_input = os_input.clone(); - let config = config.clone(); + let config = config; move || { input_loop( os_input,