ui: Refer to child/parents with FolderHash in BackendFolder
- use a stack to build folder order list in conf/accounts.rs - update side menu printembed
parent
596194fa47
commit
1e44089d84
|
@ -239,12 +239,13 @@ pub trait BackendFolder: Debug {
|
||||||
fn name(&self) -> &str;
|
fn name(&self) -> &str;
|
||||||
fn change_name(&mut self, new_name: &str);
|
fn change_name(&mut self, new_name: &str);
|
||||||
fn clone(&self) -> Folder;
|
fn clone(&self) -> Folder;
|
||||||
fn children(&self) -> &Vec<usize>;
|
fn children(&self) -> &Vec<FolderHash>;
|
||||||
|
fn parent(&self) -> Option<FolderHash>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct DummyFolder {
|
struct DummyFolder {
|
||||||
v: Vec<usize>,
|
v: Vec<FolderHash>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BackendFolder for DummyFolder {
|
impl BackendFolder for DummyFolder {
|
||||||
|
@ -262,9 +263,13 @@ impl BackendFolder for DummyFolder {
|
||||||
folder_default()
|
folder_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children(&self) -> &Vec<usize> {
|
fn children(&self) -> &Vec<FolderHash> {
|
||||||
&self.v
|
&self.v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parent(&self) -> Option<FolderHash> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn folder_default() -> Folder {
|
pub fn folder_default() -> Folder {
|
||||||
|
|
|
@ -193,11 +193,17 @@ pub struct MaildirFolder {
|
||||||
hash: FolderHash,
|
hash: FolderHash,
|
||||||
name: String,
|
name: String,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
children: Vec<usize>,
|
parent: Option<FolderHash>,
|
||||||
|
children: Vec<FolderHash>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MaildirFolder {
|
impl MaildirFolder {
|
||||||
pub fn new(path: String, file_name: String, children: Vec<usize>) -> Result<Self> {
|
pub fn new(
|
||||||
|
path: String,
|
||||||
|
file_name: String,
|
||||||
|
parent: Option<FolderHash>,
|
||||||
|
children: Vec<FolderHash>,
|
||||||
|
) -> Result<Self> {
|
||||||
let pathbuf = PathBuf::from(path);
|
let pathbuf = PathBuf::from(path);
|
||||||
let mut h = DefaultHasher::new();
|
let mut h = DefaultHasher::new();
|
||||||
pathbuf.hash(&mut h);
|
pathbuf.hash(&mut h);
|
||||||
|
@ -206,6 +212,7 @@ impl MaildirFolder {
|
||||||
hash: h.finish(),
|
hash: h.finish(),
|
||||||
name: file_name,
|
name: file_name,
|
||||||
path: pathbuf,
|
path: pathbuf,
|
||||||
|
parent,
|
||||||
children,
|
children,
|
||||||
};
|
};
|
||||||
ret.is_valid()?;
|
ret.is_valid()?;
|
||||||
|
@ -243,7 +250,7 @@ impl BackendFolder for MaildirFolder {
|
||||||
self.name = s.to_string();
|
self.name = s.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children(&self) -> &Vec<usize> {
|
fn children(&self) -> &Vec<FolderHash> {
|
||||||
&self.children
|
&self.children
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +260,11 @@ impl BackendFolder for MaildirFolder {
|
||||||
name: self.name.clone(),
|
name: self.name.clone(),
|
||||||
path: self.path.clone(),
|
path: self.path.clone(),
|
||||||
children: self.children.clone(),
|
children: self.children.clone(),
|
||||||
|
parent: self.parent.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parent(&self) -> Option<FolderHash> {
|
||||||
|
self.parent.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ pub type HashIndexes = Arc<Mutex<FnvHashMap<FolderHash, HashIndex>>>;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MaildirType {
|
pub struct MaildirType {
|
||||||
name: String,
|
name: String,
|
||||||
folders: Vec<MaildirFolder>,
|
folders: FnvHashMap<FolderHash, MaildirFolder>,
|
||||||
//folder_index: FnvHashMap<FolderHash, usize>,
|
//folder_index: FnvHashMap<FolderHash, usize>,
|
||||||
hash_indexes: HashIndexes,
|
hash_indexes: HashIndexes,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
@ -144,7 +144,10 @@ fn move_to_cur(p: PathBuf) -> PathBuf {
|
||||||
|
|
||||||
impl MailBackend for MaildirType {
|
impl MailBackend for MaildirType {
|
||||||
fn folders(&self) -> FnvHashMap<FolderHash, Folder> {
|
fn folders(&self) -> FnvHashMap<FolderHash, Folder> {
|
||||||
self.folders.iter().map(|f| (f.hash(), f.clone())).collect()
|
self.folders
|
||||||
|
.iter()
|
||||||
|
.map(|(h, f)| (*h, f.clone() as Folder))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> {
|
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> {
|
||||||
self.multicore(4, folder)
|
self.multicore(4, folder)
|
||||||
|
@ -417,7 +420,7 @@ eprintln!("removed but not contained in index");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save(&self, bytes: &[u8], folder: &str) -> Result<()> {
|
fn save(&self, bytes: &[u8], folder: &str) -> Result<()> {
|
||||||
for f in &self.folders {
|
for f in self.folders.values() {
|
||||||
if f.name == folder {
|
if f.name == folder {
|
||||||
let mut path = f.path.clone();
|
let mut path = f.path.clone();
|
||||||
path.push("cur");
|
path.push("cur");
|
||||||
|
@ -464,25 +467,34 @@ eprintln!("removed but not contained in index");
|
||||||
|
|
||||||
impl MaildirType {
|
impl MaildirType {
|
||||||
pub fn new(f: &AccountSettings) -> Self {
|
pub fn new(f: &AccountSettings) -> Self {
|
||||||
let mut folders: Vec<MaildirFolder> = Vec::new();
|
let name = f.name.clone();
|
||||||
fn recurse_folders<P: AsRef<Path>>(folders: &mut Vec<MaildirFolder>, p: P) -> Vec<usize> {
|
let mut folders: FnvHashMap<FolderHash, MaildirFolder> = Default::default();
|
||||||
|
fn recurse_folders<P: AsRef<Path>>(
|
||||||
|
folders: &mut FnvHashMap<FolderHash, MaildirFolder>,
|
||||||
|
p: P,
|
||||||
|
) -> Vec<FolderHash> {
|
||||||
let mut children = Vec::new();
|
let mut children = Vec::new();
|
||||||
for mut f in fs::read_dir(p).unwrap() {
|
for mut f in fs::read_dir(p).unwrap() {
|
||||||
for f in f.iter_mut() {
|
'entries: for f in f.iter_mut() {
|
||||||
{
|
{
|
||||||
let path = f.path();
|
let path = f.path();
|
||||||
if path.ends_with("cur") || path.ends_with("new") || path.ends_with("tmp") {
|
if path.ends_with("cur") || path.ends_with("new") || path.ends_with("tmp") {
|
||||||
continue;
|
continue 'entries;
|
||||||
}
|
}
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
let path_children = recurse_folders(folders, &path);
|
let path_children = std::dbg!(recurse_folders(folders, &path));
|
||||||
if let Ok(f) = MaildirFolder::new(
|
if let Ok(f) = MaildirFolder::new(
|
||||||
path.to_str().unwrap().to_string(),
|
path.to_str().unwrap().to_string(),
|
||||||
path.file_name().unwrap().to_str().unwrap().to_string(),
|
path.file_name().unwrap().to_str().unwrap().to_string(),
|
||||||
|
None,
|
||||||
path_children,
|
path_children,
|
||||||
) {
|
) {
|
||||||
folders.push(f);
|
f.children
|
||||||
children.push(folders.len() - 1);
|
.iter()
|
||||||
|
.map(|c| folders.get_mut(c).map(|f| f.parent = Some(f.hash)))
|
||||||
|
.count();
|
||||||
|
children.push(f.hash);
|
||||||
|
folders.insert(f.hash, f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -495,18 +507,28 @@ impl MaildirType {
|
||||||
if let Ok(f) = MaildirFolder::new(
|
if let Ok(f) = MaildirFolder::new(
|
||||||
path.to_str().unwrap().to_string(),
|
path.to_str().unwrap().to_string(),
|
||||||
path.file_name().unwrap().to_str().unwrap().to_string(),
|
path.file_name().unwrap().to_str().unwrap().to_string(),
|
||||||
|
None,
|
||||||
Vec::with_capacity(0),
|
Vec::with_capacity(0),
|
||||||
) {
|
) {
|
||||||
if f.is_valid().is_ok() {
|
let l: MaildirFolder = f;
|
||||||
folders.push(f);
|
folders.insert(l.hash, l);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if folders.is_empty() {
|
if folders.is_empty() {
|
||||||
recurse_folders(&mut folders, &path);
|
let children = recurse_folders(&mut folders, &path);
|
||||||
|
children
|
||||||
|
.iter()
|
||||||
|
.map(|c| folders.get_mut(c).map(|f| f.parent = None))
|
||||||
|
.count();
|
||||||
} else {
|
} else {
|
||||||
folders[0].children = recurse_folders(&mut folders, &path);
|
let root_hash = *folders.keys().nth(0).unwrap();
|
||||||
|
let children = recurse_folders(&mut folders, &path);
|
||||||
|
children
|
||||||
|
.iter()
|
||||||
|
.map(|c| folders.get_mut(c).map(|f| f.parent = Some(root_hash)))
|
||||||
|
.count();
|
||||||
|
folders.get_mut(&root_hash).map(|f| f.children = children);
|
||||||
}
|
}
|
||||||
|
|
||||||
let hash_indexes = Arc::new(Mutex::new(FnvHashMap::with_capacity_and_hasher(
|
let hash_indexes = Arc::new(Mutex::new(FnvHashMap::with_capacity_and_hasher(
|
||||||
|
@ -515,12 +537,12 @@ impl MaildirType {
|
||||||
)));
|
)));
|
||||||
{
|
{
|
||||||
let mut hash_indexes = hash_indexes.lock().unwrap();
|
let mut hash_indexes = hash_indexes.lock().unwrap();
|
||||||
for f in &folders {
|
for &fh in folders.keys() {
|
||||||
hash_indexes.insert(
|
hash_indexes.insert(
|
||||||
f.hash(),
|
fh,
|
||||||
HashIndex {
|
HashIndex {
|
||||||
index: FnvHashMap::with_capacity_and_hasher(0, Default::default()),
|
index: FnvHashMap::with_capacity_and_hasher(0, Default::default()),
|
||||||
hash: f.hash(),
|
hash: fh,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -532,10 +554,10 @@ impl MaildirType {
|
||||||
path: PathBuf::from(f.root_folder()),
|
path: PathBuf::from(f.root_folder()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn owned_folder_idx(&self, folder: &Folder) -> usize {
|
fn owned_folder_idx(&self, folder: &Folder) -> FolderHash {
|
||||||
self.folders
|
*self
|
||||||
|
.folders
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
|
||||||
.find(|(_, f)| f.hash() == folder.hash())
|
.find(|(_, f)| f.hash() == folder.hash())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.0
|
.0
|
||||||
|
@ -548,7 +570,7 @@ impl MaildirType {
|
||||||
let handle = {
|
let handle = {
|
||||||
let tx = w.tx();
|
let tx = w.tx();
|
||||||
// TODO: Avoid clone
|
// TODO: Avoid clone
|
||||||
let folder: &MaildirFolder = &self.folders[self.owned_folder_idx(folder)];
|
let folder: &MaildirFolder = &self.folders[&self.owned_folder_idx(folder)];
|
||||||
let folder_hash = folder.hash();
|
let folder_hash = folder.hash();
|
||||||
let tx_final = w.tx();
|
let tx_final = w.tx();
|
||||||
let path: PathBuf = folder.path().into();
|
let path: PathBuf = folder.path().into();
|
||||||
|
|
|
@ -43,7 +43,6 @@ pub use contacts::*;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Debug, Display};
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
|
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
use super::*;
|
use super::*;
|
||||||
use melib::backends::Folder;
|
use melib::backends::Folder;
|
||||||
|
use melib::backends::FolderHash;
|
||||||
|
|
||||||
pub mod listing;
|
pub mod listing;
|
||||||
pub use listing::*;
|
pub use listing::*;
|
||||||
|
@ -91,35 +92,23 @@ impl AccountMenu {
|
||||||
eprintln!("BUG: invalid area in print_account");
|
eprintln!("BUG: invalid area in print_account");
|
||||||
}
|
}
|
||||||
// Each entry and its index in the account
|
// Each entry and its index in the account
|
||||||
let entries: Vec<(usize, Folder)> = {
|
let entries: FnvHashMap<FolderHash, Folder> = context.accounts[a.index]
|
||||||
let a = &context.accounts[a.index];
|
.list_folders()
|
||||||
let mut entries = Vec::with_capacity(a.len());
|
.into_iter()
|
||||||
for (idx, acc) in a.list_folders().into_iter().enumerate() {
|
.map(|f| (f.hash(), f))
|
||||||
entries.push((idx, acc));
|
.collect();
|
||||||
}
|
let folders_order: FnvHashMap<FolderHash, usize> = context.accounts[a.index]
|
||||||
entries
|
.folders_order()
|
||||||
};
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, &fh)| (fh, i))
|
||||||
|
.collect();
|
||||||
|
|
||||||
let upper_left = upper_left!(area);
|
let upper_left = upper_left!(area);
|
||||||
let bottom_right = bottom_right!(area);
|
let bottom_right = bottom_right!(area);
|
||||||
|
|
||||||
let highlight = self.cursor.map(|(x, _)| x == a.index).unwrap_or(false);
|
let highlight = self.cursor.map(|(x, _)| x == a.index).unwrap_or(false);
|
||||||
|
|
||||||
let mut parents: Vec<Option<usize>> = vec![None; entries.len()];
|
|
||||||
|
|
||||||
for (idx, e) in entries.iter().enumerate() {
|
|
||||||
for &c in e.1.children() {
|
|
||||||
if c < parents.len() {
|
|
||||||
parents[c] = Some(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut roots = Vec::new();
|
|
||||||
for (idx, c) in parents.iter().enumerate() {
|
|
||||||
if c.is_none() {
|
|
||||||
roots.push(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut inc = 0;
|
let mut inc = 0;
|
||||||
let mut depth = String::from("");
|
let mut depth = String::from("");
|
||||||
let mut s = format!("{}\n", a.name);
|
let mut s = format!("{}\n", a.name);
|
||||||
|
@ -133,50 +122,72 @@ impl AccountMenu {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print(
|
fn print(
|
||||||
root: usize,
|
folder_idx: FolderHash,
|
||||||
parents: &[Option<usize>],
|
|
||||||
depth: &mut String,
|
depth: &mut String,
|
||||||
entries: &[(usize, Folder)],
|
|
||||||
s: &mut String,
|
|
||||||
inc: &mut usize,
|
inc: &mut usize,
|
||||||
|
entries: &FnvHashMap<FolderHash, Folder>,
|
||||||
|
folders_order: &FnvHashMap<FolderHash, usize>,
|
||||||
|
s: &mut String,
|
||||||
index: usize, //account index
|
index: usize, //account index
|
||||||
context: &mut Context,
|
context: &mut Context,
|
||||||
) {
|
) {
|
||||||
if root >= entries.len() {
|
match context.accounts[index].status(entries[&folder_idx].hash()) {
|
||||||
return;
|
Ok(_) => {
|
||||||
}
|
let count = context.accounts[index][entries[&folder_idx].hash()]
|
||||||
let len = s.len();
|
.as_ref()
|
||||||
match context.accounts[index].status(entries[root].1.hash()) {
|
.unwrap()
|
||||||
Ok(_) => {}
|
.collection
|
||||||
|
.values()
|
||||||
|
.filter(|e| !e.is_seen())
|
||||||
|
.count();
|
||||||
|
let len = s.len();
|
||||||
|
s.insert_str(
|
||||||
|
len,
|
||||||
|
&format!("{} {} {}\n ", *inc, &entries[&folder_idx].name(), count),
|
||||||
|
);
|
||||||
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
return;
|
let len = s.len();
|
||||||
// TODO: Show progress visually
|
s.insert_str(
|
||||||
|
len,
|
||||||
|
&format!("{} {} ...\n ", *inc, &entries[&folder_idx].name()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let count = context.accounts[index][root]
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.collection
|
|
||||||
.values()
|
|
||||||
.filter(|e| !e.is_seen())
|
|
||||||
.count();
|
|
||||||
s.insert_str(
|
|
||||||
len,
|
|
||||||
&format!("{} {} {}\n ", *inc, &entries[root].1.name(), count),
|
|
||||||
);
|
|
||||||
*inc += 1;
|
*inc += 1;
|
||||||
for child in entries[root].1.children().iter() {
|
let mut children: Vec<FolderHash> = entries[&folder_idx].children().to_vec();
|
||||||
|
children
|
||||||
|
.sort_unstable_by(|a, b| folders_order[a].partial_cmp(&folders_order[b]).unwrap());
|
||||||
|
for child in entries[&folder_idx].children().iter() {
|
||||||
let len = s.len();
|
let len = s.len();
|
||||||
s.insert_str(len, &format!("{} ", depth));
|
s.insert_str(len, &format!("{} ", depth));
|
||||||
push(depth, ' ');
|
push(depth, ' ');
|
||||||
print(*child, parents, depth, entries, s, inc, index, context);
|
print(
|
||||||
|
*child,
|
||||||
|
depth,
|
||||||
|
inc,
|
||||||
|
entries,
|
||||||
|
folders_order,
|
||||||
|
s,
|
||||||
|
index,
|
||||||
|
context,
|
||||||
|
);
|
||||||
pop(depth);
|
pop(depth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for r in roots {
|
for f in entries.keys() {
|
||||||
print(
|
if entries[f].parent().is_none() {
|
||||||
r, &parents, &mut depth, &entries, &mut s, &mut inc, a.index, context,
|
print(
|
||||||
);
|
*f,
|
||||||
|
&mut depth,
|
||||||
|
&mut inc,
|
||||||
|
&entries,
|
||||||
|
&folders_order,
|
||||||
|
&mut s,
|
||||||
|
a.index,
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let lines: Vec<&str> = s.lines().collect();
|
let lines: Vec<&str> = s.lines().collect();
|
||||||
|
|
|
@ -54,63 +54,6 @@ pub struct ThreadView {
|
||||||
id: ComponentId,
|
id: ComponentId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct StackVec {
|
|
||||||
len: usize,
|
|
||||||
array: [usize; 8],
|
|
||||||
heap_vec: Vec<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StackVec {
|
|
||||||
fn new() -> Self {
|
|
||||||
StackVec {
|
|
||||||
len: 0,
|
|
||||||
array: [0, 0, 0, 0, 0, 0, 0, 0],
|
|
||||||
heap_vec: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn push(&mut self, ind: usize) {
|
|
||||||
if self.len == self.array.len() {
|
|
||||||
self.heap_vec.clear();
|
|
||||||
self.heap_vec.reserve(16);
|
|
||||||
self.heap_vec.copy_from_slice(&self.array);
|
|
||||||
self.heap_vec.push(ind);
|
|
||||||
} else if self.len > self.array.len() {
|
|
||||||
self.heap_vec.push(ind);
|
|
||||||
} else {
|
|
||||||
self.array[self.len] = ind;
|
|
||||||
}
|
|
||||||
self.len += 1;
|
|
||||||
}
|
|
||||||
fn pop(&mut self) -> usize {
|
|
||||||
if self.len >= self.array.len() {
|
|
||||||
self.heap_vec.pop().unwrap()
|
|
||||||
} else {
|
|
||||||
let ret = self.array[self.len];
|
|
||||||
self.len = self.len.saturating_sub(1);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.len
|
|
||||||
}
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.len == 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for StackVec {
|
|
||||||
type Output = usize;
|
|
||||||
|
|
||||||
fn index(&self, idx: usize) -> &usize {
|
|
||||||
if self.len >= self.array.len() {
|
|
||||||
&self.heap_vec[idx]
|
|
||||||
} else {
|
|
||||||
&self.array[idx]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ThreadView {
|
impl ThreadView {
|
||||||
/*
|
/*
|
||||||
* coordinates: (account index, mailbox index, root set thread_node index)
|
* coordinates: (account index, mailbox index, root set thread_node index)
|
||||||
|
@ -133,7 +76,8 @@ impl ThreadView {
|
||||||
cursor_pos: 1,
|
cursor_pos: 1,
|
||||||
new_cursor_pos: 0,
|
new_cursor_pos: 0,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
id: ComponentId::new_v4(), ..Default::default()
|
id: ComponentId::new_v4(),
|
||||||
|
..Default::default()
|
||||||
};
|
};
|
||||||
view.initiate(expanded_idx, context);
|
view.initiate(expanded_idx, context);
|
||||||
view.new_cursor_pos = view.new_expanded_pos;
|
view.new_cursor_pos = view.new_expanded_pos;
|
||||||
|
@ -875,7 +819,7 @@ impl Component for ThreadView {
|
||||||
.operation(envelope.hash(), mailbox.folder.hash());
|
.operation(envelope.hash(), mailbox.folder.hash());
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"sending action edit for {}, {}",
|
"sending action edit for {}, {}",
|
||||||
envelope.message_id(),
|
envelope.message_id(),
|
||||||
op.description()
|
op.description()
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use super::AccountConf;
|
use super::AccountConf;
|
||||||
|
use crate::StackVec;
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use melib::async_workers::{Async, AsyncBuilder, AsyncStatus};
|
use melib::async_workers::{Async, AsyncBuilder, AsyncStatus};
|
||||||
use melib::backends::FolderHash;
|
use melib::backends::FolderHash;
|
||||||
|
@ -69,7 +70,7 @@ pub struct Account {
|
||||||
|
|
||||||
pub(crate) settings: AccountConf,
|
pub(crate) settings: AccountConf,
|
||||||
pub(crate) runtime_settings: AccountConf,
|
pub(crate) runtime_settings: AccountConf,
|
||||||
pub(crate) backend: Box<MailBackend>,
|
pub(crate) backend: Box<dyn MailBackend>,
|
||||||
notify_fn: Arc<NotifyFn>,
|
notify_fn: Arc<NotifyFn>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,19 +129,10 @@ impl Account {
|
||||||
let mut ref_folders: FnvHashMap<FolderHash, Folder> = backend.folders();
|
let mut ref_folders: FnvHashMap<FolderHash, Folder> = backend.folders();
|
||||||
let mut folders: FnvHashMap<FolderHash, Option<Result<Mailbox>>> =
|
let mut folders: FnvHashMap<FolderHash, Option<Result<Mailbox>>> =
|
||||||
FnvHashMap::with_capacity_and_hasher(ref_folders.len(), Default::default());
|
FnvHashMap::with_capacity_and_hasher(ref_folders.len(), Default::default());
|
||||||
let mut folders_order: Vec<FolderHash> = ref_folders.values().map(|f| f.hash()).collect();
|
let mut folders_order: Vec<FolderHash> = Vec::with_capacity(folders.len());
|
||||||
let mut workers: FnvHashMap<FolderHash, Worker> = FnvHashMap::default();
|
let mut workers: FnvHashMap<FolderHash, Worker> = FnvHashMap::default();
|
||||||
let notify_fn = Arc::new(notify_fn);
|
let notify_fn = Arc::new(notify_fn);
|
||||||
|
|
||||||
if let Some(pos) = ref_folders
|
|
||||||
.values()
|
|
||||||
.position(|f| f.name().eq_ignore_ascii_case("INBOX"))
|
|
||||||
{
|
|
||||||
folders_order.swap(pos, 0);
|
|
||||||
}
|
|
||||||
let sent_folder = ref_folders
|
|
||||||
.values()
|
|
||||||
.position(|x: &Folder| x.name() == settings.account().sent_folder);
|
|
||||||
if let Some(folder_confs) = settings.conf().folders() {
|
if let Some(folder_confs) = settings.conf().folders() {
|
||||||
//if cfg!(debug_assertions) {
|
//if cfg!(debug_assertions) {
|
||||||
//eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
//eprint!("{}:{}_{}: ", file!(), line!(), column!());
|
||||||
|
@ -154,10 +146,28 @@ impl Account {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (h, f) in ref_folders.into_iter() {
|
let mut stack: StackVec<FolderHash> = StackVec::new();
|
||||||
folders.insert(h, None);
|
for (h, f) in ref_folders.iter() {
|
||||||
workers.insert(h, Account::new_worker(f, &mut backend, notify_fn.clone()));
|
if f.parent().is_none() {
|
||||||
|
folders_order.push(f.hash());
|
||||||
|
for &c in f.children() {
|
||||||
|
stack.push(c);
|
||||||
|
}
|
||||||
|
while !stack.is_empty() {
|
||||||
|
let next = stack.pop();
|
||||||
|
folders_order.push(next);
|
||||||
|
for c in ref_folders[&next].children() {
|
||||||
|
stack.push(*c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
folders.insert(*h, None);
|
||||||
|
workers.insert(
|
||||||
|
*h,
|
||||||
|
Account::new_worker(f.clone(), &mut backend, notify_fn.clone()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let data_dir = xdg::BaseDirectories::with_profile("meli", &name).unwrap();
|
let data_dir = xdg::BaseDirectories::with_profile("meli", &name).unwrap();
|
||||||
let address_book = if let Ok(data) = data_dir.place_data_file("addressbook") {
|
let address_book = if let Ok(data) = data_dir.place_data_file("addressbook") {
|
||||||
if data.exists() {
|
if data.exists() {
|
||||||
|
@ -180,7 +190,7 @@ impl Account {
|
||||||
folders,
|
folders,
|
||||||
folders_order,
|
folders_order,
|
||||||
address_book,
|
address_book,
|
||||||
sent_folder,
|
sent_folder: None,
|
||||||
workers,
|
workers,
|
||||||
settings: settings.clone(),
|
settings: settings.clone(),
|
||||||
runtime_settings: settings,
|
runtime_settings: settings,
|
||||||
|
@ -295,10 +305,18 @@ impl Account {
|
||||||
folders.swap(pos, 0);
|
folders.swap(pos, 0);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
self.folders_order
|
let order: FnvHashMap<FolderHash, usize> = self
|
||||||
|
.folders_order
|
||||||
.iter()
|
.iter()
|
||||||
.map(|ref h| folders.remove(&h).unwrap())
|
.enumerate()
|
||||||
.collect()
|
.map(|(i, &fh)| (fh, i))
|
||||||
|
.collect();
|
||||||
|
let mut folders: Vec<Folder> = folders.drain().map(|(_, f)| f).collect();
|
||||||
|
folders.sort_unstable_by(|a, b| order[&a.hash()].partial_cmp(&order[&b.hash()]).unwrap());
|
||||||
|
folders
|
||||||
|
}
|
||||||
|
pub fn folders_order(&self) -> &Vec<FolderHash> {
|
||||||
|
&self.folders_order
|
||||||
}
|
}
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
&self.name
|
&self.name
|
||||||
|
|
|
@ -31,6 +31,7 @@ use melib::EnvelopeHash;
|
||||||
use melib::RefreshEvent;
|
use melib::RefreshEvent;
|
||||||
use std;
|
use std;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::ops::Index;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
@ -128,3 +129,65 @@ pub struct Notification {
|
||||||
|
|
||||||
_timestamp: std::time::Instant,
|
_timestamp: std::time::Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct StackVec<T: Default + Copy + std::fmt::Debug> {
|
||||||
|
len: usize,
|
||||||
|
array: [T; 8],
|
||||||
|
heap_vec: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Default + Copy + std::fmt::Debug> StackVec<T> {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
StackVec {
|
||||||
|
len: 0,
|
||||||
|
array: [T::default(); 8],
|
||||||
|
heap_vec: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub(crate) fn push(&mut self, ind: T) {
|
||||||
|
if self.len == self.array.len() {
|
||||||
|
if self.heap_vec.is_empty() {
|
||||||
|
self.heap_vec.reserve(16);
|
||||||
|
for _ in 0..8 {
|
||||||
|
self.heap_vec.push(T::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.heap_vec[0..8].copy_from_slice(&self.array);
|
||||||
|
self.heap_vec.push(ind);
|
||||||
|
} else if self.len > self.array.len() {
|
||||||
|
self.heap_vec.push(ind);
|
||||||
|
} else {
|
||||||
|
self.array[self.len] = ind;
|
||||||
|
}
|
||||||
|
self.len += 1;
|
||||||
|
}
|
||||||
|
pub(crate) fn pop(&mut self) -> T {
|
||||||
|
if self.len >= self.array.len() {
|
||||||
|
self.len -= 1;
|
||||||
|
self.heap_vec.pop().unwrap()
|
||||||
|
} else {
|
||||||
|
let ret = self.array[self.len - 1];
|
||||||
|
self.len = self.len - 1;
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub(crate) fn len(&self) -> usize {
|
||||||
|
self.len
|
||||||
|
}
|
||||||
|
pub(crate) fn is_empty(&self) -> bool {
|
||||||
|
self.len == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Default + Copy + std::fmt::Debug> Index<usize> for StackVec<T> {
|
||||||
|
type Output = T;
|
||||||
|
|
||||||
|
fn index(&self, idx: usize) -> &T {
|
||||||
|
if self.len >= self.array.len() {
|
||||||
|
&self.heap_vec[idx]
|
||||||
|
} else {
|
||||||
|
&self.array[idx]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue