This commit is contained in:
a-kenji 2021-03-05 19:23:06 +01:00
parent 3e0174cc4a
commit c644a1c243
10 changed files with 103 additions and 52 deletions

View File

@ -22,6 +22,8 @@ _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]' \
'-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]' \
'-d[]' \ '-d[]' \

View File

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

View File

@ -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" -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" -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'

8
config.yaml Normal file
View File

@ -0,0 +1,8 @@
---
macro:
{name:"closePane", sequence: [NewPane: Right,]}
keybinds:
Normal:
Backspace: [NewPane:, NewPane:,]
{F: 1}: [NewPane:,]

View File

@ -24,6 +24,10 @@ pub struct CliArgs {
#[structopt(short, long)] #[structopt(short, long)]
pub layout: Option<PathBuf>, pub layout: Option<PathBuf>,
/// Path to the configuration yaml file
#[structopt(short, long)]
pub config: Option<PathBuf>,
#[structopt(short, long)] #[structopt(short, long)]
pub debug: bool, pub debug: bool,
} }

View File

@ -1,14 +1,15 @@
//! Deserializes configuration options. //! Deserializes configuration options.
use std; use std;
use std::collections::HashMap; //use std::collections::HashMap;
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::PathBuf;
use super::input::{keybinds,handler}; use super::input::{keybinds, macros};
use directories_next::ProjectDirs;
use serde::Deserialize; use serde::Deserialize;
/// Intermediate struct /// Intermediate struct
@ -16,17 +17,17 @@ use serde::Deserialize;
//} //}
/// Intermediate struct /// Intermediate struct
//#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct ConfigFromYaml { pub struct ConfigFromYaml {
keybinds: HashMap<handler::InputMode,Vec<keybinds::Keybinds>>, keybinds: Option<keybinds::Keybinds>,
macros: Option<Vec<macros::Macro>>,
} }
///// Deserialized config state ///// Deserialized config state
#[derive(Debug, Clone, Default, Deserialize)] #[derive(Debug, Clone, Default, Deserialize)]
pub struct Config { pub struct Config {
keybinds: Vec<keybinds::Keybinds>, pub keybinds: keybinds::Keybinds,
} }
#[derive(Debug)] #[derive(Debug)]
@ -43,36 +44,51 @@ pub enum ConfigError {
Serde(serde_yaml::Error), Serde(serde_yaml::Error),
//Eof, //Eof,
// io::Error // io::Error
Io(io::Error) Io(io::Error),
} }
impl Config { impl Config {
/// Deserializes from given path /// Deserializes from given path
pub fn new(path: &PathBuf) -> Result<Config, ConfigError> { pub fn new(path: &PathBuf) -> Result<Config, ConfigError> {
let config_deserialized: Config; let config: Config;
let config_deserialized: ConfigFromYaml;
let mut config_string = String::new(); let mut config_string = String::new();
// TODO fix this unwrap
match File::open(path) { match File::open(path) {
Ok(mut file) => { Ok(mut file) => {
file.read_to_string(&mut config_string)?; file.read_to_string(&mut config_string)?;
config_deserialized = serde_yaml::from_str(&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 // TODO logging, if a file is not found
// at an expected position - should not // at an expected position - should not
// panic @a-kenji // panic @a-kenji
config_deserialized = Config::default(); eprintln!("{}", e);
config = Config::default();
} }
} }
Ok(config_deserialized) Ok(config)
}
} }
//impl de::Error for ConfigError { pub fn from_option_or_default(option: Option<PathBuf>) -> Result<Config, ConfigError> {
//fn custom<T: Display>(msg: T) -> Self { let config;
//ConfigError::Message(msg.to_string()) 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 Display for ConfigError { impl Display for ConfigError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
@ -88,14 +104,6 @@ impl Display for ConfigError {
} }
impl std::error::Error for ConfigError { impl std::error::Error for ConfigError {
fn description(&self) -> &str {
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(),
}
}
fn cause(&self) -> Option<&dyn error::Error> { fn cause(&self) -> Option<&dyn error::Error> {
match *self { match *self {
// N.B. Both of these implicitly cast `err` from their concrete // N.B. Both of these implicitly cast `err` from their concrete
@ -120,10 +128,3 @@ impl From<serde_yaml::Error> for ConfigError {
ConfigError::Serde(err) ConfigError::Serde(err)
} }
} }
//impl From<de::Error::Message> for ConfigError {
//fn from(err: de::Error::Message) -> ConfigError {
//ConfigError::Message(err)
//}
//}

View File

@ -2,6 +2,7 @@
use super::actions::Action; use super::actions::Action;
use super::keybinds::get_default_keybinds; use super::keybinds::get_default_keybinds;
use crate::common::config::Config;
use crate::common::{update_state, AppInstruction, AppState, SenderWithContext, OPENCALLS}; use crate::common::{update_state, AppInstruction, AppState, SenderWithContext, OPENCALLS};
use crate::errors::ContextType; use crate::errors::ContextType;
use crate::os_input_output::OsApi; use crate::os_input_output::OsApi;
@ -22,6 +23,7 @@ struct InputHandler {
/// The current input mode /// The current input mode
mode: InputMode, mode: InputMode,
os_input: Box<dyn OsApi>, os_input: Box<dyn OsApi>,
config: Config,
command_is_executing: CommandIsExecuting, command_is_executing: CommandIsExecuting,
send_screen_instructions: SenderWithContext<ScreenInstruction>, send_screen_instructions: SenderWithContext<ScreenInstruction>,
send_pty_instructions: SenderWithContext<PtyInstruction>, send_pty_instructions: SenderWithContext<PtyInstruction>,
@ -34,6 +36,7 @@ impl InputHandler {
fn new( fn new(
os_input: Box<dyn OsApi>, os_input: Box<dyn OsApi>,
command_is_executing: CommandIsExecuting, command_is_executing: CommandIsExecuting,
config: Config,
send_screen_instructions: SenderWithContext<ScreenInstruction>, send_screen_instructions: SenderWithContext<ScreenInstruction>,
send_pty_instructions: SenderWithContext<PtyInstruction>, send_pty_instructions: SenderWithContext<PtyInstruction>,
send_plugin_instructions: SenderWithContext<PluginInstruction>, send_plugin_instructions: SenderWithContext<PluginInstruction>,
@ -42,6 +45,7 @@ impl InputHandler {
InputHandler { InputHandler {
mode: InputMode::Normal, mode: InputMode::Normal,
os_input, os_input,
config,
command_is_executing, command_is_executing,
send_screen_instructions, send_screen_instructions,
send_pty_instructions, send_pty_instructions,
@ -59,6 +63,8 @@ impl InputHandler {
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) = get_default_keybinds() { if let Ok(keybinds) = get_default_keybinds() {
let mut merged_keybinds = keybinds;
merged_keybinds.extend(self.config.keybinds.clone().into_iter());
'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();
@ -76,9 +82,14 @@ impl InputHandler {
// been revised. Sorry about this (@categorille) // been revised. Sorry about this (@categorille)
if { if {
let mut should_break = false; let mut should_break = false;
for action in // Hacked on way to have a means of testing Macros, needs to
key_to_actions(&key, raw_bytes, &self.mode, &keybinds) // get properly integrated
{ for action in key_to_actions(
&key,
raw_bytes,
&self.mode,
&merged_keybinds,
) {
should_break |= self.dispatch_action(action); should_break |= self.dispatch_action(action);
} }
should_break should_break
@ -324,6 +335,7 @@ pub fn get_help(mode: InputMode) -> Help {
/// its [`InputHandler::handle_input()`] loop. /// its [`InputHandler::handle_input()`] loop.
pub fn input_loop( pub fn input_loop(
os_input: Box<dyn OsApi>, os_input: Box<dyn OsApi>,
config: Config,
command_is_executing: CommandIsExecuting, command_is_executing: CommandIsExecuting,
send_screen_instructions: SenderWithContext<ScreenInstruction>, send_screen_instructions: SenderWithContext<ScreenInstruction>,
send_pty_instructions: SenderWithContext<PtyInstruction>, send_pty_instructions: SenderWithContext<PtyInstruction>,
@ -333,6 +345,7 @@ pub fn input_loop(
let _handler = InputHandler::new( let _handler = InputHandler::new(
os_input, os_input,
command_is_executing, command_is_executing,
config,
send_screen_instructions, send_screen_instructions,
send_pty_instructions, send_pty_instructions,
send_plugin_instructions, send_plugin_instructions,

View File

@ -23,7 +23,7 @@ pub fn get_default_keybinds() -> Result<Keybinds, String> {
Ok(defaults) 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<ModeKeybinds, String> { fn get_defaults_for_mode(mode: &InputMode) -> Result<ModeKeybinds, String> {
let mut defaults = ModeKeybinds::new(); let mut defaults = ModeKeybinds::new();

View File

@ -8,5 +8,5 @@ use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct Macro { pub struct Macro {
name: Option<String>, name: Option<String>,
sequence: Vec<Action> sequence: Vec<Action>,
} }

View File

@ -1,5 +1,5 @@
pub mod config;
pub mod command_is_executing; pub mod command_is_executing;
pub mod config;
pub mod errors; pub mod errors;
pub mod input; pub mod input;
pub mod install; pub mod install;
@ -46,10 +46,17 @@ pub enum ApiCommand {
MoveFocus, MoveFocus,
} }
// FIXME: It would be good to add some more things to this over time // 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 struct AppState {
pub input_mode: InputMode, 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 // 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<dyn OsApi>, opts: CliArgs) {
.get_stdout_writer() .get_stdout_writer()
.write(take_snapshot.as_bytes()) .write(take_snapshot.as_bytes())
.unwrap(); .unwrap();
let mut app_state = AppState::default(); 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 command_is_executing = CommandIsExecuting::new();
let full_screen_ws = os_input.get_terminal_size_using_fd(0); let full_screen_ws = os_input.get_terminal_size_using_fd(0);
@ -638,9 +650,11 @@ 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();
move || { move || {
input_loop( input_loop(
os_input, os_input,
config,
command_is_executing, command_is_executing,
send_screen_instructions, send_screen_instructions,
send_pty_instructions, send_pty_instructions,