ui: add manual_refresh, refresh_command settings
manual_refresh Ar boolean (optional) if true, do not monitor account for changes (shortcut listing.refresh) refresh_command Ar String (optional) command to execute when manually refreshing (shortcut listing.refresh)memfd
parent
5e912db461
commit
86d8419ce7
31
meli.conf.5
31
meli.conf.5
|
@ -53,7 +53,7 @@ is not a comment:
|
||||||
The accepted regular expression is
|
The accepted regular expression is
|
||||||
.Li ^\es*include\es*\&\\&\e"(\e\e.|[^\e"])+\e"\es*$
|
.Li ^\es*include\es*\&\\&\e"(\e\e.|[^\e"])+\e"\es*$
|
||||||
.Sh SECTIONS
|
.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
|
.Pp
|
||||||
.Sy example configuration
|
.Sy example configuration
|
||||||
|
|
||||||
|
@ -138,6 +138,12 @@ plain:shows one row per mail, regardless of threading
|
||||||
.It Ic read_only Ar boolean
|
.It Ic read_only Ar boolean
|
||||||
attempt to not make any changes to this account.
|
attempt to not make any changes to this account.
|
||||||
.Pq Em false
|
.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
|
.It Ic cache_type Ar String
|
||||||
(optional) choose which cache backend to use. Available options are 'none' and 'sqlite3'
|
(optional) choose which cache backend to use. Available options are 'none' and 'sqlite3'
|
||||||
.Pq Em "sqlite3"
|
.Pq Em "sqlite3"
|
||||||
|
@ -351,6 +357,14 @@ Go to next account.
|
||||||
Start new mail draft in new tab
|
Start new mail draft in new tab
|
||||||
.\" default value
|
.\" default value
|
||||||
.Pq Em m
|
.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
|
.It Ic search
|
||||||
Search within list of e-mails.
|
Search within list of e-mails.
|
||||||
.\" default value
|
.\" default value
|
||||||
|
@ -563,6 +577,21 @@ enable freedesktop-spec notifications. this is usually what you want
|
||||||
.\" default value
|
.\" default value
|
||||||
.Pq Em 80
|
.Pq Em 80
|
||||||
.El
|
.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
|
.Sh TAGS
|
||||||
.Bl -tag -width 36n
|
.Bl -tag -width 36n
|
||||||
.It Ic colours Ar hash table String[Color]
|
.It Ic colours Ar hash table String[Color]
|
||||||
|
|
|
@ -591,7 +591,7 @@ impl CompactListing {
|
||||||
subject.truncate_at_boundary(150);
|
subject.truncate_at_boundary(150);
|
||||||
if thread_node.len() > 0 {
|
if thread_node.len() > 0 {
|
||||||
EntryStrings {
|
EntryStrings {
|
||||||
date: DateString(ConversationsListing::format_date(thread_node)),
|
date: DateString(ConversationsListing::format_date(context, thread_node)),
|
||||||
subject: SubjectString(format!("{} ({})", subject, thread_node.len(),)),
|
subject: SubjectString(format!("{} ({})", subject, thread_node.len(),)),
|
||||||
flag: FlagString(format!(
|
flag: FlagString(format!(
|
||||||
"{}{}",
|
"{}{}",
|
||||||
|
@ -603,7 +603,7 @@ impl CompactListing {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
EntryStrings {
|
EntryStrings {
|
||||||
date: DateString(ConversationsListing::format_date(thread_node)),
|
date: DateString(ConversationsListing::format_date(context, thread_node)),
|
||||||
subject: SubjectString(subject),
|
subject: SubjectString(subject),
|
||||||
flag: FlagString(format!(
|
flag: FlagString(format!(
|
||||||
"{}{}",
|
"{}{}",
|
||||||
|
|
|
@ -562,7 +562,7 @@ impl ConversationsListing {
|
||||||
subject.truncate_at_boundary(150);
|
subject.truncate_at_boundary(150);
|
||||||
if thread_node.len() > 0 {
|
if thread_node.len() > 0 {
|
||||||
EntryStrings {
|
EntryStrings {
|
||||||
date: DateString(ConversationsListing::format_date(thread_node)),
|
date: DateString(ConversationsListing::format_date(context, thread_node)),
|
||||||
subject: SubjectString(format!("{} ({})", subject, thread_node.len(),)),
|
subject: SubjectString(format!("{} ({})", subject, thread_node.len(),)),
|
||||||
flag: FlagString(format!(
|
flag: FlagString(format!(
|
||||||
"{}{}",
|
"{}{}",
|
||||||
|
@ -574,7 +574,7 @@ impl ConversationsListing {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
EntryStrings {
|
EntryStrings {
|
||||||
date: DateString(ConversationsListing::format_date(thread_node)),
|
date: DateString(ConversationsListing::format_date(context, thread_node)),
|
||||||
subject: SubjectString(subject),
|
subject: SubjectString(subject),
|
||||||
flag: FlagString(format!(
|
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 d = std::time::UNIX_EPOCH + std::time::Duration::from_secs(thread_node.date());
|
||||||
let now: std::time::Duration = std::time::SystemTime::now()
|
let now: std::time::Duration = std::time::SystemTime::now()
|
||||||
.duration_since(d)
|
.duration_since(d)
|
||||||
.unwrap_or_else(|_| std::time::Duration::new(std::u64::MAX, 0));
|
.unwrap_or_else(|_| std::time::Duration::new(std::u64::MAX, 0));
|
||||||
match now.as_secs() {
|
match now.as_secs() {
|
||||||
n if n < 60 * 60 => format!(
|
n if context.settings.listing.recent_dates && n < 60 * 60 => format!(
|
||||||
"{} minute{} ago",
|
"{} minute{} ago",
|
||||||
n / (60),
|
n / (60),
|
||||||
if n / 60 == 1 { "" } else { "s" }
|
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",
|
"{} hour{} ago",
|
||||||
n / (60 * 60),
|
n / (60 * 60),
|
||||||
if n / (60 * 60) == 1 { "" } else { "s" }
|
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",
|
"{} day{} ago",
|
||||||
n / (24 * 60 * 60),
|
n / (24 * 60 * 60),
|
||||||
if n / (24 * 60 * 60) == 1 { "" } else { "s" }
|
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")),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ pub mod pgp;
|
||||||
pub mod tags;
|
pub mod tags;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod shortcuts;
|
pub mod shortcuts;
|
||||||
|
mod listing;
|
||||||
pub mod terminal;
|
pub mod terminal;
|
||||||
|
|
||||||
pub mod accounts;
|
pub mod accounts;
|
||||||
|
@ -41,6 +42,7 @@ pub use self::shortcuts::*;
|
||||||
pub use self::tags::*;
|
pub use self::tags::*;
|
||||||
|
|
||||||
use self::default_vals::*;
|
use self::default_vals::*;
|
||||||
|
use self::listing::ListingSettings;
|
||||||
use self::notifications::NotificationsSettings;
|
use self::notifications::NotificationsSettings;
|
||||||
use self::terminal::TerminalSettings;
|
use self::terminal::TerminalSettings;
|
||||||
use crate::pager::PagerSettings;
|
use crate::pager::PagerSettings;
|
||||||
|
@ -68,6 +70,7 @@ macro_rules! split_command {
|
||||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct MailUIConf {
|
pub struct MailUIConf {
|
||||||
pub pager: Option<PagerSettings>,
|
pub pager: Option<PagerSettings>,
|
||||||
|
pub listing: Option<ListingSettings>,
|
||||||
pub notifications: Option<NotificationsSettings>,
|
pub notifications: Option<NotificationsSettings>,
|
||||||
pub shortcuts: Option<Shortcuts>,
|
pub shortcuts: Option<Shortcuts>,
|
||||||
pub composing: Option<ComposingSettings>,
|
pub composing: Option<ComposingSettings>,
|
||||||
|
@ -114,6 +117,8 @@ pub struct FileAccount {
|
||||||
cache_type: CacheType,
|
cache_type: CacheType,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub manual_refresh: bool,
|
pub manual_refresh: bool,
|
||||||
|
#[serde(default = "none")]
|
||||||
|
pub refresh_command: Option<String>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
#[serde(deserialize_with = "extra_settings")]
|
#[serde(deserialize_with = "extra_settings")]
|
||||||
pub extra: HashMap<String, String>, /* use custom deserializer to convert any given value (eg bool, number, etc) to string */
|
pub extra: HashMap<String, String>, /* use custom deserializer to convert any given value (eg bool, number, etc) to string */
|
||||||
|
@ -230,6 +235,8 @@ pub struct FileSettings {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pager: PagerSettings,
|
pager: PagerSettings,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
listing: ListingSettings,
|
||||||
|
#[serde(default)]
|
||||||
notifications: NotificationsSettings,
|
notifications: NotificationsSettings,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
shortcuts: Shortcuts,
|
shortcuts: Shortcuts,
|
||||||
|
@ -267,6 +274,7 @@ impl AccountConf {
|
||||||
pub struct Settings {
|
pub struct Settings {
|
||||||
pub accounts: HashMap<String, AccountConf>,
|
pub accounts: HashMap<String, AccountConf>,
|
||||||
pub pager: PagerSettings,
|
pub pager: PagerSettings,
|
||||||
|
pub listing: ListingSettings,
|
||||||
pub notifications: NotificationsSettings,
|
pub notifications: NotificationsSettings,
|
||||||
pub shortcuts: Shortcuts,
|
pub shortcuts: Shortcuts,
|
||||||
pub tags: TagsSettings,
|
pub tags: TagsSettings,
|
||||||
|
@ -359,6 +367,7 @@ impl FileSettings {
|
||||||
folders,
|
folders,
|
||||||
extra,
|
extra,
|
||||||
manual_refresh,
|
manual_refresh,
|
||||||
|
refresh_command: _,
|
||||||
index_style: _,
|
index_style: _,
|
||||||
cache_type: _,
|
cache_type: _,
|
||||||
} = acc;
|
} = acc;
|
||||||
|
@ -401,6 +410,7 @@ impl Settings {
|
||||||
Ok(Settings {
|
Ok(Settings {
|
||||||
accounts: s,
|
accounts: s,
|
||||||
pager: fs.pager,
|
pager: fs.pager,
|
||||||
|
listing: fs.listing,
|
||||||
notifications: fs.notifications,
|
notifications: fs.notifications,
|
||||||
shortcuts: fs.shortcuts,
|
shortcuts: fs.shortcuts,
|
||||||
tags: fs.tags,
|
tags: fs.tags,
|
||||||
|
|
|
@ -723,6 +723,18 @@ impl Account {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pub fn refresh(&mut self, folder_hash: FolderHash) -> Result<()> {
|
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 sender_ = self.sender.clone();
|
||||||
let r = RefreshEventConsumer::new(Box::new(move |r| {
|
let r = RefreshEventConsumer::new(Box::new(move |r| {
|
||||||
sender_.send(ThreadEvent::from(r)).unwrap();
|
sender_.send(ThreadEvent::from(r)).unwrap();
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<String>,
|
||||||
|
|
||||||
|
/// Show recent dates as `X {minutes,hours,days} ago`, up to 7 days.
|
||||||
|
/// Default: true
|
||||||
|
#[serde(default = "true_val")]
|
||||||
|
pub recent_dates: bool,
|
||||||
|
}
|
Loading…
Reference in New Issue