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 = [
"autocfg",
"hashbrown",
"serde",
]
[[package]]
@ -902,6 +903,7 @@ dependencies = [
"bitflags",
"crossbeam",
"futures",
"indexmap",
"libc",
"linkify",
"melib",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -271,7 +271,7 @@ impl StatusPanel {
Some(2),
);
for (i, a) in context.accounts.iter().enumerate() {
for (i, (_h, a)) in context.accounts.iter().enumerate() {
for x in 2..(120 - 1) {
set_and_join_box(&mut self.content, (x, 12 + i * 10), BoxBoundary::Horizontal);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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