diff --git a/src/conf.rs b/src/conf.rs index 8e149a99..21d316aa 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -249,7 +249,7 @@ pub struct FileSettings { pub log: LogSettings, } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, Serialize)] pub struct AccountConf { pub(crate) account: AccountSettings, pub(crate) conf: FileAccount, @@ -272,7 +272,7 @@ impl AccountConf { } } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, Serialize)] pub struct Settings { pub accounts: HashMap, pub pager: PagerSettings, @@ -827,3 +827,84 @@ pub struct LogSettings { #[serde(default)] maximum_level: melib::LoggingLevel, } + +pub trait DotAddressable: Serialize { + fn lookup(&self, parent_field: &str, path: &[&str]) -> Result { + if !path.is_empty() { + Err(MeliError::new(format!( + "{} has no fields, it is of type {}", + parent_field, + std::any::type_name::() + ))) + } else { + Ok(toml::to_string(self).map_err(|err| err.to_string())?) + } + } +} + +impl DotAddressable for bool {} + +impl DotAddressable for String {} +impl DotAddressable for IndexStyle {} +impl DotAddressable for u64 {} +impl DotAddressable for crate::terminal::Color {} +impl DotAddressable for crate::terminal::Attr {} +impl DotAddressable for usize {} +impl DotAddressable for Query {} +impl DotAddressable for melib::LoggingLevel {} +impl DotAddressable for PathBuf {} +impl DotAddressable for ToggleFlag {} +impl DotAddressable for Option {} +impl DotAddressable + for HashMap +{ +} +impl DotAddressable for HashSet {} + +impl DotAddressable for LogSettings { + fn lookup(&self, parent_field: &str, path: &[&str]) -> Result { + match path.first() { + Some(field) => { + let tail = &path[1..]; + match *field { + "log_file" => self.log_file.lookup(field, tail), + "maximum_level" => self.maximum_level.lookup(field, tail), + + other => Err(MeliError::new(format!( + "{} has no field named {}", + parent_field, other + ))), + } + } + None => Ok(toml::to_string(self).map_err(|err| err.to_string())?), + } + } +} +impl DotAddressable for Settings { + fn lookup(&self, parent_field: &str, path: &[&str]) -> Result { + match path.first() { + Some(field) => { + let tail = &path[1..]; + match *field { + "accounts" => Err(MeliError::new("unimplemented")), + "pager" => self.pager.lookup(field, tail), + "listing" => self.listing.lookup(field, tail), + "notifications" => Err(MeliError::new("unimplemented")), + "shortcuts" => Err(MeliError::new("unimplemented")), + "tags" => Err(MeliError::new("unimplemented")), + "composing" => Err(MeliError::new("unimplemented")), + "pgp" => Err(MeliError::new("unimplemented")), + "terminal" => self.terminal.lookup(field, tail), + "plugins" => Err(MeliError::new("unimplemented")), + "log" => self.log.lookup(field, tail), + + other => Err(MeliError::new(format!( + "{} has no field named {}", + parent_field, other + ))), + } + } + None => Ok(toml::to_string(self).map_err(|err| err.to_string())?), + } + } +} diff --git a/src/conf/listing.rs b/src/conf/listing.rs index d67a7291..2904e5c7 100644 --- a/src/conf/listing.rs +++ b/src/conf/listing.rs @@ -19,8 +19,9 @@ * along with meli. If not, see . */ -use super::{default_vals::*, IndexStyle}; +use super::{default_vals::*, DotAddressable, IndexStyle}; use melib::search::Query; +use melib::{MeliError, Result}; /// Settings for mail listings #[derive(Debug, Deserialize, Clone, Serialize)] @@ -60,3 +61,25 @@ impl Default for ListingSettings { } } } + +impl DotAddressable for ListingSettings { + fn lookup(&self, parent_field: &str, path: &[&str]) -> Result { + match path.first() { + Some(field) => { + let tail = &path[1..]; + match *field { + "context_lines" => self.context_lines.lookup(field, tail), + "datetime_fmt" => self.datetime_fmt.lookup(field, tail), + "recent_dates" => self.recent_dates.lookup(field, tail), + "filter" => self.filter.lookup(field, tail), + "index_style" => self.index_style.lookup(field, tail), + other => Err(MeliError::new(format!( + "{} has no field named {}", + parent_field, other + ))), + } + } + None => Ok(toml::to_string(self).map_err(|err| err.to_string())?), + } + } +} diff --git a/src/conf/pager.rs b/src/conf/pager.rs index 5365423a..226bc317 100644 --- a/src/conf/pager.rs +++ b/src/conf/pager.rs @@ -23,7 +23,8 @@ use super::default_vals::*; use super::deserializers::*; -use melib::ToggleFlag; +use super::DotAddressable; +use melib::{MeliError, Result, ToggleFlag}; /// Settings for the pager function. #[derive(Debug, Deserialize, Clone, Serialize)] @@ -103,3 +104,32 @@ impl Default for PagerSettings { } } } + +impl DotAddressable for PagerSettings { + fn lookup(&self, parent_field: &str, path: &[&str]) -> Result { + match path.first() { + Some(field) => { + let tail = &path[1..]; + match *field { + "pager_context" => self.pager_context.lookup(field, tail), + "pager_stop" => self.pager_stop.lookup(field, tail), + "headers_sticky" => self.headers_sticky.lookup(field, tail), + "pager_ratio" => self.pager_ratio.lookup(field, tail), + "filter" => self.filter.lookup(field, tail), + "html_filter" => self.html_filter.lookup(field, tail), + "format_flowed" => self.format_flowed.lookup(field, tail), + "split_long_lines" => self.split_long_lines.lookup(field, tail), + "minimum_width" => self.minimum_width.lookup(field, tail), + "auto_choose_multipart_alternative" => { + self.auto_choose_multipart_alternative.lookup(field, tail) + } + other => Err(MeliError::new(format!( + "{} has no field named {}", + parent_field, other + ))), + } + } + None => Ok(toml::to_string(self).map_err(|err| err.to_string())?), + } + } +} diff --git a/src/conf/tags.rs b/src/conf/tags.rs index a9d2bc6a..cee7a55f 100644 --- a/src/conf/tags.rs +++ b/src/conf/tags.rs @@ -21,7 +21,9 @@ //! E-mail tag configuration and {de,}serializing. +use super::DotAddressable; use crate::terminal::Color; +use melib::{MeliError, Result}; use serde::{Deserialize, Deserializer}; use std::collections::{hash_map::DefaultHasher, HashMap, HashSet}; use std::hash::Hasher; @@ -89,3 +91,22 @@ where .collect::>() .into()) } + +impl DotAddressable for TagsSettings { + fn lookup(&self, parent_field: &str, path: &[&str]) -> Result { + match path.first() { + Some(field) => { + let tail = &path[1..]; + match *field { + "colors" => self.colors.lookup(field, tail), + "ignore_tags" => self.ignore_tags.lookup(field, tail), + other => Err(MeliError::new(format!( + "{} has no field named {}", + parent_field, other + ))), + } + } + None => Ok(toml::to_string(self).map_err(|err| err.to_string())?), + } + } +} diff --git a/src/conf/terminal.rs b/src/conf/terminal.rs index ef6ee714..df3a4f83 100644 --- a/src/conf/terminal.rs +++ b/src/conf/terminal.rs @@ -22,8 +22,9 @@ //! Settings for terminal display use super::deserializers::non_empty_string; +use super::DotAddressable; use super::Themes; -use super::ToggleFlag; +use melib::{MeliError, Result, ToggleFlag}; /// Settings for terminal display #[derive(Debug, Deserialize, Clone, Serialize)] @@ -61,3 +62,25 @@ impl TerminalSettings { || (self.use_color.is_false() && !self.use_color.is_internal())) } } + +impl DotAddressable for TerminalSettings { + fn lookup(&self, parent_field: &str, path: &[&str]) -> Result { + match path.first() { + Some(field) => { + let tail = &path[1..]; + match *field { + "theme" => self.theme.lookup(field, tail), + "themes" => Err(MeliError::new("unimplemented")), + "ascii_drawing" => self.ascii_drawing.lookup(field, tail), + "use_color" => self.use_color.lookup(field, tail), + "window_title" => self.window_title.lookup(field, tail), + other => Err(MeliError::new(format!( + "{} has no field named {}", + parent_field, other + ))), + } + } + None => Ok(toml::to_string(self).map_err(|err| err.to_string())?), + } + } +} diff --git a/src/execute.rs b/src/execute.rs index 810701a9..0da50f6f 100644 --- a/src/execute.rs +++ b/src/execute.rs @@ -646,7 +646,21 @@ define_commands!([ )(input.trim()) } ) - } + }, + { tags: ["print "], + desc: "print ACCOUNT SETTING", + tokens: &[One(Literal("print")), One(AccountName), One(QuotedStringValue)], + parser:( + fn print_setting(input: &[u8]) -> IResult<&[u8], Action> { + let (input, _) = tag("print")(input.trim())?; + let (input, _) = is_a(" ")(input)?; + let (input, account) = quoted_argument(input)?; + let (input, _) = is_a(" ")(input)?; + let (input, setting) = quoted_argument(input)?; + Ok((input, AccountAction(account.to_string(), PrintSetting(setting.to_string())))) + } + ) + } ]); fn usize_c(input: &[u8]) -> IResult<&[u8], usize> { @@ -705,7 +719,7 @@ fn compose_action(input: &[u8]) -> IResult<&[u8], Action> { } fn account_action(input: &[u8]) -> IResult<&[u8], Action> { - reindex(input) + alt((reindex, print_setting))(input) } fn view(input: &[u8]) -> IResult<&[u8], Action> { diff --git a/src/execute/actions.rs b/src/execute/actions.rs index a95fc2c3..4bc6446c 100644 --- a/src/execute/actions.rs +++ b/src/execute/actions.rs @@ -91,6 +91,7 @@ pub enum ComposeAction { #[derive(Debug)] pub enum AccountAction { ReIndex, + PrintSetting(String), } #[derive(Debug)] diff --git a/src/state.rs b/src/state.rs index b3cb3173..2c8a4a9e 100644 --- a/src/state.rs +++ b/src/state.rs @@ -909,6 +909,18 @@ impl State { Some(NotificationType::ERROR), )); } + AccountAction(ref _account_name, PrintSetting(ref setting)) => { + let path = setting.split(".").collect::>(); + self.context + .replies + .push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(format!( + "{}", + self.context + .settings + .lookup("settings", &path) + .unwrap_or_else(|err| err.to_string()) + )))); + } v => { self.rcv_event(UIEvent::Action(v)); }