Browse Source

Preserve Account order from configuration file

Use IndexMap to preserve the order of accounts in the UI from the
account definitions.
tags/alpha-0.6.2
Manos Pitsidianakis 1 year ago
parent
commit
8a6bf3b217
Signed by untrusted user: epilys GPG Key ID: 73627C2F690DF710
  1. 2
      Cargo.lock
  2. 1
      Cargo.toml
  3. 2
      src/bin.rs
  4. 8
      src/command/actions.rs
  5. 15
      src/components/contacts/contact_list.rs
  6. 7
      src/components/mail.rs
  7. 96
      src/components/mail/compose.rs
  8. 80
      src/components/mail/listing.rs
  9. 78
      src/components/mail/listing/compact.rs
  10. 74
      src/components/mail/listing/conversations.rs
  11. 14
      src/components/mail/listing/offline.rs
  12. 68
      src/components/mail/listing/plain.rs
  13. 65
      src/components/mail/listing/thread.rs
  14. 2
      src/components/mail/status.rs
  15. 18
      src/components/mail/view.rs
  16. 6
      src/components/mail/view/envelope.rs
  17. 20
      src/components/mail/view/thread.rs
  18. 10
      src/components/utilities.rs
  19. 45
      src/conf.rs
  20. 42
      src/conf/accounts.rs
  21. 88
      src/state.rs
  22. 8
      src/types.rs

2
Cargo.lock

