Add print setting action
Add experimental print setting action. The command is of the form: print account_name listing.index_style account_name is currently ignored. The path, e.g. listing.index_style is split by "." and fed to DotAddressable lookup trait method. The method checks the first segment in the path if it matches any of the struct's fields, and then calls the field's lookup method.async
parent
c6c2865a54
commit
996abd323f
85
src/conf.rs
85
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<String, AccountConf>,
|
||||
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<String> {
|
||||
if !path.is_empty() {
|
||||
Err(MeliError::new(format!(
|
||||
"{} has no fields, it is of type {}",
|
||||
parent_field,
|
||||
std::any::type_name::<Self>()
|
||||
)))
|
||||
} 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<T: DotAddressable> DotAddressable for Option<T> {}
|
||||
impl<K: DotAddressable + std::cmp::Eq + std::hash::Hash, V: DotAddressable> DotAddressable
|
||||
for HashMap<K, V>
|
||||
{
|
||||
}
|
||||
impl<K: DotAddressable + std::cmp::Eq + std::hash::Hash> DotAddressable for HashSet<K> {}
|
||||
|
||||
impl DotAddressable for LogSettings {
|
||||
fn lookup(&self, parent_field: &str, path: &[&str]) -> Result<String> {
|
||||
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<String> {
|
||||
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())?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,9 @@
|
|||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<String> {
|
||||
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())?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String> {
|
||||
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())?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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::<HashMap<u64, Color>>()
|
||||
.into())
|
||||
}
|
||||
|
||||
impl DotAddressable for TagsSettings {
|
||||
fn lookup(&self, parent_field: &str, path: &[&str]) -> Result<String> {
|
||||
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())?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String> {
|
||||
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())?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -91,6 +91,7 @@ pub enum ComposeAction {
|
|||
#[derive(Debug)]
|
||||
pub enum AccountAction {
|
||||
ReIndex,
|
||||
PrintSetting(String),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
12
src/state.rs
12
src/state.rs
|
@ -909,6 +909,18 @@ impl State {
|
|||
Some(NotificationType::ERROR),
|
||||
));
|
||||
}
|
||||
AccountAction(ref _account_name, PrintSetting(ref setting)) => {
|
||||
let path = setting.split(".").collect::<SmallVec<[&str; 16]>>();
|
||||
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));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue