Poking around

This commit is contained in:
a-kenji 2021-03-11 13:58:58 +01:00
parent c97c553870
commit 2b2b7325e7
11 changed files with 193 additions and 154 deletions

View File

@ -22,7 +22,6 @@ _zellij() {
'--max-panes=[Maximum panes on screen, caution: opening more panes will close old ones]' \ '--max-panes=[Maximum panes on screen, caution: opening more panes will close old ones]' \
'-l+[Path to a layout yaml file]' \ '-l+[Path to a layout yaml file]' \
'--layout=[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]' \ '--config=[Path to the configuration yaml file]' \
'-m[Send "move focused pane" to active zellij session]' \ '-m[Send "move focused pane" to active zellij session]' \
'--move-focus[Send "move focused pane" to active zellij session]' \ '--move-focus[Send "move focused pane" to active zellij session]' \

View File

@ -20,7 +20,7 @@ _zellij() {
case "${cmd}" in case "${cmd}" in
zellij) 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 if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0
@ -59,10 +59,6 @@ _zellij() {
COMPREPLY=($(compgen -f "${cur}")) COMPREPLY=($(compgen -f "${cur}"))
return 0 return 0
;; ;;
-c)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
*) *)
COMPREPLY=() COMPREPLY=()
;; ;;

View File

@ -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" -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" -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 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 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 d -l debug
complete -c zellij -n "__fish_use_subcommand" -s h -l help -d 'Prints help information' complete -c zellij -n "__fish_use_subcommand" -s h -l help -d 'Prints help information'

View File

@ -1,12 +1,17 @@
--- ---
keybinds: keybinds:
Normal: Normal:
- {F: 1}: [GoToTab: 1,] - action: [GoToTab: 1,]
- {F: 2}: [GoToTab: 2,] key: [F: 1,]
- {F: 3}: [GoToTab: 3,] - action: [GoToTab: 2,]
- {F: 4}: [GoToTab: 4,] key: [F: 2,]
- {F: 5}: [NewTab: ,] - action: [GoToTab: 3,]
- ? - F: 6 key: [F: 3,]
- F: 7 - action: [GoToTab: 4,]
: - {GoToTab: 5} key: [F: 3,]
- Backspace: [NewPane: Right, NewPane: Right,] - action: [NewTab,]
key: [F: 5,]
- action: [NewPane: Right, NewPane: Right,]
key: [F: 6,]
- action: [NewPane: Right, NewPane: Right,]
key: [F: 6,]

View File

@ -25,7 +25,7 @@ pub struct CliArgs {
pub layout: Option<PathBuf>, pub layout: Option<PathBuf>,
/// Path to the configuration yaml file /// Path to the configuration yaml file
#[structopt(short, long)] #[structopt(long)]
pub config: Option<PathBuf>, pub config: Option<PathBuf>,
#[structopt(short, long)] #[structopt(short, long)]

View File

@ -1,12 +1,11 @@
//! Deserializes configuration options. //! Deserializes configuration options.
use std;
use std::error; use std::error;
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use std::fs::File; use std::fs::File;
use std::io::{self, Read}; 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 crate::utils::logging::*;
use directories_next::ProjectDirs; use directories_next::ProjectDirs;
@ -15,7 +14,7 @@ use serde::Deserialize;
/// Intermediate deserialisation config struct /// Intermediate deserialisation config struct
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct ConfigFromYaml { pub struct ConfigFromYaml {
pub keybinds: Option<MultipleKeybinds>, pub keybinds: Option<KeybindsFromYaml>,
} }
/// Main configuration. /// Main configuration.
@ -53,7 +52,7 @@ impl Config {
/// The allow is here, because rust assumes there is no /// The allow is here, because rust assumes there is no
/// error handling when logging the error to the log file. /// error handling when logging the error to the log file.
#[allow(unused_must_use)] #[allow(unused_must_use)]
pub fn new(path: &PathBuf) -> Result<Config, ConfigError> { pub fn new(path: &Path) -> Result<Config, ConfigError> {
match File::open(path) { match File::open(path) {
Ok(mut file) => { Ok(mut file) => {
let mut yaml_config = String::new(); let mut yaml_config = String::new();
@ -81,7 +80,7 @@ impl Config {
Ok(Config::new(&config_path)?) Ok(Config::new(&config_path)?)
} else { } else {
let project_dirs = ProjectDirs::from("org", "Zellij Contributors", "Zellij").unwrap(); 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"); config_path.push("config.yaml");
Ok(Config::new(&config_path)?) Ok(Config::new(&config_path)?)
} }

View File

@ -60,49 +60,43 @@ impl InputHandler {
self.send_pty_instructions.update(err_ctx); self.send_pty_instructions.update(err_ctx);
self.send_app_instructions.update(err_ctx); self.send_app_instructions.update(err_ctx);
self.send_screen_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();
let keybinds = self.config.keybinds.clone(); 'input_loop: loop {
'input_loop: loop { //@@@ I think this should actually just iterate over stdin directly
//@@@ I think this should actually just iterate over stdin directly let stdin_buffer = self.os_input.read_from_stdin();
let stdin_buffer = self.os_input.read_from_stdin(); drop(
drop( self.send_plugin_instructions
self.send_plugin_instructions .send(PluginInstruction::GlobalInput(stdin_buffer.clone())),
.send(PluginInstruction::GlobalInput(stdin_buffer.clone())), );
); for key_result in stdin_buffer.events_and_raw() {
for key_result in stdin_buffer.events_and_raw() { match key_result {
match key_result { Ok((event, raw_bytes)) => match event {
Ok((event, raw_bytes)) => match event { termion::event::Event::Key(key) => {
termion::event::Event::Key(key) => { // FIXME this explicit break is needed because the current test
// FIXME this explicit break is needed because the current test // framework relies on it to not create dead threads that loop
// framework relies on it to not create dead threads that loop // and eat up CPUs. Do not remove until the test framework has
// and eat up CPUs. Do not remove until the test framework has // been revised. Sorry about this (@categorille)
// been revised. Sorry about this (@categorille) if {
if { let mut should_break = false;
let mut should_break = false; // Hacked on way to have a means of testing Macros, needs to
// Hacked on way to have a means of testing Macros, needs to // get properly integrated
// get properly integrated for action in
for action in Keybinds::key_to_actions( Keybinds::key_to_actions(&key, raw_bytes, &self.mode, &keybinds)
&key, raw_bytes, &self.mode, &keybinds, {
) { should_break |= self.dispatch_action(action);
should_break |= self.dispatch_action(action);
}
should_break
} {
break 'input_loop;
} }
should_break
} {
break 'input_loop;
} }
termion::event::Event::Mouse(_) }
| termion::event::Event::Unsupported(_) => { termion::event::Event::Mouse(_) | termion::event::Event::Unsupported(_) => {
unimplemented!("Mouse and unsupported events aren't supported!"); unimplemented!("Mouse and unsupported events aren't supported!");
} }
}, },
Err(err) => panic!("Encountered read error: {:?}", err), Err(err) => panic!("Encountered read error: {:?}", err),
}
} }
} }
} else {
//@@@ Error handling?
self.exit();
} }
} }

View File

@ -8,50 +8,41 @@ use serde::Deserialize;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use termion::event::Key; use termion::event::Key;
#[derive(Clone, Debug, PartialEq, Deserialize)] #[derive(Clone, Debug, PartialEq)]
pub struct Keybinds(HashMap<InputMode, ModeKeybinds>); pub struct Keybinds(HashMap<InputMode, ModeKeybinds>);
#[derive(Clone, Debug, Default, PartialEq, Deserialize)] #[derive(Clone, Debug, Default, PartialEq)]
pub struct ModeKeybinds(HashMap<Key, Vec<Action>>); pub struct ModeKeybinds(HashMap<Key, Vec<Action>>);
/// Intermediate struct for configuration. /// Intermediate struct used for deserialisation
#[derive(Clone, Debug, Default, PartialEq, Deserialize)] #[derive(Clone, Debug, PartialEq, Deserialize)]
pub struct MultipleKeybinds(HashMap<InputMode, Vec<ModeKeybind>>); pub struct KeybindsFromYaml(HashMap<InputMode, Vec<KeyActionFromYaml>>);
/// Intermediate struct for configuration.
#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
struct MultipleModeKeybinds(HashMap<Vec<Key>, Vec<Action>>);
/// Intermediate enum for configuration. /// Intermediate struct used for deserialisation
#[derive(Debug, Clone, PartialEq, Deserialize)] #[derive(Clone, Debug, PartialEq, Deserialize)]
#[serde(untagged)] pub struct KeyActionFromYaml {
enum ModeKeybind { action: Vec<Action>,
ModeKeybinds(ModeKeybinds), key: Vec<Key>,
MultipleModeKeybinds(MultipleModeKeybinds),
} }
impl Default for Keybinds { impl Default for Keybinds {
fn default() -> 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::<InputMode, ModeKeybinds>::new())
}
pub fn get_default_keybinds() -> Result<Keybinds, String> {
let mut defaults = Keybinds::new(); let mut defaults = Keybinds::new();
for mode in InputMode::iter() { for mode in InputMode::iter() {
defaults defaults
.0 .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::<InputMode, ModeKeybinds>::new())
} }
pub fn get_default_keybinds_with_config(keybinds: Option<MultipleKeybinds>) -> Keybinds { pub fn get_default_keybinds_with_config(keybinds: Option<KeybindsFromYaml>) -> Keybinds {
let default_keybinds = Keybinds::default(); let default_keybinds = Keybinds::default();
if let Some(keybinds) = keybinds { if let Some(keybinds) = keybinds {
default_keybinds.merge_keybinds(Keybinds::from(keybinds)) default_keybinds.merge_keybinds(Keybinds::from(keybinds))
@ -80,7 +71,7 @@ impl Keybinds {
} }
/// Returns the default keybinds for a given [`InputMode`]. /// Returns the default keybinds for a given [`InputMode`].
fn get_defaults_for_mode(mode: &InputMode) -> Result<ModeKeybinds, String> { fn get_defaults_for_mode(mode: &InputMode) -> ModeKeybinds {
let mut defaults = HashMap::new(); let mut defaults = HashMap::new();
match *mode { match *mode {
@ -212,8 +203,7 @@ impl Keybinds {
defaults.insert(Key::Esc, vec![Action::SwitchToMode(InputMode::Command)]); defaults.insert(Key::Esc, vec![Action::SwitchToMode(InputMode::Command)]);
} }
} }
ModeKeybinds(defaults)
Ok(ModeKeybinds::from(defaults))
} }
/// Converts a [`Key`] terminal event to a sequence of [`Action`]s according to the current /// Converts a [`Key`] terminal event to a sequence of [`Action`]s according to the current
@ -242,39 +232,27 @@ impl Keybinds {
} }
impl ModeKeybinds { impl ModeKeybinds {
pub fn new() -> ModeKeybinds { fn new() -> ModeKeybinds {
ModeKeybinds::from(HashMap::<Key, Vec<Action>>::new()) ModeKeybinds(HashMap::<Key, Vec<Action>>::new())
} }
/// Merges `self` with `other`, if keys are the same, `other` overwrites. /// 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; let mut merged = self;
merged.0.extend(other.0.clone()); merged.0.extend(other.0);
merged merged
} }
} }
/// Converts from the `MultipleKeybinds` struct to a `Keybinds` struct. impl From<KeybindsFromYaml> for Keybinds {
/// TODO @a-kenji Error on conflicting keybinds? fn from(keybinds_from_yaml: KeybindsFromYaml) -> Keybinds {
/// Atm the Lower Keybind will take precedence and will overwrite the
/// one further up.
impl From<MultipleKeybinds> for Keybinds {
fn from(multiple: MultipleKeybinds) -> Keybinds {
let mut keybinds = Keybinds::new(); let mut keybinds = Keybinds::new();
for mode in InputMode::iter() { for mode in InputMode::iter() {
let mut mode_keybinds = ModeKeybinds::new(); let mut mode_keybinds = ModeKeybinds::new();
for mode_keybind in multiple.0.get(&mode).iter() { for key_action in keybinds_from_yaml.0.get(&mode).iter() {
for keybind in mode_keybind.iter() { for keybind in key_action.iter() {
match keybind { mode_keybinds = mode_keybinds.merge(ModeKeybinds::from(keybind.clone()));
ModeKeybind::ModeKeybinds(k) => {
mode_keybinds = mode_keybinds.clone().merge(k.clone());
}
ModeKeybind::MultipleModeKeybinds(k) => {
mode_keybinds =
mode_keybinds.clone().merge(ModeKeybinds::from(k.clone()));
}
}
} }
} }
keybinds.0.insert(mode, mode_keybinds); keybinds.0.insert(mode, mode_keybinds);
@ -283,25 +261,18 @@ impl From<MultipleKeybinds> for Keybinds {
} }
} }
impl From<HashMap<InputMode, ModeKeybinds>> for Keybinds { /// For each `Key` assigned to `Action`s,
fn from(map: HashMap<InputMode, ModeKeybinds>) -> Keybinds { /// map the `Action`s to the key
Keybinds(map) impl From<KeyActionFromYaml> for ModeKeybinds {
} fn from(key_action: KeyActionFromYaml) -> ModeKeybinds {
} let keys = key_action.key;
impl From<HashMap<Key, Vec<Action>>> for ModeKeybinds { let actions = key_action.action;
fn from(map: HashMap<Key, Vec<Action>>) -> ModeKeybinds {
ModeKeybinds(map)
}
}
impl From<MultipleModeKeybinds> for ModeKeybinds { ModeKeybinds(
fn from(multiple: MultipleModeKeybinds) -> ModeKeybinds { keys.into_iter()
let single: HashMap<Key, Vec<Action>> = multiple .map(|k| (k, actions.clone()))
.0 .collect::<HashMap<Key, Vec<Action>>>(),
.into_iter() )
.flat_map(|(k, v)| (k.into_iter().map(move |k| (k, v.clone()))))
.collect();
ModeKeybinds::from(single)
} }
} }

View File

@ -1,13 +1,12 @@
//! For Configuration Options //! For Configuration Options
use super::super::config::*; use super::super::config::*;
use crate::common::input::keybinds::*;
use crate::common::input::actions::*; use crate::common::input::actions::*;
use crate::common::input::keybinds::*;
use std::path::PathBuf; use std::path::PathBuf;
use termion::event::Key; use termion::event::Key;
#[test] #[test]
fn no_config_file_equals_default_config() { fn no_config_file_equals_default_config() {
let no_file = PathBuf::from(r"../fixtures/config/config.yamlll"); 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); assert_eq!(config, default);
} }
#[test] //#[test]
fn multiple_keys_mapped_to_one_action() { //fn multiple_keys_mapped_to_one_action() {
let options = r" //let options = r"
--- //---
keybindings: //keybindings:
Normal: //Normal:
- ? - F: 6 //- ? - F: 6
- F: 7 //- F: 7
- F: 8 //- F: 8
: - {GoToTab: 5} //: - {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] //#[test]
//fn merge_keybinds_merges(){ //fn merge_keybinds_merges(){
//let mut self_keybinds = Keybinds::new(); //let mut self_keybinds = Keybinds::new();
//let mut self_mode_keybinds = ModeKeybinds::new(); //let mut self_mode_keybinds = ModeKeybinds::new();
//self_mode_keybinds.0.insert(Key::F(1), vec![Action::GoToTab(5)]); //self_mode_keybinds.0.insert(Key::F(1), vec![Action::GoToTab(5)]);
//let mut other_keybinds = Keybinds::new(); //let mut other_keybinds = Keybinds::new();
//let mut self_mode_keybinds = ModeKeybinds::new(); //let mut self_mode_keybinds = ModeKeybinds::new();
//let mut expected = Keybinds::new(); //let mut expected = Keybinds::new();
//} //}

View File

@ -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)
)
}

View File

@ -656,7 +656,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
let send_pty_instructions = send_pty_instructions.clone(); let send_pty_instructions = send_pty_instructions.clone();
let send_plugin_instructions = send_plugin_instructions.clone(); let send_plugin_instructions = send_plugin_instructions.clone();
let os_input = os_input.clone(); let os_input = os_input.clone();
let config = config.clone(); let config = config;
move || { move || {
input_loop( input_loop(
os_input, os_input,