From c644a1c2437ac439425eaa185d4f69911cf5ee45 Mon Sep 17 00:00:00 2001 From: a-kenji Date: Fri, 5 Mar 2021 19:23:06 +0100 Subject: [PATCH] poking --- assets/completions/_zellij | 2 + assets/completions/zellij.bash | 10 +++- assets/completions/zellij.fish | 1 + config.yaml | 8 ++++ src/cli.rs | 4 ++ src/common/config.rs | 85 +++++++++++++++++----------------- src/common/input/handler.rs | 19 ++++++-- src/common/input/keybinds.rs | 2 +- src/common/input/macros.rs | 4 +- src/common/mod.rs | 20 ++++++-- 10 files changed, 103 insertions(+), 52 deletions(-) create mode 100644 config.yaml diff --git a/assets/completions/_zellij b/assets/completions/_zellij index 64bd538c..cd8dce56 100644 --- a/assets/completions/_zellij +++ b/assets/completions/_zellij @@ -22,6 +22,8 @@ _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]' \ '-d[]' \ diff --git a/assets/completions/zellij.bash b/assets/completions/zellij.bash index a921e7c9..0ede5cce 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 --move-focus --debug --help --version --split --open-file --max-panes --layout " + opts=" -m -d -h -V -s -o -l -c --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 @@ -55,6 +55,14 @@ _zellij() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --config) + 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 e902823f..eaba9fa4 100644 --- a/assets/completions/zellij.fish +++ b/assets/completions/zellij.fish @@ -2,6 +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" -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 new file mode 100644 index 00000000..b1657775 --- /dev/null +++ b/config.yaml @@ -0,0 +1,8 @@ +--- +macro: + {name:"closePane", sequence: [NewPane: Right,]} + +keybinds: + Normal: + Backspace: [NewPane:, NewPane:,] + {F: 1}: [NewPane:,] diff --git a/src/cli.rs b/src/cli.rs index 6e384e16..67a92196 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -24,6 +24,10 @@ pub struct CliArgs { #[structopt(short, long)] pub layout: Option, + /// Path to the configuration yaml file + #[structopt(short, long)] + pub config: Option, + #[structopt(short, long)] pub debug: bool, } diff --git a/src/common/config.rs b/src/common/config.rs index 2ce25bff..705c1592 100644 --- a/src/common/config.rs +++ b/src/common/config.rs @@ -1,14 +1,15 @@ //! Deserializes configuration options. use std; -use std::collections::HashMap; +//use std::collections::HashMap; use std::error; use std::fmt::{self, Display}; use std::fs::File; -use std::io::{self,Read}; +use std::io::{self, Read}; use std::path::PathBuf; -use super::input::{keybinds,handler}; +use super::input::{keybinds, macros}; +use directories_next::ProjectDirs; use serde::Deserialize; /// Intermediate struct @@ -16,17 +17,17 @@ use serde::Deserialize; //} - /// Intermediate struct -//#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize)] pub struct ConfigFromYaml { - keybinds: HashMap>, + keybinds: Option, + macros: Option>, } ///// Deserialized config state #[derive(Debug, Clone, Default, Deserialize)] pub struct Config { - keybinds: Vec, + pub keybinds: keybinds::Keybinds, } #[derive(Debug)] @@ -43,37 +44,52 @@ pub enum ConfigError { Serde(serde_yaml::Error), //Eof, // io::Error - Io(io::Error) + Io(io::Error), } impl Config { /// Deserializes from given path - pub fn new(path: &PathBuf) -> Result { - let config_deserialized: Config; + pub fn new(path: &PathBuf) -> Result { + let config: Config; + let config_deserialized: ConfigFromYaml; let mut config_string = String::new(); + // TODO fix this unwrap match File::open(path) { Ok(mut file) => { file.read_to_string(&mut config_string)?; config_deserialized = serde_yaml::from_str(&config_string)?; + config = Config { + keybinds: config_deserialized + .keybinds + .unwrap_or_else(|| keybinds::get_default_keybinds().unwrap()), + } } - Err(_) => { + Err(e) => { // TODO logging, if a file is not found // at an expected position - should not // panic @a-kenji - config_deserialized = Config::default(); + eprintln!("{}", e); + config = Config::default(); } } - Ok(config_deserialized) + Ok(config) + } + + pub fn from_option_or_default(option: Option) -> Result { + let config; + if let Some(config_path) = option { + config = Config::new(&config_path)?; + } else { + let project_dirs = ProjectDirs::from("org", "Zellij Contributors", "Zellij").unwrap(); + //let config_path = PathBuf::from(project_dirs.config_dir().as_os_str()); + let config_path = project_dirs.config_dir().to_owned().into(); + config = Config::new(&config_path)?; + } + return Ok(config); } } -//impl de::Error for ConfigError { - //fn custom(msg: T) -> Self { - //ConfigError::Message(msg.to_string()) - //} -//} - impl Display for ConfigError { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { match self { @@ -88,25 +104,17 @@ impl Display for ConfigError { } impl std::error::Error for ConfigError { - fn description(&self) -> &str { + fn cause(&self) -> Option<&dyn error::Error> { match *self { - //ConfigError::Message(ref err) => err, - ConfigError::Io(ref err) => err.to_string().as_str(), - ConfigError::Serde(ref err) => err.to_string().as_str(), + // N.B. Both of these implicitly cast `err` from their concrete + // types (either `&io::Error` or `&num::ParseIntError`) + // to a trait object `&Error`. This works because both error types + // implement `Error`. + ConfigError::Io(ref err) => Some(err), + //ConfigError::Message(ref err) => Some(err), + ConfigError::Serde(ref err) => Some(err), } } - - fn cause(&self) -> Option<&dyn error::Error> { - match *self { - // N.B. Both of these implicitly cast `err` from their concrete - // types (either `&io::Error` or `&num::ParseIntError`) - // to a trait object `&Error`. This works because both error types - // implement `Error`. - ConfigError::Io(ref err) => Some(err), - //ConfigError::Message(ref err) => Some(err), - ConfigError::Serde(ref err) => Some(err), - } -} } impl From for ConfigError { @@ -120,10 +128,3 @@ impl From for ConfigError { ConfigError::Serde(err) } } - -//impl From for ConfigError { - //fn from(err: de::Error::Message) -> ConfigError { - //ConfigError::Message(err) - //} -//} - diff --git a/src/common/input/handler.rs b/src/common/input/handler.rs index 5c4f1971..9d8b2cf2 100644 --- a/src/common/input/handler.rs +++ b/src/common/input/handler.rs @@ -2,6 +2,7 @@ use super::actions::Action; use super::keybinds::get_default_keybinds; +use crate::common::config::Config; use crate::common::{update_state, AppInstruction, AppState, SenderWithContext, OPENCALLS}; use crate::errors::ContextType; use crate::os_input_output::OsApi; @@ -22,6 +23,7 @@ struct InputHandler { /// The current input mode mode: InputMode, os_input: Box, + config: Config, command_is_executing: CommandIsExecuting, send_screen_instructions: SenderWithContext, send_pty_instructions: SenderWithContext, @@ -34,6 +36,7 @@ impl InputHandler { fn new( os_input: Box, command_is_executing: CommandIsExecuting, + config: Config, send_screen_instructions: SenderWithContext, send_pty_instructions: SenderWithContext, send_plugin_instructions: SenderWithContext, @@ -42,6 +45,7 @@ impl InputHandler { InputHandler { mode: InputMode::Normal, os_input, + config, command_is_executing, send_screen_instructions, send_pty_instructions, @@ -59,6 +63,8 @@ impl InputHandler { self.send_app_instructions.update(err_ctx); self.send_screen_instructions.update(err_ctx); if let Ok(keybinds) = get_default_keybinds() { + let mut merged_keybinds = keybinds; + merged_keybinds.extend(self.config.keybinds.clone().into_iter()); 'input_loop: loop { //@@@ I think this should actually just iterate over stdin directly let stdin_buffer = self.os_input.read_from_stdin(); @@ -76,9 +82,14 @@ impl InputHandler { // been revised. Sorry about this (@categorille) if { let mut should_break = false; - for action in - key_to_actions(&key, raw_bytes, &self.mode, &keybinds) - { + // Hacked on way to have a means of testing Macros, needs to + // get properly integrated + for action in key_to_actions( + &key, + raw_bytes, + &self.mode, + &merged_keybinds, + ) { should_break |= self.dispatch_action(action); } should_break @@ -324,6 +335,7 @@ pub fn get_help(mode: InputMode) -> Help { /// its [`InputHandler::handle_input()`] loop. pub fn input_loop( os_input: Box, + config: Config, command_is_executing: CommandIsExecuting, send_screen_instructions: SenderWithContext, send_pty_instructions: SenderWithContext, @@ -333,6 +345,7 @@ pub fn input_loop( let _handler = InputHandler::new( os_input, command_is_executing, + config, send_screen_instructions, send_pty_instructions, send_plugin_instructions, diff --git a/src/common/input/keybinds.rs b/src/common/input/keybinds.rs index 0ea0695f..8799649d 100644 --- a/src/common/input/keybinds.rs +++ b/src/common/input/keybinds.rs @@ -23,7 +23,7 @@ pub fn get_default_keybinds() -> Result { Ok(defaults) } -/// Returns the default keybinds for a givent [`InputMode`]. +/// Returns the default keybinds for a given [`InputMode`]. fn get_defaults_for_mode(mode: &InputMode) -> Result { let mut defaults = ModeKeybinds::new(); diff --git a/src/common/input/macros.rs b/src/common/input/macros.rs index cbd14332..4b7c6df1 100644 --- a/src/common/input/macros.rs +++ b/src/common/input/macros.rs @@ -2,11 +2,11 @@ //! defined predictable order. use super::actions::Action; - + use serde::Deserialize; #[derive(Debug, Clone, Deserialize)] pub struct Macro { name: Option, - sequence: Vec + sequence: Vec, } diff --git a/src/common/mod.rs b/src/common/mod.rs index 5ba2e15d..c8b2ec98 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -1,5 +1,5 @@ -pub mod config; pub mod command_is_executing; +pub mod config; pub mod errors; pub mod input; pub mod install; @@ -46,10 +46,17 @@ pub enum ApiCommand { MoveFocus, } // FIXME: It would be good to add some more things to this over time -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub struct AppState { pub input_mode: InputMode, - pub config : Config, +} + +impl Default for AppState { + fn default() -> Self { + AppState { + input_mode: InputMode::default(), + } + } } // FIXME: Make this a method on the big `Communication` struct, so that app_tx can be extracted @@ -158,8 +165,13 @@ pub fn start(mut os_input: Box, opts: CliArgs) { .get_stdout_writer() .write(take_snapshot.as_bytes()) .unwrap(); + let mut app_state = AppState::default(); + let config = Config::from_option_or_default(opts.config) + .map_err(|e| eprintln!{"Config Error: {}", e}) + .unwrap(); + let command_is_executing = CommandIsExecuting::new(); let full_screen_ws = os_input.get_terminal_size_using_fd(0); @@ -638,9 +650,11 @@ 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(); move || { input_loop( os_input, + config, command_is_executing, send_screen_instructions, send_pty_instructions,