diff --git a/src/common/config.rs b/src/common/config.rs new file mode 100644 index 00000000..2ce25bff --- /dev/null +++ b/src/common/config.rs @@ -0,0 +1,129 @@ +//! Deserializes configuration options. +use std; +use std::collections::HashMap; +use std::error; +use std::fmt::{self, Display}; +use std::fs::File; +use std::io::{self,Read}; +use std::path::PathBuf; + +use super::input::{keybinds,handler}; + +use serde::Deserialize; + +/// Intermediate struct +//pub struct KeybingsFromYaml { + +//} + + +/// Intermediate struct +//#[derive(Debug, Deserialize)] +pub struct ConfigFromYaml { + keybinds: HashMap>, +} + +///// Deserialized config state +#[derive(Debug, Clone, Default, Deserialize)] +pub struct Config { + keybinds: Vec, +} + +#[derive(Debug)] +pub enum ConfigError { + // from the serde documentation + // https://serde.rs/error-handling.html + // One or more variants that can be created by data structures through the + // `ser::Error` and `de::Error` traits. For example the Serialize impl for + // Mutex might return an error because the mutex is poisoned, or the + // Deserialize impl for a struct may return an error because a required + // field is missing. + //Message(String), + // serde_yaml error + Serde(serde_yaml::Error), + //Eof, + // io::Error + Io(io::Error) +} + +impl Config { + /// Deserializes from given path + pub fn new(path: &PathBuf) -> Result { + let config_deserialized: Config; + let mut config_string = String::new(); + + match File::open(path) { + Ok(mut file) => { + file.read_to_string(&mut config_string)?; + config_deserialized = serde_yaml::from_str(&config_string)?; + } + Err(_) => { + // TODO logging, if a file is not found + // at an expected position - should not + // panic @a-kenji + config_deserialized = Config::default(); + } + } + Ok(config_deserialized) + } +} + +//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 { + //ConfigError::Message(msg) => formatter.write_str(msg), + //ConfigError::Eof => formatter.write_str("unexpected end of input"), + // + ConfigError::Io(ref err) => write!(formatter, "Io error: {}", err), + ConfigError::Serde(ref err) => write!(formatter, "Serde error: {}", err), + /* and so forth */ + } + } +} + +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> { + 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 { + fn from(err: io::Error) -> ConfigError { + ConfigError::Io(err) + } +} + +impl From for ConfigError { + fn from(err: serde_yaml::Error) -> ConfigError { + ConfigError::Serde(err) + } +} + +//impl From for ConfigError { + //fn from(err: de::Error::Message) -> ConfigError { + //ConfigError::Message(err) + //} +//} + diff --git a/src/common/input/actions.rs b/src/common/input/actions.rs index fe5e2dad..d03ca859 100644 --- a/src/common/input/actions.rs +++ b/src/common/input/actions.rs @@ -1,9 +1,11 @@ //! Definition of the actions that can be bound to keys. use super::handler; +//use super::macros; +use serde::Deserialize; /// The four directions (left, right, up, down). -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Deserialize)] pub enum Direction { Left, Right, @@ -12,7 +14,7 @@ pub enum Direction { } /// Actions that can be bound to keys. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Deserialize)] pub enum Action { /// Quit Zellij. Quit, diff --git a/src/common/input/keybinds.rs b/src/common/input/keybinds.rs index e56488b4..0ea0695f 100644 --- a/src/common/input/keybinds.rs +++ b/src/common/input/keybinds.rs @@ -8,7 +8,7 @@ use std::collections::HashMap; use strum::IntoEnumIterator; use termion::event::Key; -type Keybinds = HashMap; +pub type Keybinds = HashMap; type ModeKeybinds = HashMap>; /// Populates the default hashmap of keybinds. diff --git a/src/common/input/macros.rs b/src/common/input/macros.rs new file mode 100644 index 00000000..cbd14332 --- /dev/null +++ b/src/common/input/macros.rs @@ -0,0 +1,12 @@ +//! Use a list of commands and execute them in a +//! defined predictable order. + +use super::actions::Action; + +use serde::Deserialize; + +#[derive(Debug, Clone, Deserialize)] +pub struct Macro { + name: Option, + sequence: Vec +} diff --git a/src/common/input/mod.rs b/src/common/input/mod.rs index 20c30dae..438df224 100644 --- a/src/common/input/mod.rs +++ b/src/common/input/mod.rs @@ -3,3 +3,4 @@ pub mod actions; pub mod handler; pub mod keybinds; +pub mod macros; diff --git a/src/common/mod.rs b/src/common/mod.rs index f78303ea..5ba2e15d 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -1,3 +1,4 @@ +pub mod config; pub mod command_is_executing; pub mod errors; pub mod input; @@ -26,6 +27,7 @@ use wasmer::{ChainableNamedResolver, Instance, Module, Store, Value}; use wasmer_wasi::{Pipe, WasiState}; use crate::cli::CliArgs; +use crate::common::config::Config; use crate::layout::Layout; use command_is_executing::CommandIsExecuting; use errors::{AppContext, ContextType, ErrorContext, PluginContext, PtyContext, ScreenContext}; @@ -47,6 +49,7 @@ pub enum ApiCommand { #[derive(Debug, Clone, Default)] pub struct AppState { pub input_mode: InputMode, + pub config : Config, } // FIXME: Make this a method on the big `Communication` struct, so that app_tx can be extracted