diff --git a/meli.conf.5 b/meli.conf.5 index fc8e5e05..2b6445d1 100644 --- a/meli.conf.5 +++ b/meli.conf.5 @@ -53,7 +53,7 @@ is not a comment: The accepted regular expression is .Li ^\es*include\es*\&\\&\e"(\e\e.|[^\e"])+\e"\es*$ .Sh SECTIONS -The top level sections of the config are accounts, shortcuts, notifications, pager, composing, pgp, terminal. +The top level sections of the config are accounts, shortcuts, notifications, pager, listing, composing, pgp, terminal. .Pp .Sy example configuration @@ -138,6 +138,12 @@ plain:shows one row per mail, regardless of threading .It Ic read_only Ar boolean attempt to not make any changes to this account. .Pq Em false +.It Ic manual_refresh Ar boolean +(optional) if true, do not monitor account for changes (shortcut listing.refresh) +.Pq Em false +.It Ic refresh_command Ar String +(optional) command to execute when manually refreshing (shortcut listing.refresh) +.Pq Em None .It Ic cache_type Ar String (optional) choose which cache backend to use. Available options are 'none' and 'sqlite3' .Pq Em "sqlite3" @@ -351,6 +357,14 @@ Go to next account. Start new mail draft in new tab .\" default value .Pq Em m +.It Ic set_seen +Set thread as seen. +.\" default value +.Pq Em n +.It Ic refresh +Manually request a folder refresh. +.\" default value +.Pq Em F5 .It Ic search Search within list of e-mails. .\" default value @@ -563,6 +577,21 @@ enable freedesktop-spec notifications. this is usually what you want .\" default value .Pq Em 80 .El +.Sh LISTING +.Bl -tag -width 36n +.It Ic context_lines Ar num +(optional) number of context lines when going to next page. (Unimplemented) +.\" default value +.Pq Em 0 +.It Ic datetime_fmt Ar String +(optional) datetime formatting passed verbatim to strftime(3). +.\" default value +.Pq Em \&%Y-\&%m-\&%d \&%T +.It Ic recent_dates Ar Boolean +(optional) Show recent dates as `X {minutes,hours,days} ago`, up to 7 days. +.\" default value +.Pq Em true +.El .Sh TAGS .Bl -tag -width 36n .It Ic colours Ar hash table String[Color] diff --git a/ui/src/components/mail/listing/compact.rs b/ui/src/components/mail/listing/compact.rs index 47f81d01..59923106 100644 --- a/ui/src/components/mail/listing/compact.rs +++ b/ui/src/components/mail/listing/compact.rs @@ -591,7 +591,7 @@ impl CompactListing { subject.truncate_at_boundary(150); if thread_node.len() > 0 { EntryStrings { - date: DateString(ConversationsListing::format_date(thread_node)), + date: DateString(ConversationsListing::format_date(context, thread_node)), subject: SubjectString(format!("{} ({})", subject, thread_node.len(),)), flag: FlagString(format!( "{}{}", @@ -603,7 +603,7 @@ impl CompactListing { } } else { EntryStrings { - date: DateString(ConversationsListing::format_date(thread_node)), + date: DateString(ConversationsListing::format_date(context, thread_node)), subject: SubjectString(subject), flag: FlagString(format!( "{}{}", diff --git a/ui/src/components/mail/listing/conversations.rs b/ui/src/components/mail/listing/conversations.rs index 3b322706..b26b006f 100644 --- a/ui/src/components/mail/listing/conversations.rs +++ b/ui/src/components/mail/listing/conversations.rs @@ -562,7 +562,7 @@ impl ConversationsListing { subject.truncate_at_boundary(150); if thread_node.len() > 0 { EntryStrings { - date: DateString(ConversationsListing::format_date(thread_node)), + date: DateString(ConversationsListing::format_date(context, thread_node)), subject: SubjectString(format!("{} ({})", subject, thread_node.len(),)), flag: FlagString(format!( "{}{}", @@ -574,7 +574,7 @@ impl ConversationsListing { } } else { EntryStrings { - date: DateString(ConversationsListing::format_date(thread_node)), + date: DateString(ConversationsListing::format_date(context, thread_node)), subject: SubjectString(subject), flag: FlagString(format!( "{}{}", @@ -890,28 +890,37 @@ impl ConversationsListing { } } - pub(super) fn format_date(thread_node: &ThreadNode) -> String { + pub(super) fn format_date(context: &Context, thread_node: &ThreadNode) -> String { let d = std::time::UNIX_EPOCH + std::time::Duration::from_secs(thread_node.date()); let now: std::time::Duration = std::time::SystemTime::now() .duration_since(d) .unwrap_or_else(|_| std::time::Duration::new(std::u64::MAX, 0)); match now.as_secs() { - n if n < 60 * 60 => format!( + n if context.settings.listing.recent_dates && n < 60 * 60 => format!( "{} minute{} ago", n / (60), if n / 60 == 1 { "" } else { "s" } ), - n if n < 24 * 60 * 60 => format!( + n if context.settings.listing.recent_dates && n < 24 * 60 * 60 => format!( "{} hour{} ago", n / (60 * 60), if n / (60 * 60) == 1 { "" } else { "s" } ), - n if n < 7 * 24 * 60 * 60 => format!( + n if context.settings.listing.recent_dates && n < 7 * 24 * 60 * 60 => format!( "{} day{} ago", n / (24 * 60 * 60), if n / (24 * 60 * 60) == 1 { "" } else { "s" } ), - _ => melib::datetime::timestamp_to_string(thread_node.date(), Some("%Y-%m-%d %T")), + _ => melib::datetime::timestamp_to_string( + thread_node.date(), + context + .settings + .listing + .datetime_fmt + .as_ref() + .map(String::as_str) + .or(Some("%Y-%m-%d %T")), + ), } } diff --git a/ui/src/conf.rs b/ui/src/conf.rs index 550ab3d8..06dbfc9f 100644 --- a/ui/src/conf.rs +++ b/ui/src/conf.rs @@ -31,6 +31,7 @@ pub mod pgp; pub mod tags; #[macro_use] pub mod shortcuts; +mod listing; pub mod terminal; pub mod accounts; @@ -41,6 +42,7 @@ pub use self::shortcuts::*; pub use self::tags::*; use self::default_vals::*; +use self::listing::ListingSettings; use self::notifications::NotificationsSettings; use self::terminal::TerminalSettings; use crate::pager::PagerSettings; @@ -68,6 +70,7 @@ macro_rules! split_command { #[derive(Default, Debug, Clone, Serialize, Deserialize)] pub struct MailUIConf { pub pager: Option, + pub listing: Option, pub notifications: Option, pub shortcuts: Option, pub composing: Option, @@ -114,6 +117,8 @@ pub struct FileAccount { cache_type: CacheType, #[serde(default)] pub manual_refresh: bool, + #[serde(default = "none")] + pub refresh_command: Option, #[serde(flatten)] #[serde(deserialize_with = "extra_settings")] pub extra: HashMap, /* use custom deserializer to convert any given value (eg bool, number, etc) to string */ @@ -230,6 +235,8 @@ pub struct FileSettings { #[serde(default)] pager: PagerSettings, #[serde(default)] + listing: ListingSettings, + #[serde(default)] notifications: NotificationsSettings, #[serde(default)] shortcuts: Shortcuts, @@ -267,6 +274,7 @@ impl AccountConf { pub struct Settings { pub accounts: HashMap, pub pager: PagerSettings, + pub listing: ListingSettings, pub notifications: NotificationsSettings, pub shortcuts: Shortcuts, pub tags: TagsSettings, @@ -359,6 +367,7 @@ impl FileSettings { folders, extra, manual_refresh, + refresh_command: _, index_style: _, cache_type: _, } = acc; @@ -401,6 +410,7 @@ impl Settings { Ok(Settings { accounts: s, pager: fs.pager, + listing: fs.listing, notifications: fs.notifications, shortcuts: fs.shortcuts, tags: fs.tags, diff --git a/ui/src/conf/accounts.rs b/ui/src/conf/accounts.rs index c4c6ac7c..116d1200 100644 --- a/ui/src/conf/accounts.rs +++ b/ui/src/conf/accounts.rs @@ -723,6 +723,18 @@ impl Account { None } pub fn refresh(&mut self, folder_hash: FolderHash) -> Result<()> { + if let Some(ref refresh_command) = self.settings.conf().refresh_command { + let parts = crate::split_command!(refresh_command); + let (cmd, args) = (parts[0], &parts[1..]); + std::process::Command::new(cmd) + .args(args) + .stdin(std::process::Stdio::null()) + .stdout(std::process::Stdio::null()) + .stderr(std::process::Stdio::piped()) + .spawn()?; + return Ok(()); + } + let sender_ = self.sender.clone(); let r = RefreshEventConsumer::new(Box::new(move |r| { sender_.send(ThreadEvent::from(r)).unwrap(); diff --git a/ui/src/conf/listing.rs b/ui/src/conf/listing.rs new file mode 100644 index 00000000..7d382502 --- /dev/null +++ b/ui/src/conf/listing.rs @@ -0,0 +1,41 @@ +/* + * meli - listing conf module + * + * Copyright 2020 Manos Pitsidianakis + * + * This file is part of meli. + * + * meli is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * meli is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with meli. If not, see . + */ + +use super::default_vals::*; + +/// Settings for mail listings +#[derive(Debug, Deserialize, Clone, Default, Serialize)] +pub struct ListingSettings { + /// Number of context lines when going to next page. + /// Default: 0 + #[serde(default = "zero_val")] + pub context_lines: usize, + + /// Datetime formatting passed verbatim to strftime(3). + /// Default: %Y-%m-%d %T + #[serde(default = "none")] + pub datetime_fmt: Option, + + /// Show recent dates as `X {minutes,hours,days} ago`, up to 7 days. + /// Default: true + #[serde(default = "true_val")] + pub recent_dates: bool, +}