Browse Source

listing/conversations.rs: add `thread_subject_pack` command to pack different inner thread subjects in entry title

137-memory-eating
Manos Pitsidianakis 3 months ago
parent
commit
8c7b001aa5
  1. 1
      CHANGELOG.md
  2. 28
      docs/meli.conf.5
  3. 1
      melib/src/thread.rs
  4. 75
      src/components/mail/listing/conversations.rs
  5. 8
      src/conf/listing.rs
  6. 6
      src/conf/overrides.rs

1
CHANGELOG.md

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### 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`)
- `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

28
docs/meli.conf.5

@ -1059,6 +1059,11 @@ The URL will be given as the first argument of the command.
.El
.Sh LISTING
.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
.Pq Em optional
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.
.\" default value
.Pq Em 90
.It Ic show_menu_scrollbar Ar boolean
.Pq Em optional
Show auto-hiding scrollbar in accounts sidebar menu.
.It Ic unseen_flag Ar Option<String>
Flag to show if thread entry contains unseen mail.
.\" 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
.Ss Examples of sidebar mailbox tree customization
The default values

1
melib/src/thread.rs

@ -834,6 +834,7 @@ impl Threads {
}
}
}
for i in 0..self.thread_nodes[&id].children.len() {
let child_hash = self.thread_nodes[&id].children[i];
if let Some(child_env_hash) = self.thread_nodes[&child_hash].message() {

75
src/components/mail/listing/conversations.rs

@ -22,6 +22,7 @@
use super::*;
use crate::components::PageMovement;
use crate::jobs::JoinHandle;
use indexmap::IndexSet;
use std::iter::FromIterator;
macro_rules! row_attr {
@ -240,6 +241,7 @@ impl MailListingTrait for ConversationsListing {
}
let mut max_entry_columns = 0;
let mut other_subjects = IndexSet::new();
let mut from_address_list = Vec::new();
let mut from_address_set: std::collections::HashSet<Vec<u8>> =
std::collections::HashSet::new();
@ -273,17 +275,30 @@ impl MailListingTrait for ConversationsListing {
panic!();
}
other_subjects.clear();
from_address_list.clear();
from_address_set.clear();
for envelope in threads
for (envelope, show_subject) in threads
.thread_group_iter(thread)
.filter_map(|(_, h)| threads.thread_nodes()[&h].message())
.map(|env_hash| {
context.accounts[&self.cursor_pos.0]
.collection
.get_env(env_hash)
.filter_map(|(_, h)| {
Some((
threads.thread_nodes()[&h].message()?,
threads.thread_nodes()[&h].show_subject(),
))
})
.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() {
if from_address_set.contains(addr.address_spec_raw()) {
continue;
@ -313,6 +328,7 @@ impl MailListingTrait for ConversationsListing {
context,
&from_address_list,
&threads,
&other_subjects,
thread,
);
max_entry_columns = std::cmp::max(
@ -627,8 +643,9 @@ impl ConversationsListing {
&self,
e: &Envelope,
context: &Context,
from: &Vec<Address>,
from: &[Address],
threads: &Threads,
other_subjects: &IndexSet<String>,
hash: ThreadHash,
) -> EntryStrings {
let thread = threads.thread_ref(hash);
@ -669,8 +686,24 @@ impl ConversationsListing {
tags.pop();
}
}
let mut subject = e.subject().to_string();
subject.truncate_at_boundary(150);
let mut subject = if *mailbox_settings!(
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 {
EntryStrings {
date: DateString(ConversationsListing::format_date(context, thread.date())),
@ -755,18 +788,29 @@ impl ConversationsListing {
let idx: usize = self.order[&thread_hash];
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_set: std::collections::HashSet<Vec<u8>> =
std::collections::HashSet::new();
for envelope in threads
for (envelope, show_subject) in threads
.thread_group_iter(thread_hash)
.filter_map(|(_, h)| threads.thread_nodes()[&h].message())
.map(|env_hash| {
context.accounts[&self.cursor_pos.0]
.collection
.get_env(env_hash)
.filter_map(|(_, h)| {
threads.thread_nodes()[&h]
.message()
.map(|env_hash| (env_hash, threads.thread_nodes()[&h].show_subject()))
})
.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() {
if from_address_set.contains(addr.address_spec_raw()) {
continue;
@ -781,6 +825,7 @@ impl ConversationsListing {
context,
&from_address_list,
&threads,
&other_subjects,
thread_hash,
);
drop(envelope);

8
src/conf/listing.rs

@ -129,6 +129,12 @@ pub struct ListingSettings {
/// Default: "πŸ“Ž"
#[serde(default)]
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 {
@ -158,6 +164,7 @@ impl Default for ListingSettings {
thread_snoozed_flag: None,
selected_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),
"selected_flag" => self.selected_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!(
"{} has no field named {}",
parent_field, other

6
src/conf/overrides.rs

@ -171,6 +171,11 @@ pub struct ListingSettingsOverride {
#[doc = " Default: \"πŸ“Ž\""]
#[serde(default)]
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 {
fn default() -> Self {
@ -191,6 +196,7 @@ impl Default for ListingSettingsOverride {
thread_snoozed_flag: None,
selected_flag: None,
attachment_flag: None,
thread_subject_pack: None,
}
}
}

Loading…
Cancel
Save