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]' \
'-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[]' \

View File

@ -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=()
;;

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

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)]
pub layout: Option<PathBuf>,
/// Path to the configuration yaml file
#[structopt(short, long)]
pub config: Option<PathBuf>,
#[structopt(short, long)]
pub debug: bool,
}

View File

@ -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<handler::InputMode,Vec<keybinds::Keybinds>>,
keybinds: Option<keybinds::Keybinds>,
macros: Option<Vec<macros::Macro>>,
}
///// Deserialized config state
#[derive(Debug, Clone, Default, Deserialize)]
pub struct Config {
keybinds: Vec<keybinds::Keybinds>,
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<Config,ConfigError> {
let config_deserialized: Config;
pub fn new(path: &PathBuf) -> Result<Config, ConfigError> {
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<PathBuf>) -> Result<Config, ConfigError> {
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<T: Display>(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<io::Error> for ConfigError {
@ -120,10 +128,3 @@ impl From<serde_yaml::Error> for ConfigError {
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::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<dyn OsApi>,
config: Config,
command_is_executing: CommandIsExecuting,
send_screen_instructions: SenderWithContext<ScreenInstruction>,
send_pty_instructions: SenderWithContext<PtyInstruction>,
@ -34,6 +36,7 @@ impl InputHandler {
fn new(
os_input: Box<dyn OsApi>,
command_is_executing: CommandIsExecuting,
config: Config,
send_screen_instructions: SenderWithContext<ScreenInstruction>,
send_pty_instructions: SenderWithContext<PtyInstruction>,
send_plugin_instructions: SenderWithContext<PluginInstruction>,
@ -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<dyn OsApi>,
config: Config,
command_is_executing: CommandIsExecuting,
send_screen_instructions: SenderWithContext<ScreenInstruction>,
send_pty_instructions: SenderWithContext<PtyInstruction>,
@ -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,

View File

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

View File

@ -8,5 +8,5 @@ use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
pub struct Macro {
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 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<dyn OsApi>, 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<dyn OsApi>, 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,