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
pull/144/head
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).
.\" default value
.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
.Sh SHORTCUTS
Shortcuts can take the following values:

View File

@ -219,15 +219,34 @@ impl Composer {
let mut ret = Composer::with_account(coordinates.0, context);
let account = &context.accounts[&coordinates.0];
let envelope = account.collection.get_env(coordinates.2);
let subject = envelope.subject();
ret.draft.set_header(
"Subject",
if !subject.starts_with("Re: ") {
format!("Re: {}", subject)
let subject = {
let subject = envelope.subject();
let prefix_list = account_settings!(
context[ret.account_hash]
.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 {
subject.into()
},
);
subject.to_string()
}
};
ret.draft.set_header("Subject", subject);
ret.draft.set_header(
"References",
format!(

View File

@ -77,6 +77,13 @@ pub struct ComposingSettings {
/// Default: ask
#[serde(default = "ask", alias = "forward-as-attachment")]
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 {
@ -92,10 +99,16 @@ impl Default for ComposingSettings {
attribution_format_string: None,
attribution_use_posix_locale: true,
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 {
($variant:ident) => {
pub mod $variant {

View File

@ -323,6 +323,15 @@ pub struct ComposingSettingsOverride {
#[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:\", \"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 {
fn default() -> Self {
@ -337,6 +346,8 @@ impl Default for ComposingSettingsOverride {
attribution_format_string: None,
attribution_use_posix_locale: None,
forward_as_attachment: None,
reply_prefix_list_to_strip: None,
reply_prefix: None,
}
}
}