listing/conversations.rs: add `thread_subject_pack` command to pack different inner thread subjects in entry title
parent
9dc4d4055c
commit
8c7b001aa5
|
@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Added listing configuration setting `thread_subject_pack` (see meli.conf.5)
|
||||||
- Added shortcuts for focusing to sidebar menu and back to the e-mail view (`focus_left` and `focus_right`)
|
- Added shortcuts for focusing to sidebar menu and back to the e-mail view (`focus_left` and `focus_right`)
|
||||||
- `f76f4ea3` A new manual page, `meli.7` which contains a general tutorial for using meli.
|
- `f76f4ea3` A new manual page, `meli.7` which contains a general tutorial for using meli.
|
||||||
- `cbe593cf` add configurable header preample suffix and prefix for editing
|
- `cbe593cf` add configurable header preample suffix and prefix for editing
|
||||||
|
|
|
@ -1059,6 +1059,11 @@ The URL will be given as the first argument of the command.
|
||||||
.El
|
.El
|
||||||
.Sh LISTING
|
.Sh LISTING
|
||||||
.Bl -tag -width 36n
|
.Bl -tag -width 36n
|
||||||
|
.It Ic show_menu_scrollbar Ar boolean
|
||||||
|
.Pq Em optional
|
||||||
|
Show auto-hiding scrollbar in accounts sidebar menu.
|
||||||
|
.\" default value
|
||||||
|
.Pq Em true
|
||||||
.It Ic datetime_fmt Ar String
|
.It Ic datetime_fmt Ar String
|
||||||
.Pq Em optional
|
.Pq Em optional
|
||||||
Datetime formatting passed verbatim to strftime(3).
|
Datetime formatting passed verbatim to strftime(3).
|
||||||
|
@ -1106,11 +1111,26 @@ Sets the character to print as the divider between the accounts list and the mes
|
||||||
This is the width of the right container to the entire screen width.
|
This is the width of the right container to the entire screen width.
|
||||||
.\" default value
|
.\" default value
|
||||||
.Pq Em 90
|
.Pq Em 90
|
||||||
.It Ic show_menu_scrollbar Ar boolean
|
.It Ic unseen_flag Ar Option<String>
|
||||||
.Pq Em optional
|
Flag to show if thread entry contains unseen mail.
|
||||||
Show auto-hiding scrollbar in accounts sidebar menu.
|
|
||||||
.\" default value
|
.\" default value
|
||||||
.Pq Em true
|
.Pq Em "●"
|
||||||
|
.It Ic thread_snoozed_flag Ar Option<String>
|
||||||
|
Flag to show if thread has been snoozed.
|
||||||
|
.\" default value
|
||||||
|
.Pq Em "💤"
|
||||||
|
.It Ic selected_flag Ar Option<String>
|
||||||
|
Flag to show if thread entry has been selected.
|
||||||
|
.\" default value
|
||||||
|
.Pq Em "☑️"
|
||||||
|
.It Ic attachment_flag Ar Option<String>
|
||||||
|
Flag to show if thread entry contains attachments.
|
||||||
|
.\" default value
|
||||||
|
.Pq Em "📎"
|
||||||
|
.It Ic thread_subject_pack Ar bool
|
||||||
|
Should threads with differentiating Subjects show a list of those subjects on the entry title?
|
||||||
|
.\" default value
|
||||||
|
.Pq Em "true"
|
||||||
.El
|
.El
|
||||||
.Ss Examples of sidebar mailbox tree customization
|
.Ss Examples of sidebar mailbox tree customization
|
||||||
The default values
|
The default values
|
||||||
|
|
|
@ -834,6 +834,7 @@ impl Threads {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0..self.thread_nodes[&id].children.len() {
|
for i in 0..self.thread_nodes[&id].children.len() {
|
||||||
let child_hash = self.thread_nodes[&id].children[i];
|
let child_hash = self.thread_nodes[&id].children[i];
|
||||||
if let Some(child_env_hash) = self.thread_nodes[&child_hash].message() {
|
if let Some(child_env_hash) = self.thread_nodes[&child_hash].message() {
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::components::PageMovement;
|
use crate::components::PageMovement;
|
||||||
use crate::jobs::JoinHandle;
|
use crate::jobs::JoinHandle;
|
||||||
|
use indexmap::IndexSet;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
macro_rules! row_attr {
|
macro_rules! row_attr {
|
||||||
|
@ -240,6 +241,7 @@ impl MailListingTrait for ConversationsListing {
|
||||||
}
|
}
|
||||||
let mut max_entry_columns = 0;
|
let mut max_entry_columns = 0;
|
||||||
|
|
||||||
|
let mut other_subjects = IndexSet::new();
|
||||||
let mut from_address_list = Vec::new();
|
let mut from_address_list = Vec::new();
|
||||||
let mut from_address_set: std::collections::HashSet<Vec<u8>> =
|
let mut from_address_set: std::collections::HashSet<Vec<u8>> =
|
||||||
std::collections::HashSet::new();
|
std::collections::HashSet::new();
|
||||||
|
@ -273,17 +275,30 @@ impl MailListingTrait for ConversationsListing {
|
||||||
|
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
other_subjects.clear();
|
||||||
from_address_list.clear();
|
from_address_list.clear();
|
||||||
from_address_set.clear();
|
from_address_set.clear();
|
||||||
for envelope in threads
|
for (envelope, show_subject) in threads
|
||||||
.thread_group_iter(thread)
|
.thread_group_iter(thread)
|
||||||
.filter_map(|(_, h)| threads.thread_nodes()[&h].message())
|
.filter_map(|(_, h)| {
|
||||||
.map(|env_hash| {
|
Some((
|
||||||
context.accounts[&self.cursor_pos.0]
|
threads.thread_nodes()[&h].message()?,
|
||||||
.collection
|
threads.thread_nodes()[&h].show_subject(),
|
||||||
.get_env(env_hash)
|
))
|
||||||
|
})
|
||||||
|
.map(|(env_hash, show_subject)| {
|
||||||
|
(
|
||||||
|
context.accounts[&self.cursor_pos.0]
|
||||||
|
.collection
|
||||||
|
.get_env(env_hash),
|
||||||
|
show_subject,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
|
if show_subject {
|
||||||
|
other_subjects.insert(envelope.subject().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
for addr in envelope.from().iter() {
|
for addr in envelope.from().iter() {
|
||||||
if from_address_set.contains(addr.address_spec_raw()) {
|
if from_address_set.contains(addr.address_spec_raw()) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -313,6 +328,7 @@ impl MailListingTrait for ConversationsListing {
|
||||||
context,
|
context,
|
||||||
&from_address_list,
|
&from_address_list,
|
||||||
&threads,
|
&threads,
|
||||||
|
&other_subjects,
|
||||||
thread,
|
thread,
|
||||||
);
|
);
|
||||||
max_entry_columns = std::cmp::max(
|
max_entry_columns = std::cmp::max(
|
||||||
|
@ -627,8 +643,9 @@ impl ConversationsListing {
|
||||||
&self,
|
&self,
|
||||||
e: &Envelope,
|
e: &Envelope,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
from: &Vec<Address>,
|
from: &[Address],
|
||||||
threads: &Threads,
|
threads: &Threads,
|
||||||
|
other_subjects: &IndexSet<String>,
|
||||||
hash: ThreadHash,
|
hash: ThreadHash,
|
||||||
) -> EntryStrings {
|
) -> EntryStrings {
|
||||||
let thread = threads.thread_ref(hash);
|
let thread = threads.thread_ref(hash);
|
||||||
|
@ -669,8 +686,24 @@ impl ConversationsListing {
|
||||||
tags.pop();
|
tags.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut subject = e.subject().to_string();
|
let mut subject = if *mailbox_settings!(
|
||||||
subject.truncate_at_boundary(150);
|
context[self.cursor_pos.0][&self.cursor_pos.1]
|
||||||
|
.listing
|
||||||
|
.thread_subject_pack
|
||||||
|
) {
|
||||||
|
other_subjects
|
||||||
|
.into_iter()
|
||||||
|
.fold(String::new(), |mut acc, s| {
|
||||||
|
if !acc.is_empty() {
|
||||||
|
acc.push_str(", ");
|
||||||
|
}
|
||||||
|
acc.push_str(&s);
|
||||||
|
acc
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
e.subject().to_string()
|
||||||
|
};
|
||||||
|
subject.truncate_at_boundary(100);
|
||||||
if thread.len() > 1 {
|
if thread.len() > 1 {
|
||||||
EntryStrings {
|
EntryStrings {
|
||||||
date: DateString(ConversationsListing::format_date(context, thread.date())),
|
date: DateString(ConversationsListing::format_date(context, thread.date())),
|
||||||
|
@ -755,18 +788,29 @@ impl ConversationsListing {
|
||||||
let idx: usize = self.order[&thread_hash];
|
let idx: usize = self.order[&thread_hash];
|
||||||
let env_hash = threads.thread_nodes()[&thread_node_hash].message().unwrap();
|
let env_hash = threads.thread_nodes()[&thread_node_hash].message().unwrap();
|
||||||
|
|
||||||
|
let mut other_subjects = IndexSet::new();
|
||||||
let mut from_address_list = Vec::new();
|
let mut from_address_list = Vec::new();
|
||||||
let mut from_address_set: std::collections::HashSet<Vec<u8>> =
|
let mut from_address_set: std::collections::HashSet<Vec<u8>> =
|
||||||
std::collections::HashSet::new();
|
std::collections::HashSet::new();
|
||||||
for envelope in threads
|
for (envelope, show_subject) in threads
|
||||||
.thread_group_iter(thread_hash)
|
.thread_group_iter(thread_hash)
|
||||||
.filter_map(|(_, h)| threads.thread_nodes()[&h].message())
|
.filter_map(|(_, h)| {
|
||||||
.map(|env_hash| {
|
threads.thread_nodes()[&h]
|
||||||
context.accounts[&self.cursor_pos.0]
|
.message()
|
||||||
.collection
|
.map(|env_hash| (env_hash, threads.thread_nodes()[&h].show_subject()))
|
||||||
.get_env(env_hash)
|
})
|
||||||
|
.map(|(env_hash, show_subject)| {
|
||||||
|
(
|
||||||
|
context.accounts[&self.cursor_pos.0]
|
||||||
|
.collection
|
||||||
|
.get_env(env_hash),
|
||||||
|
show_subject,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
|
if show_subject {
|
||||||
|
other_subjects.insert(envelope.subject().to_string());
|
||||||
|
}
|
||||||
for addr in envelope.from().iter() {
|
for addr in envelope.from().iter() {
|
||||||
if from_address_set.contains(addr.address_spec_raw()) {
|
if from_address_set.contains(addr.address_spec_raw()) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -781,6 +825,7 @@ impl ConversationsListing {
|
||||||
context,
|
context,
|
||||||
&from_address_list,
|
&from_address_list,
|
||||||
&threads,
|
&threads,
|
||||||
|
&other_subjects,
|
||||||
thread_hash,
|
thread_hash,
|
||||||
);
|
);
|
||||||
drop(envelope);
|
drop(envelope);
|
||||||
|
|
|
@ -129,6 +129,12 @@ pub struct ListingSettings {
|
||||||
/// Default: "📎"
|
/// Default: "📎"
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub attachment_flag: Option<String>,
|
pub attachment_flag: Option<String>,
|
||||||
|
|
||||||
|
/// Should threads with differentiating Subjects show a list of those subjects on the entry
|
||||||
|
/// title?
|
||||||
|
/// Default: "true"
|
||||||
|
#[serde(default = "true_val")]
|
||||||
|
pub thread_subject_pack: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn default_divider() -> char {
|
const fn default_divider() -> char {
|
||||||
|
@ -158,6 +164,7 @@ impl Default for ListingSettings {
|
||||||
thread_snoozed_flag: None,
|
thread_snoozed_flag: None,
|
||||||
selected_flag: None,
|
selected_flag: None,
|
||||||
attachment_flag: None,
|
attachment_flag: None,
|
||||||
|
thread_subject_pack: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,6 +199,7 @@ impl DotAddressable for ListingSettings {
|
||||||
"thread_snoozed_flag" => self.thread_snoozed_flag.lookup(field, tail),
|
"thread_snoozed_flag" => self.thread_snoozed_flag.lookup(field, tail),
|
||||||
"selected_flag" => self.selected_flag.lookup(field, tail),
|
"selected_flag" => self.selected_flag.lookup(field, tail),
|
||||||
"attachment_flag" => self.attachment_flag.lookup(field, tail),
|
"attachment_flag" => self.attachment_flag.lookup(field, tail),
|
||||||
|
"thread_subject_pack" => self.thread_subject_pack.lookup(field, tail),
|
||||||
other => Err(MeliError::new(format!(
|
other => Err(MeliError::new(format!(
|
||||||
"{} has no field named {}",
|
"{} has no field named {}",
|
||||||
parent_field, other
|
parent_field, other
|
||||||
|
|
|
@ -171,6 +171,11 @@ pub struct ListingSettingsOverride {
|
||||||
#[doc = " Default: \"📎\""]
|
#[doc = " Default: \"📎\""]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub attachment_flag: Option<Option<String>>,
|
pub attachment_flag: Option<Option<String>>,
|
||||||
|
#[doc = " Should threads with differentiating Subjects show a list of those subjects on the entry"]
|
||||||
|
#[doc = " title?"]
|
||||||
|
#[doc = " Default: \"true\""]
|
||||||
|
#[serde(default)]
|
||||||
|
pub thread_subject_pack: Option<bool>,
|
||||||
}
|
}
|
||||||
impl Default for ListingSettingsOverride {
|
impl Default for ListingSettingsOverride {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -191,6 +196,7 @@ impl Default for ListingSettingsOverride {
|
||||||
thread_snoozed_flag: None,
|
thread_snoozed_flag: None,
|
||||||
selected_flag: None,
|
selected_flag: None,
|
||||||
attachment_flag: None,
|
attachment_flag: None,
|
||||||
|
thread_subject_pack: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue