Preserve Account order from configuration file

Use IndexMap to preserve the order of accounts in the UI from the
account definitions.
memfd
Manos Pitsidianakis 2020-08-17 15:31:30 +03:00
parent dede8d2a9e
commit 8a6bf3b217
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
22 changed files with 381 additions and 368 deletions

2
Cargo.lock generated
View File

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

View File

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

View File

@ -473,7 +473,7 @@ fn run_app(opt: Opt) -> Result<()> {
}, },
ThreadEvent::JobFinished(id) => { ThreadEvent::JobFinished(id) => {
debug!("Job finished {}", 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) { if account.process_event(&id) {
break; break;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -94,8 +94,8 @@ macro_rules! row_attr {
#[derive(Debug)] #[derive(Debug)]
pub struct ConversationsListing { pub struct ConversationsListing {
/// (x, y, z): x is accounts, y is mailboxes, z is index inside a mailbox. /// (x, y, z): x is accounts, y is mailboxes, z is index inside a mailbox.
cursor_pos: (usize, MailboxHash, usize), cursor_pos: (AccountHash, MailboxHash, usize),
new_cursor_pos: (usize, MailboxHash, usize), new_cursor_pos: (AccountHash, MailboxHash, usize),
length: usize, length: usize,
sort: (SortField, SortOrder), sort: (SortField, SortOrder),
subsort: (SortField, SortOrder), subsort: (SortField, SortOrder),
@ -194,7 +194,7 @@ impl MailListingTrait for ConversationsListing {
} }
// Get mailbox as a reference. // 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(()) => {} Ok(()) => {}
Err(_) => { Err(_) => {
let default_cell = { let default_cell = {
@ -205,7 +205,7 @@ impl MailListingTrait for ConversationsListing {
ret ret
}; };
let message: String = 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 = self.content =
CellBuffer::new_with_context(message.len(), 1, default_cell, context); CellBuffer::new_with_context(message.len(), 1, default_cell, context);
self.length = 0; 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 .collection
.get_threads(self.cursor_pos.1); .get_threads(self.cursor_pos.1);
self.all_threads.clear(); self.all_threads.clear();
@ -230,7 +230,7 @@ impl MailListingTrait for ConversationsListing {
threads.group_inner_sort_by( threads.group_inner_sort_by(
&mut roots, &mut roots,
self.sort, self.sort,
&context.accounts[self.cursor_pos.0].collection.envelopes, &context.accounts[&self.cursor_pos.0].collection.envelopes,
); );
self.redraw_threads_list( self.redraw_threads_list(
@ -253,7 +253,7 @@ impl MailListingTrait for ConversationsListing {
context: &Context, context: &Context,
items: Box<dyn Iterator<Item = ThreadHash>>, 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); let threads = account.collection.get_threads(self.cursor_pos.1);
self.order.clear(); self.order.clear();
@ -284,12 +284,12 @@ impl MailListingTrait for ConversationsListing {
} else { } else {
continue 'items_for_loop; 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!("key = {}", root_env_hash);
debug!( debug!(
"name = {} {}", "name = {} {}",
account[&self.cursor_pos.1].name(), account[&self.cursor_pos.1].name(),
context.accounts[self.cursor_pos.0].name() context.accounts[&self.cursor_pos.0].name()
); );
debug!("{:#?}", context.accounts); debug!("{:#?}", context.accounts);
@ -300,7 +300,7 @@ impl MailListingTrait for ConversationsListing {
for (_, h) in threads.thread_group_iter(thread) { for (_, h) in threads.thread_group_iter(thread) {
let env_hash = threads.thread_nodes()[&h].message().unwrap(); 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 .collection
.get_env(env_hash); .get_env(env_hash);
for addr in envelope.from().iter() { for addr in envelope.from().iter() {
@ -311,7 +311,7 @@ impl MailListingTrait for ConversationsListing {
from_address_list.push(addr.clone()); 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 .collection
.get_env(root_env_hash); .get_env(root_env_hash);
use melib::search::QueryTrait; use melib::search::QueryTrait;
@ -361,7 +361,7 @@ impl MailListingTrait for ConversationsListing {
let padding_fg = self.color_cache.padding.fg; let padding_fg = self.color_cache.padding.fg;
for ((idx, (thread, root_env_hash)), strings) in rows { 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!(); panic!();
} }
let thread = threads.thread_ref(thread); let thread = threads.thread_ref(thread);
@ -487,11 +487,11 @@ impl MailListingTrait for ConversationsListing {
} }
impl ListingTrait 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) (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.new_cursor_pos = (coordinates.0, coordinates.1, 0); self.new_cursor_pos = (coordinates.0, coordinates.1, 0);
self.unfocused = false; self.unfocused = false;
@ -508,7 +508,7 @@ impl ListingTrait for ConversationsListing {
} }
let thread_hash = self.get_thread_under_cursor(idx); 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 threads = account.collection.get_threads(self.cursor_pos.1);
let thread = threads.thread_ref(thread_hash); let thread = threads.thread_ref(thread_hash);
@ -769,7 +769,7 @@ impl ListingTrait for ConversationsListing {
*v = false; *v = false;
} }
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[&self.cursor_pos.0];
match results { match results {
Ok(results) => { Ok(results) => {
let threads = account.collection.get_threads(self.cursor_pos.1); let threads = account.collection.get_threads(self.cursor_pos.1);
@ -796,7 +796,7 @@ impl ListingTrait for ConversationsListing {
threads.group_inner_sort_by( threads.group_inner_sort_by(
&mut self.filtered_selection, &mut self.filtered_selection,
self.sort, self.sort,
&context.accounts[self.cursor_pos.0].collection.envelopes, &context.accounts[&self.cursor_pos.0].collection.envelopes,
); );
self.new_cursor_pos.2 = self.new_cursor_pos.2 =
std::cmp::min(self.filtered_selection.len() - 1, self.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 { impl ConversationsListing {
const DESCRIPTION: &'static str = "conversations listing"; const DESCRIPTION: &'static str = "conversations listing";
pub fn new(coordinates: (usize, MailboxHash)) -> Self { pub fn new(coordinates: (AccountHash, MailboxHash)) -> Self {
ConversationsListing { ConversationsListing {
cursor_pos: (0, 1, 0), cursor_pos: (coordinates.0, 1, 0),
new_cursor_pos: (coordinates.0, coordinates.1, 0), new_cursor_pos: (coordinates.0, coordinates.1, 0),
length: 0, length: 0,
sort: (Default::default(), Default::default()), sort: (Default::default(), Default::default()),
@ -899,7 +899,7 @@ impl ConversationsListing {
let thread = threads.thread_ref(hash); let thread = threads.thread_ref(hash);
let mut tags = String::new(); let mut tags = String::new();
let mut colors = SmallVec::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() { if let Some(t) = backend_lck.tags() {
let tags_lck = t.read().unwrap(); let tags_lck = t.read().unwrap();
for t in e.labels().iter() { for t in e.labels().iter() {
@ -1006,7 +1006,7 @@ impl ConversationsListing {
} }
fn update_line(&mut self, context: &Context, thread_hash: ThreadHash) { 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 threads = account.collection.get_threads(self.cursor_pos.1);
let thread = threads.thread_ref(thread_hash); let thread = threads.thread_ref(thread_hash);
let thread_node_hash = threads.thread_group_iter(thread_hash).next().unwrap().1; 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) { for (_, h) in threads.thread_group_iter(thread_hash) {
let env_hash = threads.thread_nodes()[&h].message().unwrap(); 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 .collection
.get_env(env_hash); .get_env(env_hash);
for addr in envelope.from().iter() { for addr in envelope.from().iter() {
@ -1294,7 +1294,7 @@ impl Component for ConversationsListing {
return true; return true;
} }
UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => { 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); let threads = account.collection.get_threads(self.cursor_pos.1);
if !account.collection.contains_key(&new_hash) { if !account.collection.contains_key(&new_hash) {
return false; return false;
@ -1312,11 +1312,15 @@ impl Component for ConversationsListing {
self.dirty = true; self.dirty = true;
self.view if self.unfocused {
.process_event(&mut UIEvent::EnvelopeRename(*old_hash, *new_hash), context); self.view.process_event(
&mut UIEvent::EnvelopeRename(*old_hash, *new_hash),
context,
);
}
} }
UIEvent::EnvelopeUpdate(ref env_hash) => { 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); let threads = account.collection.get_threads(self.cursor_pos.1);
if !account.collection.contains_key(&env_hash) { if !account.collection.contains_key(&env_hash) {
return false; return false;
@ -1334,8 +1338,10 @@ impl Component for ConversationsListing {
self.dirty = true; self.dirty = true;
self.view if self.unfocused {
.process_event(&mut UIEvent::EnvelopeUpdate(*env_hash), context); self.view
.process_event(&mut UIEvent::EnvelopeUpdate(*env_hash), context);
}
} }
UIEvent::Action(ref action) => match action { UIEvent::Action(ref action) => match action {
Action::SubSort(field, order) if !self.unfocused => { Action::SubSort(field, order) if !self.unfocused => {
@ -1356,12 +1362,12 @@ impl Component for ConversationsListing {
/* /*
self.sort = (*field, *order); self.sort = (*field, *order);
if !self.filtered_selection.is_empty() { 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]; [&self.cursor_pos.1];
threads.vec_inner_sort_by( threads.vec_inner_sort_by(
&mut self.filtered_selection, &mut self.filtered_selection,
self.sort, self.sort,
&context.accounts[self.cursor_pos.0].collection.envelopes, &context.accounts[&self.cursor_pos.0].collection.envelopes,
); );
self.dirty = true; self.dirty = true;
} else { } else {
@ -1372,7 +1378,7 @@ impl Component for ConversationsListing {
} }
Action::ToggleThreadSnooze if !self.unfocused => { Action::ToggleThreadSnooze if !self.unfocused => {
let thread = self.get_thread_under_cursor(self.cursor_pos.2); 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 account
.collection .collection
.threads .threads
@ -1411,16 +1417,16 @@ impl Component for ConversationsListing {
} }
UIEvent::Action(ref action) => match action { UIEvent::Action(ref action) => match action {
Action::Listing(Search(ref filter_term)) if !self.unfocused => { 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, filter_term,
self.sort, self.sort,
self.cursor_pos.1, self.cursor_pos.1,
) { ) {
Ok(job) => { 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 .job_executor
.spawn_specialized(job); .spawn_specialized(job);
context.accounts[self.cursor_pos.0] context.accounts[&self.cursor_pos.0]
.active_jobs .active_jobs
.insert(job_id, crate::conf::accounts::JobRequest::Search(handle)); .insert(job_id, crate::conf::accounts::JobRequest::Search(handle));
self.search_job = Some((filter_term.to_string(), chan, job_id)); self.search_job = Some((filter_term.to_string(), chan, job_id));

View File

@ -24,7 +24,7 @@ use crate::components::utilities::PageMovement;
#[derive(Debug)] #[derive(Debug)]
pub struct OfflineListing { pub struct OfflineListing {
cursor_pos: (usize, MailboxHash), cursor_pos: (AccountHash, MailboxHash),
_row_updates: SmallVec<[ThreadHash; 8]>, _row_updates: SmallVec<[ThreadHash; 8]>,
_selection: HashMap<ThreadHash, bool>, _selection: HashMap<ThreadHash, bool>,
dirty: bool, dirty: bool,
@ -60,11 +60,11 @@ impl MailListingTrait for OfflineListing {
} }
impl ListingTrait for OfflineListing { impl ListingTrait for OfflineListing {
fn coordinates(&self) -> (usize, MailboxHash) { fn coordinates(&self) -> (AccountHash, MailboxHash) {
self.cursor_pos self.cursor_pos
} }
fn set_coordinates(&mut self, coordinates: (usize, MailboxHash)) { fn set_coordinates(&mut self, coordinates: (AccountHash, MailboxHash)) {
self.cursor_pos = coordinates; self.cursor_pos = coordinates;
} }
@ -89,7 +89,7 @@ impl fmt::Display for OfflineListing {
} }
impl OfflineListing { impl OfflineListing {
pub fn new(cursor_pos: (usize, MailboxHash)) -> Self { pub fn new(cursor_pos: (AccountHash, MailboxHash)) -> Self {
OfflineListing { OfflineListing {
cursor_pos, cursor_pos,
_row_updates: SmallVec::new(), _row_updates: SmallVec::new(),
@ -137,7 +137,7 @@ impl Component for OfflineListing {
area, area,
None, 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 .active_jobs
.iter() .iter()
.collect(); .collect();
@ -163,7 +163,9 @@ impl Component for OfflineListing {
} }
fn process_event(&mut self, event: &mut UIEvent, _context: &mut Context) -> bool { fn process_event(&mut self, event: &mut UIEvent, _context: &mut Context) -> bool {
match event { 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 false

View File

@ -47,8 +47,8 @@ macro_rules! address_list {
#[derive(Debug)] #[derive(Debug)]
pub struct PlainListing { pub struct PlainListing {
/// (x, y, z): x is accounts, y is mailboxes, z is index inside a mailbox. /// (x, y, z): x is accounts, y is mailboxes, z is index inside a mailbox.
cursor_pos: (usize, MailboxHash, usize), cursor_pos: (AccountHash, MailboxHash, usize),
new_cursor_pos: (usize, MailboxHash, usize), new_cursor_pos: (AccountHash, MailboxHash, usize),
length: usize, length: usize,
sort: (SortField, SortOrder), sort: (SortField, SortOrder),
subsort: (SortField, SortOrder), subsort: (SortField, SortOrder),
@ -148,7 +148,7 @@ impl MailListingTrait for PlainListing {
// Get mailbox as a reference. // 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(()) => {} Ok(()) => {}
Err(_) => { Err(_) => {
let default_cell = { let default_cell = {
@ -159,7 +159,7 @@ impl MailListingTrait for PlainListing {
ret ret
}; };
let message: String = 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] = self.data_columns.columns[0] =
CellBuffer::new_with_context(message.len(), 1, default_cell, context); CellBuffer::new_with_context(message.len(), 1, default_cell, context);
self.length = 0; self.length = 0;
@ -175,18 +175,18 @@ impl MailListingTrait for PlainListing {
return; return;
} }
} }
self.local_collection = context.accounts[self.cursor_pos.0] self.local_collection = context.accounts[&self.cursor_pos.0]
.collection .collection
.get_mailbox(self.cursor_pos.1) .get_mailbox(self.cursor_pos.1)
.iter() .iter()
.cloned() .cloned()
.collect(); .collect();
let env_lck = context.accounts[self.cursor_pos.0] let env_lck = context.accounts[&self.cursor_pos.0]
.collection .collection
.envelopes .envelopes
.read() .read()
.unwrap(); .unwrap();
self.thread_node_hashes = context.accounts[self.cursor_pos.0] self.thread_node_hashes = context.accounts[&self.cursor_pos.0]
.collection .collection
.get_mailbox(self.cursor_pos.1) .get_mailbox(self.cursor_pos.1)
.iter() .iter()
@ -240,7 +240,7 @@ impl MailListingTrait for PlainListing {
context: &Context, context: &Context,
items: Box<dyn Iterator<Item = ThreadHash>>, 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); let threads = account.collection.get_threads(self.cursor_pos.1);
let roots = items let roots = items
.filter_map(|r| threads.groups[&r].root().map(|r| r.root)) .filter_map(|r| threads.groups[&r].root().map(|r| r.root))
@ -262,11 +262,11 @@ impl MailListingTrait for PlainListing {
} }
impl ListingTrait 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) (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; self.unfocused = false;
self.view = MailView::default(); self.view = MailView::default();
@ -282,7 +282,7 @@ impl ListingTrait for PlainListing {
} }
let i = self.get_env_under_cursor(idx, context); 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 envelope: EnvelopeRef = account.collection.get_env(i);
let fg_color = if !envelope.is_seen() { let fg_color = if !envelope.is_seen() {
@ -616,7 +616,7 @@ impl ListingTrait for PlainListing {
*v = false; *v = false;
} }
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[&self.cursor_pos.0];
match results { match results {
Ok(results) => { Ok(results) => {
for env_hash in results { for env_hash in results {
@ -699,7 +699,7 @@ impl fmt::Display for PlainListing {
impl PlainListing { impl PlainListing {
const DESCRIPTION: &'static str = "plain listing"; const DESCRIPTION: &'static str = "plain listing";
pub fn new(coordinates: (usize, MailboxHash)) -> Self { pub fn new(coordinates: (AccountHash, MailboxHash)) -> Self {
PlainListing { PlainListing {
cursor_pos: (0, 1, 0), cursor_pos: (0, 1, 0),
new_cursor_pos: (coordinates.0, coordinates.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 { fn make_entry_string(&self, e: EnvelopeRef, context: &Context) -> EntryStrings {
let mut tags = String::new(); let mut tags = String::new();
let mut colors = SmallVec::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() { if let Some(t) = backend_lck.tags() {
let tags_lck = t.read().unwrap(); let tags_lck = t.read().unwrap();
for t in e.labels().iter() { for t in e.labels().iter() {
@ -773,7 +773,7 @@ impl PlainListing {
} }
fn redraw_list(&mut self, context: &Context, iter: Box<dyn Iterator<Item = EnvelopeHash>>) { fn redraw_list(&mut self, context: &Context, iter: Box<dyn Iterator<Item = EnvelopeHash>>) {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[&self.cursor_pos.0];
let mailbox = &account[&self.cursor_pos.1]; let mailbox = &account[&self.cursor_pos.1];
self.order.clear(); self.order.clear();
@ -783,18 +783,18 @@ impl PlainListing {
let mut min_width = (0, 0, 0, 0, 0); let mut min_width = (0, 0, 0, 0, 0);
for i in iter { 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!("key = {}", i);
debug!( debug!(
"name = {} {}", "name = {} {}",
mailbox.name(), mailbox.name(),
context.accounts[self.cursor_pos.0].name() context.accounts[&self.cursor_pos.0].name()
); );
debug!("{:#?}", context.accounts); debug!("{:#?}", context.accounts);
panic!(); 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; use melib::search::QueryTrait;
if let Some(filter_query) = mailbox_settings!( if let Some(filter_query) = mailbox_settings!(
context[self.cursor_pos.0][&self.cursor_pos.1] context[self.cursor_pos.0][&self.cursor_pos.1]
@ -858,19 +858,19 @@ impl PlainListing {
let columns = &mut self.data_columns.columns; let columns = &mut self.data_columns.columns;
for ((idx, i), strings) in iter.enumerate().zip(rows) { 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!("key = {}", i);
//debug!( //debug!(
// "name = {} {}", // "name = {} {}",
// mailbox.name(), // mailbox.name(),
// context.accounts[self.cursor_pos.0].name() // context.accounts[&self.cursor_pos.0].name()
//); //);
//debug!("{:#?}", context.accounts); //debug!("{:#?}", context.accounts);
panic!(); 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() { let row_attr = if !envelope.is_seen() {
if idx % 2 == 0 { if idx % 2 == 0 {
self.color_cache.even_unseen self.color_cache.even_unseen
@ -971,7 +971,7 @@ impl PlainListing {
for c in columns[4].row_iter(x..min_width.4, idx) { 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); 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 .collection
.get_env(i) .get_env(i)
.has_attachments() .has_attachments()
@ -1019,7 +1019,7 @@ impl PlainListing {
} }
fn perform_action(&mut self, context: &mut Context, env_hash: EnvelopeHash, a: &ListingAction) { 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 {
match a { match a {
ListingAction::SetSeen => account.backend.write().unwrap().set_flags( ListingAction::SetSeen => account.backend.write().unwrap().set_flags(
@ -1232,7 +1232,7 @@ impl Component for PlainListing {
self.set_dirty(true); self.set_dirty(true);
} }
UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => { 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) if !account.collection.contains_key(new_hash)
|| !account || !account
.collection .collection
@ -1257,11 +1257,13 @@ impl Component for PlainListing {
self.dirty = true; self.dirty = true;
self.view if self.unfocused {
.process_event(&mut UIEvent::EnvelopeRename(*old_hash, *new_hash), context); self.view
.process_event(&mut UIEvent::EnvelopeRename(*old_hash, *new_hash), context);
}
} }
UIEvent::EnvelopeUpdate(ref env_hash) => { 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) if !account.collection.contains_key(env_hash)
|| !account || !account
.collection .collection
@ -1274,8 +1276,10 @@ impl Component for PlainListing {
self.row_updates.push(*env_hash); self.row_updates.push(*env_hash);
self.dirty = true; self.dirty = true;
self.view if self.unfocused {
.process_event(&mut UIEvent::EnvelopeUpdate(*env_hash), context); self.view
.process_event(&mut UIEvent::EnvelopeUpdate(*env_hash), context);
}
} }
UIEvent::ChangeMode(UIMode::Normal) => { UIEvent::ChangeMode(UIMode::Normal) => {
self.dirty = true; self.dirty = true;
@ -1300,16 +1304,16 @@ impl Component for PlainListing {
return true; return true;
} }
UIEvent::Action(Action::Listing(Search(ref filter_term))) if !self.unfocused => { 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, filter_term,
self.sort, self.sort,
self.cursor_pos.1, self.cursor_pos.1,
) { ) {
Ok(job) => { 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 .job_executor
.spawn_specialized(job); .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)); .insert_job(job_id, crate::conf::accounts::JobRequest::Search(handle));
self.search_job = Some((filter_term.to_string(), chan, job_id)); self.search_job = Some((filter_term.to_string(), chan, job_id));
} }

View File

@ -105,8 +105,8 @@ macro_rules! row_attr {
#[derive(Debug)] #[derive(Debug)]
pub struct ThreadListing { pub struct ThreadListing {
/// (x, y, z): x is accounts, y is mailboxes, z is index inside a mailbox. /// (x, y, z): x is accounts, y is mailboxes, z is index inside a mailbox.
cursor_pos: (usize, MailboxHash, usize), cursor_pos: (AccountHash, MailboxHash, usize),
new_cursor_pos: (usize, MailboxHash, usize), new_cursor_pos: (AccountHash, MailboxHash, usize),
length: usize, length: usize,
sort: (SortField, SortOrder), sort: (SortField, SortOrder),
subsort: (SortField, SortOrder), subsort: (SortField, SortOrder),
@ -179,7 +179,7 @@ impl MailListingTrait for ThreadListing {
// Get mailbox as a reference. // 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(_) => {} Ok(_) => {}
Err(_) => { Err(_) => {
let default_cell = { let default_cell = {
@ -190,7 +190,7 @@ impl MailListingTrait for ThreadListing {
ret ret
}; };
let message: String = 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] = self.data_columns.columns[0] =
CellBuffer::new_with_context(message.len(), 1, default_cell, context); CellBuffer::new_with_context(message.len(), 1, default_cell, context);
self.length = 0; self.length = 0;
@ -206,14 +206,14 @@ impl MailListingTrait for ThreadListing {
return; return;
} }
} }
let threads = context.accounts[self.cursor_pos.0] let threads = context.accounts[&self.cursor_pos.0]
.collection .collection
.get_threads(self.cursor_pos.1); .get_threads(self.cursor_pos.1);
let mut roots = threads.roots(); let mut roots = threads.roots();
threads.group_inner_sort_by( threads.group_inner_sort_by(
&mut roots, &mut roots,
self.sort, self.sort,
&context.accounts[self.cursor_pos.0].collection.envelopes, &context.accounts[&self.cursor_pos.0].collection.envelopes,
); );
self.redraw_threads_list( self.redraw_threads_list(
@ -227,7 +227,7 @@ impl MailListingTrait for ThreadListing {
context: &Context, context: &Context,
items: Box<dyn Iterator<Item = ThreadHash>>, 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); let threads = account.collection.get_threads(self.cursor_pos.1);
self.length = 0; self.length = 0;
self.order.clear(); self.order.clear();
@ -414,10 +414,10 @@ impl MailListingTrait for ThreadListing {
} }
impl ListingTrait 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) (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; self.unfocused = false;
self.view = None; self.view = None;
@ -714,7 +714,7 @@ impl ListingTrait for ThreadListing {
} }
let env_hash = self.get_env_under_cursor(idx, context); 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 .collection
.get_env(env_hash); .get_env(env_hash);
@ -748,9 +748,9 @@ impl fmt::Display for ThreadListing {
} }
impl ThreadListing { impl ThreadListing {
pub fn new(coordinates: (usize, MailboxHash)) -> Self { pub fn new(coordinates: (AccountHash, MailboxHash)) -> Self {
ThreadListing { ThreadListing {
cursor_pos: (0, 1, 0), cursor_pos: (coordinates.0, 0, 0),
new_cursor_pos: (coordinates.0, coordinates.1, 0), new_cursor_pos: (coordinates.0, coordinates.1, 0),
length: 0, length: 0,
sort: (Default::default(), Default::default()), sort: (Default::default(), Default::default()),
@ -779,7 +779,7 @@ impl ThreadListing {
} }
let env_hash = self.get_env_under_cursor(idx, context); 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 .collection
.get_env(env_hash); .get_env(env_hash);
@ -850,7 +850,7 @@ impl ThreadListing {
fn make_entry_string(&self, e: &Envelope, context: &Context) -> EntryStrings { fn make_entry_string(&self, e: &Envelope, context: &Context) -> EntryStrings {
let mut tags = String::new(); let mut tags = String::new();
let mut colors: SmallVec<[_; 8]> = SmallVec::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() { if let Some(t) = backend_lck.tags() {
let tags_lck = t.read().unwrap(); let tags_lck = t.read().unwrap();
for t in e.labels().iter() { for t in e.labels().iter() {
@ -913,12 +913,12 @@ impl ThreadListing {
self.rows.iter().skip(start).take(end - start + 1) self.rows.iter().skip(start).take(end - start + 1)
{ {
let idx = *idx; 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!("key = {}", root_env_hash);
//debug!( //debug!(
// "name = {} {}", // "name = {} {}",
// account[&self.cursor_pos.1].name(), // account[&self.cursor_pos.1].name(),
// context.accounts[self.cursor_pos.0].name() // context.accounts[&self.cursor_pos.0].name()
//); //);
//debug!("{:#?}", context.accounts); //debug!("{:#?}", context.accounts);
@ -1109,7 +1109,7 @@ impl Component for ThreadListing {
if self.length == 0 { if self.length == 0 {
false false
} else { } else {
let account = &context.accounts[self.cursor_pos.0]; let account = &context.accounts[&self.cursor_pos.0];
let envelope: EnvelopeRef = account let envelope: EnvelopeRef = account
.collection .collection
.get_env(self.get_env_under_cursor(idx, context)); .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 = Some(MailView::new(coordinates, None, None, context));
} }
self.view.as_mut().unwrap().draw( if let Some(v) = self.view.as_mut() {
grid, v.draw(grid, (set_y(upper_left, mid + 1), bottom_right), context);
(set_y(upper_left, mid + 1), bottom_right), }
context,
);
self.dirty = false; self.dirty = false;
} }
@ -1207,7 +1205,7 @@ impl Component for ThreadListing {
self.set_dirty(true); self.set_dirty(true);
} }
UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => { 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) { if !account.collection.contains_key(&new_hash) {
return false; return false;
} }
@ -1219,9 +1217,14 @@ impl Component for ThreadListing {
self.dirty = true; self.dirty = true;
self.view.as_mut().map(|c| { if self.unfocused {
c.process_event(&mut UIEvent::EnvelopeRename(*old_hash, *new_hash), context) if let Some(v) = self.view.as_mut() {
}); v.process_event(
&mut UIEvent::EnvelopeRename(*old_hash, *new_hash),
context,
);
}
}
} }
UIEvent::EnvelopeRemove(ref env_hash, _) => { UIEvent::EnvelopeRemove(ref env_hash, _) => {
if self.order.contains_key(env_hash) { if self.order.contains_key(env_hash) {
@ -1230,7 +1233,7 @@ impl Component for ThreadListing {
} }
} }
UIEvent::EnvelopeUpdate(ref env_hash) => { 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) { if !account.collection.contains_key(env_hash) {
return false; return false;
} }
@ -1240,9 +1243,11 @@ impl Component for ThreadListing {
self.dirty = true; self.dirty = true;
self.view if self.unfocused {
.as_mut() if let Some(v) = self.view.as_mut() {
.map(|c| c.process_event(&mut UIEvent::EnvelopeUpdate(*env_hash), context)); v.process_event(&mut UIEvent::EnvelopeUpdate(*env_hash), context);
}
}
} }
UIEvent::ChangeMode(UIMode::Normal) => { UIEvent::ChangeMode(UIMode::Normal) => {
self.dirty = true; self.dirty = true;

View File

@ -271,7 +271,7 @@ impl StatusPanel {
Some(2), 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) { for x in 2..(120 - 1) {
set_and_join_box(&mut self.content, (x, 12 + i * 10), BoxBoundary::Horizontal); set_and_join_box(&mut self.content, (x, 12 + i * 10), BoxBoundary::Horizontal);
} }

View File

@ -90,7 +90,7 @@ impl ViewMode {
/// menus /// menus
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct MailView { pub struct MailView {
coordinates: (usize, MailboxHash, EnvelopeHash), coordinates: (AccountHash, MailboxHash, EnvelopeHash),
pager: Pager, pager: Pager,
subview: Option<Box<dyn Component>>, subview: Option<Box<dyn Component>>,
dirty: bool, dirty: bool,
@ -152,7 +152,7 @@ impl fmt::Display for MailView {
impl MailView { impl MailView {
const DESCRIPTION: &'static str = "view mail"; const DESCRIPTION: &'static str = "view mail";
pub fn new( pub fn new(
coordinates: (usize, MailboxHash, EnvelopeHash), coordinates: (AccountHash, MailboxHash, EnvelopeHash),
pager: Option<Pager>, pager: Option<Pager>,
subview: Option<Box<dyn Component>>, subview: Option<Box<dyn Component>>,
context: &mut Context, context: &mut Context,
@ -185,7 +185,7 @@ impl MailView {
fn init_futures(&mut self, context: &mut Context) { fn init_futures(&mut self, context: &mut Context) {
debug!("init_futures"); 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)) { if debug!(account.contains_key(self.coordinates.2)) {
{ {
match account match account
@ -372,7 +372,7 @@ impl MailView {
pub fn update( pub fn update(
&mut self, &mut self,
new_coordinates: (usize, MailboxHash, EnvelopeHash), new_coordinates: (AccountHash, MailboxHash, EnvelopeHash),
context: &mut Context, context: &mut Context,
) { ) {
self.coordinates = new_coordinates; self.coordinates = new_coordinates;
@ -553,7 +553,7 @@ impl Component for MailView {
let bottom_right = bottom_right!(area); let bottom_right = bottom_right!(area);
let y: usize = { let y: usize = {
let account = &context.accounts[self.coordinates.0]; let account = &context.accounts[&self.coordinates.0];
if !account.contains_key(self.coordinates.2) { if !account.contains_key(self.coordinates.2) {
/* The envelope has been renamed or removed, so wait for the appropriate event to /* The envelope has been renamed or removed, so wait for the appropriate event to
* arrive */ * arrive */
@ -966,7 +966,7 @@ impl Component for MailView {
if *id == s.id() => if *id == s.id() =>
{ {
if let Some(results) = results.downcast_ref::<Vec<Card>>() { if let Some(results) = results.downcast_ref::<Vec<Card>>() {
let account = &mut context.accounts[self.coordinates.0]; let account = &mut context.accounts[&self.coordinates.0];
{ {
for card in results.iter() { for card in results.iter() {
account.address_book.add_card(card.clone()); account.address_book.add_card(card.clone());
@ -1074,7 +1074,7 @@ impl Component for MailView {
key == shortcuts[MailView::DESCRIPTION]["add_addresses_to_contacts"] 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 envelope: EnvelopeRef = account.collection.get_env(self.coordinates.2);
let mut entries = Vec::new(); let mut entries = Vec::new();
@ -1285,7 +1285,7 @@ impl Component for MailView {
self.coordinates.2 = new_hash; self.coordinates.2 = new_hash;
} }
UIEvent::Action(View(ViewAction::SaveAttachment(a_i, ref path))) => { 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) { if !account.contains_key(self.coordinates.2) {
/* The envelope has been renamed or removed, so wait for the appropriate event to /* The envelope has been renamed or removed, so wait for the appropriate event to
* arrive */ * arrive */
@ -1445,7 +1445,7 @@ impl Component for MailView {
} }
} }
UIEvent::Action(MailingListAction(ref e)) => { 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) { if !account.contains_key(self.coordinates.2) {
/* The envelope has been renamed or removed, so wait for the appropriate event to /* The envelope has been renamed or removed, so wait for the appropriate event to
* arrive */ * arrive */

View File

@ -53,7 +53,7 @@ pub struct EnvelopeView {
mode: ViewMode, mode: ViewMode,
wrapper: EnvelopeWrapper, wrapper: EnvelopeWrapper,
account_pos: usize, account_hash: AccountHash,
cmd_buf: String, cmd_buf: String,
id: ComponentId, id: ComponentId,
} }
@ -70,7 +70,7 @@ impl EnvelopeView {
wrapper: EnvelopeWrapper, wrapper: EnvelopeWrapper,
pager: Option<Pager>, pager: Option<Pager>,
subview: Option<Box<dyn Component>>, subview: Option<Box<dyn Component>>,
account_pos: usize, account_hash: AccountHash,
) -> Self { ) -> Self {
EnvelopeView { EnvelopeView {
pager, pager,
@ -78,7 +78,7 @@ impl EnvelopeView {
dirty: true, dirty: true,
mode: ViewMode::Normal, mode: ViewMode::Normal,
wrapper, wrapper,
account_pos, account_hash,
cmd_buf: String::with_capacity(4), cmd_buf: String::with_capacity(4),
id: ComponentId::new_v4(), id: ComponentId::new_v4(),
} }

View File

@ -42,7 +42,7 @@ pub struct ThreadView {
expanded_pos: usize, expanded_pos: usize,
new_expanded_pos: usize, new_expanded_pos: usize,
reversed: bool, reversed: bool,
coordinates: (usize, MailboxHash, usize), coordinates: (AccountHash, MailboxHash, usize),
thread_group: ThreadHash, thread_group: ThreadHash,
mailview: MailView, mailview: MailView,
show_mailview: bool, show_mailview: bool,
@ -66,7 +66,7 @@ impl ThreadView {
* context: current context * context: current context
*/ */
pub fn new( pub fn new(
coordinates: (usize, MailboxHash, usize), coordinates: (AccountHash, MailboxHash, usize),
thread_group: ThreadHash, thread_group: ThreadHash,
expanded_hash: Option<ThreadNodeHash>, expanded_hash: Option<ThreadNodeHash>,
context: &Context, context: &Context,
@ -160,7 +160,7 @@ impl ThreadView {
} }
fn initiate(&mut self, expanded_hash: Option<ThreadNodeHash>, context: &Context) { fn initiate(&mut self, expanded_hash: Option<ThreadNodeHash>, 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); let threads = account.collection.get_threads(self.coordinates.1);
if !threads.groups.contains_key(&self.thread_group) { if !threads.groups.contains_key(&self.thread_group) {
@ -197,7 +197,7 @@ impl ThreadView {
let mut highlight_reply_subjects: Vec<Option<usize>> = let mut highlight_reply_subjects: Vec<Option<usize>> =
Vec::with_capacity(self.entries.len()); Vec::with_capacity(self.entries.len());
for e in &mut self.entries { for e in &mut self.entries {
let envelope: EnvelopeRef = context.accounts[self.coordinates.0] let envelope: EnvelopeRef = context.accounts[&self.coordinates.0]
.collection .collection
.get_env(e.msg_hash); .get_env(e.msg_hash);
let thread_node = &threads.thread_nodes()[&e.index.1]; let thread_node = &threads.thread_nodes()[&e.index.1];
@ -274,7 +274,7 @@ impl ThreadView {
None, None,
); );
{ {
let envelope: EnvelopeRef = context.accounts[self.coordinates.0] let envelope: EnvelopeRef = context.accounts[&self.coordinates.0]
.collection .collection
.get_env(e.msg_hash); .get_env(e.msg_hash);
if envelope.has_attachments() { if envelope.has_attachments() {
@ -357,7 +357,7 @@ impl ThreadView {
None, None,
); );
{ {
let envelope: EnvelopeRef = context.accounts[self.coordinates.0] let envelope: EnvelopeRef = context.accounts[&self.coordinates.0]
.collection .collection
.get_env(e.msg_hash); .get_env(e.msg_hash);
if envelope.has_attachments() { if envelope.has_attachments() {
@ -647,7 +647,7 @@ impl ThreadView {
/* First draw the thread subject on the first row */ /* First draw the thread subject on the first row */
let y = if self.dirty { let y = if self.dirty {
clear_area(grid, area, crate::conf::value(context, "theme_default")); 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 threads = account.collection.get_threads(self.coordinates.1);
let thread_root = threads let thread_root = threads
.thread_group_iter(self.thread_group) .thread_group_iter(self.thread_group)
@ -748,7 +748,7 @@ impl ThreadView {
/* First draw the thread subject on the first row */ /* First draw the thread subject on the first row */
let y = { let y = {
clear_area(grid, area, crate::conf::value(context, "theme_default")); 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 threads = account.collection.get_threads(self.coordinates.1);
let thread_root = threads let thread_root = threads
.thread_group_iter(self.thread_group) .thread_group_iter(self.thread_group)
@ -1103,7 +1103,7 @@ impl Component for ThreadView {
self.set_dirty(true); self.set_dirty(true);
} }
UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => { 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() { for e in self.entries.iter_mut() {
if e.msg_hash == *old_hash { if e.msg_hash == *old_hash {
e.msg_hash = *new_hash; e.msg_hash = *new_hash;
@ -1118,7 +1118,7 @@ impl Component for ThreadView {
.process_event(&mut UIEvent::EnvelopeRename(*old_hash, *new_hash), context); .process_event(&mut UIEvent::EnvelopeRename(*old_hash, *new_hash), context);
} }
UIEvent::EnvelopeUpdate(ref env_hash) => { 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() { for e in self.entries.iter_mut() {
if e.msg_hash == *env_hash { if e.msg_hash == *env_hash {
let seen: bool = account.collection.get_env(*env_hash).is_seen(); let seen: bool = account.collection.get_env(*env_hash).is_seen();

View File

@ -1666,8 +1666,8 @@ impl Component for Tabbed {
self.dirty = true; self.dirty = true;
return true; return true;
} }
UIEvent::Action(Tab(NewDraft(account_idx, ref draft))) => { UIEvent::Action(Tab(NewDraft(account_hash, ref draft))) => {
let mut composer = Composer::new(*account_idx, context); let mut composer = Composer::new(*account_hash, context);
if let Some(draft) = draft { if let Some(draft) = draft {
composer.set_draft(draft.clone()); composer.set_draft(draft.clone());
} }
@ -1692,8 +1692,8 @@ impl Component for Tabbed {
self.help_curr_views = children_maps; self.help_curr_views = children_maps;
return true; return true;
} }
UIEvent::Action(Tab(Edit(account_pos, msg))) => { UIEvent::Action(Tab(Edit(account_hash, msg))) => {
let composer = match Composer::edit(*account_pos, *msg, context) { let composer = match Composer::edit(*account_hash, *msg, context) {
Ok(c) => c, Ok(c) => c,
Err(e) => { Err(e) => {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
@ -1704,7 +1704,7 @@ impl Component for Tabbed {
log( log(
format!( format!(
"Failed to open envelope {}: {}", "Failed to open envelope {}: {}",
context.accounts[*account_pos] context.accounts[&*account_hash]
.collection .collection
.get_env(*msg) .get_env(*msg)
.message_id_display(), .message_id_display(),

View File

@ -62,6 +62,7 @@ use melib::error::*;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use indexmap::IndexMap;
use std::collections::HashMap; use std::collections::HashMap;
use std::env; use std::env;
use std::fs::OpenOptions; use std::fs::OpenOptions;
@ -78,8 +79,8 @@ macro_rules! split_command {
#[macro_export] #[macro_export]
macro_rules! mailbox_acc_settings { macro_rules! mailbox_acc_settings {
($context:ident[$account_idx:expr].$setting:ident.$field:ident) => {{ ($context:ident[$account_hash:expr].$setting:ident.$field:ident) => {{
$context.accounts[$account_idx] $context.accounts[&$account_hash]
.settings .settings
.conf_override .conf_override
.$setting .$setting
@ -90,14 +91,14 @@ macro_rules! mailbox_acc_settings {
} }
#[macro_export] #[macro_export]
macro_rules! mailbox_settings { macro_rules! mailbox_settings {
($context:ident[$account_idx:expr][$mailbox_path:expr].$setting:ident.$field:ident) => {{ ($context:ident[$account_hash:expr][$mailbox_path:expr].$setting:ident.$field:ident) => {{
$context.accounts[$account_idx][$mailbox_path] $context.accounts[&$account_hash][$mailbox_path]
.conf .conf
.conf_override .conf_override
.$setting .$setting
.$field .$field
.as_ref() .as_ref()
.or($context.accounts[$account_idx] .or($context.accounts[&$account_hash]
.settings .settings
.conf_override .conf_override
.$setting .$setting
@ -163,7 +164,7 @@ pub struct FileAccount {
#[serde(default)] #[serde(default)]
subscribed_mailboxes: Vec<String>, subscribed_mailboxes: Vec<String>,
#[serde(default)] #[serde(default)]
mailboxes: HashMap<String, FileMailboxConf>, mailboxes: IndexMap<String, FileMailboxConf>,
#[serde(default)] #[serde(default)]
search_backend: SearchBackend, search_backend: SearchBackend,
#[serde(default = "false_val")] #[serde(default = "false_val")]
@ -174,11 +175,11 @@ pub struct FileAccount {
pub conf_override: MailUIConf, pub conf_override: MailUIConf,
#[serde(flatten)] #[serde(flatten)]
#[serde(deserialize_with = "extra_settings")] #[serde(deserialize_with = "extra_settings")]
pub extra: HashMap<String, String>, /* use custom deserializer to convert any given value (eg bool, number, etc) to string */ pub extra: IndexMap<String, String>, /* use custom deserializer to convert any given value (eg bool, number, etc) to string */
} }
impl FileAccount { impl FileAccount {
pub fn mailboxes(&self) -> &HashMap<String, FileMailboxConf> { pub fn mailboxes(&self) -> &IndexMap<String, FileMailboxConf> {
&self.mailboxes &self.mailboxes
} }
@ -194,7 +195,7 @@ impl FileAccount {
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct FileSettings { pub struct FileSettings {
pub accounts: HashMap<String, FileAccount>, pub accounts: IndexMap<String, FileAccount>,
#[serde(default)] #[serde(default)]
pub pager: PagerSettings, pub pager: PagerSettings,
#[serde(default)] #[serde(default)]
@ -211,7 +212,7 @@ pub struct FileSettings {
#[serde(default)] #[serde(default)]
pub terminal: TerminalSettings, pub terminal: TerminalSettings,
#[serde(default)] #[serde(default)]
pub plugins: HashMap<String, Plugin>, pub plugins: IndexMap<String, Plugin>,
#[serde(default)] #[serde(default)]
pub log: LogSettings, pub log: LogSettings,
} }
@ -221,7 +222,7 @@ pub struct AccountConf {
pub account: AccountSettings, pub account: AccountSettings,
pub conf: FileAccount, pub conf: FileAccount,
pub conf_override: MailUIConf, pub conf_override: MailUIConf,
pub mailbox_confs: HashMap<String, FileMailboxConf>, pub mailbox_confs: IndexMap<String, FileMailboxConf>,
} }
impl AccountConf { impl AccountConf {
@ -261,7 +262,7 @@ impl From<FileAccount> for AccountConf {
subscribed_mailboxes: x.subscribed_mailboxes.clone(), subscribed_mailboxes: x.subscribed_mailboxes.clone(),
mailboxes, mailboxes,
manual_refresh: x.manual_refresh, manual_refresh: x.manual_refresh,
extra: x.extra.clone(), extra: x.extra.clone().into_iter().collect(),
}; };
let mailbox_confs = x.mailboxes.clone(); let mailbox_confs = x.mailboxes.clone();
@ -422,7 +423,7 @@ impl FileSettings {
.into_iter() .into_iter()
.map(|(k, v)| (k, v.mailbox_conf)) .map(|(k, v)| (k, v.mailbox_conf))
.collect(), .collect(),
extra, extra: extra.into_iter().collect(),
}; };
backends.validate_config(&lowercase_format, &s)?; backends.validate_config(&lowercase_format, &s)?;
} }
@ -433,7 +434,7 @@ impl FileSettings {
#[derive(Debug, Clone, Default, Serialize)] #[derive(Debug, Clone, Default, Serialize)]
pub struct Settings { pub struct Settings {
pub accounts: HashMap<String, AccountConf>, pub accounts: IndexMap<String, AccountConf>,
pub pager: PagerSettings, pub pager: PagerSettings,
pub listing: ListingSettings, pub listing: ListingSettings,
pub notifications: NotificationsSettings, pub notifications: NotificationsSettings,
@ -442,14 +443,14 @@ pub struct Settings {
pub composing: ComposingSettings, pub composing: ComposingSettings,
pub pgp: PGPSettings, pub pgp: PGPSettings,
pub terminal: TerminalSettings, pub terminal: TerminalSettings,
pub plugins: HashMap<String, Plugin>, pub plugins: IndexMap<String, Plugin>,
pub log: LogSettings, pub log: LogSettings,
} }
impl Settings { impl Settings {
pub fn new() -> Result<Settings> { pub fn new() -> Result<Settings> {
let fs = FileSettings::new()?; let fs = FileSettings::new()?;
let mut s: HashMap<String, AccountConf> = HashMap::new(); let mut s: IndexMap<String, AccountConf> = IndexMap::new();
for (id, x) in fs.accounts { for (id, x) in fs.accounts {
let mut ac = AccountConf::from(x); let mut ac = AccountConf::from(x);
@ -490,7 +491,7 @@ impl Settings {
} }
Ok(Settings { Ok(Settings {
accounts: HashMap::new(), accounts: IndexMap::new(),
pager: fs.pager, pager: fs.pager,
listing: fs.listing, listing: fs.listing,
notifications: fs.notifications, notifications: fs.notifications,
@ -583,10 +584,10 @@ mod deserializers {
Ok(ret) Ok(ret)
} }
use std::collections::HashMap; use indexmap::IndexMap;
pub(in crate::conf) fn extra_settings<'de, D>( pub(in crate::conf) fn extra_settings<'de, D>(
deserializer: D, deserializer: D,
) -> std::result::Result<HashMap<String, String>, D::Error> ) -> std::result::Result<IndexMap<String, String>, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@ -596,7 +597,7 @@ mod deserializers {
#[derive(Deserialize)] #[derive(Deserialize)]
struct Wrapper(#[serde(deserialize_with = "any_of")] String); struct Wrapper(#[serde(deserialize_with = "any_of")] String);
let v = <HashMap<String, Wrapper>>::deserialize(deserializer)?; let v = <IndexMap<String, Wrapper>>::deserialize(deserializer)?;
Ok(v.into_iter().map(|(k, Wrapper(v))| (k, v)).collect()) Ok(v.into_iter().map(|(k, Wrapper(v))| (k, v)).collect())
} }
} }
@ -869,6 +870,10 @@ mod dotaddressable {
for HashMap<K, V> for HashMap<K, V>
{ {
} }
impl<K: DotAddressable + std::cmp::Eq + std::hash::Hash, V: DotAddressable> DotAddressable
for IndexMap<K, V>
{
}
impl<K: DotAddressable + std::cmp::Eq + std::hash::Hash> DotAddressable for HashSet<K> {} impl<K: DotAddressable + std::cmp::Eq + std::hash::Hash> DotAddressable for HashSet<K> {}
impl DotAddressable for LogSettings { impl DotAddressable for LogSettings {

View File

@ -25,6 +25,7 @@
use super::{AccountConf, FileMailboxConf}; use super::{AccountConf, FileMailboxConf};
use crate::jobs::{JobChannel, JobExecutor, JobId, JoinHandle}; use crate::jobs::{JobChannel, JobExecutor, JobId, JoinHandle};
use indexmap::IndexMap;
use melib::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext}; use melib::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use melib::backends::*; use melib::backends::*;
use melib::email::*; use melib::email::*;
@ -141,12 +142,11 @@ impl MailboxEntry {
#[derive(Debug)] #[derive(Debug)]
pub struct Account { pub struct Account {
pub index: usize,
name: String, name: String,
hash: AccountHash, hash: AccountHash,
pub is_online: Result<()>, pub is_online: Result<()>,
pub last_online_request: std::time::Instant, pub last_online_request: std::time::Instant,
pub(crate) mailbox_entries: HashMap<MailboxHash, MailboxEntry>, pub(crate) mailbox_entries: IndexMap<MailboxHash, MailboxEntry>,
pub(crate) mailboxes_order: Vec<MailboxHash>, pub(crate) mailboxes_order: Vec<MailboxHash>,
tree: Vec<MailboxNode>, tree: Vec<MailboxNode>,
sent_mailbox: Option<MailboxHash>, sent_mailbox: Option<MailboxHash>,
@ -351,7 +351,6 @@ pub struct MailboxNode {
impl Account { impl Account {
pub fn new( pub fn new(
index: usize,
hash: AccountHash, hash: AccountHash,
name: String, name: String,
mut settings: AccountConf, mut settings: AccountConf,
@ -410,7 +409,6 @@ impl Account {
} }
} }
let mut ret = Account { let mut ret = Account {
index,
hash, hash,
name, name,
is_online: if !backend.capabilities().is_remote { is_online: if !backend.capabilities().is_remote {
@ -451,8 +449,8 @@ impl Account {
self.backend.read().unwrap().mailboxes()? self.backend.read().unwrap().mailboxes()?
}; };
self.backend_capabilities = self.backend.read().unwrap().capabilities(); self.backend_capabilities = self.backend.read().unwrap().capabilities();
let mut mailbox_entries: HashMap<MailboxHash, MailboxEntry> = let mut mailbox_entries: IndexMap<MailboxHash, MailboxEntry> =
HashMap::with_capacity_and_hasher(ref_mailboxes.len(), Default::default()); IndexMap::with_capacity_and_hasher(ref_mailboxes.len(), Default::default());
let mut mailboxes_order: Vec<MailboxHash> = Vec::with_capacity(ref_mailboxes.len()); let mut mailboxes_order: Vec<MailboxHash> = Vec::with_capacity(ref_mailboxes.len());
let mut sent_mailbox = None; let mut sent_mailbox = None;
@ -818,7 +816,7 @@ impl Account {
.ignore .ignore
.is_true() .is_true()
{ {
return Some(UIEvent::MailboxUpdate((self.index, mailbox_hash))); return Some(UIEvent::MailboxUpdate((self.hash, mailbox_hash)));
} }
let thread = { let thread = {
@ -833,10 +831,10 @@ impl Account {
.thread_ref(thread) .thread_ref(thread)
.snoozed() .snoozed()
{ {
return Some(UIEvent::MailboxUpdate((self.index, mailbox_hash))); return Some(UIEvent::MailboxUpdate((self.hash, mailbox_hash)));
} }
if is_seen || is_draft { if is_seen || is_draft {
return Some(UIEvent::MailboxUpdate((self.index, mailbox_hash))); return Some(UIEvent::MailboxUpdate((self.hash, mailbox_hash)));
} }
return Some(Notification( return Some(Notification(
@ -1201,7 +1199,7 @@ impl Account {
}); });
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate(( .send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate((
self.index, self.hash,
mailbox_hash, mailbox_hash,
)))) ))))
.unwrap(); .unwrap();
@ -1441,7 +1439,7 @@ impl Account {
)?; )?;
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::MailboxCreate(( .send(ThreadEvent::UIEvent(UIEvent::MailboxCreate((
self.index, self.hash,
mailbox_hash, mailbox_hash,
)))) ))))
.unwrap(); .unwrap();
@ -1515,7 +1513,7 @@ impl Account {
)?; )?;
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::MailboxDelete(( .send(ThreadEvent::UIEvent(UIEvent::MailboxDelete((
self.index, self.hash,
mailbox_hash, mailbox_hash,
)))) ))))
.unwrap(); .unwrap();
@ -1664,7 +1662,7 @@ impl Account {
} }
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::AccountStatusChange( .send(ThreadEvent::UIEvent(UIEvent::AccountStatusChange(
self.index, self.hash,
))) )))
.unwrap(); .unwrap();
} }
@ -1769,7 +1767,7 @@ impl Account {
}); });
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate(( .send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate((
self.index, self.hash,
mailbox_hash, mailbox_hash,
)))) ))))
.unwrap(); .unwrap();
@ -1802,7 +1800,7 @@ impl Account {
}); });
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate(( .send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate((
self.index, self.hash,
mailbox_hash, mailbox_hash,
)))) ))))
.unwrap(); .unwrap();
@ -1819,15 +1817,13 @@ impl Account {
{ {
for f in updated_mailboxes { for f in updated_mailboxes {
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate(( .send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate((self.hash, f))))
self.index, f,
))))
.unwrap(); .unwrap();
} }
} }
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate(( .send(ThreadEvent::UIEvent(UIEvent::MailboxUpdate((
self.index, self.hash,
mailbox_hash, mailbox_hash,
)))) ))))
.unwrap(); .unwrap();
@ -1837,7 +1833,7 @@ impl Account {
if let Some(is_online) = is_online { if let Some(is_online) = is_online {
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::AccountStatusChange( .send(ThreadEvent::UIEvent(UIEvent::AccountStatusChange(
self.index, self.hash,
))) )))
.unwrap(); .unwrap();
if is_online.is_ok() { if is_online.is_ok() {
@ -1893,7 +1889,7 @@ impl Account {
self.is_online = Ok(()); self.is_online = Ok(());
self.sender self.sender
.send(ThreadEvent::UIEvent(UIEvent::AccountStatusChange( .send(ThreadEvent::UIEvent(UIEvent::AccountStatusChange(
self.index, self.hash,
))) )))
.unwrap(); .unwrap();
} }
@ -2156,7 +2152,7 @@ impl IndexMut<&MailboxHash> for Account {
fn build_mailboxes_order( fn build_mailboxes_order(
tree: &mut Vec<MailboxNode>, tree: &mut Vec<MailboxNode>,
mailbox_entries: &HashMap<MailboxHash, MailboxEntry>, mailbox_entries: &IndexMap<MailboxHash, MailboxEntry>,
mailboxes_order: &mut Vec<MailboxHash>, mailboxes_order: &mut Vec<MailboxHash>,
) { ) {
tree.clear(); tree.clear();
@ -2165,7 +2161,7 @@ fn build_mailboxes_order(
if f.ref_mailbox.parent().is_none() { if f.ref_mailbox.parent().is_none() {
fn rec( fn rec(
h: MailboxHash, h: MailboxHash,
mailbox_entries: &HashMap<MailboxHash, MailboxEntry>, mailbox_entries: &IndexMap<MailboxHash, MailboxEntry>,
depth: usize, depth: usize,
) -> MailboxNode { ) -> MailboxNode {
let mut node = MailboxNode { let mut node = MailboxNode {

View File

@ -34,8 +34,8 @@ use melib::backends::{AccountHash, MailboxHash, NotifyFn};
use crate::jobs::JobExecutor; use crate::jobs::JobExecutor;
use crossbeam::channel::{unbounded, Receiver, Sender}; use crossbeam::channel::{unbounded, Receiver, Sender};
use indexmap::IndexMap;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::collections::HashMap;
use std::env; use std::env;
use std::io::Write; use std::io::Write;
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
@ -101,8 +101,7 @@ impl InputHandler {
/// A context container for loaded settings, accounts, UI changes, etc. /// A context container for loaded settings, accounts, UI changes, etc.
pub struct Context { pub struct Context {
pub accounts: Vec<Account>, pub accounts: IndexMap<AccountHash, Account>,
pub account_hashes: HashMap<AccountHash, usize>,
pub settings: Settings, pub settings: Settings,
pub runtime_settings: Settings, pub runtime_settings: Settings,
@ -135,7 +134,7 @@ impl Context {
self.input_thread.restore(); 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 { let Context {
ref mut accounts, ref mut accounts,
ref mut replies, ref mut replies,
@ -155,15 +154,20 @@ impl Context {
} }
accounts[account_pos].watch(); 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 { if ret.is_ok() != was_online {
replies.push_back(UIEvent::AccountStatusChange(account_pos)); replies.push_back(UIEvent::AccountStatusChange(accounts[account_pos].hash()));
} }
ret 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 { pub fn work_controller(&self) -> &WorkController {
&self.work_controller &self.work_controller
} }
@ -257,20 +261,13 @@ impl State {
let cols = termsize.0 as usize; let cols = termsize.0 as usize;
let rows = termsize.1 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 work_controller = WorkController::new(sender.clone());
let job_executor = Arc::new(JobExecutor::new(sender.clone())); let job_executor = Arc::new(JobExecutor::new(sender.clone()));
let accounts: Vec<Account> = { let accounts = {
let mut file_accs = settings settings
.accounts .accounts
.iter() .iter()
.collect::<Vec<(&String, &AccountConf)>>(); .map(|(n, a_s)| {
file_accs.sort_by(|a, b| a.0.cmp(&b.0));
file_accs
.into_iter()
.enumerate()
.map(|(index, (n, a_s))| {
let sender = sender.clone(); let sender = sender.clone();
let account_hash = { let account_hash = {
use std::collections::hash_map::DefaultHasher; use std::collections::hash_map::DefaultHasher;
@ -279,9 +276,7 @@ impl State {
hasher.write(n.as_bytes()); hasher.write(n.as_bytes());
hasher.finish() hasher.finish()
}; };
account_hashes.insert(account_hash, index);
Account::new( Account::new(
index,
account_hash, account_hash,
n.to_string(), n.to_string(),
a_s.clone(), a_s.clone(),
@ -301,6 +296,7 @@ impl State {
}) })
.collect::<Result<Vec<Account>>>()? .collect::<Result<Vec<Account>>>()?
}; };
let accounts = accounts.into_iter().map(|acc| (acc.hash(), acc)).collect();
let timer = { let timer = {
let sender = sender.clone(); let sender = sender.clone();
@ -343,7 +339,6 @@ impl State {
context: Context { context: Context {
accounts, accounts,
account_hashes,
settings: settings.clone(), settings: settings.clone(),
runtime_settings: settings, runtime_settings: settings,
dirty_areas: VecDeque::with_capacity(5), dirty_areas: VecDeque::with_capacity(5),
@ -378,7 +373,7 @@ impl State {
if !s.context.accounts[i].backend_capabilities.is_remote { if !s.context.accounts[i].backend_capabilities.is_remote {
s.context.accounts[i].watch(); 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!( //return Err(MeliError::new(format!(
// "Account {} has no mailboxes configured.", // "Account {} has no mailboxes configured.",
// s.context.accounts[i].name() // s.context.accounts[i].name()
@ -397,29 +392,30 @@ impl State {
pub fn refresh_event(&mut self, event: RefreshEvent) { pub fn refresh_event(&mut self, event: RefreshEvent) {
let account_hash = event.account_hash(); let account_hash = event.account_hash();
let mailbox_hash = event.mailbox_hash(); let mailbox_hash = event.mailbox_hash();
if let Some(&idxa) = self.context.account_hashes.get(&account_hash) { if self.context.accounts[&account_hash]
if self.context.accounts[idxa] .mailbox_entries
.mailbox_entries .contains_key(&mailbox_hash)
.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));
self.context.replies.push_back(UIEvent::from(event)); return;
return; }
} let Context {
let Context { ref mut accounts, ..
ref mut accounts, .. } = &mut self.context;
} = &mut self.context;
if let Some(notification) = accounts[idxa].reload(event, mailbox_hash) { if let Some(notification) = accounts[&account_hash].reload(event, mailbox_hash) {
if let UIEvent::Notification(_, _, _) = notification { if let UIEvent::Notification(_, _, _) = notification {
self.rcv_event(UIEvent::MailboxUpdate((idxa, mailbox_hash))); 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);
} }
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 if let Some(account) = self
.context .context
.accounts .accounts
.iter_mut() .values_mut()
.find(|a| a.name() == account_name) .find(|a| a.name() == account_name)
{ {
match account.mailbox_operation(op) { match account.mailbox_operation(op) {
@ -868,7 +864,7 @@ impl State {
.context .context
.accounts .accounts
.iter() .iter()
.position(|acc| acc.name() == account_name) .position(|(_, acc)| acc.name() == account_name)
{ {
a a
} else { } else {
@ -937,7 +933,7 @@ impl State {
.context .context
.accounts .accounts
.iter() .iter()
.position(|a| a.name() == account_name) .position(|(_h, a)| a.name() == account_name)
{ {
self.context.replies.push_back(UIEvent::StatusEvent( self.context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::UpdateStatus(format!( StatusEvent::UpdateStatus(format!(
@ -1033,9 +1029,7 @@ impl State {
return; return;
} }
UIEvent::WorkerProgress(account_hash, mailbox_hash) => { UIEvent::WorkerProgress(account_hash, mailbox_hash) => {
if let Some(&account_idx) = self.context.account_hashes.get(&account_hash) { let _ = self.context.accounts[&account_hash].load(mailbox_hash);
let _ = self.context.accounts[account_idx].load(mailbox_hash);
}
return; return;
} }
UIEvent::ChangeMode(m) => { UIEvent::ChangeMode(m) => {
@ -1169,7 +1163,7 @@ impl State {
pub fn check_accounts(&mut self) { pub fn check_accounts(&mut self) {
let mut ctr = 0; let mut ctr = 0;
for i in 0..self.context.accounts.len() { 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; ctr += 1;
} }
} }

View File

@ -114,10 +114,10 @@ pub enum UIEvent {
Notification(Option<String>, String, Option<NotificationType>), Notification(Option<String>, String, Option<NotificationType>),
Action(Action), Action(Action),
StatusEvent(StatusEvent), StatusEvent(StatusEvent),
MailboxUpdate((usize, MailboxHash)), // (account_idx, mailbox_idx) MailboxUpdate((AccountHash, MailboxHash)), // (account_idx, mailbox_idx)
MailboxDelete((usize, MailboxHash)), MailboxDelete((AccountHash, MailboxHash)),
MailboxCreate((usize, MailboxHash)), MailboxCreate((AccountHash, MailboxHash)),
AccountStatusChange(usize), AccountStatusChange(AccountHash),
ComponentKill(Uuid), ComponentKill(Uuid),
WorkerProgress(AccountHash, MailboxHash), WorkerProgress(AccountHash, MailboxHash),
StartupCheck(MailboxHash), StartupCheck(MailboxHash),