@ -678,6 +678,7 @@ checksum = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9"
dependencies = [
"autocfg",
"hashbrown",
"serde",
]
[[package]]
@ -902,6 +903,7 @@ dependencies = [
"bitflags",
"crossbeam",
"futures",
"indexmap",
"libc",
"linkify",
"melib",

1
Cargo.toml

@ -37,6 +37,7 @@ serde = "1.0.71"
serde_derive = "1.0.71"
serde_json = "1.0"
toml = { version = "0.5.6", features = ["preserve_order", ] }
indexmap = { version = "^1.5", features = ["serde-1", ] }
linkify = "0.4.0"
xdg-utils = "0.3.0"
notify = "4.0.1" # >:c

2
src/bin.rs

@ -473,7 +473,7 @@ fn run_app(opt: Opt) -> Result<()> {
},
ThreadEvent::JobFinished(id) => {
debug!("Job finished {}", id);
for account in state.context.accounts.iter_mut() {
for account in state.context.accounts.values_mut() {
if account.process_event(&id) {
break;
}

8
src/command/actions.rs

@ -24,7 +24,7 @@
*/
use crate::components::Component;
use melib::backends::MailboxHash;
use melib::backends::{AccountHash, MailboxHash};
pub use melib::thread::{SortField, SortOrder};
use melib::{Draft, EnvelopeHash};
@ -59,10 +59,10 @@ pub enum ListingAction {
#[derive(Debug)]
pub enum TabAction {
New(Option<Box<dyn Component>>),
NewDraft(usize, Option<Draft>),
Reply((usize, MailboxHash), EnvelopeHash), // thread coordinates (account, mailbox) and envelope
NewDraft(AccountHash, Option<Draft>),
Reply((AccountHash, MailboxHash), EnvelopeHash), // thread coordinates (account, mailbox) and envelope
Close,
Edit(usize, EnvelopeHash), // account_position, envelope hash
Edit(AccountHash, EnvelopeHash), // account_position, envelope hash
Kill(Uuid),
}

15
src/components/contacts/contact_list.rs

@ -20,8 +20,9 @@
*/
use super::*;
use crate::melib::text_processing::TextProcessing;
use melib::backends::AccountHash;
use melib::CardId;
use std::cmp;
#[derive(Debug, PartialEq)]
@ -33,6 +34,7 @@ enum ViewMode {
#[derive(Debug)]
struct AccountMenuEntry {
name: String,
hash: AccountHash,
// Index in the config account vector.
index: usize,
}
@ -74,8 +76,9 @@ impl ContactList {
.accounts
.iter()
.enumerate()
.map(|(i, a)| AccountMenuEntry {
.map(|(i, (h, a))| AccountMenuEntry {
name: a.name().to_string(),
hash: *h,
index: i,
})
.collect();
@ -633,15 +636,15 @@ impl Component for ContactList {
&& self.length > 0 =>
{
let account = &context.accounts[self.account_pos];
let account_hash = account.hash();
let book = &account.address_book;
let card = &book[&self.id_positions[self.cursor_pos]];
let mut draft: Draft = Draft::default();
*draft.headers_mut().get_mut("To").unwrap() =
format!("{} <{}>", &card.name(), &card.email());
context.replies.push_back(UIEvent::Action(Tab(NewDraft(
self.account_pos,
Some(draft),
))));
context
.replies
.push_back(UIEvent::Action(Tab(NewDraft(account_hash, Some(draft)))));
return true;
}

7
src/components/mail.rs

@ -22,8 +22,7 @@
/*! Entities that handle Mail specific functions.
*/
use super::*;
use melib::backends::Mailbox;
use melib::backends::MailboxHash;
use melib::backends::{AccountHash, Mailbox, MailboxHash};
use melib::thread::ThreadNodeHash;
pub mod listing;
@ -38,8 +37,8 @@ pub mod pgp;
mod status;
pub use self::status::*;
fn get_display_name(context: &Context, idx: usize) -> String {
let settings = context.accounts[idx].settings.account();
fn get_display_name(context: &Context, account_hash: AccountHash) -> String {
let settings = context.accounts[&account_hash].settings.account();
if let Some(d) = settings.display_name.as_ref() {
format!("{} <{}>", d, settings.identity)
} else {

96
src/components/mail/compose.rs

@ -67,7 +67,7 @@ impl std::ops::DerefMut for EmbedStatus {
pub struct Composer {
reply_context: Option<(MailboxHash, EnvelopeHash)>,
reply_bytes_request: Option<(JobId, JobChannel<Vec<u8>>)>,
account_cursor: usize,
account_hash: AccountHash,
cursor: Cursor,
@ -93,7 +93,7 @@ impl Default for Composer {
Composer {
reply_context: None,
reply_bytes_request: None,
account_cursor: 0,
account_hash: 0,
cursor: Cursor::Headers,
@ -146,14 +146,14 @@ impl fmt::Display for Composer {
impl Composer {
const DESCRIPTION: &'static str = "composing";
pub fn new(account_cursor: usize, context: &Context) -> Self {
pub fn new(account_hash: AccountHash, context: &Context) -> Self {
let mut ret = Composer {
account_cursor,
account_hash,
id: ComponentId::new_v4(),
..Default::default()
};
for (h, v) in
mailbox_acc_settings!(context[account_cursor].composing.default_header_values).iter()
mailbox_acc_settings!(context[account_hash].composing.default_header_values).iter()
{
if v.is_empty() {
continue;
@ -176,23 +176,23 @@ impl Composer {
ret
}
pub fn edit(account_pos: usize, h: EnvelopeHash, context: &Context) -> Result<Self> {
pub fn edit(new_account_hash: AccountHash, h: EnvelopeHash, context: &Context) -> Result<Self> {
let mut ret = Composer::default();
let op = context.accounts[account_pos].operation(h)?;
let envelope: EnvelopeRef = context.accounts[account_pos].collection.get_env(h);
let op = context.accounts[&new_account_hash].operation(h)?;
let envelope: EnvelopeRef = context.accounts[&new_account_hash].collection.get_env(h);
ret.draft = Draft::edit(&envelope, op)?;
ret.account_cursor = account_pos;
ret.account_hash = new_account_hash;
Ok(ret)
}
pub fn with_context(
coordinates: (usize, MailboxHash),
coordinates: (AccountHash, MailboxHash),
msg: EnvelopeHash,
context: &mut Context,
) -> Self {
let account = &context.accounts[coordinates.0];
let account = &context.accounts[&coordinates.0];
let mut ret = Composer::default();
ret.pager
.set_colors(crate::conf::value(context, "theme_default"));
@ -245,7 +245,7 @@ impl Composer {
);
drop(parent_message);
match context.accounts[coordinates.0]
match context.accounts[&coordinates.0]
.operation(msg)
.and_then(|mut op| op.as_bytes())
{
@ -257,10 +257,10 @@ impl Composer {
));
}
Ok(fut) => {
let (mut rcvr, handle, job_id) = context.accounts[coordinates.0]
let (mut rcvr, handle, job_id) = context.accounts[&coordinates.0]
.job_executor
.spawn_specialized(fut);
context.accounts[coordinates.0]
context.accounts[&coordinates.0]
.active_jobs
.insert(job_id, JobRequest::AsBytes(handle));
if let Ok(Some(parent_bytes)) = try_recv_timeout!(&mut rcvr) {
@ -274,8 +274,9 @@ impl Composer {
}
Ok(parent_bytes) => {
let env_hash = msg;
let parent_message =
context.accounts[coordinates.0].collection.get_env(env_hash);
let parent_message = context.accounts[&coordinates.0]
.collection
.get_env(env_hash);
let mut new_draft = Draft::new_reply(&parent_message, &parent_bytes);
new_draft
.headers_mut()
@ -291,7 +292,7 @@ impl Composer {
}
}
}
ret.account_cursor = coordinates.0;
ret.account_hash = coordinates.0;
ret.reply_context = Some((coordinates.1, msg));
ret
}
@ -317,14 +318,14 @@ impl Composer {
self.form.hide_buttons();
self.form.set_cursor(old_cursor);
let headers = self.draft.headers();
let account_cursor = self.account_cursor;
let account_hash = self.account_hash;
for &k in &["Date", "From", "To", "Cc", "Bcc", "Subject"] {
if k == "To" || k == "Cc" || k == "Bcc" {
self.form.push_cl((
k.into(),
headers[k].to_string(),
Box::new(move |c, term| {
let book: &AddressBook = &c.accounts[account_cursor].address_book;
let book: &AddressBook = &c.accounts[&account_hash].address_book;
let results: Vec<String> = book.search(term);
results
.into_iter()
@ -346,7 +347,7 @@ impl Composer {
write_string_to_grid(
&format!(
"โ˜‘ sign with {}",
mailbox_acc_settings!(context[self.account_cursor].pgp.key)
mailbox_acc_settings!(context[self.account_hash].pgp.key)
.as_ref()
.map(|s| s.as_str())
.unwrap_or("default key")
@ -438,14 +439,14 @@ impl Component for Composer {
if !self.initialized {
if self.sign_mail.is_unset() {
self.sign_mail = ToggleFlag::InternalVal(*mailbox_acc_settings!(
context[self.account_cursor].pgp.auto_sign
context[self.account_hash].pgp.auto_sign
));
}
if !self.draft.headers().contains_key("From") || self.draft.headers()["From"].is_empty()
{
self.draft.headers_mut().insert(
"From".into(),
crate::components::mail::get_display_name(context, self.account_cursor),
crate::components::mail::get_display_name(context, self.account_hash),
);
}
self.pager.update_from_str(self.draft.body(), Some(77));
@ -644,7 +645,7 @@ impl Component for Composer {
match bytes {
Ok(parent_bytes) => {
let env_hash = self.reply_context.unwrap().1;
let parent_message = context.accounts[self.account_cursor]
let parent_message = context.accounts[&self.account_hash]
.collection
.get_env(env_hash);
let mut new_draft = Draft::new_reply(&parent_message, &parent_bytes);
@ -681,7 +682,7 @@ impl Component for Composer {
match send_draft(
self.sign_mail,
context,
self.account_cursor,
self.account_hash,
self.draft.clone(),
SpecialUsageMailbox::Sent,
Flag::SEEN,
@ -726,7 +727,7 @@ impl Component for Composer {
context,
SpecialUsageMailbox::Drafts,
Flag::SEEN | Flag::DRAFT,
self.account_cursor,
self.account_hash,
);
self.mode = ViewMode::Edit;
}
@ -774,7 +775,7 @@ impl Component for Composer {
context,
SpecialUsageMailbox::Drafts,
Flag::SEEN | Flag::DRAFT,
self.account_cursor,
self.account_hash,
);
context.replies.push_back(UIEvent::Action(Tab(Kill(*u))));
return true;
@ -808,7 +809,7 @@ impl Component for Composer {
if let ViewMode::WaitingForSendResult(_, handle, job_id, chan) =
std::mem::replace(&mut self.mode, ViewMode::Edit)
{
context.accounts[self.account_cursor].active_jobs.insert(
context.accounts[&self.account_hash].active_jobs.insert(
job_id,
JobRequest::SendMessageBackground(handle, chan),
);
@ -863,10 +864,9 @@ impl Component for Composer {
/*
/* Switch e-mail From: field to the `left` configured account. */
UIEvent::Input(Key::Left) if self.cursor == Cursor::From => {
self.account_cursor = self.account_cursor.saturating_sub(1);
self.draft.headers_mut().insert(
"From".into(),
get_display_name(context, self.account_cursor),
get_display_name(context, self.account_hash),
);
self.dirty = true;
return true;
@ -1039,7 +1039,7 @@ impl Component for Composer {
{
/* Edit draft in $EDITOR */
let editor = if let Some(editor_command) =
mailbox_acc_settings!(context[self.account_cursor].composing.editor_command)
mailbox_acc_settings!(context[self.account_hash].composing.editor_command)
.as_ref()
{
editor_command.to_string()
@ -1065,7 +1065,7 @@ impl Component for Composer {
true,
);
if *mailbox_acc_settings!(context[self.account_cursor].composing.embed) {
if *mailbox_acc_settings!(context[self.account_hash].composing.embed) {
self.embed = Some(EmbedStatus::Running(
crate::terminal::embed::create_pty(
width!(self.embed_area),
@ -1249,7 +1249,7 @@ impl Component for Composer {
context,
SpecialUsageMailbox::Drafts,
Flag::SEEN | Flag::DRAFT,
self.account_cursor,
self.account_hash,
);
return true;
}
@ -1319,7 +1319,7 @@ impl Component for Composer {
};
let our_map: ShortcutMap =
mailbox_acc_settings!(context[self.account_cursor].shortcuts.composing).key_values();
mailbox_acc_settings!(context[self.account_hash].shortcuts.composing).key_values();
map.insert(Composer::DESCRIPTION, our_map);
map
@ -1366,13 +1366,13 @@ impl Component for Composer {
pub fn send_draft(
sign_mail: ToggleFlag,
context: &mut Context,
account_cursor: usize,
account_hash: AccountHash,
mut draft: Draft,
mailbox_type: SpecialUsageMailbox,
flags: Flag,
complete_in_background: bool,
) -> Result<Option<(JobId, JoinHandle, JobChannel<()>)>> {
let format_flowed = *mailbox_acc_settings!(context[account_cursor].composing.format_flowed);
let format_flowed = *mailbox_acc_settings!(context[account_hash].composing.format_flowed);
if sign_mail.is_true() {
let mut content_type = ContentType::default();
if format_flowed {
@ -1407,10 +1407,10 @@ pub fn send_draft(
}
let output = crate::components::mail::pgp::sign(
body.into(),
mailbox_acc_settings!(context[account_cursor].pgp.gpg_binary)
mailbox_acc_settings!(context[account_hash].pgp.gpg_binary)
.as_ref()
.map(|s| s.as_str()),
mailbox_acc_settings!(context[account_cursor].pgp.key)
mailbox_acc_settings!(context[account_hash].pgp.key)
.as_ref()
.map(|s| s.as_str()),
);
@ -1420,7 +1420,7 @@ pub fn send_draft(
log(
format!(
"Could not sign draft in account `{}`: {}.",
context.accounts[account_cursor].name(),
context.accounts[&account_hash].name(),
err.to_string()
),
ERROR,
@ -1428,7 +1428,7 @@ pub fn send_draft(
context.replies.push_back(UIEvent::Notification(
Some(format!(
"Could not sign draft in account `{}`.",
context.accounts[account_cursor].name()
context.accounts[&account_hash].name()
)),
err.to_string(),
Some(NotificationType::ERROR),
@ -1459,16 +1459,10 @@ pub fn send_draft(
}
}
let bytes = draft.finalise().unwrap();
let send_mail = mailbox_acc_settings!(context[account_cursor].composing.send_mail).clone();
let send_mail = mailbox_acc_settings!(context[account_hash].composing.send_mail).clone();
let ret =
context.accounts[account_cursor].send(bytes.clone(), send_mail, complete_in_background);
save_draft(
bytes.as_bytes(),
context,
mailbox_type,
flags,
account_cursor,
);
context.accounts[&account_hash].send(bytes.clone(), send_mail, complete_in_background);
save_draft(bytes.as_bytes(), context, mailbox_type, flags, account_hash);
ret
}
@ -1477,9 +1471,9 @@ pub fn save_draft(
context: &mut Context,
mailbox_type: SpecialUsageMailbox,
flags: Flag,
account_cursor: usize,
account_hash: AccountHash,
) {
match context.accounts[account_cursor].save_special(bytes, mailbox_type, flags) {
match context.accounts[&account_hash].save_special(bytes, mailbox_type, flags) {
Err(MeliError {
summary, details, ..
}) => {
@ -1494,7 +1488,7 @@ pub fn save_draft(
Some("Message saved".into()),
format!(
"Message saved in `{}`",
&context.accounts[account_cursor].mailbox_entries[&mailbox_hash].name
&context.accounts[&account_hash].mailbox_entries[&mailbox_hash].name
),
Some(NotificationType::INFO),
));

80
src/components/mail/listing.rs

@ -134,7 +134,7 @@ column_str!(struct TagString(String, SmallVec<[Option<Color>; 8]>));
#[derive(Debug)]
struct AccountMenuEntry {
name: String,
// Index in the config account vector.
hash: AccountHash,
index: usize,
entries: SmallVec<[(usize, MailboxHash); 16]>,
}
@ -146,8 +146,8 @@ pub trait MailListingTrait: ListingTrait {
thread_hashes: SmallVec<[ThreadHash; 8]>,
a: &ListingAction,
) {
let account_pos = self.coordinates().0;
let account = &mut context.accounts[account_pos];
let account_hash = self.coordinates().0;
let account = &mut context.accounts[&account_hash];
let mut envs_to_set: SmallVec<[EnvelopeHash; 8]> = SmallVec::new();
let mailbox_hash = self.coordinates().1;
{
@ -361,8 +361,8 @@ pub trait MailListingTrait: ListingTrait {
}
pub trait ListingTrait: Component {
fn coordinates(&self) -> (usize, MailboxHash);
fn set_coordinates(&mut self, _: (usize, MailboxHash));
fn coordinates(&self) -> (AccountHash, MailboxHash);
fn set_coordinates(&mut self, _: (AccountHash, MailboxHash));
fn draw_list(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context);
fn highlight_line(&mut self, grid: &mut CellBuffer, area: Area, idx: usize, context: &Context);
fn filter(
@ -482,10 +482,6 @@ impl fmt::Display for Listing {
impl Component for Listing {
fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
for i in 0..context.accounts.len() {
let _ = context.is_online(i);
}
if !self.is_dirty() {
return;
}
@ -524,12 +520,13 @@ impl Component for Listing {
.push_back(((mid, get_y(upper_left)), (mid, get_y(bottom_right))));
}
let account_hash = self.accounts[self.cursor_pos.0].hash;
if right_component_width == total_cols {
if context.is_online(self.cursor_pos.0).is_err() {
if context.is_online(account_hash).is_err() {
match self.component {
ListingComponent::Offline(_) => {}
_ => {
self.component = Offline(OfflineListing::new((self.cursor_pos.0, 0)));
self.component = Offline(OfflineListing::new((account_hash, 0)));
}
}
}
@ -539,11 +536,11 @@ impl Component for Listing {
self.draw_menu(grid, area, context);
} else {
self.draw_menu(grid, (upper_left, (mid, get_y(bottom_right))), context);
if context.is_online(self.cursor_pos.0).is_err() {
if context.is_online(account_hash).is_err() {
match self.component {
ListingComponent::Offline(_) => {}
_ => {
self.component = Offline(OfflineListing::new((self.cursor_pos.0, 0)));
self.component = Offline(OfflineListing::new((account_hash, 0)));
}
}
}
@ -571,15 +568,19 @@ impl Component for Listing {
);
}
}
UIEvent::AccountStatusChange(account_index) => {
if self.cursor_pos.0 == *account_index {
UIEvent::AccountStatusChange(account_hash) => {
let account_index = context
.accounts
.get_index_of(account_hash)
.expect("Invalid account_hash in UIEventMailbox{Delete,Create}");
if self.cursor_pos.0 == account_index {
self.change_account(context);
} else {
self.accounts[*account_index].entries = context.accounts[*account_index]
self.accounts[account_index].entries = context.accounts[&*account_hash]
.list_mailboxes()
.into_iter()
.filter(|mailbox_node| {
context.accounts[*account_index][&mailbox_node.hash]
context.accounts[&*account_hash][&mailbox_node.hash]
.ref_mailbox
.is_subscribed()
})
@ -589,25 +590,29 @@ impl Component for Listing {
}
return true;
}
UIEvent::MailboxDelete((account_index, _mailbox_hash))
| UIEvent::MailboxCreate((account_index, _mailbox_hash)) => {
self.accounts[*account_index].entries = context.accounts[*account_index]
UIEvent::MailboxDelete((account_hash, _mailbox_hash))
| UIEvent::MailboxCreate((account_hash, _mailbox_hash)) => {
let account_index = context
.accounts
.get_index_of(account_hash)
.expect("Invalid account_hash in UIEventMailbox{Delete,Create}");
self.accounts[account_index].entries = context.accounts[&*account_hash]
.list_mailboxes()
.into_iter()
.filter(|mailbox_node| {
context.accounts[*account_index][&mailbox_node.hash]
context.accounts[&*account_hash][&mailbox_node.hash]
.ref_mailbox
.is_subscribed()
})
.map(|f| (f.depth, f.hash))
.collect::<_>();
if self.cursor_pos.0 == *account_index {
if self.cursor_pos.0 == account_index {
self.cursor_pos.1 = std::cmp::min(
self.accounts[self.cursor_pos.0].entries.len() - 1,
self.cursor_pos.1,
);
self.component.set_coordinates((
self.cursor_pos.0,
self.accounts[self.cursor_pos.0].hash,
self.accounts[self.cursor_pos.0].entries[self.cursor_pos.1].1,
));
self.component.refresh_mailbox(context, true);
@ -759,9 +764,10 @@ impl Component for Listing {
if let Some((_, mailbox_hash)) =
self.accounts[self.cursor_pos.0].entries.get(*idx)
{
let account_hash = self.accounts[self.cursor_pos.0].hash;
self.cursor_pos.1 = *idx;
self.component
.set_coordinates((self.cursor_pos.0, *mailbox_hash));
.set_coordinates((account_hash, *mailbox_hash));
self.set_dirty(true);
} else {
return true;
@ -1092,9 +1098,10 @@ impl Component for Listing {
UIEvent::Input(ref k)
if shortcut!(k == shortcuts[Listing::DESCRIPTION]["new_mail"]) =>
{
let account_hash = context.accounts[self.cursor_pos.0].hash();
context
.replies
.push_back(UIEvent::Action(Tab(NewDraft(self.cursor_pos.0, None))));
.push_back(UIEvent::Action(Tab(NewDraft(account_hash, None))));
return true;
}
UIEvent::StartupCheck(_) => {
@ -1190,17 +1197,6 @@ impl Component for Listing {
}
}
impl From<(IndexStyle, (usize, MailboxHash))> for ListingComponent {
fn from((index_style, coordinates): (IndexStyle, (usize, MailboxHash))) -> Self {
match index_style {
IndexStyle::Plain => Plain(PlainListing::new(coordinates)),
IndexStyle::Threaded => Threaded(ThreadListing::new(coordinates)),
IndexStyle::Compact => Compact(CompactListing::new(coordinates)),
IndexStyle::Conversations => Conversations(ConversationsListing::new(coordinates)),
}
}
}
impl Listing {
pub const DESCRIPTION: &'static str = "listing";
pub fn new(context: &mut Context) -> Self {
@ -1208,7 +1204,7 @@ impl Listing {
.accounts
.iter()
.enumerate()
.map(|(i, a)| {
.map(|(i, (h, a))| {
let entries: SmallVec<[(usize, MailboxHash); 16]> = a
.list_mailboxes()
.into_iter()
@ -1218,13 +1214,14 @@ impl Listing {
AccountMenuEntry {
name: a.name().to_string(),
hash: *h,
index: i,
entries,
}
})
.collect();
let mut ret = Listing {
component: Offline(OfflineListing::new((0, 0))),
component: Offline(OfflineListing::new((account_entries[0].hash, 0))),
accounts: account_entries,
visible: true,
dirty: true,
@ -1477,6 +1474,7 @@ impl Listing {
}
fn change_account(&mut self, context: &mut Context) {
let account_hash = context.accounts[self.cursor_pos.0].hash();
self.accounts[self.cursor_pos.0].entries = context.accounts[self.cursor_pos.0]
.list_mailboxes()
.into_iter()
@ -1493,15 +1491,15 @@ impl Listing {
.get(self.cursor_pos.1)
{
self.component
.set_coordinates((self.cursor_pos.0, *mailbox_hash));
.set_coordinates((account_hash, *mailbox_hash));
/* Check if per-mailbox configuration overrides general configuration */
let index_style =
mailbox_settings!(context[self.cursor_pos.0][mailbox_hash].listing.index_style);
mailbox_settings!(context[account_hash][mailbox_hash].listing.index_style);
self.component.set_style(*index_style);
} else {
/* Set to dummy */
self.component = Offline(OfflineListing::new((self.cursor_pos.0, 0)));
self.component = Offline(OfflineListing::new((account_hash, 0)));
}
self.set_dirty(true);
context

78
src/components/mail/listing/compact.rs

@ -124,8 +124,8 @@ macro_rules! row_attr {
#[derive(Debug)]
pub struct CompactListing {
/// (x, y, z): x is accounts, y is mailboxes, z is index inside a mailbox.
cursor_pos: (usize, MailboxHash, usize),
new_cursor_pos: (usize, MailboxHash, usize),
cursor_pos: (AccountHash, MailboxHash, usize),
new_cursor_pos: (AccountHash, MailboxHash, usize),
length: usize,
sort: (SortField, SortOrder),
subsort: (SortField, SortOrder),
@ -231,7 +231,7 @@ impl MailListingTrait for CompactListing {
// Get mailbox as a reference.
//
match context.accounts[self.cursor_pos.0].load(self.cursor_pos.1) {
match context.accounts[&self.cursor_pos.0].load(self.cursor_pos.1) {
Ok(()) => {}
Err(_) => {
let default_cell = {
@ -242,7 +242,7 @@ impl MailListingTrait for CompactListing {
ret
};
let message: String =
context.accounts[self.cursor_pos.0][&self.cursor_pos.1].status();
context.accounts[&self.cursor_pos.0][&self.cursor_pos.1].status();
self.data_columns.columns[0] =
CellBuffer::new_with_context(message.len(), 1, default_cell, context);
self.length = 0;
@ -259,14 +259,14 @@ impl MailListingTrait for CompactListing {
}
}
let threads = context.accounts[self.cursor_pos.0]
let threads = context.accounts[&self.cursor_pos.0]
.collection
.get_threads(self.cursor_pos.1);
let mut roots = threads.roots();
threads.group_inner_sort_by(
&mut roots,
self.sort,
&context.accounts[self.cursor_pos.0].collection.envelopes,
&context.accounts[&self.cursor_pos.0].collection.envelopes,
);
self.redraw_threads_list(
@ -288,7 +288,7 @@ impl MailListingTrait for CompactListing {
context: &Context,
items: Box<dyn Iterator<Item = ThreadHash>>,
) {
let account = &context.accounts[self.cursor_pos.0];
let account = &context.accounts[&self.cursor_pos.0];
let threads = account.collection.get_threads(self.cursor_pos.1);
self.order.clear();
@ -328,18 +328,18 @@ impl MailListingTrait for CompactListing {
} else {
continue 'items_for_loop;
};
if !context.accounts[self.cursor_pos.0].contains_key(root_env_hash) {
if !context.accounts[&self.cursor_pos.0].contains_key(root_env_hash) {
debug!("key = {}", root_env_hash);
debug!(
"name = {} {}",
account[&self.cursor_pos.1].name(),
context.accounts[self.cursor_pos.0].name()
context.accounts[&self.cursor_pos.0].name()
);
debug!("{:#?}", context.accounts);
panic!();
}
let root_envelope: EnvelopeRef = context.accounts[self.cursor_pos.0]
let root_envelope: EnvelopeRef = context.accounts[&self.cursor_pos.0]
.collection
.get_env(root_env_hash);
use melib::search::QueryTrait;
@ -455,11 +455,11 @@ impl MailListingTrait for CompactListing {
}
impl ListingTrait for CompactListing {
fn coordinates(&self) -> (usize, MailboxHash) {
fn coordinates(&self) -> (AccountHash, MailboxHash) {
(self.new_cursor_pos.0, self.new_cursor_pos.1)
}
fn set_coordinates(&mut self, coordinates: (usize, MailboxHash)) {
fn set_coordinates(&mut self, coordinates: (AccountHash, MailboxHash)) {
self.new_cursor_pos = (coordinates.0, coordinates.1, 0);
self.unfocused = false;
self.view = ThreadView::default();
@ -475,7 +475,7 @@ impl ListingTrait for CompactListing {
}
let thread_hash = self.get_thread_under_cursor(idx);
let account = &context.accounts[self.cursor_pos.0];
let account = &context.accounts[&self.cursor_pos.0];
let threads = account.collection.get_threads(self.cursor_pos.1);
let thread = threads.thread_ref(thread_hash);
@ -698,7 +698,7 @@ impl ListingTrait for CompactListing {
}
}
let account = &context.accounts[self.cursor_pos.0];
let account = &context.accounts[&self.cursor_pos.0];
let threads = account.collection.get_threads(self.cursor_pos.1);
for r in 0..cmp::min(self.length - top_idx, rows) {
let thread_hash = self.get_thread_under_cursor(r + top_idx);
@ -778,7 +778,7 @@ impl ListingTrait for CompactListing {
self.filter_term = filter_term;
self.row_updates.clear();
let account = &context.accounts[self.cursor_pos.0];
let account = &context.accounts[&self.cursor_pos.0];
match results {
Ok(results) => {
let threads = account.collection.get_threads(self.cursor_pos.1);
@ -805,7 +805,7 @@ impl ListingTrait for CompactListing {
threads.group_inner_sort_by(
&mut self.filtered_selection,
self.sort,
&context.accounts[self.cursor_pos.0].collection.envelopes,
&context.accounts[&self.cursor_pos.0].collection.envelopes,
);
self.new_cursor_pos.2 =
std::cmp::min(self.filtered_selection.len() - 1, self.cursor_pos.2);
@ -873,9 +873,9 @@ impl fmt::Display for CompactListing {
impl CompactListing {
pub const DESCRIPTION: &'static str = "compact listing";
pub fn new(coordinates: (usize, MailboxHash)) -> Self {
pub fn new(coordinates: (AccountHash, MailboxHash)) -> Self {
CompactListing {
cursor_pos: (0, 1, 0),
cursor_pos: (coordinates.0, 1, 0),
new_cursor_pos: (coordinates.0, coordinates.1, 0),
length: 0,
sort: (Default::default(), Default::default()),
@ -911,7 +911,7 @@ impl CompactListing {
let thread = threads.thread_ref(hash);
let mut tags = String::new();
let mut colors: SmallVec<[_; 8]> = SmallVec::new();
let backend_lck = context.accounts[self.cursor_pos.0].backend.read().unwrap();
let backend_lck = context.accounts[&self.cursor_pos.0].backend.read().unwrap();
if let Some(t) = backend_lck.tags() {
let tags_lck = t.read().unwrap();
for t in e.labels().iter() {
@ -984,7 +984,7 @@ impl CompactListing {
}
fn update_line(&mut self, context: &Context, thread_hash: ThreadHash) {
let account = &context.accounts[self.cursor_pos.0];
let account = &context.accounts[&self.cursor_pos.0];
let threads = account.collection.get_threads(self.cursor_pos.1);
let thread = threads.thread_ref(thread_hash);
let thread_node_hash = threads.thread_group_iter(thread_hash).next().unwrap().1;
@ -1144,7 +1144,7 @@ impl CompactListing {
self.data_columns.columns[3].size().0,
self.data_columns.columns[4].size().0,
);
let account = &context.accounts[self.cursor_pos.0];
let account = &context.accounts[&self.cursor_pos.0];
let threads = account.collection.get_threads(self.cursor_pos.1);
@ -1152,12 +1152,12 @@ impl CompactListing {
self.rows.iter().skip(start).take(end - start + 1)
{
let idx = *idx;
if !context.accounts[self.cursor_pos.0].contains_key(*root_env_hash) {
if !context.accounts[&self.cursor_pos.0].contains_key(*root_env_hash) {
//debug!("key = {}", root_env_hash);
//debug!(
// "name = {} {}",
// account[&self.cursor_pos.1].name(),
// context.accounts[self.cursor_pos.0].name()
// context.accounts[&self.cursor_pos.0].name()
//);
//debug!("{:#?}", context.accounts);
@ -1316,7 +1316,7 @@ impl CompactListing {
results: Result<SmallVec<[EnvelopeHash; 512]>>,
context: &mut Context,
) {
let account = &context.accounts[self.cursor_pos.0];
let account = &context.accounts[&self.cursor_pos.0];
match results {
Ok(results) => {
let threads = account.collection.get_threads(self.cursor_pos.1);
@ -1500,7 +1500,7 @@ impl Component for CompactListing {
}
Action::ToggleThreadSnooze if !self.unfocused => {
let thread = self.get_thread_under_cursor(self.cursor_pos.2);
let account = &mut context.accounts[self.cursor_pos.0];
let account = &mut context.accounts[&self.cursor_pos.0];
account
.collection
.threads
@ -1534,7 +1534,7 @@ impl Component for CompactListing {
self.set_dirty(true);
}
UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => {
let account = &context.accounts[self.cursor_pos.0];
let account = &context.accounts[&self.cursor_pos.0];
let threads = account.collection.get_threads(self.cursor_pos.1);
if !account.collection.contains_key(&new_hash) {
return false;
@ -1552,8 +1552,10 @@ impl Component for CompactListing {
self.dirty = true;
self.view
.process_event(&mut UIEvent::EnvelopeRename(*old_hash, *new_hash), context);
if self.unfocused {
self.view
.process_event(&mut UIEvent::EnvelopeRename(*old_hash, *new_hash), context);
}
}
UIEvent::EnvelopeRemove(ref _env_hash, ref thread_hash) => {
if self.order.contains_key(thread_hash) {
@ -1562,7 +1564,7 @@ impl Component for CompactListing {
}
}
UIEvent::EnvelopeUpdate(ref env_hash) => {
let account = &context.accounts[self.cursor_pos.0];
let account = &context.accounts[&self.cursor_pos.0];
let threads = account.collection.get_threads(self.cursor_pos.1);
if !account.collection.contains_key(&env_hash) {
return false;
@ -1580,8 +1582,10 @@ impl Component for CompactListing {
self.dirty = true;
self.view
.process_event(&mut UIEvent::EnvelopeUpdate(*env_hash), context);
if self.unfocused {
self.view
.process_event(&mut UIEvent::EnvelopeUpdate(*env_hash), context);
}
}
UIEvent::ChangeMode(UIMode::Normal) => {
self.dirty = true;
@ -1606,16 +1610,16 @@ impl Component for CompactListing {
return true;
}
UIEvent::Action(Action::Listing(Search(ref filter_term))) if !self.unfocused => {
match context.accounts[self.cursor_pos.0].search(
match context.accounts[&self.cursor_pos.0].search(
filter_term,
self.sort,
self.cursor_pos.1,
) {
Ok(job) => {
let (chan, handle, job_id) = context.accounts[self.cursor_pos.0]
let (chan, handle, job_id) = context.accounts[&self.cursor_pos.0]
.job_executor
.spawn_specialized(job);
context.accounts[self.cursor_pos.0]
context.accounts[&self.cursor_pos.0]
.active_jobs
.insert(job_id, crate::conf::accounts::JobRequest::Search(handle));
self.search_job = Some((filter_term.to_string(), chan, job_id));
@ -1631,19 +1635,19 @@ impl Component for CompactListing {
self.set_dirty(true);
}
UIEvent::Action(Action::Listing(Select(ref search_term))) if !self.unfocused => {
match context.accounts[self.cursor_pos.0].search(
match context.accounts[&self.cursor_pos.0].search(
search_term,
self.sort,
self.cursor_pos.1,
) {
Ok(job) => {
let (mut chan, handle, job_id) = context.accounts[self.cursor_pos.0]
let (mut chan, handle, job_id) = context.accounts[&self.cursor_pos.0]
.job_executor
.spawn_specialized(job);
if let Ok(Some(search_result)) = try_recv_timeout!(&mut chan) {
self.select(search_term, search_result, context);
} else {
context.accounts[self.cursor_pos.0]
context.accounts[&self.cursor_pos.0]
.active_jobs
.insert(job_id, crate::conf::accounts::JobRequest::Search(handle));
self.select_job = Some((search_term.to_string(), chan, job_id));

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

@ -94,8 +94,8 @@ macro_rules! row_attr {
#[derive(Debug)]
pub struct ConversationsListing {
/// (x, y, z): x is accounts, y is mailboxes, z is index inside a mailbox.
cursor_pos: (usize, MailboxHash, usize),
new_cursor_pos: (usize, MailboxHash, usize),
cursor_pos: (AccountHash, MailboxHash, usize),
new_cursor_pos: (AccountHash, MailboxHash, usize),
length: usize,
sort: (SortField, SortOrder),
subsort: (SortField, SortOrder),
@ -194,7 +194,7 @@ impl MailListingTrait for ConversationsListing {
}
// Get mailbox as a reference.
//
match context.accounts[self.cursor_pos.0].load(self.cursor_pos.1) {
match context.accounts[&self.cursor_pos.0].load(self.cursor_pos.1) {
Ok(()) => {}
Err(_) => {
let default_cell = {
@ -205,7 +205,7 @@ impl MailListingTrait for ConversationsListing {
ret
};
let message: String =
context.accounts[self.cursor_pos.0][&self.cursor_pos.1].status();
context.accounts[&self.cursor_pos.0][&self.cursor_pos.1].status();
self.content =
CellBuffer::new_with_context(message.len(), 1, default_cell, context);
self.length = 0;
@ -222,7 +222,7 @@ impl MailListingTrait for ConversationsListing {
}
}
let threads = context.accounts[self.cursor_pos.0]
let threads = context.accounts[&self.cursor_pos.0]
.collection
.get_threads(self.cursor_pos.1);
self.all_threads.clear();
@ -230,7 +230,7 @@ impl MailListingTrait for ConversationsListing {
threads.group_inner_sort_by(
&mut roots,
self.sort,
&context.accounts[self.cursor_pos.0].collection.envelopes,
&context.accounts[&self.cursor_pos.0].collection.envelopes,
);
self.redraw_threads_list(
@ -253,7 +253,7 @@ impl MailListingTrait for ConversationsListing {
context: &Context,
items: Box<dyn Iterator<Item = ThreadHash>>,
) {
let account = &context.accounts[self.cursor_pos.0];
let account = &context.accounts[&self.cursor_pos.0];
let threads = account.collection.get_threads(self.cursor_pos.1);
self.order.clear();
@ -284,12 +284,12 @@ impl MailListingTrait for ConversationsListing {
} else {
continue 'items_for_loop;
};
if !context.accounts[self.cursor_pos.0].contains_key(root_env_hash) {
if !context.accounts[&self.cursor_pos.0].contains_key(root_env_hash) {
debug!("key = {}", root_env_hash);
debug!(
"name = {} {}",
account[&self.cursor_pos.1].name(),
context.accounts[self.cursor_pos.0].name()
context.accounts[&self.cursor_pos.0].name()
);
debug!("{:#?}", context.accounts);
@ -300,7 +300,7 @@ impl MailListingTrait for ConversationsListing {
for (_, h) in threads.thread_group_iter(thread) {
let env_hash = threads.thread_nodes()[&h].message().unwrap();
let envelope: &EnvelopeRef = &context.accounts[self.cursor_pos.0]
let envelope: &EnvelopeRef = &context.accounts[&self.cursor_pos.0]
.collection
.get_env(env_hash);
for addr in envelope.from().iter() {
@ -311,7 +311,7 @@ impl MailListingTrait for ConversationsListing {
from_address_list.push(addr.clone());
}
}
let root_envelope: &EnvelopeRef = &context.accounts[self.cursor_pos.0]
let root_envelope: &EnvelopeRef = &context.accounts[&self.cursor_pos.0]
.collection
.get_env(root_env_hash);
use melib::search::QueryTrait;
@ -361,7 +361,7 @@ impl MailListingTrait for ConversationsListing {
let padding_fg = self.color_cache.padding.fg;
for ((idx, (thread, root_env_hash)), strings) in rows {
if !context.accounts[self.cursor_pos.0].contains_key(root_env_hash) {
if !context.accounts[&self.cursor_pos.0].contains_key(root_env_hash) {
panic!();
}
let thread = threads.thread_ref(thread);
@ -487,11 +487,11 @@ impl MailListingTrait for ConversationsListing {
}
impl ListingTrait for ConversationsListing {
fn coordinates(&self) -> (usize, MailboxHash) {
fn coordinates(&self) -> (AccountHash, MailboxHash) {
(self.new_cursor_pos.0, self.new_cursor_pos.1)
}
fn set_coordinates(&mut self, coordinates: (usize, MailboxHash)) {
fn set_coordinates(&mut self, coordinates: (AccountHash, MailboxHash)) {
self.new_cursor_pos = (coordinates.0, coordinates.1, 0);
self.new_cursor_pos = (coordinates.0, coordinates.1, 0);
self.unfocused = false;
@ -508,7 +508,7 @@ impl ListingTrait for ConversationsListing {
}
let thread_hash = self.get_thread_under_cursor(idx);
let account = &context.accounts[self.cursor_pos.0];
let account = &context.accounts[&self.cursor_pos.0];
let threads = account.collection.get_threads(self.cursor_pos.1);
let thread = threads.thread_ref(thread_hash);
@ -769,7 +769,7 @@ impl ListingTrait for ConversationsListing {
*v = false;
}
let account = &context.accounts[self.cursor_pos.0];
let account = &context.accounts[&self.cursor_pos.0];