diff --git a/Cargo.lock b/Cargo.lock index d9ae7b313..8401d4940 100644 --- a/Cargo.lock +++ b/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", diff --git a/Cargo.toml b/Cargo.toml index 7f12c6e9f..f3864d7fb 100644 --- a/Cargo.toml +++ b/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 diff --git a/src/bin.rs b/src/bin.rs index aa0878ffb..d511f634e 100644 --- a/src/bin.rs +++ b/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; } diff --git a/src/command/actions.rs b/src/command/actions.rs index 13d128a91..7e9dde583 100644 --- a/src/command/actions.rs +++ b/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>), - NewDraft(usize, Option), - Reply((usize, MailboxHash), EnvelopeHash), // thread coordinates (account, mailbox) and envelope + NewDraft(AccountHash, Option), + 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), } diff --git a/src/components/contacts/contact_list.rs b/src/components/contacts/contact_list.rs index ab745e0f0..ce5e41a8b 100644 --- a/src/components/contacts/contact_list.rs +++ b/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; } diff --git a/src/components/mail.rs b/src/components/mail.rs index f0961b239..44642330c 100644 --- a/src/components/mail.rs +++ b/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 { diff --git a/src/components/mail/compose.rs b/src/components/mail/compose.rs index df2aab711..2ab9b9091 100644 --- a/src/components/mail/compose.rs +++ b/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>)>, - 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 { + pub fn edit(new_account_hash: AccountHash, h: EnvelopeHash, context: &Context) -> Result { 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 = 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)>> { - 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), )); diff --git a/src/components/mail/listing.rs b/src/components/mail/listing.rs index c6b4ff431..d4795ebf9 100644 --- a/src/components/mail/listing.rs +++ b/src/components/mail/listing.rs @@ -134,7 +134,7 @@ column_str!(struct TagString(String, SmallVec<[Option; 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 diff --git a/src/components/mail/listing/compact.rs b/src/components/mail/listing/compact.rs index f2464b2b5..58b3def3f 100644 --- a/src/components/mail/listing/compact.rs +++ b/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>, ) { - 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>, 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)); diff --git a/src/components/mail/listing/conversations.rs b/src/components/mail/listing/conversations.rs index 0e16ba1aa..f9faa1ef8 100644 --- a/src/components/mail/listing/conversations.rs +++ b/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>, ) { - 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]; match results { Ok(results) => { let threads = account.collection.get_threads(self.cursor_pos.1); @@ -796,7 +796,7 @@ impl ListingTrait for ConversationsListing { 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); @@ -863,9 +863,9 @@ impl fmt::Display for ConversationsListing { impl ConversationsListing { const DESCRIPTION: &'static str = "conversations listing"; - pub fn new(coordinates: (usize, MailboxHash)) -> Self { + pub fn new(coordinates: (AccountHash, MailboxHash)) -> Self { ConversationsListing { - 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()), @@ -899,7 +899,7 @@ impl ConversationsListing { let thread = threads.thread_ref(hash); let mut tags = String::new(); let mut colors = 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() { @@ -1006,7 +1006,7 @@ impl ConversationsListing { } 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; @@ -1029,7 +1029,7 @@ impl ConversationsListing { for (_, h) in threads.thread_group_iter(thread_hash) { 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() { @@ -1294,7 +1294,7 @@ impl Component for ConversationsListing { return 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; @@ -1312,11 +1312,15 @@ impl Component for ConversationsListing { 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::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; @@ -1334,8 +1338,10 @@ impl Component for ConversationsListing { 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::Action(ref action) => match action { Action::SubSort(field, order) if !self.unfocused => { @@ -1356,12 +1362,12 @@ impl Component for ConversationsListing { /* self.sort = (*field, *order); if !self.filtered_selection.is_empty() { - let threads = &context.accounts[self.cursor_pos.0].collection.threads + let threads = &context.accounts[&self.cursor_pos.0].collection.threads [&self.cursor_pos.1]; threads.vec_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.dirty = true; } else { @@ -1372,7 +1378,7 @@ impl Component for ConversationsListing { } 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 @@ -1411,16 +1417,16 @@ impl Component for ConversationsListing { } UIEvent::Action(ref action) => match 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)); diff --git a/src/components/mail/listing/offline.rs b/src/components/mail/listing/offline.rs index 1f506eeb9..044b983ea 100644 --- a/src/components/mail/listing/offline.rs +++ b/src/components/mail/listing/offline.rs @@ -24,7 +24,7 @@ use crate::components::utilities::PageMovement; #[derive(Debug)] pub struct OfflineListing { - cursor_pos: (usize, MailboxHash), + cursor_pos: (AccountHash, MailboxHash), _row_updates: SmallVec<[ThreadHash; 8]>, _selection: HashMap, dirty: bool, @@ -60,11 +60,11 @@ impl MailListingTrait for OfflineListing { } impl ListingTrait for OfflineListing { - fn coordinates(&self) -> (usize, MailboxHash) { + fn coordinates(&self) -> (AccountHash, MailboxHash) { self.cursor_pos } - fn set_coordinates(&mut self, coordinates: (usize, MailboxHash)) { + fn set_coordinates(&mut self, coordinates: (AccountHash, MailboxHash)) { self.cursor_pos = coordinates; } @@ -89,7 +89,7 @@ impl fmt::Display for OfflineListing { } impl OfflineListing { - pub fn new(cursor_pos: (usize, MailboxHash)) -> Self { + pub fn new(cursor_pos: (AccountHash, MailboxHash)) -> Self { OfflineListing { cursor_pos, _row_updates: SmallVec::new(), @@ -137,7 +137,7 @@ impl Component for OfflineListing { area, None, ); - let mut jobs: SmallVec<[_; 64]> = context.accounts[self.cursor_pos.0] + let mut jobs: SmallVec<[_; 64]> = context.accounts[&self.cursor_pos.0] .active_jobs .iter() .collect(); @@ -163,7 +163,9 @@ impl Component for OfflineListing { } fn process_event(&mut self, event: &mut UIEvent, _context: &mut Context) -> bool { match event { - UIEvent::AccountStatusChange(idx) if *idx == self.cursor_pos.0 => self.dirty = true, + UIEvent::AccountStatusChange(account_hash) if *account_hash == self.cursor_pos.0 => { + self.dirty = true + } _ => {} } false diff --git a/src/components/mail/listing/plain.rs b/src/components/mail/listing/plain.rs index bcdaaa9e9..7d52325d8 100644 --- a/src/components/mail/listing/plain.rs +++ b/src/components/mail/listing/plain.rs @@ -47,8 +47,8 @@ macro_rules! address_list { #[derive(Debug)] pub struct PlainListing { /// (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), @@ -148,7 +148,7 @@ impl MailListingTrait for PlainListing { // 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 = { @@ -159,7 +159,7 @@ impl MailListingTrait for PlainListing { 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; @@ -175,18 +175,18 @@ impl MailListingTrait for PlainListing { return; } } - self.local_collection = context.accounts[self.cursor_pos.0] + self.local_collection = context.accounts[&self.cursor_pos.0] .collection .get_mailbox(self.cursor_pos.1) .iter() .cloned() .collect(); - let env_lck = context.accounts[self.cursor_pos.0] + let env_lck = context.accounts[&self.cursor_pos.0] .collection .envelopes .read() .unwrap(); - self.thread_node_hashes = context.accounts[self.cursor_pos.0] + self.thread_node_hashes = context.accounts[&self.cursor_pos.0] .collection .get_mailbox(self.cursor_pos.1) .iter() @@ -240,7 +240,7 @@ impl MailListingTrait for PlainListing { context: &Context, items: Box>, ) { - 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 roots = items .filter_map(|r| threads.groups[&r].root().map(|r| r.root)) @@ -262,11 +262,11 @@ impl MailListingTrait for PlainListing { } impl ListingTrait for PlainListing { - 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 = MailView::default(); @@ -282,7 +282,7 @@ impl ListingTrait for PlainListing { } let i = self.get_env_under_cursor(idx, context); - let account = &context.accounts[self.cursor_pos.0]; + let account = &context.accounts[&self.cursor_pos.0]; let envelope: EnvelopeRef = account.collection.get_env(i); let fg_color = if !envelope.is_seen() { @@ -616,7 +616,7 @@ impl ListingTrait for PlainListing { *v = false; } - let account = &context.accounts[self.cursor_pos.0]; + let account = &context.accounts[&self.cursor_pos.0]; match results { Ok(results) => { for env_hash in results { @@ -699,7 +699,7 @@ impl fmt::Display for PlainListing { impl PlainListing { const DESCRIPTION: &'static str = "plain listing"; - pub fn new(coordinates: (usize, MailboxHash)) -> Self { + pub fn new(coordinates: (AccountHash, MailboxHash)) -> Self { PlainListing { cursor_pos: (0, 1, 0), new_cursor_pos: (coordinates.0, coordinates.1, 0), @@ -734,7 +734,7 @@ impl PlainListing { fn make_entry_string(&self, e: EnvelopeRef, context: &Context) -> EntryStrings { let mut tags = String::new(); let mut colors = 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() { @@ -773,7 +773,7 @@ impl PlainListing { } fn redraw_list(&mut self, context: &Context, iter: Box>) { - let account = &context.accounts[self.cursor_pos.0]; + let account = &context.accounts[&self.cursor_pos.0]; let mailbox = &account[&self.cursor_pos.1]; self.order.clear(); @@ -783,18 +783,18 @@ impl PlainListing { let mut min_width = (0, 0, 0, 0, 0); for i in iter { - if !context.accounts[self.cursor_pos.0].contains_key(i) { + if !context.accounts[&self.cursor_pos.0].contains_key(i) { debug!("key = {}", i); debug!( "name = {} {}", mailbox.name(), - context.accounts[self.cursor_pos.0].name() + context.accounts[&self.cursor_pos.0].name() ); debug!("{:#?}", context.accounts); panic!(); } - let envelope: EnvelopeRef = context.accounts[self.cursor_pos.0].collection.get_env(i); + let envelope: EnvelopeRef = context.accounts[&self.cursor_pos.0].collection.get_env(i); use melib::search::QueryTrait; if let Some(filter_query) = mailbox_settings!( context[self.cursor_pos.0][&self.cursor_pos.1] @@ -858,19 +858,19 @@ impl PlainListing { let columns = &mut self.data_columns.columns; for ((idx, i), strings) in iter.enumerate().zip(rows) { - if !context.accounts[self.cursor_pos.0].contains_key(i) { + if !context.accounts[&self.cursor_pos.0].contains_key(i) { //debug!("key = {}", i); //debug!( // "name = {} {}", // mailbox.name(), - // context.accounts[self.cursor_pos.0].name() + // context.accounts[&self.cursor_pos.0].name() //); //debug!("{:#?}", context.accounts); panic!(); } - let envelope: EnvelopeRef = context.accounts[self.cursor_pos.0].collection.get_env(i); + let envelope: EnvelopeRef = context.accounts[&self.cursor_pos.0].collection.get_env(i); let row_attr = if !envelope.is_seen() { if idx % 2 == 0 { self.color_cache.even_unseen @@ -971,7 +971,7 @@ impl PlainListing { for c in columns[4].row_iter(x..min_width.4, idx) { columns[4][c].set_bg(row_attr.bg).set_attrs(row_attr.attrs); } - if context.accounts[self.cursor_pos.0] + if context.accounts[&self.cursor_pos.0] .collection .get_env(i) .has_attachments() @@ -1019,7 +1019,7 @@ impl PlainListing { } fn perform_action(&mut self, context: &mut Context, env_hash: EnvelopeHash, a: &ListingAction) { - let account = &mut context.accounts[self.cursor_pos.0]; + let account = &mut context.accounts[&self.cursor_pos.0]; match { match a { ListingAction::SetSeen => account.backend.write().unwrap().set_flags( @@ -1232,7 +1232,7 @@ impl Component for PlainListing { 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]; if !account.collection.contains_key(new_hash) || !account .collection @@ -1257,11 +1257,13 @@ impl Component for PlainListing { 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::EnvelopeUpdate(ref env_hash) => { - let account = &context.accounts[self.cursor_pos.0]; + let account = &context.accounts[&self.cursor_pos.0]; if !account.collection.contains_key(env_hash) || !account .collection @@ -1274,8 +1276,10 @@ impl Component for PlainListing { self.row_updates.push(*env_hash); 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; @@ -1300,16 +1304,16 @@ impl Component for PlainListing { 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] .insert_job(job_id, crate::conf::accounts::JobRequest::Search(handle)); self.search_job = Some((filter_term.to_string(), chan, job_id)); } diff --git a/src/components/mail/listing/thread.rs b/src/components/mail/listing/thread.rs index 0cb85743f..532bed750 100644 --- a/src/components/mail/listing/thread.rs +++ b/src/components/mail/listing/thread.rs @@ -105,8 +105,8 @@ macro_rules! row_attr { #[derive(Debug)] pub struct ThreadListing { /// (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), @@ -179,7 +179,7 @@ impl MailListingTrait for ThreadListing { // 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 = { @@ -190,7 +190,7 @@ impl MailListingTrait for ThreadListing { 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; @@ -206,14 +206,14 @@ impl MailListingTrait for ThreadListing { return; } } - 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( @@ -227,7 +227,7 @@ impl MailListingTrait for ThreadListing { context: &Context, items: Box>, ) { - 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.length = 0; self.order.clear(); @@ -414,10 +414,10 @@ impl MailListingTrait for ThreadListing { } impl ListingTrait for ThreadListing { - 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 = None; @@ -714,7 +714,7 @@ impl ListingTrait for ThreadListing { } let env_hash = self.get_env_under_cursor(idx, context); - let envelope: EnvelopeRef = context.accounts[self.cursor_pos.0] + let envelope: EnvelopeRef = context.accounts[&self.cursor_pos.0] .collection .get_env(env_hash); @@ -748,9 +748,9 @@ impl fmt::Display for ThreadListing { } impl ThreadListing { - pub fn new(coordinates: (usize, MailboxHash)) -> Self { + pub fn new(coordinates: (AccountHash, MailboxHash)) -> Self { ThreadListing { - cursor_pos: (0, 1, 0), + cursor_pos: (coordinates.0, 0, 0), new_cursor_pos: (coordinates.0, coordinates.1, 0), length: 0, sort: (Default::default(), Default::default()), @@ -779,7 +779,7 @@ impl ThreadListing { } let env_hash = self.get_env_under_cursor(idx, context); - let envelope: EnvelopeRef = context.accounts[self.cursor_pos.0] + let envelope: EnvelopeRef = context.accounts[&self.cursor_pos.0] .collection .get_env(env_hash); @@ -850,7 +850,7 @@ impl ThreadListing { fn make_entry_string(&self, e: &Envelope, context: &Context) -> EntryStrings { 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() { @@ -913,12 +913,12 @@ impl ThreadListing { self.rows.iter().skip(start).take(end - start + 1) { let idx = *idx; - if !context.accounts[self.cursor_pos.0].contains_key(*env_hash) { + if !context.accounts[&self.cursor_pos.0].contains_key(*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); @@ -1109,7 +1109,7 @@ impl Component for ThreadListing { if self.length == 0 { false } else { - let account = &context.accounts[self.cursor_pos.0]; + let account = &context.accounts[&self.cursor_pos.0]; let envelope: EnvelopeRef = account .collection .get_env(self.get_env_under_cursor(idx, context)); @@ -1169,11 +1169,9 @@ impl Component for ThreadListing { self.view = Some(MailView::new(coordinates, None, None, context)); } - self.view.as_mut().unwrap().draw( - grid, - (set_y(upper_left, mid + 1), bottom_right), - context, - ); + if let Some(v) = self.view.as_mut() { + v.draw(grid, (set_y(upper_left, mid + 1), bottom_right), context); + } self.dirty = false; } @@ -1207,7 +1205,7 @@ impl Component for ThreadListing { 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]; if !account.collection.contains_key(&new_hash) { return false; } @@ -1219,9 +1217,14 @@ impl Component for ThreadListing { self.dirty = true; - self.view.as_mut().map(|c| { - c.process_event(&mut UIEvent::EnvelopeRename(*old_hash, *new_hash), context) - }); + if self.unfocused { + if let Some(v) = self.view.as_mut() { + v.process_event( + &mut UIEvent::EnvelopeRename(*old_hash, *new_hash), + context, + ); + } + } } UIEvent::EnvelopeRemove(ref env_hash, _) => { if self.order.contains_key(env_hash) { @@ -1230,7 +1233,7 @@ impl Component for ThreadListing { } } UIEvent::EnvelopeUpdate(ref env_hash) => { - let account = &context.accounts[self.cursor_pos.0]; + let account = &context.accounts[&self.cursor_pos.0]; if !account.collection.contains_key(env_hash) { return false; } @@ -1240,9 +1243,11 @@ impl Component for ThreadListing { self.dirty = true; - self.view - .as_mut() - .map(|c| c.process_event(&mut UIEvent::EnvelopeUpdate(*env_hash), context)); + if self.unfocused { + if let Some(v) = self.view.as_mut() { + v.process_event(&mut UIEvent::EnvelopeUpdate(*env_hash), context); + } + } } UIEvent::ChangeMode(UIMode::Normal) => { self.dirty = true; diff --git a/src/components/mail/status.rs b/src/components/mail/status.rs index d29e4368d..37951691b 100644 --- a/src/components/mail/status.rs +++ b/src/components/mail/status.rs @@ -271,7 +271,7 @@ impl StatusPanel { Some(2), ); - for (i, a) in context.accounts.iter().enumerate() { + for (i, (_h, a)) in context.accounts.iter().enumerate() { for x in 2..(120 - 1) { set_and_join_box(&mut self.content, (x, 12 + i * 10), BoxBoundary::Horizontal); } diff --git a/src/components/mail/view.rs b/src/components/mail/view.rs index 86d200d19..398e58bde 100644 --- a/src/components/mail/view.rs +++ b/src/components/mail/view.rs @@ -90,7 +90,7 @@ impl ViewMode { /// menus #[derive(Debug, Default)] pub struct MailView { - coordinates: (usize, MailboxHash, EnvelopeHash), + coordinates: (AccountHash, MailboxHash, EnvelopeHash), pager: Pager, subview: Option>, dirty: bool, @@ -152,7 +152,7 @@ impl fmt::Display for MailView { impl MailView { const DESCRIPTION: &'static str = "view mail"; pub fn new( - coordinates: (usize, MailboxHash, EnvelopeHash), + coordinates: (AccountHash, MailboxHash, EnvelopeHash), pager: Option, subview: Option>, context: &mut Context, @@ -185,7 +185,7 @@ impl MailView { fn init_futures(&mut self, context: &mut Context) { debug!("init_futures"); - let account = &mut context.accounts[self.coordinates.0]; + let account = &mut context.accounts[&self.coordinates.0]; if debug!(account.contains_key(self.coordinates.2)) { { match account @@ -372,7 +372,7 @@ impl MailView { pub fn update( &mut self, - new_coordinates: (usize, MailboxHash, EnvelopeHash), + new_coordinates: (AccountHash, MailboxHash, EnvelopeHash), context: &mut Context, ) { self.coordinates = new_coordinates; @@ -553,7 +553,7 @@ impl Component for MailView { let bottom_right = bottom_right!(area); let y: usize = { - let account = &context.accounts[self.coordinates.0]; + let account = &context.accounts[&self.coordinates.0]; if !account.contains_key(self.coordinates.2) { /* The envelope has been renamed or removed, so wait for the appropriate event to * arrive */ @@ -966,7 +966,7 @@ impl Component for MailView { if *id == s.id() => { if let Some(results) = results.downcast_ref::>() { - let account = &mut context.accounts[self.coordinates.0]; + let account = &mut context.accounts[&self.coordinates.0]; { for card in results.iter() { account.address_book.add_card(card.clone()); @@ -1074,7 +1074,7 @@ impl Component for MailView { key == shortcuts[MailView::DESCRIPTION]["add_addresses_to_contacts"] ) => { - let account = &context.accounts[self.coordinates.0]; + let account = &context.accounts[&self.coordinates.0]; let envelope: EnvelopeRef = account.collection.get_env(self.coordinates.2); let mut entries = Vec::new(); @@ -1285,7 +1285,7 @@ impl Component for MailView { self.coordinates.2 = new_hash; } UIEvent::Action(View(ViewAction::SaveAttachment(a_i, ref path))) => { - let account = &context.accounts[self.coordinates.0]; + let account = &context.accounts[&self.coordinates.0]; if !account.contains_key(self.coordinates.2) { /* The envelope has been renamed or removed, so wait for the appropriate event to * arrive */ @@ -1445,7 +1445,7 @@ impl Component for MailView { } } UIEvent::Action(MailingListAction(ref e)) => { - let account = &context.accounts[self.coordinates.0]; + let account = &context.accounts[&self.coordinates.0]; if !account.contains_key(self.coordinates.2) { /* The envelope has been renamed or removed, so wait for the appropriate event to * arrive */ diff --git a/src/components/mail/view/envelope.rs b/src/components/mail/view/envelope.rs index e4b98e056..ed3b9a14d 100644 --- a/src/components/mail/view/envelope.rs +++ b/src/components/mail/view/envelope.rs @@ -53,7 +53,7 @@ pub struct EnvelopeView { mode: ViewMode, wrapper: EnvelopeWrapper, - account_pos: usize, + account_hash: AccountHash, cmd_buf: String, id: ComponentId, } @@ -70,7 +70,7 @@ impl EnvelopeView { wrapper: EnvelopeWrapper, pager: Option, subview: Option>, - account_pos: usize, + account_hash: AccountHash, ) -> Self { EnvelopeView { pager, @@ -78,7 +78,7 @@ impl EnvelopeView { dirty: true, mode: ViewMode::Normal, wrapper, - account_pos, + account_hash, cmd_buf: String::with_capacity(4), id: ComponentId::new_v4(), } diff --git a/src/components/mail/view/thread.rs b/src/components/mail/view/thread.rs index cbbf4130c..b542d3991 100644 --- a/src/components/mail/view/thread.rs +++ b/src/components/mail/view/thread.rs @@ -42,7 +42,7 @@ pub struct ThreadView { expanded_pos: usize, new_expanded_pos: usize, reversed: bool, - coordinates: (usize, MailboxHash, usize), + coordinates: (AccountHash, MailboxHash, usize), thread_group: ThreadHash, mailview: MailView, show_mailview: bool, @@ -66,7 +66,7 @@ impl ThreadView { * context: current context */ pub fn new( - coordinates: (usize, MailboxHash, usize), + coordinates: (AccountHash, MailboxHash, usize), thread_group: ThreadHash, expanded_hash: Option, context: &Context, @@ -160,7 +160,7 @@ impl ThreadView { } fn initiate(&mut self, expanded_hash: Option, context: &Context) { - let account = &context.accounts[self.coordinates.0]; + let account = &context.accounts[&self.coordinates.0]; let threads = account.collection.get_threads(self.coordinates.1); if !threads.groups.contains_key(&self.thread_group) { @@ -197,7 +197,7 @@ impl ThreadView { let mut highlight_reply_subjects: Vec> = Vec::with_capacity(self.entries.len()); for e in &mut self.entries { - let envelope: EnvelopeRef = context.accounts[self.coordinates.0] + let envelope: EnvelopeRef = context.accounts[&self.coordinates.0] .collection .get_env(e.msg_hash); let thread_node = &threads.thread_nodes()[&e.index.1]; @@ -274,7 +274,7 @@ impl ThreadView { None, ); { - let envelope: EnvelopeRef = context.accounts[self.coordinates.0] + let envelope: EnvelopeRef = context.accounts[&self.coordinates.0] .collection .get_env(e.msg_hash); if envelope.has_attachments() { @@ -357,7 +357,7 @@ impl ThreadView { None, ); { - let envelope: EnvelopeRef = context.accounts[self.coordinates.0] + let envelope: EnvelopeRef = context.accounts[&self.coordinates.0] .collection .get_env(e.msg_hash); if envelope.has_attachments() { @@ -647,7 +647,7 @@ impl ThreadView { /* First draw the thread subject on the first row */ let y = if self.dirty { clear_area(grid, area, crate::conf::value(context, "theme_default")); - let account = &context.accounts[self.coordinates.0]; + let account = &context.accounts[&self.coordinates.0]; let threads = account.collection.get_threads(self.coordinates.1); let thread_root = threads .thread_group_iter(self.thread_group) @@ -748,7 +748,7 @@ impl ThreadView { /* First draw the thread subject on the first row */ let y = { clear_area(grid, area, crate::conf::value(context, "theme_default")); - let account = &context.accounts[self.coordinates.0]; + let account = &context.accounts[&self.coordinates.0]; let threads = account.collection.get_threads(self.coordinates.1); let thread_root = threads .thread_group_iter(self.thread_group) @@ -1103,7 +1103,7 @@ impl Component for ThreadView { self.set_dirty(true); } UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => { - let account = &context.accounts[self.coordinates.0]; + let account = &context.accounts[&self.coordinates.0]; for e in self.entries.iter_mut() { if e.msg_hash == *old_hash { e.msg_hash = *new_hash; @@ -1118,7 +1118,7 @@ impl Component for ThreadView { .process_event(&mut UIEvent::EnvelopeRename(*old_hash, *new_hash), context); } UIEvent::EnvelopeUpdate(ref env_hash) => { - let account = &context.accounts[self.coordinates.0]; + let account = &context.accounts[&self.coordinates.0]; for e in self.entries.iter_mut() { if e.msg_hash == *env_hash { let seen: bool = account.collection.get_env(*env_hash).is_seen(); diff --git a/src/components/utilities.rs b/src/components/utilities.rs index 949680610..c3eab5240 100644 --- a/src/components/utilities.rs +++ b/src/components/utilities.rs @@ -1666,8 +1666,8 @@ impl Component for Tabbed { self.dirty = true; return true; } - UIEvent::Action(Tab(NewDraft(account_idx, ref draft))) => { - let mut composer = Composer::new(*account_idx, context); + UIEvent::Action(Tab(NewDraft(account_hash, ref draft))) => { + let mut composer = Composer::new(*account_hash, context); if let Some(draft) = draft { composer.set_draft(draft.clone()); } @@ -1692,8 +1692,8 @@ impl Component for Tabbed { self.help_curr_views = children_maps; return true; } - UIEvent::Action(Tab(Edit(account_pos, msg))) => { - let composer = match Composer::edit(*account_pos, *msg, context) { + UIEvent::Action(Tab(Edit(account_hash, msg))) => { + let composer = match Composer::edit(*account_hash, *msg, context) { Ok(c) => c, Err(e) => { context.replies.push_back(UIEvent::Notification( @@ -1704,7 +1704,7 @@ impl Component for Tabbed { log( format!( "Failed to open envelope {}: {}", - context.accounts[*account_pos] + context.accounts[&*account_hash] .collection .get_env(*msg) .message_id_display(), diff --git a/src/conf.rs b/src/conf.rs index 0dc11f62b..c85319c4a 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -62,6 +62,7 @@ use melib::error::*; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; +use indexmap::IndexMap; use std::collections::HashMap; use std::env; use std::fs::OpenOptions; @@ -78,8 +79,8 @@ macro_rules! split_command { #[macro_export] macro_rules! mailbox_acc_settings { - ($context:ident[$account_idx:expr].$setting:ident.$field:ident) => {{ - $context.accounts[$account_idx] + ($context:ident[$account_hash:expr].$setting:ident.$field:ident) => {{ + $context.accounts[&$account_hash] .settings .conf_override .$setting @@ -90,14 +91,14 @@ macro_rules! mailbox_acc_settings { } #[macro_export] macro_rules! mailbox_settings { - ($context:ident[$account_idx:expr][$mailbox_path:expr].$setting:ident.$field:ident) => {{ - $context.accounts[$account_idx][$mailbox_path] + ($context:ident[$account_hash:expr][$mailbox_path:expr].$setting:ident.$field:ident) => {{ + $context.accounts[&$account_hash][$mailbox_path] .conf .conf_override .$setting .$field .as_ref() - .or($context.accounts[$account_idx] + .or($context.accounts[&$account_hash] .settings .conf_override .$setting @@ -163,7 +164,7 @@ pub struct FileAccount { #[serde(default)] subscribed_mailboxes: Vec, #[serde(default)] - mailboxes: HashMap, + mailboxes: IndexMap, #[serde(default)] search_backend: SearchBackend, #[serde(default = "false_val")] @@ -174,11 +175,11 @@ pub struct FileAccount { pub conf_override: MailUIConf, #[serde(flatten)] #[serde(deserialize_with = "extra_settings")] - pub extra: HashMap, /* use custom deserializer to convert any given value (eg bool, number, etc) to string */ + pub extra: IndexMap, /* use custom deserializer to convert any given value (eg bool, number, etc) to string */ } impl FileAccount { - pub fn mailboxes(&self) -> &HashMap { + pub fn mailboxes(&self) -> &IndexMap { &self.mailboxes } @@ -194,7 +195,7 @@ impl FileAccount { #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct FileSettings { - pub accounts: HashMap, + pub accounts: IndexMap, #[serde(default)] pub pager: PagerSettings, #[serde(default)] @@ -211,7 +212,7 @@ pub struct FileSettings { #[serde(default)] pub terminal: TerminalSettings, #[serde(default)] - pub plugins: HashMap, + pub plugins: IndexMap, #[serde(default)] pub log: LogSettings, } @@ -221,7 +222,7 @@ pub struct AccountConf { pub account: AccountSettings, pub conf: FileAccount, pub conf_override: MailUIConf, - pub mailbox_confs: HashMap, + pub mailbox_confs: IndexMap, } impl AccountConf { @@ -261,7 +262,7 @@ impl From for AccountConf { subscribed_mailboxes: x.subscribed_mailboxes.clone(), mailboxes, manual_refresh: x.manual_refresh, - extra: x.extra.clone(), + extra: x.extra.clone().into_iter().collect(), }; let mailbox_confs = x.mailboxes.clone(); @@ -422,7 +423,7 @@ impl FileSettings { .into_iter() .map(|(k, v)| (k, v.mailbox_conf)) .collect(), - extra, + extra: extra.into_iter().collect(), }; backends.validate_config(&lowercase_format, &s)?; } @@ -433,7 +434,7 @@ impl FileSettings { #[derive(Debug, Clone, Default, Serialize)] pub struct Settings { - pub accounts: HashMap, + pub accounts: IndexMap, pub pager: PagerSettings, pub listing: ListingSettings, pub notifications: NotificationsSettings, @@ -442,14 +443,14 @@ pub struct Settings { pub composing: ComposingSettings, pub pgp: PGPSettings, pub terminal: TerminalSettings, - pub plugins: HashMap, + pub plugins: IndexMap, pub log: LogSettings, } impl Settings { pub fn new() -> Result { let fs = FileSettings::new()?; - let mut s: HashMap = HashMap::new(); + let mut s: IndexMap = IndexMap::new(); for (id, x) in fs.accounts { let mut ac = AccountConf::from(x); @@ -490,7 +491,7 @@ impl Settings { } Ok(Settings { - accounts: HashMap::new(), + accounts: IndexMap::new(), pager: fs.pager, listing: fs.listing, notifications: fs.notifications, @@ -583,10 +584,10 @@ mod deserializers { Ok(ret) } - use std::collections::HashMap; + use indexmap::IndexMap; pub(in crate::conf) fn extra_settings<'de, D>( deserializer: D, - ) -> std::result::Result, D::Error> + ) -> std::result::Result, D::Error> where D: Deserializer<'de>, { @@ -596,7 +597,7 @@ mod deserializers { #[derive(Deserialize)] struct Wrapper(#[serde(deserialize_with = "any_of")] String); - let v = >::deserialize(deserializer)?; + let v = >::deserialize(deserializer)?; Ok(v.into_iter().map(|(k, Wrapper(v))| (k, v)).collect()) } } @@ -869,6 +870,10 @@ mod dotaddressable { for HashMap { } + impl DotAddressable + for IndexMap + { + } impl DotAddressable for HashSet {} impl DotAddressable for LogSettings { diff --git a/src/conf/accounts.rs b/src/conf/accounts.rs index a3f31e7e4..b70458f2c 100644 --- a/src/conf/accounts.rs +++ b/src/conf/accounts.rs @@ -25,6 +25,7 @@ use super::{AccountConf, FileMailboxConf}; use crate::jobs::{JobChannel, JobExecutor, JobId, JoinHandle}; +use indexmap::IndexMap; use melib::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext}; use melib::backends::*; use melib::email::*; @@ -141,12 +142,11 @@ impl MailboxEntry { #[derive(Debug)] pub struct Account { - pub index: usize, name: String, hash: AccountHash, pub is_online: Result<()>, pub last_online_request: std::time::Instant, - pub(crate) mailbox_entries: HashMap, + pub(crate) mailbox_entries: IndexMap, pub(crate) mailboxes_order: Vec, tree: Vec, sent_mailbox: Option, @@ -351,7 +351,6 @@ pub struct MailboxNode { impl Account { pub fn new( - index: usize, hash: AccountHash, name: String, mut settings: AccountConf, @@ -410,7 +409,6 @@ impl Account { } } let mut ret = Account { - index, hash, name, is_online: if !backend.capabilities().is_remote { @@ -451,8 +449,8 @@ impl Account { self.backend.read().unwrap().mailboxes()? }; self.backend_capabilities = self.backend.read().unwrap().capabilities(); - let mut mailbox_entries: HashMap = - HashMap::with_capacity_and_hasher(ref_mailboxes.len(), Default::default()); + let mut mailbox_entries: IndexMap = + IndexMap::with_capacity_and_hasher(ref_mailboxes.len(), Default::default()); let mut mailboxes_order: Vec = Vec::with_capacity(ref_mailboxes.len()); let mut sent_mailbox = None; @@ -818,7 +816,7 @@ impl Account { .ignore .is_true() { - return Some(UIEvent::MailboxUpdate((self.index, mailbox_hash))); + return Some(UIEvent::MailboxUpdate((self.hash, mailbox_hash))); } let thread = { @@ -833,10 +831,10 @@ impl Account { .thread_ref(thread) .snoozed() { - return Some(UIEvent::MailboxUpdate((self.index, mailbox_hash))); + return Some(UIEvent::MailboxUpdate((self.hash, mailbox_hash))); } if is_seen || is_draft { - return Some(UIEvent::MailboxUpdate((self.index, mailbox_hash))); + return Some(UIEvent::MailboxUpdate((self.hash, mailbox_hash))); } return Some(Notification( @@ -1201,7 +1199,7 @@ impl Account { }); self.sender .send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate(( - self.index, + self.hash, mailbox_hash, )))) .unwrap(); @@ -1441,7 +1439,7 @@ impl Account { )?; self.sender .send(ThreadEvent::UIEvent(UIEvent::MailboxCreate(( - self.index, + self.hash, mailbox_hash, )))) .unwrap(); @@ -1515,7 +1513,7 @@ impl Account { )?; self.sender .send(ThreadEvent::UIEvent(UIEvent::MailboxDelete(( - self.index, + self.hash, mailbox_hash, )))) .unwrap(); @@ -1664,7 +1662,7 @@ impl Account { } self.sender .send(ThreadEvent::UIEvent(UIEvent::AccountStatusChange( - self.index, + self.hash, ))) .unwrap(); } @@ -1769,7 +1767,7 @@ impl Account { }); self.sender .send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate(( - self.index, + self.hash, mailbox_hash, )))) .unwrap(); @@ -1802,7 +1800,7 @@ impl Account { }); self.sender .send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate(( - self.index, + self.hash, mailbox_hash, )))) .unwrap(); @@ -1819,15 +1817,13 @@ impl Account { { for f in updated_mailboxes { self.sender - .send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate(( - self.index, f, - )))) + .send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate((self.hash, f)))) .unwrap(); } } self.sender .send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate(( - self.index, + self.hash, mailbox_hash, )))) .unwrap(); @@ -1837,7 +1833,7 @@ impl Account { if let Some(is_online) = is_online { self.sender .send(ThreadEvent::UIEvent(UIEvent::AccountStatusChange( - self.index, + self.hash, ))) .unwrap(); if is_online.is_ok() { @@ -1893,7 +1889,7 @@ impl Account { self.is_online = Ok(()); self.sender .send(ThreadEvent::UIEvent(UIEvent::AccountStatusChange( - self.index, + self.hash, ))) .unwrap(); } @@ -2156,7 +2152,7 @@ impl IndexMut<&MailboxHash> for Account { fn build_mailboxes_order( tree: &mut Vec, - mailbox_entries: &HashMap, + mailbox_entries: &IndexMap, mailboxes_order: &mut Vec, ) { tree.clear(); @@ -2165,7 +2161,7 @@ fn build_mailboxes_order( if f.ref_mailbox.parent().is_none() { fn rec( h: MailboxHash, - mailbox_entries: &HashMap, + mailbox_entries: &IndexMap, depth: usize, ) -> MailboxNode { let mut node = MailboxNode { diff --git a/src/state.rs b/src/state.rs index 75c4d49c3..034ef97c1 100644 --- a/src/state.rs +++ b/src/state.rs @@ -34,8 +34,8 @@ use melib::backends::{AccountHash, MailboxHash, NotifyFn}; use crate::jobs::JobExecutor; use crossbeam::channel::{unbounded, Receiver, Sender}; +use indexmap::IndexMap; use smallvec::SmallVec; -use std::collections::HashMap; use std::env; use std::io::Write; use std::os::unix::io::RawFd; @@ -101,8 +101,7 @@ impl InputHandler { /// A context container for loaded settings, accounts, UI changes, etc. pub struct Context { - pub accounts: Vec, - pub account_hashes: HashMap, + pub accounts: IndexMap, pub settings: Settings, pub runtime_settings: Settings, @@ -135,7 +134,7 @@ impl Context { self.input_thread.restore(); } - pub fn is_online(&mut self, account_pos: usize) -> Result<()> { + pub fn is_online_idx(&mut self, account_pos: usize) -> Result<()> { let Context { ref mut accounts, ref mut replies, @@ -155,15 +154,20 @@ impl Context { } accounts[account_pos].watch(); - replies.push_back(UIEvent::AccountStatusChange(account_pos)); + replies.push_back(UIEvent::AccountStatusChange(accounts[account_pos].hash())); } } if ret.is_ok() != was_online { - replies.push_back(UIEvent::AccountStatusChange(account_pos)); + replies.push_back(UIEvent::AccountStatusChange(accounts[account_pos].hash())); } ret } + pub fn is_online(&mut self, account_hash: AccountHash) -> Result<()> { + let idx = self.accounts.get_index_of(&account_hash).unwrap(); + self.is_online_idx(idx) + } + pub fn work_controller(&self) -> &WorkController { &self.work_controller } @@ -257,20 +261,13 @@ impl State { let cols = termsize.0 as usize; let rows = termsize.1 as usize; - let mut account_hashes = HashMap::with_capacity_and_hasher(1, Default::default()); let work_controller = WorkController::new(sender.clone()); let job_executor = Arc::new(JobExecutor::new(sender.clone())); - let accounts: Vec = { - let mut file_accs = settings + let accounts = { + settings .accounts .iter() - .collect::>(); - file_accs.sort_by(|a, b| a.0.cmp(&b.0)); - - file_accs - .into_iter() - .enumerate() - .map(|(index, (n, a_s))| { + .map(|(n, a_s)| { let sender = sender.clone(); let account_hash = { use std::collections::hash_map::DefaultHasher; @@ -279,9 +276,7 @@ impl State { hasher.write(n.as_bytes()); hasher.finish() }; - account_hashes.insert(account_hash, index); Account::new( - index, account_hash, n.to_string(), a_s.clone(), @@ -301,6 +296,7 @@ impl State { }) .collect::>>()? }; + let accounts = accounts.into_iter().map(|acc| (acc.hash(), acc)).collect(); let timer = { let sender = sender.clone(); @@ -343,7 +339,6 @@ impl State { context: Context { accounts, - account_hashes, settings: settings.clone(), runtime_settings: settings, dirty_areas: VecDeque::with_capacity(5), @@ -378,7 +373,7 @@ impl State { if !s.context.accounts[i].backend_capabilities.is_remote { s.context.accounts[i].watch(); } - if s.context.is_online(i).is_ok() && s.context.accounts[i].is_empty() { + if s.context.is_online_idx(i).is_ok() && s.context.accounts[i].is_empty() { //return Err(MeliError::new(format!( // "Account {} has no mailboxes configured.", // s.context.accounts[i].name() @@ -397,29 +392,30 @@ impl State { pub fn refresh_event(&mut self, event: RefreshEvent) { let account_hash = event.account_hash(); let mailbox_hash = event.mailbox_hash(); - if let Some(&idxa) = self.context.account_hashes.get(&account_hash) { - if self.context.accounts[idxa] - .mailbox_entries - .contains_key(&mailbox_hash) + if self.context.accounts[&account_hash] + .mailbox_entries + .contains_key(&mailbox_hash) + { + if self.context.accounts[&account_hash] + .load(mailbox_hash) + .is_err() { - if self.context.accounts[idxa].load(mailbox_hash).is_err() { - self.context.replies.push_back(UIEvent::from(event)); - return; - } - let Context { - ref mut accounts, .. - } = &mut self.context; + self.context.replies.push_back(UIEvent::from(event)); + return; + } + let Context { + ref mut accounts, .. + } = &mut self.context; - if let Some(notification) = accounts[idxa].reload(event, mailbox_hash) { - if let UIEvent::Notification(_, _, _) = notification { - self.rcv_event(UIEvent::MailboxUpdate((idxa, mailbox_hash))); - } - self.rcv_event(notification); - } - } else { - if let melib::backends::RefreshEventKind::Failure(err) = event.kind() { - debug!(err); + if let Some(notification) = accounts[&account_hash].reload(event, mailbox_hash) { + if let UIEvent::Notification(_, _, _) = notification { + self.rcv_event(UIEvent::MailboxUpdate((account_hash, mailbox_hash))); } + self.rcv_event(notification); + } + } else { + if let melib::backends::RefreshEventKind::Failure(err) = event.kind() { + debug!(err); } } } @@ -838,7 +834,7 @@ impl State { if let Some(account) = self .context .accounts - .iter_mut() + .values_mut() .find(|a| a.name() == account_name) { match account.mailbox_operation(op) { @@ -868,7 +864,7 @@ impl State { .context .accounts .iter() - .position(|acc| acc.name() == account_name) + .position(|(_, acc)| acc.name() == account_name) { a } else { @@ -937,7 +933,7 @@ impl State { .context .accounts .iter() - .position(|a| a.name() == account_name) + .position(|(_h, a)| a.name() == account_name) { self.context.replies.push_back(UIEvent::StatusEvent( StatusEvent::UpdateStatus(format!( @@ -1033,9 +1029,7 @@ impl State { return; } UIEvent::WorkerProgress(account_hash, mailbox_hash) => { - if let Some(&account_idx) = self.context.account_hashes.get(&account_hash) { - let _ = self.context.accounts[account_idx].load(mailbox_hash); - } + let _ = self.context.accounts[&account_hash].load(mailbox_hash); return; } UIEvent::ChangeMode(m) => { @@ -1169,7 +1163,7 @@ impl State { pub fn check_accounts(&mut self) { let mut ctr = 0; for i in 0..self.context.accounts.len() { - if self.context.is_online(i).is_ok() { + if self.context.is_online_idx(i).is_ok() { ctr += 1; } } diff --git a/src/types.rs b/src/types.rs index 148f83ba3..20e692291 100644 --- a/src/types.rs +++ b/src/types.rs @@ -114,10 +114,10 @@ pub enum UIEvent { Notification(Option, String, Option), Action(Action), StatusEvent(StatusEvent), - MailboxUpdate((usize, MailboxHash)), // (account_idx, mailbox_idx) - MailboxDelete((usize, MailboxHash)), - MailboxCreate((usize, MailboxHash)), - AccountStatusChange(usize), + MailboxUpdate((AccountHash, MailboxHash)), // (account_idx, mailbox_idx) + MailboxDelete((AccountHash, MailboxHash)), + MailboxCreate((AccountHash, MailboxHash)), + AccountStatusChange(AccountHash), ComponentKill(Uuid), WorkerProgress(AccountHash, MailboxHash), StartupCheck(MailboxHash),