Add option to highlight self in mailing list threads
Use under `listing` options such as: globally ======== [listing] highlight_self = true per-account =========== [accounts.work] root_mailbox = '[Gmail]' format = "imap" subscribed_mailboxes = ["*"] listing.index_style = "compact" listing.highlight_self = true per-mailbox =========== [accounts.work.mailboxes] "INBOX/Lists/project-devel" = { listing.highlight_self=true } Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>pull/360/head
parent
3884c0da1f
commit
e2cdebe89c
|
@ -1589,6 +1589,15 @@ Flag to show if thread entry has been selected.
|
|||
.It Ic attachment_flag Ar Option<String>
|
||||
Flag to show if thread entry contains attachments.
|
||||
.LiteralStringValueRenders 📎\e\uu{FE0E} 📎︎ \" default value
|
||||
.It Ic highlight_self_flag Ar Option<String>
|
||||
Flag to show if any thread entry contains your address as a receiver.
|
||||
Useful to make mailing list threads that CC you stand out.
|
||||
.Pq Em "✸" \" default value
|
||||
.It Ic highlight_self Ar boolean
|
||||
Show
|
||||
.Ic highlight_self_flag
|
||||
or not.
|
||||
.Pq Em false \" default value
|
||||
.It Ic thread_subject_pack Ar boolean
|
||||
Should threads with differentiating Subjects show a list of those subjects on
|
||||
the entry title?
|
||||
|
|
|
@ -62,7 +62,7 @@ use std::{
|
|||
|
||||
use indexmap::IndexMap;
|
||||
use melib::{
|
||||
conf::{AccountSettings, MailboxConf, ToggleFlag},
|
||||
conf::{AccountSettings, ActionFlag, MailboxConf, ToggleFlag},
|
||||
error::*,
|
||||
};
|
||||
use pager::PagerSettings;
|
||||
|
@ -679,16 +679,29 @@ mod default_vals {
|
|||
None
|
||||
}
|
||||
|
||||
pub(in crate::conf) fn internal_value_false<T: std::convert::From<super::ToggleFlag>>() -> T {
|
||||
super::ToggleFlag::InternalVal(false).into()
|
||||
pub(in crate::conf) fn internal_value_false<T: std::convert::From<melib::conf::ToggleFlag>>(
|
||||
) -> T {
|
||||
melib::conf::ToggleFlag::InternalVal(false).into()
|
||||
}
|
||||
|
||||
pub(in crate::conf) fn internal_value_true<T: std::convert::From<super::ToggleFlag>>() -> T {
|
||||
super::ToggleFlag::InternalVal(true).into()
|
||||
pub(in crate::conf) fn internal_value_true<T: std::convert::From<melib::conf::ToggleFlag>>() -> T
|
||||
{
|
||||
melib::conf::ToggleFlag::InternalVal(true).into()
|
||||
}
|
||||
|
||||
pub(in crate::conf) fn ask<T: std::convert::From<super::ToggleFlag>>() -> T {
|
||||
super::ToggleFlag::Ask.into()
|
||||
pub(in crate::conf) fn action_internal_value_false<T: std::convert::From<melib::ActionFlag>>(
|
||||
) -> T {
|
||||
melib::conf::ActionFlag::InternalVal(false).into()
|
||||
}
|
||||
|
||||
//pub(in crate::conf) fn action_internal_value_true<
|
||||
// T: std::convert::From<melib::conf::ActionFlag>,
|
||||
//>() -> T {
|
||||
// melib::conf::ActionFlag::InternalVal(true).into()
|
||||
//}
|
||||
|
||||
pub(in crate::conf) fn ask<T: std::convert::From<melib::conf::ActionFlag>>() -> T {
|
||||
melib::conf::ActionFlag::Ask.into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1041,6 +1054,7 @@ mod dotaddressable {
|
|||
impl DotAddressable for melib::LogLevel {}
|
||||
impl DotAddressable for PathBuf {}
|
||||
impl DotAddressable for ToggleFlag {}
|
||||
impl DotAddressable for ActionFlag {}
|
||||
impl DotAddressable for SearchBackend {}
|
||||
impl DotAddressable for melib::SpecialUsageMailbox {}
|
||||
impl<T: DotAddressable> DotAddressable for Option<T> {}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
//! Configuration for composing email.
|
||||
use std::collections::HashMap;
|
||||
|
||||
use melib::{email::HeaderName, ToggleFlag};
|
||||
use melib::{conf::ActionFlag, email::HeaderName};
|
||||
use serde::{de, Deserialize, Deserializer};
|
||||
|
||||
use super::{
|
||||
|
@ -92,7 +92,7 @@ pub struct ComposingSettings {
|
|||
/// Forward emails as attachment? (Alternative is inline)
|
||||
/// Default: ask
|
||||
#[serde(default = "ask", alias = "forward-as-attachment")]
|
||||
pub forward_as_attachment: ToggleFlag,
|
||||
pub forward_as_attachment: ActionFlag,
|
||||
/// Alternative lists of reply prefixes (etc. ["Re:", "RE:", ...]) to strip
|
||||
/// Default: `["Re:", "RE:", "Fwd:", "Fw:", "回复:", "回覆:", "SV:", "Sv:",
|
||||
/// "VS:", "Antw:", "Doorst:", "VS:", "VL:", "REF:", "TR:", "TR:", "AW:",
|
||||
|
@ -126,7 +126,7 @@ impl Default for ComposingSettings {
|
|||
wrap_header_preamble: None,
|
||||
attribution_format_string: None,
|
||||
attribution_use_posix_locale: true,
|
||||
forward_as_attachment: ToggleFlag::Ask,
|
||||
forward_as_attachment: ActionFlag::Ask,
|
||||
reply_prefix_list_to_strip: None,
|
||||
reply_prefix: res(),
|
||||
custom_compose_hooks: vec![],
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use melib::{search::Query, Error, Result};
|
||||
use melib::{search::Query, Error, Result, ToggleFlag};
|
||||
|
||||
use super::{default_vals::*, DotAddressable, IndexStyle};
|
||||
|
||||
|
@ -130,6 +130,17 @@ pub struct ListingSettings {
|
|||
#[serde(default)]
|
||||
pub attachment_flag: Option<String>,
|
||||
|
||||
/// Flag to show if any thread entry contains your address as a receiver.
|
||||
/// Useful to make mailing list threads that CC you stand out.
|
||||
/// Default: "✸"
|
||||
#[serde(default)]
|
||||
pub highlight_self_flag: Option<String>,
|
||||
|
||||
/// Show `highlight_self_flag` or not.
|
||||
/// Default: false
|
||||
#[serde(default)]
|
||||
pub highlight_self: ToggleFlag,
|
||||
|
||||
/// Should threads with different Subjects show a list of those
|
||||
/// subjects on the entry title?
|
||||
/// Default: "true"
|
||||
|
@ -185,6 +196,8 @@ impl Default for ListingSettings {
|
|||
thread_snoozed_flag: None,
|
||||
selected_flag: None,
|
||||
attachment_flag: None,
|
||||
highlight_self_flag: None,
|
||||
highlight_self: ToggleFlag::Unset,
|
||||
thread_subject_pack: true,
|
||||
threaded_repeat_identical_from_values: false,
|
||||
relative_menu_indices: true,
|
||||
|
@ -224,6 +237,8 @@ impl DotAddressable for ListingSettings {
|
|||
"thread_snoozed_flag" => self.thread_snoozed_flag.lookup(field, tail),
|
||||
"selected_flag" => self.selected_flag.lookup(field, tail),
|
||||
"attachment_flag" => self.attachment_flag.lookup(field, tail),
|
||||
"highlight_self_flag" => self.highlight_self_flag.lookup(field, tail),
|
||||
"highlight_self" => self.highlight_self.lookup(field, tail),
|
||||
"thread_subject_pack" => self.thread_subject_pack.lookup(field, tail),
|
||||
"threaded_repeat_identical_from_values" => self
|
||||
.threaded_repeat_identical_from_values
|
||||
|
|
|
@ -29,15 +29,15 @@ use melib::HeaderName;
|
|||
|
||||
# [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct PagerSettingsOverride { # [doc = " Number of context lines when going to next page."] # [doc = " Default: 0"] # [serde (alias = "pager-context")] # [serde (default)] pub pager_context : Option < usize > , # [doc = " Stop at the end instead of displaying next mail."] # [doc = " Default: false"] # [serde (alias = "pager-stop")] # [serde (default)] pub pager_stop : Option < bool > , # [doc = " Always show headers when scrolling."] # [doc = " Default: true"] # [serde (alias = "sticky-headers" , alias = "headers-sticky" , alias = "headers_sticky")] # [serde (default)] pub sticky_headers : Option < bool > , # [doc = " The height of the pager in mail view, in percent."] # [doc = " Default: 80"] # [serde (alias = "pager-ratio")] # [serde (default)] pub pager_ratio : Option < usize > , # [doc = " A command to pipe mail output through for viewing in pager."] # [doc = " Default: None"] # [serde (deserialize_with = "non_empty_opt_string")] # [serde (default)] pub filter : Option < Option < String > > , # [doc = " A command to pipe html output before displaying it in a pager"] # [doc = " Default: None"] # [serde (deserialize_with = "non_empty_opt_string" , alias = "html-filter")] # [serde (default)] pub html_filter : Option < Option < String > > , # [doc = " Respect \"format=flowed\""] # [doc = " Default: true"] # [serde (alias = "format-flowed")] # [serde (default)] pub format_flowed : Option < bool > , # [doc = " Split long lines that would overflow on the x axis."] # [doc = " Default: true"] # [serde (alias = "split-long-lines")] # [serde (default)] pub split_long_lines : Option < bool > , # [doc = " Minimum text width in columns."] # [doc = " Default: 80"] # [serde (alias = "minimum-width")] # [serde (default)] pub minimum_width : Option < usize > , # [doc = " Choose `text/html` alternative if `text/plain` is empty in"] # [doc = " `multipart/alternative` attachments."] # [doc = " Default: true"] # [serde (alias = "auto-choose-multipart-alternative")] # [serde (default)] pub auto_choose_multipart_alternative : Option < ToggleFlag > , # [doc = " Show Date: in my timezone"] # [doc = " Default: true"] # [serde (alias = "show-date-in-my-timezone")] # [serde (default)] pub show_date_in_my_timezone : Option < ToggleFlag > , # [doc = " A command to launch URLs with. The URL will be given as the first"] # [doc = " argument of the command. Default: None"] # [serde (deserialize_with = "non_empty_opt_string")] # [serde (default)] pub url_launcher : Option < Option < String > > , # [doc = " A command to open html files."] # [doc = " Default: None"] # [serde (deserialize_with = "non_empty_opt_string" , alias = "html-open")] # [serde (default)] pub html_open : Option < Option < String > > , # [doc = " Extra headers to display, if present, in the default header preamble."] # [doc = " Default: []"] # [serde (alias = "show-extra-headers")] # [serde (default)] pub show_extra_headers : Option < Vec < String > > } impl Default for PagerSettingsOverride { fn default () -> Self { Self { pager_context : None , pager_stop : None , sticky_headers : None , pager_ratio : None , filter : None , html_filter : None , format_flowed : None , split_long_lines : None , minimum_width : None , auto_choose_multipart_alternative : None , show_date_in_my_timezone : None , url_launcher : None , html_open : None , show_extra_headers : None } } }
|
||||
|
||||
# [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct ListingSettingsOverride { # [doc = " Number of context lines when going to next page."] # [doc = " Default: 0"] # [serde (alias = "context-lines")] # [serde (default)] pub context_lines : Option < usize > , # [doc = " Show auto-hiding scrollbar in accounts sidebar menu."] # [doc = " Default: True"] # [serde (default)] pub show_menu_scrollbar : Option < bool > , # [doc = " Datetime formatting passed verbatim to strftime(3)."] # [doc = " Default: %Y-%m-%d %T"] # [serde (alias = "datetime-fmt")] # [serde (default)] pub datetime_fmt : Option < Option < String > > , # [doc = " Show recent dates as `X {minutes,hours,days} ago`, up to 7 days."] # [doc = " Default: true"] # [serde (alias = "recent-dates")] # [serde (default)] pub recent_dates : Option < bool > , # [doc = " Show only envelopes that match this query"] # [doc = " Default: None"] # [serde (default)] pub filter : Option < Option < Query > > , # [serde (alias = "index-style")] # [serde (default)] pub index_style : Option < IndexStyle > , # [doc = " Default: \" \""] # [serde (default)] pub sidebar_mailbox_tree_has_sibling : Option < Option < String > > , # [doc = " Default: \" \""] # [serde (default)] pub sidebar_mailbox_tree_no_sibling : Option < Option < String > > , # [doc = " Default: \" \""] # [serde (default)] pub sidebar_mailbox_tree_has_sibling_leaf : Option < Option < String > > , # [doc = " Default: \" \""] # [serde (default)] pub sidebar_mailbox_tree_no_sibling_leaf : Option < Option < String > > , # [doc = " Default: ' '"] # [serde (default)] pub sidebar_divider : Option < char > , # [doc = " Default: 90"] # [serde (default)] pub sidebar_ratio : Option < usize > , # [doc = " Flag to show if thread entry contains unseen mail."] # [doc = " Default: \"●\""] # [serde (default)] pub unseen_flag : Option < Option < String > > , # [doc = " Flag to show if thread has been snoozed."] # [doc = " Default: \"💤\""] # [serde (default)] pub thread_snoozed_flag : Option < Option < String > > , # [doc = " Flag to show if thread entry has been selected."] # [doc = " Default: \"☑\u{fe0f}\""] # [serde (default)] pub selected_flag : Option < Option < String > > , # [doc = " Flag to show if thread entry contains attachments."] # [doc = " Default: \"📎\""] # [serde (default)] pub attachment_flag : Option < Option < String > > , # [doc = " Should threads with different Subjects show a list of those"] # [doc = " subjects on the entry title?"] # [doc = " Default: \"true\""] # [serde (default)] pub thread_subject_pack : Option < bool > , # [doc = " In threaded listing style, repeat identical From column values within a"] # [doc = " thread. Not repeating adds empty space in the From column which"] # [doc = " might result in less visual clutter."] # [doc = " Default: \"false\""] # [serde (default)] pub threaded_repeat_identical_from_values : Option < bool > , # [doc = " Show relative indices in menu mailboxes to quickly help with jumping to"] # [doc = " them. Default: \"true\""] # [serde (alias = "relative-menu-indices")] # [serde (default)] pub relative_menu_indices : Option < bool > , # [doc = " Show relative indices in listings to quickly help with jumping to"] # [doc = " them. Default: \"true\""] # [serde (alias = "relative-list-indices")] # [serde (default)] pub relative_list_indices : Option < bool > , # [doc = " Hide sidebar on launch. Default: \"false\""] # [serde (alias = "hide-sidebar-on-launch")] # [serde (default)] pub hide_sidebar_on_launch : Option < bool > } impl Default for ListingSettingsOverride { fn default () -> Self { Self { context_lines : None , show_menu_scrollbar : None , datetime_fmt : None , recent_dates : None , filter : None , index_style : None , sidebar_mailbox_tree_has_sibling : None , sidebar_mailbox_tree_no_sibling : None , sidebar_mailbox_tree_has_sibling_leaf : None , sidebar_mailbox_tree_no_sibling_leaf : None , sidebar_divider : None , sidebar_ratio : None , unseen_flag : None , thread_snoozed_flag : None , selected_flag : None , attachment_flag : None , thread_subject_pack : None , threaded_repeat_identical_from_values : None , relative_menu_indices : None , relative_list_indices : None , hide_sidebar_on_launch : None } } }
|
||||
# [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct ListingSettingsOverride { # [doc = " Number of context lines when going to next page."] # [doc = " Default: 0"] # [serde (alias = "context-lines")] # [serde (default)] pub context_lines : Option < usize > , # [doc = " Show auto-hiding scrollbar in accounts sidebar menu."] # [doc = " Default: True"] # [serde (default)] pub show_menu_scrollbar : Option < bool > , # [doc = " Datetime formatting passed verbatim to strftime(3)."] # [doc = " Default: %Y-%m-%d %T"] # [serde (alias = "datetime-fmt")] # [serde (default)] pub datetime_fmt : Option < Option < String > > , # [doc = " Show recent dates as `X {minutes,hours,days} ago`, up to 7 days."] # [doc = " Default: true"] # [serde (alias = "recent-dates")] # [serde (default)] pub recent_dates : Option < bool > , # [doc = " Show only envelopes that match this query"] # [doc = " Default: None"] # [serde (default)] pub filter : Option < Option < Query > > , # [serde (alias = "index-style")] # [serde (default)] pub index_style : Option < IndexStyle > , # [doc = " Default: \" \""] # [serde (default)] pub sidebar_mailbox_tree_has_sibling : Option < Option < String > > , # [doc = " Default: \" \""] # [serde (default)] pub sidebar_mailbox_tree_no_sibling : Option < Option < String > > , # [doc = " Default: \" \""] # [serde (default)] pub sidebar_mailbox_tree_has_sibling_leaf : Option < Option < String > > , # [doc = " Default: \" \""] # [serde (default)] pub sidebar_mailbox_tree_no_sibling_leaf : Option < Option < String > > , # [doc = " Default: ' '"] # [serde (default)] pub sidebar_divider : Option < char > , # [doc = " Default: 90"] # [serde (default)] pub sidebar_ratio : Option < usize > , # [doc = " Flag to show if thread entry contains unseen mail."] # [doc = " Default: \"●\""] # [serde (default)] pub unseen_flag : Option < Option < String > > , # [doc = " Flag to show if thread has been snoozed."] # [doc = " Default: \"💤\""] # [serde (default)] pub thread_snoozed_flag : Option < Option < String > > , # [doc = " Flag to show if thread entry has been selected."] # [doc = " Default: \"☑\u{fe0f}\""] # [serde (default)] pub selected_flag : Option < Option < String > > , # [doc = " Flag to show if thread entry contains attachments."] # [doc = " Default: \"📎\""] # [serde (default)] pub attachment_flag : Option < Option < String > > , # [doc = " Flag to show if any thread entry contains your address as a receiver."] # [doc = " Useful to make mailing list threads that CC you stand out."] # [doc = " Default: \"✸\""] # [serde (default)] pub highlight_self_flag : Option < Option < String > > , # [doc = " Show `highlight_self_flag` or not."] # [doc = " Default: false"] # [serde (default)] pub highlight_self : Option < ToggleFlag > , # [doc = " Should threads with different Subjects show a list of those"] # [doc = " subjects on the entry title?"] # [doc = " Default: \"true\""] # [serde (default)] pub thread_subject_pack : Option < bool > , # [doc = " In threaded listing style, repeat identical From column values within a"] # [doc = " thread. Not repeating adds empty space in the From column which"] # [doc = " might result in less visual clutter."] # [doc = " Default: \"false\""] # [serde (default)] pub threaded_repeat_identical_from_values : Option < bool > , # [doc = " Show relative indices in menu mailboxes to quickly help with jumping to"] # [doc = " them. Default: \"true\""] # [serde (alias = "relative-menu-indices")] # [serde (default)] pub relative_menu_indices : Option < bool > , # [doc = " Show relative indices in listings to quickly help with jumping to"] # [doc = " them. Default: \"true\""] # [serde (alias = "relative-list-indices")] # [serde (default)] pub relative_list_indices : Option < bool > , # [doc = " Hide sidebar on launch. Default: \"false\""] # [serde (alias = "hide-sidebar-on-launch")] # [serde (default)] pub hide_sidebar_on_launch : Option < bool > } impl Default for ListingSettingsOverride { fn default () -> Self { Self { context_lines : None , show_menu_scrollbar : None , datetime_fmt : None , recent_dates : None , filter : None , index_style : None , sidebar_mailbox_tree_has_sibling : None , sidebar_mailbox_tree_no_sibling : None , sidebar_mailbox_tree_has_sibling_leaf : None , sidebar_mailbox_tree_no_sibling_leaf : None , sidebar_divider : None , sidebar_ratio : None , unseen_flag : None , thread_snoozed_flag : None , selected_flag : None , attachment_flag : None , highlight_self_flag : None , highlight_self : None , thread_subject_pack : None , threaded_repeat_identical_from_values : None , relative_menu_indices : None , relative_list_indices : None , hide_sidebar_on_launch : None } } }
|
||||
|
||||
# [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct NotificationsSettingsOverride { # [doc = " Enable notifications."] # [doc = " Default: True"] # [serde (default)] pub enable : Option < bool > , # [doc = " A command to pipe notifications through."] # [doc = " Default: None"] # [serde (default)] pub script : Option < Option < String > > , # [doc = " A command to pipe new mail notifications through (preferred over"] # [doc = " `script`). Default: None"] # [serde (default)] pub new_mail_script : Option < Option < String > > , # [doc = " A file location which has its size changed when new mail arrives (max"] # [doc = " 128 bytes). Can be used to trigger new mail notifications eg with"] # [doc = " `xbiff(1)`. Default: None"] # [serde (alias = "xbiff-file-path")] # [serde (default)] pub xbiff_file_path : Option < Option < String > > , # [serde (alias = "play-sound")] # [serde (default)] pub play_sound : Option < ToggleFlag > , # [serde (alias = "sound-file")] # [serde (default)] pub sound_file : Option < Option < String > > } impl Default for NotificationsSettingsOverride { fn default () -> Self { Self { enable : None , script : None , new_mail_script : None , xbiff_file_path : None , play_sound : None , sound_file : None } } }
|
||||
|
||||
# [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct ShortcutsOverride { # [serde (default)] pub general : Option < GeneralShortcuts > , # [serde (default)] pub listing : Option < ListingShortcuts > , # [serde (default)] pub composing : Option < ComposingShortcuts > , # [serde (alias = "contact-list")] # [serde (default)] pub contact_list : Option < ContactListShortcuts > , # [serde (alias = "envelope-view")] # [serde (default)] pub envelope_view : Option < EnvelopeViewShortcuts > , # [serde (alias = "thread-view")] # [serde (default)] pub thread_view : Option < ThreadViewShortcuts > , # [serde (default)] pub pager : Option < PagerShortcuts > } impl Default for ShortcutsOverride { fn default () -> Self { Self { general : None , listing : None , composing : None , contact_list : None , envelope_view : None , thread_view : None , pager : None } } }
|
||||
|
||||
# [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct ComposingSettingsOverride { # [doc = " A command to pipe new emails to"] # [doc = " Required"] # [serde (default)] pub send_mail : Option < SendMail > , # [doc = " Command to launch editor. Can have arguments. Draft filename is given as"] # [doc = " the last argument. If it's missing, the environment variable $EDITOR is"] # [doc = " looked up."] # [serde (alias = "editor-command" , alias = "editor-cmd" , alias = "editor_cmd")] # [serde (default)] pub editor_command : Option < Option < String > > , # [doc = " Embedded editor (for terminal interfaces) instead of forking and"] # [doc = " waiting."] # [serde (alias = "embed")] # [serde (default)] pub embedded_pty : Option < bool > , # [doc = " Set \"format=flowed\" in plain text attachments."] # [doc = " Default: true"] # [serde (alias = "format-flowed")] # [serde (default)] pub format_flowed : Option < bool > , # [doc = " Set User-Agent"] # [doc = " Default: empty"] # [serde (alias = "insert_user_agent")] # [serde (default)] pub insert_user_agent : Option < bool > , # [doc = " Set default header values for new drafts"] # [doc = " Default: empty"] # [serde (alias = "default-header-values")] # [serde (default)] pub default_header_values : Option < HashMap < HeaderName , String > > , # [doc = " Wrap header preamble when editing a draft in an editor. This allows you"] # [doc = " to write non-plain text email without the preamble creating syntax"] # [doc = " errors. They are stripped when you return from the editor. The"] # [doc = " values should be a two element array of strings, a prefix and suffix."] # [doc = " Default: None"] # [serde (alias = "wrap-header-preamble")] # [serde (default)] pub wrap_header_preamble : Option < Option < (String , String) > > , # [doc = " Store sent mail after successful submission. This setting is meant to be"] # [doc = " disabled for non-standard behaviour in gmail, which auto-saves sent"] # [doc = " mail on its own. Default: true"] # [serde (default)] pub store_sent_mail : Option < bool > , # [doc = " The attribution line appears above the quoted reply text."] # [doc = " The format specifiers for the replied address are:"] # [doc = " - `%+f` — the sender's name and email address."] # [doc = " - `%+n` — the sender's name (or email address, if no name is included)."] # [doc = " - `%+a` — the sender's email address."] # [doc = " The format string is passed to strftime(3) with the replied envelope's"] # [doc = " date. Default: \"On %a, %0e %b %Y %H:%M, %+f wrote:%n\""] # [serde (default)] pub attribution_format_string : Option < Option < String > > , # [doc = " Whether the strftime call for the attribution string uses the POSIX"] # [doc = " locale instead of the user's active locale"] # [doc = " Default: true"] # [serde (default)] pub attribution_use_posix_locale : Option < bool > , # [doc = " Forward emails as attachment? (Alternative is inline)"] # [doc = " Default: ask"] # [serde (alias = "forward-as-attachment")] # [serde (default)] pub forward_as_attachment : Option < ToggleFlag > , # [doc = " Alternative lists of reply prefixes (etc. [\"Re:\", \"RE:\", ...]) to strip"] # [doc = " Default: `[\"Re:\", \"RE:\", \"Fwd:\", \"Fw:\", \"回复:\", \"回覆:\", \"SV:\", \"Sv:\","] # [doc = " \"VS:\", \"Antw:\", \"Doorst:\", \"VS:\", \"VL:\", \"REF:\", \"TR:\", \"TR:\", \"AW:\","] # [doc = " \"WG:\", \"ΑΠ:\", \"Απ:\", \"απ:\", \"ΠΡΘ:\", \"Πρθ:\", \"πρθ:\", \"ΣΧΕΤ:\", \"Σχετ:\","] # [doc = " \"σχετ:\", \"ΠΡΘ:\", \"Πρθ:\", \"πρθ:\", \"Vá:\", \"Továbbítás:\", \"R:\", \"I:\","] # [doc = " \"RIF:\", \"FS:\", \"BLS:\", \"TRS:\", \"VS:\", \"VB:\", \"RV:\", \"RES:\", \"Res\","] # [doc = " \"ENC:\", \"Odp:\", \"PD:\", \"YNT:\", \"İLT:\", \"ATB:\", \"YML:\"]`"] # [serde (alias = "reply-prefix-list-to-strip")] # [serde (default)] pub reply_prefix_list_to_strip : Option < Option < Vec < String > > > , # [doc = " The prefix to use in reply subjects. The de facto prefix is \"Re:\"."] # [serde (alias = "reply-prefix")] # [serde (default)] pub reply_prefix : Option < String > , # [doc = " Custom `compose-hooks`."] # [serde (alias = "custom-compose-hooks")] # [serde (default)] pub custom_compose_hooks : Option < Vec < ComposeHook > > , # [doc = " Disabled `compose-hooks`."] # [serde (alias = "disabled-compose-hooks")] # [serde (default)] pub disabled_compose_hooks : Option < Vec < String > > } impl Default for ComposingSettingsOverride { fn default () -> Self { Self { send_mail : None , editor_command : None , embedded_pty : None , format_flowed : None , insert_user_agent : None , default_header_values : None , wrap_header_preamble : None , store_sent_mail : None , attribution_format_string : None , attribution_use_posix_locale : None , forward_as_attachment : None , reply_prefix_list_to_strip : None , reply_prefix : None , custom_compose_hooks : None , disabled_compose_hooks : None } } }
|
||||
# [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct ComposingSettingsOverride { # [doc = " A command to pipe new emails to"] # [doc = " Required"] # [serde (default)] pub send_mail : Option < SendMail > , # [doc = " Command to launch editor. Can have arguments. Draft filename is given as"] # [doc = " the last argument. If it's missing, the environment variable $EDITOR is"] # [doc = " looked up."] # [serde (alias = "editor-command" , alias = "editor-cmd" , alias = "editor_cmd")] # [serde (default)] pub editor_command : Option < Option < String > > , # [doc = " Embedded editor (for terminal interfaces) instead of forking and"] # [doc = " waiting."] # [serde (alias = "embed")] # [serde (default)] pub embedded_pty : Option < bool > , # [doc = " Set \"format=flowed\" in plain text attachments."] # [doc = " Default: true"] # [serde (alias = "format-flowed")] # [serde (default)] pub format_flowed : Option < bool > , # [doc = " Set User-Agent"] # [doc = " Default: empty"] # [serde (alias = "insert_user_agent")] # [serde (default)] pub insert_user_agent : Option < bool > , # [doc = " Set default header values for new drafts"] # [doc = " Default: empty"] # [serde (alias = "default-header-values")] # [serde (default)] pub default_header_values : Option < HashMap < HeaderName , String > > , # [doc = " Wrap header preamble when editing a draft in an editor. This allows you"] # [doc = " to write non-plain text email without the preamble creating syntax"] # [doc = " errors. They are stripped when you return from the editor. The"] # [doc = " values should be a two element array of strings, a prefix and suffix."] # [doc = " Default: None"] # [serde (alias = "wrap-header-preamble")] # [serde (default)] pub wrap_header_preamble : Option < Option < (String , String) > > , # [doc = " Store sent mail after successful submission. This setting is meant to be"] # [doc = " disabled for non-standard behaviour in gmail, which auto-saves sent"] # [doc = " mail on its own. Default: true"] # [serde (default)] pub store_sent_mail : Option < bool > , # [doc = " The attribution line appears above the quoted reply text."] # [doc = " The format specifiers for the replied address are:"] # [doc = " - `%+f` — the sender's name and email address."] # [doc = " - `%+n` — the sender's name (or email address, if no name is included)."] # [doc = " - `%+a` — the sender's email address."] # [doc = " The format string is passed to strftime(3) with the replied envelope's"] # [doc = " date. Default: \"On %a, %0e %b %Y %H:%M, %+f wrote:%n\""] # [serde (default)] pub attribution_format_string : Option < Option < String > > , # [doc = " Whether the strftime call for the attribution string uses the POSIX"] # [doc = " locale instead of the user's active locale"] # [doc = " Default: true"] # [serde (default)] pub attribution_use_posix_locale : Option < bool > , # [doc = " Forward emails as attachment? (Alternative is inline)"] # [doc = " Default: ask"] # [serde (alias = "forward-as-attachment")] # [serde (default)] pub forward_as_attachment : Option < ActionFlag > , # [doc = " Alternative lists of reply prefixes (etc. [\"Re:\", \"RE:\", ...]) to strip"] # [doc = " Default: `[\"Re:\", \"RE:\", \"Fwd:\", \"Fw:\", \"回复:\", \"回覆:\", \"SV:\", \"Sv:\","] # [doc = " \"VS:\", \"Antw:\", \"Doorst:\", \"VS:\", \"VL:\", \"REF:\", \"TR:\", \"TR:\", \"AW:\","] # [doc = " \"WG:\", \"ΑΠ:\", \"Απ:\", \"απ:\", \"ΠΡΘ:\", \"Πρθ:\", \"πρθ:\", \"ΣΧΕΤ:\", \"Σχετ:\","] # [doc = " \"σχετ:\", \"ΠΡΘ:\", \"Πρθ:\", \"πρθ:\", \"Vá:\", \"Továbbítás:\", \"R:\", \"I:\","] # [doc = " \"RIF:\", \"FS:\", \"BLS:\", \"TRS:\", \"VS:\", \"VB:\", \"RV:\", \"RES:\", \"Res\","] # [doc = " \"ENC:\", \"Odp:\", \"PD:\", \"YNT:\", \"İLT:\", \"ATB:\", \"YML:\"]`"] # [serde (alias = "reply-prefix-list-to-strip")] # [serde (default)] pub reply_prefix_list_to_strip : Option < Option < Vec < String > > > , # [doc = " The prefix to use in reply subjects. The de facto prefix is \"Re:\"."] # [serde (alias = "reply-prefix")] # [serde (default)] pub reply_prefix : Option < String > , # [doc = " Custom `compose-hooks`."] # [serde (alias = "custom-compose-hooks")] # [serde (default)] pub custom_compose_hooks : Option < Vec < ComposeHook > > , # [doc = " Disabled `compose-hooks`."] # [serde (alias = "disabled-compose-hooks")] # [serde (default)] pub disabled_compose_hooks : Option < Vec < String > > } impl Default for ComposingSettingsOverride { fn default () -> Self { Self { send_mail : None , editor_command : None , embedded_pty : None , format_flowed : None , insert_user_agent : None , default_header_values : None , wrap_header_preamble : None , store_sent_mail : None , attribution_format_string : None , attribution_use_posix_locale : None , forward_as_attachment : None , reply_prefix_list_to_strip : None , reply_prefix : None , custom_compose_hooks : None , disabled_compose_hooks : None } } }
|
||||
|
||||
# [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct TagsSettingsOverride { # [serde (deserialize_with = "tag_color_de")] # [serde (default)] pub colors : Option < HashMap < TagHash , Color > > , # [serde (deserialize_with = "tag_set_de" , alias = "ignore-tags")] # [serde (default)] pub ignore_tags : Option < HashSet < TagHash > > } impl Default for TagsSettingsOverride { fn default () -> Self { Self { colors : None , ignore_tags : None } } }
|
||||
|
||||
# [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct PGPSettingsOverride { # [doc = " auto verify signed e-mail according to RFC3156"] # [doc = " Default: true"] # [serde (alias = "auto-verify-signatures")] # [serde (default)] pub auto_verify_signatures : Option < bool > , # [doc = " auto decrypt encrypted e-mail"] # [doc = " Default: true"] # [serde (alias = "auto-decrypt")] # [serde (default)] pub auto_decrypt : Option < bool > , # [doc = " always sign sent e-mail"] # [doc = " Default: false"] # [serde (alias = "auto-sign")] # [serde (default)] pub auto_sign : Option < bool > , # [doc = " Auto encrypt sent e-mail"] # [doc = " Default: false"] # [serde (alias = "auto-encrypt")] # [serde (default)] pub auto_encrypt : Option < bool > , # [doc = " Default: None"] # [serde (alias = "sign-key")] # [serde (default)] pub sign_key : Option < Option < String > > , # [doc = " Default: None"] # [serde (alias = "decrypt-key")] # [serde (default)] pub decrypt_key : Option < Option < String > > , # [doc = " Default: None"] # [serde (alias = "encrypt-key")] # [serde (default)] pub encrypt_key : Option < Option < String > > , # [doc = " Allow remote lookups"] # [doc = " Default: None"] # [serde (alias = "allow-remote-lookups")] # [serde (default)] pub allow_remote_lookup : Option < ToggleFlag > , # [doc = " Remote lookup mechanisms."] # [doc = " Default: \"local,wkd\""] # [cfg_attr (feature = "gpgme" , serde (alias = "remote-lookup-mechanisms"))] # [cfg (feature = "gpgme")] # [serde (default)] pub remote_lookup_mechanisms : Option < melib :: gpgme :: LocateKey > , # [cfg (not (feature = "gpgme"))] # [cfg_attr (not (feature = "gpgme") , serde (alias = "remote-lookup-mechanisms"))] # [serde (default)] pub remote_lookup_mechanisms : Option < String > } impl Default for PGPSettingsOverride { fn default () -> Self { Self { auto_verify_signatures : None , auto_decrypt : None , auto_sign : None , auto_encrypt : None , sign_key : None , decrypt_key : None , encrypt_key : None , allow_remote_lookup : None , remote_lookup_mechanisms : None } } }
|
||||
# [derive (Debug , Serialize , Deserialize , Clone)] # [serde (deny_unknown_fields)] pub struct PGPSettingsOverride { # [doc = " auto verify signed e-mail according to RFC3156"] # [doc = " Default: true"] # [serde (alias = "auto-verify-signatures")] # [serde (default)] pub auto_verify_signatures : Option < ActionFlag > , # [doc = " auto decrypt encrypted e-mail"] # [doc = " Default: true"] # [serde (alias = "auto-decrypt")] # [serde (default)] pub auto_decrypt : Option < ActionFlag > , # [doc = " always sign sent e-mail"] # [doc = " Default: false"] # [serde (alias = "auto-sign")] # [serde (default)] pub auto_sign : Option < ActionFlag > , # [doc = " Auto encrypt sent e-mail"] # [doc = " Default: false"] # [serde (alias = "auto-encrypt")] # [serde (default)] pub auto_encrypt : Option < ActionFlag > , # [doc = " Default: None"] # [serde (alias = "sign-key")] # [serde (default)] pub sign_key : Option < Option < String > > , # [doc = " Default: None"] # [serde (alias = "decrypt-key")] # [serde (default)] pub decrypt_key : Option < Option < String > > , # [doc = " Default: None"] # [serde (alias = "encrypt-key")] # [serde (default)] pub encrypt_key : Option < Option < String > > , # [doc = " Allow remote lookups"] # [doc = " Default: False"] # [serde (alias = "allow-remote-lookups")] # [serde (default)] pub allow_remote_lookup : Option < ActionFlag > , # [doc = " Remote lookup mechanisms."] # [doc = " Default: \"local,wkd\""] # [cfg_attr (feature = "gpgme" , serde (alias = "remote-lookup-mechanisms"))] # [cfg (feature = "gpgme")] # [serde (default)] pub remote_lookup_mechanisms : Option < melib :: gpgme :: LocateKey > , # [cfg (not (feature = "gpgme"))] # [cfg_attr (not (feature = "gpgme") , serde (alias = "remote-lookup-mechanisms"))] # [serde (default)] pub remote_lookup_mechanisms : Option < String > } impl Default for PGPSettingsOverride { fn default () -> Self { Self { auto_verify_signatures : None , auto_decrypt : None , auto_sign : None , auto_encrypt : None , sign_key : None , decrypt_key : None , encrypt_key : None , allow_remote_lookup : None , remote_lookup_mechanisms : None } } }
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use melib::conf::ToggleFlag;
|
||||
use melib::conf::ActionFlag;
|
||||
|
||||
use super::default_vals::*;
|
||||
|
||||
|
@ -30,22 +30,22 @@ pub struct PGPSettings {
|
|||
/// auto verify signed e-mail according to RFC3156
|
||||
/// Default: true
|
||||
#[serde(default = "true_val", alias = "auto-verify-signatures")]
|
||||
pub auto_verify_signatures: bool,
|
||||
pub auto_verify_signatures: ActionFlag,
|
||||
|
||||
/// auto decrypt encrypted e-mail
|
||||
/// Default: true
|
||||
#[serde(default = "true_val", alias = "auto-decrypt")]
|
||||
pub auto_decrypt: bool,
|
||||
pub auto_decrypt: ActionFlag,
|
||||
|
||||
/// always sign sent e-mail
|
||||
/// Default: false
|
||||
#[serde(default = "false_val", alias = "auto-sign")]
|
||||
pub auto_sign: bool,
|
||||
pub auto_sign: ActionFlag,
|
||||
|
||||
/// Auto encrypt sent e-mail
|
||||
/// Default: false
|
||||
#[serde(default = "false_val", alias = "auto-encrypt")]
|
||||
pub auto_encrypt: bool,
|
||||
pub auto_encrypt: ActionFlag,
|
||||
|
||||
// https://tools.ietf.org/html/rfc4880#section-12.2
|
||||
/// Default: None
|
||||
|
@ -61,9 +61,12 @@ pub struct PGPSettings {
|
|||
pub encrypt_key: Option<String>,
|
||||
|
||||
/// Allow remote lookups
|
||||
/// Default: None
|
||||
#[serde(default = "internal_value_false", alias = "allow-remote-lookups")]
|
||||
pub allow_remote_lookup: ToggleFlag,
|
||||
/// Default: False
|
||||
#[serde(
|
||||
default = "action_internal_value_false",
|
||||
alias = "allow-remote-lookups"
|
||||
)]
|
||||
pub allow_remote_lookup: ActionFlag,
|
||||
|
||||
/// Remote lookup mechanisms.
|
||||
/// Default: "local,wkd"
|
||||
|
@ -92,14 +95,14 @@ fn default_lookup_mechanism() -> melib::gpgme::LocateKey {
|
|||
impl Default for PGPSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
auto_verify_signatures: true,
|
||||
auto_decrypt: true,
|
||||
auto_sign: false,
|
||||
auto_encrypt: false,
|
||||
auto_verify_signatures: true.into(),
|
||||
auto_decrypt: true.into(),
|
||||
auto_sign: false.into(),
|
||||
auto_encrypt: false.into(),
|
||||
sign_key: None,
|
||||
decrypt_key: None,
|
||||
encrypt_key: None,
|
||||
allow_remote_lookup: internal_value_false::<ToggleFlag>(),
|
||||
allow_remote_lookup: action_internal_value_false::<ActionFlag>(),
|
||||
#[cfg(feature = "gpgme")]
|
||||
remote_lookup_mechanisms: default_lookup_mechanism(),
|
||||
#[cfg(not(feature = "gpgme"))]
|
||||
|
|
|
@ -62,6 +62,14 @@
|
|||
clippy::cognitive_complexity,
|
||||
clippy::manual_clamp
|
||||
)]
|
||||
/* Source Code Annotation Tags:
|
||||
*
|
||||
* Global tags (in tagref format <https://github.com/stepchowfun/tagref>) for source code
|
||||
* annotation:
|
||||
*
|
||||
* - tags from melib/src/lib.rs.
|
||||
* - [tag:hardcoded_color_value] Replace hardcoded color values with user configurable ones.
|
||||
*/
|
||||
|
||||
//!
|
||||
//! This crate contains the frontend stuff of the application. The application
|
||||
|
@ -93,8 +101,8 @@ static GLOBAL: System = System;
|
|||
|
||||
pub extern crate melib;
|
||||
pub use melib::{
|
||||
error::*, log, AccountHash, Envelope, EnvelopeHash, EnvelopeRef, Flag, LogLevel, Mail, Mailbox,
|
||||
MailboxHash, ThreadHash, ToggleFlag,
|
||||
error::*, log, AccountHash, ActionFlag, Envelope, EnvelopeHash, EnvelopeRef, Flag, LogLevel,
|
||||
Mail, Mailbox, MailboxHash, ThreadHash, ToggleFlag,
|
||||
};
|
||||
|
||||
pub mod args;
|
||||
|
|
|
@ -387,15 +387,11 @@ impl Composer {
|
|||
to.extend(envelope.from().iter().cloned());
|
||||
}
|
||||
to.extend(envelope.to().iter().cloned());
|
||||
if let Ok(ours) = TryInto::<Address>::try_into(
|
||||
context.accounts[&coordinates.0]
|
||||
.settings
|
||||
.account()
|
||||
.make_display_name()
|
||||
.as_str(),
|
||||
) {
|
||||
to.remove(&ours);
|
||||
}
|
||||
let ours = context.accounts[&coordinates.0]
|
||||
.settings
|
||||
.account()
|
||||
.make_display_name();
|
||||
to.remove(&ours);
|
||||
ret.draft.set_header(HeaderName::TO, {
|
||||
let mut ret: String =
|
||||
to.into_iter()
|
||||
|
@ -671,7 +667,7 @@ To: {}
|
|||
}
|
||||
};
|
||||
|
||||
(addr, desc)
|
||||
(addr.to_string(), desc)
|
||||
})
|
||||
.map(AutoCompleteEntry::from)
|
||||
.collect::<Vec<AutoCompleteEntry>>()
|
||||
|
@ -688,7 +684,12 @@ To: {}
|
|||
let theme_default = crate::conf::value(context, "theme_default");
|
||||
grid.clear_area(area, theme_default);
|
||||
#[cfg(feature = "gpgme")]
|
||||
if self.gpg_state.sign_mail.is_true() {
|
||||
if self
|
||||
.gpg_state
|
||||
.sign_mail
|
||||
.unwrap_or(ActionFlag::False)
|
||||
.is_true()
|
||||
{
|
||||
let key_list = self
|
||||
.gpg_state
|
||||
.sign_keys
|
||||
|
@ -731,7 +732,12 @@ To: {}
|
|||
);
|
||||
}
|
||||
#[cfg(feature = "gpgme")]
|
||||
if self.gpg_state.encrypt_mail.is_true() {
|
||||
if self
|
||||
.gpg_state
|
||||
.encrypt_mail
|
||||
.unwrap_or(ActionFlag::False)
|
||||
.is_true()
|
||||
{
|
||||
let key_list = self
|
||||
.gpg_state
|
||||
.encrypt_keys
|
||||
|
@ -867,10 +873,9 @@ impl Component for Composer {
|
|||
|
||||
if !self.initialized {
|
||||
#[cfg(feature = "gpgme")]
|
||||
if self.gpg_state.sign_mail.is_unset() {
|
||||
self.gpg_state.sign_mail = ToggleFlag::InternalVal(*account_settings!(
|
||||
context[self.account_hash].pgp.auto_sign
|
||||
));
|
||||
if self.gpg_state.sign_mail.is_none() {
|
||||
self.gpg_state.sign_mail =
|
||||
Some(*account_settings!(context[self.account_hash].pgp.auto_sign));
|
||||
}
|
||||
if !self.draft.headers().contains_key(HeaderName::FROM)
|
||||
|| self.draft.headers()[HeaderName::FROM].is_empty()
|
||||
|
@ -880,7 +885,8 @@ impl Component for Composer {
|
|||
context.accounts[&self.account_hash]
|
||||
.settings
|
||||
.account()
|
||||
.make_display_name(),
|
||||
.make_display_name()
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
self.pager.update_from_str(self.draft.body(), Some(77));
|
||||
|
@ -1457,12 +1463,20 @@ impl Component for Composer {
|
|||
#[cfg(feature = "gpgme")]
|
||||
match self.cursor {
|
||||
Cursor::Sign => {
|
||||
let is_true = self.gpg_state.sign_mail.is_true();
|
||||
self.gpg_state.sign_mail = ToggleFlag::from(!is_true);
|
||||
let is_true = self
|
||||
.gpg_state
|
||||
.sign_mail
|
||||
.unwrap_or(ActionFlag::False)
|
||||
.is_true();
|
||||
self.gpg_state.sign_mail = Some(ActionFlag::from(!is_true));
|
||||
}
|
||||
Cursor::Encrypt => {
|
||||
let is_true = self.gpg_state.encrypt_mail.is_true();
|
||||
self.gpg_state.encrypt_mail = ToggleFlag::from(!is_true);
|
||||
let is_true = self
|
||||
.gpg_state
|
||||
.encrypt_mail
|
||||
.unwrap_or(ActionFlag::False)
|
||||
.is_true();
|
||||
self.gpg_state.encrypt_mail = Some(ActionFlag::from(!is_true));
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
@ -1686,7 +1700,7 @@ impl Component for Composer {
|
|||
)
|
||||
}) {
|
||||
Ok(widget) => {
|
||||
self.gpg_state.sign_mail = ToggleFlag::from(true);
|
||||
self.gpg_state.sign_mail = Some(ActionFlag::from(true));
|
||||
self.mode = ViewMode::SelectEncryptKey(false, widget);
|
||||
}
|
||||
Err(err) => {
|
||||
|
@ -1727,7 +1741,7 @@ impl Component for Composer {
|
|||
)
|
||||
}) {
|
||||
Ok(widget) => {
|
||||
self.gpg_state.encrypt_mail = ToggleFlag::from(true);
|
||||
self.gpg_state.encrypt_mail = Some(ActionFlag::from(true));
|
||||
self.mode = ViewMode::SelectEncryptKey(true, widget);
|
||||
}
|
||||
Err(err) => {
|
||||
|
@ -2166,15 +2180,23 @@ impl Component for Composer {
|
|||
}
|
||||
#[cfg(feature = "gpgme")]
|
||||
Action::Compose(ComposeAction::ToggleSign) => {
|
||||
let is_true = self.gpg_state.sign_mail.is_true();
|
||||
self.gpg_state.sign_mail = ToggleFlag::from(!is_true);
|
||||
let is_true = self
|
||||
.gpg_state
|
||||
.sign_mail
|
||||
.unwrap_or(ActionFlag::False)
|
||||
.is_true();
|
||||
self.gpg_state.sign_mail = Some(ActionFlag::from(!is_true));
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
#[cfg(feature = "gpgme")]
|
||||
Action::Compose(ComposeAction::ToggleEncrypt) => {
|
||||
let is_true = self.gpg_state.encrypt_mail.is_true();
|
||||
self.gpg_state.encrypt_mail = ToggleFlag::from(!is_true);
|
||||
let is_true = self
|
||||
.gpg_state
|
||||
.encrypt_mail
|
||||
.unwrap_or(ActionFlag::False)
|
||||
.is_true();
|
||||
self.gpg_state.encrypt_mail = Some(ActionFlag::from(!is_true));
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
|
@ -2520,13 +2542,22 @@ pub fn send_draft_async(
|
|||
>,
|
||||
> = vec![];
|
||||
#[cfg(feature = "gpgme")]
|
||||
if gpg_state.sign_mail.is_true() && !gpg_state.encrypt_mail.is_true() {
|
||||
if gpg_state.sign_mail.unwrap_or(ActionFlag::False).is_true()
|
||||
&& !gpg_state
|
||||
.encrypt_mail
|
||||
.unwrap_or(ActionFlag::False)
|
||||
.is_true()
|
||||
{
|
||||
filters_stack.push(Box::new(crate::mail::pgp::sign_filter(
|
||||
gpg_state.sign_keys,
|
||||
)?));
|
||||
} else if gpg_state.encrypt_mail.is_true() {
|
||||
} else if gpg_state
|
||||
.encrypt_mail
|
||||
.unwrap_or(ActionFlag::False)
|
||||
.is_true()
|
||||
{
|
||||
filters_stack.push(Box::new(crate::mail::pgp::encrypt_filter(
|
||||
if gpg_state.sign_mail.is_true() {
|
||||
if gpg_state.sign_mail.unwrap_or(ActionFlag::False).is_true() {
|
||||
Some(gpg_state.sign_keys.clone())
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -29,7 +29,7 @@ pub enum KeySelection {
|
|||
secret: bool,
|
||||
local: bool,
|
||||
pattern: String,
|
||||
allow_remote_lookup: ToggleFlag,
|
||||
allow_remote_lookup: ActionFlag,
|
||||
},
|
||||
Error {
|
||||
id: ComponentId,
|
||||
|
@ -52,7 +52,7 @@ impl KeySelection {
|
|||
secret: bool,
|
||||
local: bool,
|
||||
pattern: String,
|
||||
allow_remote_lookup: ToggleFlag,
|
||||
allow_remote_lookup: ActionFlag,
|
||||
context: &Context,
|
||||
) -> Result<Self> {
|
||||
use melib::gpgme::*;
|
||||
|
@ -247,8 +247,8 @@ impl Component for KeySelection {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GpgComposeState {
|
||||
pub sign_mail: ToggleFlag,
|
||||
pub encrypt_mail: ToggleFlag,
|
||||
pub sign_mail: Option<ActionFlag>,
|
||||
pub encrypt_mail: Option<ActionFlag>,
|
||||
pub encrypt_keys: Vec<melib::gpgme::Key>,
|
||||
pub encrypt_for_self: bool,
|
||||
pub sign_keys: Vec<melib::gpgme::Key>,
|
||||
|
@ -257,8 +257,8 @@ pub struct GpgComposeState {
|
|||
impl Default for GpgComposeState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
sign_mail: ToggleFlag::Unset,
|
||||
encrypt_mail: ToggleFlag::Unset,
|
||||
sign_mail: None,
|
||||
encrypt_mail: None,
|
||||
encrypt_keys: vec![],
|
||||
encrypt_for_self: true,
|
||||
sign_keys: vec![],
|
||||
|
|
|
@ -41,25 +41,11 @@ use crate::{
|
|||
components::ExtendShortcutsMaps,
|
||||
};
|
||||
|
||||
// [ref:TODO]: emoji_text_presentation_selector should be printed along with the chars
|
||||
// before it but not as a separate Cell
|
||||
//macro_rules! emoji_text_presentation_selector {
|
||||
// () => {
|
||||
// "\u{FE0E}"
|
||||
// };
|
||||
//}
|
||||
//
|
||||
//pub const DEFAULT_ATTACHMENT_FLAG: &str = concat!("📎",
|
||||
// emoji_text_presentation_selector!()); pub const DEFAULT_SELECTED_FLAG: &str =
|
||||
// concat!("☑️", emoji_text_presentation_selector!());
|
||||
// pub const DEFAULT_UNSEEN_FLAG: &str = concat!("●",
|
||||
// emoji_text_presentation_selector!()); pub const DEFAULT_SNOOZED_FLAG: &str =
|
||||
// concat!("💤", emoji_text_presentation_selector!());
|
||||
|
||||
pub const DEFAULT_ATTACHMENT_FLAG: &str = "📎";
|
||||
pub const DEFAULT_SELECTED_FLAG: &str = "☑️";
|
||||
pub const DEFAULT_UNSEEN_FLAG: &str = "●";
|
||||
pub const DEFAULT_SNOOZED_FLAG: &str = "💤";
|
||||
pub const DEFAULT_ATTACHMENT_FLAG: &str = concat!("📎", emoji_text_presentation_selector!());
|
||||
pub const DEFAULT_SELECTED_FLAG: &str = concat!("☑️", emoji_text_presentation_selector!());
|
||||
pub const DEFAULT_UNSEEN_FLAG: &str = concat!("●", emoji_text_presentation_selector!());
|
||||
pub const DEFAULT_SNOOZED_FLAG: &str = concat!("💤", emoji_text_presentation_selector!());
|
||||
pub const DEFAULT_HIGHLIGHT_SELF_FLAG: &str = concat!("✸", emoji_text_presentation_selector!());
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct RowsState<T> {
|
||||
|
@ -401,6 +387,7 @@ pub struct EntryStrings {
|
|||
pub flag: FlagString,
|
||||
pub from: FromString,
|
||||
pub tags: TagString,
|
||||
pub highlight_self: bool,
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
|
|
@ -324,6 +324,11 @@ impl MailListingTrait for CompactListing {
|
|||
let mut from_address_list = Vec::new();
|
||||
let mut from_address_set: std::collections::HashSet<Vec<u8>> =
|
||||
std::collections::HashSet::new();
|
||||
let mut highlight_self: bool;
|
||||
let my_address: Address = context.accounts[&self.cursor_pos.0]
|
||||
.settings
|
||||
.account
|
||||
.make_display_name();
|
||||
'items_for_loop: for thread in items {
|
||||
let thread_node = &threads.thread_nodes()[&threads.thread_ref(thread).root()];
|
||||
let root_env_hash = if let Some(h) = thread_node.message().or_else(|| {
|
||||
|
@ -373,6 +378,7 @@ impl MailListingTrait for CompactListing {
|
|||
tags.clear();
|
||||
from_address_list.clear();
|
||||
from_address_set.clear();
|
||||
highlight_self = false;
|
||||
for (envelope, show_subject) in threads
|
||||
.thread_iter(thread)
|
||||
.filter_map(|(_, h)| {
|
||||
|
@ -399,6 +405,11 @@ impl MailListingTrait for CompactListing {
|
|||
}
|
||||
}
|
||||
|
||||
highlight_self |= envelope
|
||||
.to()
|
||||
.iter()
|
||||
.chain(envelope.cc().iter())
|
||||
.any(|a| a == &my_address);
|
||||
for addr in envelope.from().iter() {
|
||||
if from_address_set.contains(addr.address_spec_raw()) {
|
||||
continue;
|
||||
|
@ -407,6 +418,15 @@ impl MailListingTrait for CompactListing {
|
|||
from_address_list.push(addr.clone());
|
||||
}
|
||||
}
|
||||
if !mailbox_settings!(
|
||||
context[self.cursor_pos.0][&self.cursor_pos.1]
|
||||
.listing
|
||||
.highlight_self
|
||||
)
|
||||
.is_true()
|
||||
{
|
||||
highlight_self = false;
|
||||
}
|
||||
|
||||
let row_attr = row_attr!(
|
||||
self.color_cache,
|
||||
|
@ -425,6 +445,7 @@ impl MailListingTrait for CompactListing {
|
|||
&threads,
|
||||
&other_subjects,
|
||||
&tags,
|
||||
highlight_self,
|
||||
thread,
|
||||
);
|
||||
row_widths
|
||||
|
@ -937,6 +958,7 @@ impl CompactListing {
|
|||
threads: &Threads,
|
||||
other_subjects: &IndexSet<String>,
|
||||
tags: &IndexSet<TagHash>,
|
||||
highlight_self: bool,
|
||||
hash: ThreadHash,
|
||||
) -> EntryStrings {
|
||||
let thread = threads.thread_ref(hash);
|
||||
|
@ -1096,6 +1118,7 @@ impl CompactListing {
|
|||
)),
|
||||
from: FromString(Address::display_name_slice(from)),
|
||||
tags: TagString(tags_string, colors),
|
||||
highlight_self,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1140,6 +1163,11 @@ impl CompactListing {
|
|||
let mut from_address_list = Vec::new();
|
||||
let mut from_address_set: std::collections::HashSet<Vec<u8>> =
|
||||
std::collections::HashSet::new();
|
||||
let mut highlight_self: bool = false;
|
||||
let my_address: Address = context.accounts[&self.cursor_pos.0]
|
||||
.settings
|
||||
.account
|
||||
.make_display_name();
|
||||
for (envelope, show_subject) in threads
|
||||
.thread_iter(thread_hash)
|
||||
.filter_map(|(_, h)| {
|
||||
|
@ -1164,6 +1192,11 @@ impl CompactListing {
|
|||
tags.insert(t);
|
||||
}
|
||||
}
|
||||
highlight_self |= envelope
|
||||
.to()
|
||||
.iter()
|
||||
.chain(envelope.cc().iter())
|
||||
.any(|a| a == &my_address);
|
||||
for addr in envelope.from().iter() {
|
||||
if from_address_set.contains(addr.address_spec_raw()) {
|
||||
continue;
|
||||
|
@ -1172,6 +1205,15 @@ impl CompactListing {
|
|||
from_address_list.push(addr.clone());
|
||||
}
|
||||
}
|
||||
if !mailbox_settings!(
|
||||
context[self.cursor_pos.0][&self.cursor_pos.1]
|
||||
.listing
|
||||
.highlight_self
|
||||
)
|
||||
.is_true()
|
||||
{
|
||||
highlight_self = false;
|
||||
}
|
||||
|
||||
let strings = self.make_entry_string(
|
||||
&envelope,
|
||||
|
@ -1181,6 +1223,7 @@ impl CompactListing {
|
|||
&threads,
|
||||
&other_subjects,
|
||||
&tags,
|
||||
highlight_self,
|
||||
thread_hash,
|
||||
);
|
||||
drop(envelope);
|
||||
|
@ -1458,7 +1501,34 @@ impl CompactListing {
|
|||
)
|
||||
};
|
||||
let x = {
|
||||
let area = columns[3].area().nth_row(idx).skip_cols(x);
|
||||
let mut area = columns[3].area().nth_row(idx).skip_cols(x);
|
||||
if strings.highlight_self {
|
||||
// [ref:hardcoded_color_value]: add highlight_self theme attr
|
||||
let x = columns[3]
|
||||
.grid_mut()
|
||||
.write_string(
|
||||
mailbox_settings!(
|
||||
context[self.cursor_pos.0][&self.cursor_pos.1]
|
||||
.listing
|
||||
.highlight_self_flag
|
||||
)
|
||||
.as_ref()
|
||||
.map(|s| s.as_str())
|
||||
.unwrap_or(super::DEFAULT_HIGHLIGHT_SELF_FLAG),
|
||||
Color::BLUE,
|
||||
row_attr.bg,
|
||||
row_attr.attrs | Attr::FORCE_TEXT,
|
||||
area,
|
||||
None,
|
||||
)
|
||||
.0;
|
||||
for row in columns[3].grid().bounds_iter(area.nth_row(0).take_cols(x)) {
|
||||
for c in row {
|
||||
columns[3].grid_mut()[c].set_keep_fg(true);
|
||||
}
|
||||
}
|
||||
area = area.skip_cols(x + 1);
|
||||
}
|
||||
columns[3]
|
||||
.grid_mut()
|
||||
.write_string(
|
||||
|
|
|
@ -713,7 +713,7 @@ impl ConversationsListing {
|
|||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(super) fn make_entry_string(
|
||||
fn make_entry_string(
|
||||
&self,
|
||||
root_envelope: &Envelope,
|
||||
context: &Context,
|
||||
|
@ -795,6 +795,7 @@ impl ConversationsListing {
|
|||
)),
|
||||
from: FromString(Address::display_name_slice(from)),
|
||||
tags: TagString(tags_string, colors),
|
||||
highlight_self: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -785,6 +785,7 @@ impl PlainListing {
|
|||
)),
|
||||
from: FromString(Address::display_name_slice(e.from())),
|
||||
tags: TagString(tags, colors),
|
||||
highlight_self: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -953,6 +953,7 @@ impl ThreadListing {
|
|||
)),
|
||||
from: FromString(Address::display_name_slice(e.from())),
|
||||
tags: TagString(tags, colors),
|
||||
highlight_self: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -675,7 +675,8 @@ impl Component for MailView {
|
|||
context.accounts[&coordinates.0]
|
||||
.settings
|
||||
.account()
|
||||
.make_display_name(),
|
||||
.make_display_name()
|
||||
.to_string(),
|
||||
);
|
||||
/* Manually drop stuff because borrowck doesn't do it
|
||||
* on its own */
|
||||
|
|
|
@ -257,7 +257,7 @@ impl EnvelopeView {
|
|||
}
|
||||
#[cfg(feature = "gpgme")]
|
||||
{
|
||||
if view_settings.auto_verify_signatures {
|
||||
if view_settings.auto_verify_signatures.is_true() {
|
||||
let verify_fut = crate::mail::pgp::verify(a.clone());
|
||||
let handle = main_loop_handler
|
||||
.job_executor
|
||||
|
@ -317,7 +317,7 @@ impl EnvelopeView {
|
|||
}
|
||||
#[cfg(feature = "gpgme")]
|
||||
{
|
||||
if view_settings.auto_decrypt {
|
||||
if view_settings.auto_decrypt.is_true() {
|
||||
let decrypt_fut = crate::mail::pgp::decrypt(a.raw().to_vec());
|
||||
let handle = main_loop_handler
|
||||
.job_executor
|
||||
|
|
|
@ -21,7 +21,10 @@
|
|||
|
||||
use std::fmt::Write as IoWrite;
|
||||
|
||||
use melib::{attachment_types::Charset, error::*, pgp::DecryptionMetadata, Attachment, Result};
|
||||
use melib::{
|
||||
attachment_types::Charset, conf::ActionFlag, error::*, pgp::DecryptionMetadata, Attachment,
|
||||
Result,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
conf::shortcuts::EnvelopeViewShortcuts,
|
||||
|
@ -43,8 +46,8 @@ pub struct ViewSettings {
|
|||
pub sticky_headers: bool,
|
||||
pub show_date_in_my_timezone: bool,
|
||||
pub show_extra_headers: Vec<String>,
|
||||
pub auto_verify_signatures: bool,
|
||||
pub auto_decrypt: bool,
|
||||
pub auto_verify_signatures: ActionFlag,
|
||||
pub auto_decrypt: ActionFlag,
|
||||
}
|
||||
|
||||
impl Default for ViewSettings {
|
||||
|
@ -61,8 +64,8 @@ impl Default for ViewSettings {
|
|||
sticky_headers: false,
|
||||
show_date_in_my_timezone: false,
|
||||
show_extra_headers: vec![],
|
||||
auto_verify_signatures: true,
|
||||
auto_decrypt: true,
|
||||
auto_verify_signatures: ActionFlag::InternalVal(true),
|
||||
auto_decrypt: ActionFlag::InternalVal(true),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +187,13 @@ impl ViewOptions {
|
|||
.collect::<Vec<Link>>();
|
||||
}
|
||||
for (lidx, l) in links.iter().enumerate().rev() {
|
||||
text.insert_str(l.start, &format!("[{}]", lidx));
|
||||
let mut start = l.start;
|
||||
while start < text.len() && !text.is_char_boundary(start) {
|
||||
start += 1;
|
||||
}
|
||||
if start < text.len() {
|
||||
text.insert_str(start, &format!("[{}]", lidx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,13 @@ pub enum Alignment {
|
|||
Center,
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! emoji_text_presentation_selector {
|
||||
() => {
|
||||
'\u{FE0E}'
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* CSI events we use
|
||||
*/
|
||||
|
|
|
@ -650,6 +650,7 @@ impl CellBuffer {
|
|||
let upper_left = area.upper_left();
|
||||
let bottom_right = area.bottom_right();
|
||||
let (mut x, mut y) = upper_left;
|
||||
let mut prev_coords = upper_left;
|
||||
if y == get_y(bounds) || x == get_x(bounds) {
|
||||
if self.growable {
|
||||
if !self.resize(
|
||||
|
@ -684,10 +685,17 @@ impl CellBuffer {
|
|||
}
|
||||
}
|
||||
for c in s.chars() {
|
||||
if c == crate::emoji_text_presentation_selector!() {
|
||||
let prev_attrs = self[prev_coords].attrs();
|
||||
self[prev_coords].set_attrs(prev_attrs | Attr::FORCE_TEXT);
|
||||
continue;
|
||||
}
|
||||
|
||||
if c == '\r' {
|
||||
continue;
|
||||
}
|
||||
if c == '\n' {
|
||||
prev_coords = (x, y);
|
||||
y += 1;
|
||||
if let Some(_x) = line_break {
|
||||
x = _x + get_x(upper_left);
|
||||
|
@ -710,6 +718,7 @@ impl CellBuffer {
|
|||
}
|
||||
break;
|
||||
}
|
||||
prev_coords = (x, y);
|
||||
if c == '\t' {
|
||||
self[(x, y)].set_ch(' ');
|
||||
x += 1;
|
||||
|
@ -996,7 +1005,10 @@ impl Cell {
|
|||
self.attrs
|
||||
}
|
||||
|
||||
pub fn set_attrs(&mut self, newattrs: Attr) -> &mut Self {
|
||||
pub fn set_attrs(&mut self, mut newattrs: Attr) -> &mut Self {
|
||||
if self.attrs.intersects(Attr::FORCE_TEXT) {
|
||||
newattrs |= Attr::FORCE_TEXT;
|
||||
}
|
||||
if !self.keep_attrs {
|
||||
self.attrs = newattrs;
|
||||
}
|
||||
|
@ -1079,14 +1091,15 @@ bitflags::bitflags! {
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Attr: u8 {
|
||||
/// Terminal default.
|
||||
const DEFAULT = 0b000_0000;
|
||||
const BOLD = 0b000_0001;
|
||||
const DIM = 0b000_0010;
|
||||
const ITALICS = 0b000_0100;
|
||||
const UNDERLINE = 0b000_1000;
|
||||
const BLINK = 0b001_0000;
|
||||
const REVERSE = 0b010_0000;
|
||||
const HIDDEN = 0b100_0000;
|
||||
const DEFAULT = 0;
|
||||
const BOLD = 1;
|
||||
const DIM = Self::BOLD.bits() << 1;
|
||||
const ITALICS = Self::DIM.bits() << 1;
|
||||
const UNDERLINE = Self::ITALICS.bits() << 1;
|
||||
const BLINK = Self::UNDERLINE.bits() << 1;
|
||||
const REVERSE = Self::BLINK.bits() << 1;
|
||||
const HIDDEN = Self::REVERSE.bits() << 1;
|
||||
const FORCE_TEXT = Self::HIDDEN.bits() << 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1107,6 +1120,7 @@ impl std::fmt::Display for Attr {
|
|||
Self::BLINK => write!(f, "Blink"),
|
||||
Self::REVERSE => write!(f, "Reverse"),
|
||||
Self::HIDDEN => write!(f, "Hidden"),
|
||||
Self::FORCE_TEXT => write!(f, "ForceTextRepresentation"),
|
||||
combination => {
|
||||
let mut ctr = 0;
|
||||
if combination.intersects(Self::BOLD) {
|
||||
|
@ -1154,6 +1168,12 @@ impl std::fmt::Display for Attr {
|
|||
}
|
||||
Self::HIDDEN.fmt(f)?;
|
||||
}
|
||||
if combination.intersects(Self::FORCE_TEXT) {
|
||||
if ctr > 0 {
|
||||
write!(f, "|")?;
|
||||
}
|
||||
Self::FORCE_TEXT.fmt(f)?;
|
||||
}
|
||||
write!(f, "")
|
||||
}
|
||||
}
|
||||
|
@ -1196,6 +1216,7 @@ impl Attr {
|
|||
"Blink" => Ok(Self::BLINK),
|
||||
"Reverse" => Ok(Self::REVERSE),
|
||||
"Hidden" => Ok(Self::HIDDEN),
|
||||
"ForceTextRepresentation" => Ok(Self::FORCE_TEXT),
|
||||
combination if combination.contains('|') => {
|
||||
let mut ret = Self::DEFAULT;
|
||||
for c in combination.trim().split('|') {
|
||||
|
|
|
@ -405,6 +405,9 @@ impl Screen<Tty> {
|
|||
}
|
||||
if !c.empty() {
|
||||
write!(stdout, "{}", c.ch()).unwrap();
|
||||
if c.attrs().intersects(Attr::FORCE_TEXT) {
|
||||
_ = write!(stdout, "\u{FE0E}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -432,6 +435,9 @@ impl Screen<Tty> {
|
|||
}
|
||||
if !c.empty() {
|
||||
write!(stdout, "{}", c.ch()).unwrap();
|
||||
if c.attrs().intersects(Attr::FORCE_TEXT) {
|
||||
_ = write!(stdout, "\u{FE0E}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
//! [`backends`](./backends/index.html)
|
||||
use std::{collections::HashMap, path::Path};
|
||||
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
backends::SpecialUsageMailbox,
|
||||
|
@ -55,8 +55,8 @@ pub struct AccountSettings {
|
|||
impl AccountSettings {
|
||||
/// Create the account's display name from fields
|
||||
/// [`AccountSettings::identity`] and [`AccountSettings::display_name`].
|
||||
pub fn make_display_name(&self) -> String {
|
||||
Address::new(self.display_name.clone(), self.identity.clone()).to_string()
|
||||
pub fn make_display_name(&self) -> Address {
|
||||
Address::new(self.display_name.clone(), self.identity.clone())
|
||||
}
|
||||
|
||||
pub fn order(&self) -> Option<(SortField, SortOrder)> {
|
||||
|
@ -184,117 +184,196 @@ pub const fn none<T>() -> Option<T> {
|
|||
None
|
||||
}
|
||||
|
||||
macro_rules! named_unit_variant {
|
||||
($variant:ident) => {
|
||||
pub mod $variant {
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<(), D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
struct V;
|
||||
impl<'de> serde::de::Visitor<'de> for V {
|
||||
type Value = ();
|
||||
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
f.write_str(concat!("\"", stringify!($variant), "\""))
|
||||
}
|
||||
fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
|
||||
if value == stringify!($variant) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(E::invalid_value(serde::de::Unexpected::Str(value), &self))
|
||||
pub use config_field_types::*;
|
||||
|
||||
pub mod config_field_types {
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
macro_rules! named_unit_variant {
|
||||
($variant:ident) => {
|
||||
pub mod $variant {
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<(), D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
struct V;
|
||||
impl<'de> serde::de::Visitor<'de> for V {
|
||||
type Value = ();
|
||||
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
f.write_str(concat!("\"", stringify!($variant), "\""))
|
||||
}
|
||||
fn visit_str<E: serde::de::Error>(
|
||||
self,
|
||||
value: &str,
|
||||
) -> Result<Self::Value, E> {
|
||||
if value == stringify!($variant) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(E::invalid_value(serde::de::Unexpected::Str(value), &self))
|
||||
}
|
||||
}
|
||||
}
|
||||
deserializer.deserialize_str(V)
|
||||
}
|
||||
deserializer.deserialize_str(V)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub mod strings {
|
||||
named_unit_variant!(ask);
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
pub enum ToggleFlag {
|
||||
#[default]
|
||||
Unset,
|
||||
InternalVal(bool),
|
||||
False,
|
||||
True,
|
||||
}
|
||||
|
||||
impl From<bool> for ToggleFlag {
|
||||
fn from(val: bool) -> Self {
|
||||
if val {
|
||||
Self::True
|
||||
} else {
|
||||
Self::False
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub mod strings {
|
||||
named_unit_variant!(ask);
|
||||
}
|
||||
impl ToggleFlag {
|
||||
pub fn is_unset(&self) -> bool {
|
||||
Self::Unset == *self
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
pub enum ToggleFlag {
|
||||
#[default]
|
||||
Unset,
|
||||
InternalVal(bool),
|
||||
False,
|
||||
True,
|
||||
Ask,
|
||||
}
|
||||
pub fn is_internal(&self) -> bool {
|
||||
matches!(self, Self::InternalVal(_))
|
||||
}
|
||||
|
||||
impl From<bool> for ToggleFlag {
|
||||
fn from(val: bool) -> Self {
|
||||
if val {
|
||||
Self::True
|
||||
} else {
|
||||
Self::False
|
||||
pub fn is_false(&self) -> bool {
|
||||
matches!(self, Self::False | Self::InternalVal(false))
|
||||
}
|
||||
|
||||
pub fn is_true(&self) -> bool {
|
||||
matches!(self, Self::True | Self::InternalVal(true))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ToggleFlag {
|
||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match self {
|
||||
Self::Unset | Self::InternalVal(_) => serializer.serialize_none(),
|
||||
Self::False => serializer.serialize_bool(false),
|
||||
Self::True => serializer.serialize_bool(true),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ToggleFlag {
|
||||
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum InnerToggleFlag {
|
||||
Bool(bool),
|
||||
}
|
||||
let s = <InnerToggleFlag>::deserialize(deserializer);
|
||||
Ok(
|
||||
match s.map_err(|err| {
|
||||
serde::de::Error::custom(format!(
|
||||
r#"expected one of "true", "false", found `{}`"#,
|
||||
err
|
||||
))
|
||||
})? {
|
||||
InnerToggleFlag::Bool(true) => Self::True,
|
||||
InnerToggleFlag::Bool(false) => Self::False,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
pub enum ActionFlag {
|
||||
InternalVal(bool),
|
||||
False,
|
||||
True,
|
||||
#[default]
|
||||
Ask,
|
||||
}
|
||||
|
||||
impl From<bool> for ActionFlag {
|
||||
fn from(val: bool) -> Self {
|
||||
if val {
|
||||
Self::True
|
||||
} else {
|
||||
Self::False
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ActionFlag {
|
||||
pub fn is_internal(&self) -> bool {
|
||||
matches!(self, Self::InternalVal(_))
|
||||
}
|
||||
|
||||
pub fn is_ask(&self) -> bool {
|
||||
matches!(self, Self::Ask)
|
||||
}
|
||||
|
||||
pub fn is_false(&self) -> bool {
|
||||
matches!(self, Self::False | Self::InternalVal(false))
|
||||
}
|
||||
|
||||
pub fn is_true(&self) -> bool {
|
||||
matches!(self, Self::True | Self::InternalVal(true))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ActionFlag {
|
||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match self {
|
||||
Self::InternalVal(_) => serializer.serialize_none(),
|
||||
Self::False => serializer.serialize_bool(false),
|
||||
Self::True => serializer.serialize_bool(true),
|
||||
Self::Ask => serializer.serialize_str("ask"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ActionFlag {
|
||||
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum InnerActionFlag {
|
||||
Bool(bool),
|
||||
#[serde(with = "strings::ask")]
|
||||
Ask,
|
||||
}
|
||||
let s = <InnerActionFlag>::deserialize(deserializer);
|
||||
Ok(
|
||||
match s.map_err(|err| {
|
||||
serde::de::Error::custom(format!(
|
||||
r#"expected one of "true", "false", "ask", found `{}`"#,
|
||||
err
|
||||
))
|
||||
})? {
|
||||
InnerActionFlag::Bool(true) => Self::True,
|
||||
InnerActionFlag::Bool(false) => Self::False,
|
||||
InnerActionFlag::Ask => Self::Ask,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToggleFlag {
|
||||
pub fn is_unset(&self) -> bool {
|
||||
Self::Unset == *self
|
||||
}
|
||||
|
||||
pub fn is_internal(&self) -> bool {
|
||||
matches!(self, Self::InternalVal(_))
|
||||
}
|
||||
|
||||
pub fn is_ask(&self) -> bool {
|
||||
matches!(self, Self::Ask)
|
||||
}
|
||||
|
||||
pub fn is_false(&self) -> bool {
|
||||
matches!(self, Self::False | Self::InternalVal(false))
|
||||
}
|
||||
|
||||
pub fn is_true(&self) -> bool {
|
||||
matches!(self, Self::True | Self::InternalVal(true))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ToggleFlag {
|
||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match self {
|
||||
Self::Unset | Self::InternalVal(_) => serializer.serialize_none(),
|
||||
Self::False => serializer.serialize_bool(false),
|
||||
Self::True => serializer.serialize_bool(true),
|
||||
Self::Ask => serializer.serialize_str("ask"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ToggleFlag {
|
||||
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum InnerToggleFlag {
|
||||
Bool(bool),
|
||||
#[serde(with = "strings::ask")]
|
||||
Ask,
|
||||
}
|
||||
let s = <InnerToggleFlag>::deserialize(deserializer);
|
||||
Ok(
|
||||
match s.map_err(|err| {
|
||||
serde::de::Error::custom(format!(
|
||||
r#"expected one of "true", "false", "ask", found `{}`"#,
|
||||
err
|
||||
))
|
||||
})? {
|
||||
InnerToggleFlag::Bool(true) => Self::True,
|
||||
InnerToggleFlag::Bool(false) => Self::False,
|
||||
InnerToggleFlag::Ask => Self::Ask,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1186,7 +1186,7 @@ impl JmapType {
|
|||
let store = Arc::new(Store {
|
||||
account_name: Arc::new(s.name.clone()),
|
||||
account_hash,
|
||||
main_identity: s.make_display_name(),
|
||||
main_identity: s.make_display_name().to_string(),
|
||||
extra_identities: s.extra_identities.clone(),
|
||||
online_status,
|
||||
event_consumer,
|
||||
|
|
|
@ -68,7 +68,6 @@
|
|||
* Global tags (in tagref format <https://github.com/stepchowfun/tagref>) for source code
|
||||
* annotation:
|
||||
*
|
||||
* - [tag:hardcoded_color_value] Replace hardcoded color values with user configurable ones.
|
||||
* - [tag:needs_unit_test]
|
||||
* - [tag:needs_user_doc]
|
||||
* - [tag:needs_dev_doc]
|
||||
|
|
Loading…
Reference in New Issue