compose: implement configurable subject prefix stripping when replying

Introduce functionality to strip email subject from a set list of
prefixes or from a user set list.

Also, added a setting for the reply prefix (default is "Re:").

Closes #142
tables
Manos Pitsidianakis 2022-08-31 22:33:02 +03:00
parent da9c80ccfd
commit aa99b0d787
4 changed files with 69 additions and 8 deletions

View File

@ -540,6 +540,24 @@ Whether the strftime call for the attribution string uses the POSIX locale inste
Forward emails as attachment? (Alternative is inline). Forward emails as attachment? (Alternative is inline).
.\" default value .\" default value
.Pq Em ask .Pq Em ask
.It Ic reply_prefix_list_to_strip Ar [String]
.Pq Em optional
Alternative lists of reply prefixes (etc. ["Re:", "RE:", ...]) to strip.
.\" default value
.Pq Em ["Re:", "RE:", "Fwd:", "Fw:", "回复:", "回覆:", "SV:", "Sv:", "VS:", "Antw:", "Doorst:", "VS:", "VL:", "REF:", "TR:", "TR:", "AW:", "WG:", "ΑΠ:", "Απ:", "απ:", "ΠΡΘ:", "Πρθ:", "πρθ:", "ΣΧΕΤ:", "Σχετ:", "σχετ:", "ΠΡΘ:", "Πρθ:", "πρθ:", "Vá:", "Továbbítás:", "R:", "I:", "RIF:", "FS:", "BLS:", "TRS:", "VS:", "VB:", "RV:", "RES:", "Res", "ENC:", "Odp:", "PD:", "YNT:", "İLT:", "ATB:", "YML:"]
.It Ic reply_prefix Ar String
.Pq Em optional
The prefix to use in reply subjects.
The de facto prefix is "Re:".
.\" default value
.Pq Em `Re:`
.Pp
RFC 2822, "Internet Message Format" has this to say on the matter:
.Bd -literal -offset indent -compact
When used in a reply, the field body MAY start with the string "Re: " (from
the Latin "res", in the matter of) followed by the contents of the "Subject:"
field body of the original message.
.Ed
.El .El
.Sh SHORTCUTS .Sh SHORTCUTS
Shortcuts can take the following values: Shortcuts can take the following values:

View File

@ -219,15 +219,34 @@ impl Composer {
let mut ret = Composer::with_account(coordinates.0, context); let mut ret = Composer::with_account(coordinates.0, context);
let account = &context.accounts[&coordinates.0]; let account = &context.accounts[&coordinates.0];
let envelope = account.collection.get_env(coordinates.2); let envelope = account.collection.get_env(coordinates.2);
let subject = envelope.subject(); let subject = {
ret.draft.set_header( let subject = envelope.subject();
"Subject", let prefix_list = account_settings!(
if !subject.starts_with("Re: ") { context[ret.account_hash]
format!("Re: {}", subject) .composing
.reply_prefix_list_to_strip
)
.as_ref()
.map(|v| v.iter().map(String::as_str).collect::<Vec<&str>>())
.unwrap_or(vec![]);
let subject = subject
.as_ref()
.strip_prefixes_from_list(if prefix_list.is_empty() {
<&str>::USUAL_PREFIXES
} else {
&prefix_list
})
.to_string();
let prefix =
account_settings!(context[ret.account_hash].composing.reply_prefix).as_str();
if !subject.starts_with(prefix) {
format!("{prefix} {subject}", prefix = prefix, subject = subject)
} else { } else {
subject.into() subject.to_string()
}, }
); };
ret.draft.set_header("Subject", subject);
ret.draft.set_header( ret.draft.set_header(
"References", "References",
format!( format!(

View File

@ -77,6 +77,13 @@ pub struct ComposingSettings {
/// Default: ask /// Default: ask
#[serde(default = "ask", alias = "forward-as-attachment")] #[serde(default = "ask", alias = "forward-as-attachment")]
pub forward_as_attachment: ToggleFlag, pub forward_as_attachment: ToggleFlag,
/// 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:", "WG:", "ΑΠ:", "Απ:", "απ:", "ΠΡΘ:", "Πρθ:", "πρθ:", "ΣΧΕΤ:", "Σχετ:", "σχετ:", "ΠΡΘ:", "Πρθ:", "πρθ:", "Vá:", "Továbbítás:", "R:", "I:", "RIF:", "FS:", "BLS:", "TRS:", "VS:", "VB:", "RV:", "RES:", "Res", "ENC:", "Odp:", "PD:", "YNT:", "İLT:", "ATB:", "YML:"]`
#[serde(default, alias = "reply-prefix-list-to-strip")]
pub reply_prefix_list_to_strip: Option<Vec<String>>,
/// The prefix to use in reply subjects. The de facto prefix is "Re:".
#[serde(default = "res", alias = "reply-prefix")]
pub reply_prefix: String,
} }
impl Default for ComposingSettings { impl Default for ComposingSettings {
@ -92,10 +99,16 @@ impl Default for ComposingSettings {
attribution_format_string: None, attribution_format_string: None,
attribution_use_posix_locale: true, attribution_use_posix_locale: true,
forward_as_attachment: ToggleFlag::Ask, forward_as_attachment: ToggleFlag::Ask,
reply_prefix_list_to_strip: None,
reply_prefix: res(),
} }
} }
} }
fn res() -> String {
"Re:".to_string()
}
macro_rules! named_unit_variant { macro_rules! named_unit_variant {
($variant:ident) => { ($variant:ident) => {
pub mod $variant { pub mod $variant {

View File

@ -323,6 +323,15 @@ pub struct ComposingSettingsOverride {
#[serde(alias = "forward-as-attachment")] #[serde(alias = "forward-as-attachment")]
#[serde(default)] #[serde(default)]
pub forward_as_attachment: Option<ToggleFlag>, 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:\", \"VS:\", \"Antw:\", \"Doorst:\", \"VS:\", \"VL:\", \"REF:\", \"TR:\", \"TR:\", \"AW:\", \"WG:\", \"ΑΠ:\", \"Απ:\", \"απ:\", \"ΠΡΘ:\", \"Πρθ:\", \"πρθ:\", \"ΣΧΕΤ:\", \"Σχετ:\", \"σχετ:\", \"ΠΡΘ:\", \"Πρθ:\", \"πρθ:\", \"Vá:\", \"Továbbítás:\", \"R:\", \"I:\", \"RIF:\", \"FS:\", \"BLS:\", \"TRS:\", \"VS:\", \"VB:\", \"RV:\", \"RES:\", \"Res\", \"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>,
} }
impl Default for ComposingSettingsOverride { impl Default for ComposingSettingsOverride {
fn default() -> Self { fn default() -> Self {
@ -337,6 +346,8 @@ impl Default for ComposingSettingsOverride {
attribution_format_string: None, attribution_format_string: None,
attribution_use_posix_locale: None, attribution_use_posix_locale: None,
forward_as_attachment: None, forward_as_attachment: None,
reply_prefix_list_to_strip: None,
reply_prefix: None,
} }
} }
} }