From 2b6d1e0dbf47750ee4377d532fb6b38496e4b336 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Thu, 23 Aug 2018 15:36:52 +0300 Subject: [PATCH] Run clippy lints --- melib/src/async.rs | 8 +- melib/src/mailbox/backends/maildir.rs | 177 ++++++++------- melib/src/mailbox/backends/mod.rs | 6 + melib/src/mailbox/email/attachment_types.rs | 28 ++- melib/src/mailbox/email/attachments.rs | 127 ++++++----- melib/src/mailbox/email/mod.rs | 59 +++-- melib/src/mailbox/email/parser.rs | 44 ++-- melib/src/mailbox/mod.rs | 9 +- melib/src/mailbox/thread.rs | 225 +++++++++++--------- scripts/pre-commit | 3 +- src/bin.rs | 2 - ui/src/components/mail/compose.rs | 22 +- ui/src/components/mail/listing/compact.rs | 42 ++-- ui/src/components/mail/listing/mod.rs | 29 ++- ui/src/components/mail/mod.rs | 4 +- ui/src/components/mail/view/envelope.rs | 83 +++++--- ui/src/components/mail/view/html.rs | 45 ++-- ui/src/components/mail/view/mod.rs | 91 ++++---- ui/src/components/mail/view/thread.rs | 121 +++++++---- ui/src/components/mod.rs | 31 ++- ui/src/components/utilities.rs | 60 +++--- ui/src/conf/mod.rs | 11 +- ui/src/execute/actions.rs | 3 +- ui/src/state.rs | 69 +++--- ui/src/types/accounts.rs | 184 +++++++++++----- ui/src/types/cells.rs | 19 +- ui/src/types/helpers.rs | 9 +- ui/src/types/mod.rs | 2 +- ui/src/types/position.rs | 2 +- 29 files changed, 860 insertions(+), 655 deletions(-) mode change 100644 => 100755 scripts/pre-commit diff --git a/melib/src/async.rs b/melib/src/async.rs index b9ba191f..627ed6bd 100644 --- a/melib/src/async.rs +++ b/melib/src/async.rs @@ -58,6 +58,12 @@ pub struct Async { rx: chan::Receiver, } +impl Default for AsyncBuilder { + fn default() -> Self { + AsyncBuilder::new() + } +} + impl AsyncBuilder { pub fn new() -> Self { let (sender, receiver) = chan::sync(::std::mem::size_of::()); @@ -117,6 +123,6 @@ impl Async { } let v = self.worker.take().unwrap().join().unwrap(); self.value = Some(v); - return Ok(AsyncStatus::Finished); + Ok(AsyncStatus::Finished) } } diff --git a/melib/src/mailbox/backends/maildir.rs b/melib/src/mailbox/backends/maildir.rs index 2863ca89..a045d267 100644 --- a/melib/src/mailbox/backends/maildir.rs +++ b/melib/src/mailbox/backends/maildir.rs @@ -19,15 +19,14 @@ * along with meli. If not, see . */ -extern crate xdg; extern crate bincode; +extern crate xdg; use async::*; use conf::AccountSettings; use error::{MeliError, Result}; use mailbox::backends::{ - BackendFolder, BackendOp, Folder, MailBackend, RefreshEvent, - RefreshEventConsumer, + BackendFolder, BackendOp, Folder, MailBackend, RefreshEvent, RefreshEventConsumer, }; use mailbox::email::parser; use mailbox::email::{Envelope, Flag}; @@ -46,11 +45,11 @@ extern crate crossbeam; use memmap::{Mmap, Protection}; use std::collections::hash_map::DefaultHasher; use std::fs; +use std::hash::{Hash, Hasher}; use std::io; use std::io::Read; -use std::sync::{Mutex, Arc}; -use std::hash::{Hasher, Hash}; use std::path::{Path, PathBuf}; +use std::sync::{Arc, Mutex}; extern crate fnv; use self::fnv::FnvHashMap; @@ -66,7 +65,7 @@ impl Clone for MaildirOp { fn clone(&self) -> Self { MaildirOp { hash_index: self.hash_index.clone(), - hash: self.hash.clone(), + hash: self.hash, slice: None, } } @@ -89,7 +88,7 @@ impl MaildirOp { impl<'a> BackendOp for MaildirOp { fn description(&self) -> String { - format!("Path of file:")// self.0ipath) + format!("Path of file: {}", self.path()) } fn as_bytes(&mut self) -> Result<&[u8]> { if self.slice.is_none() { @@ -133,10 +132,10 @@ impl<'a> BackendOp for MaildirOp { fn set_flag(&mut self, envelope: &mut Envelope, f: &Flag) -> Result<()> { let path = self.path(); - let idx: usize = path.rfind(":2,").ok_or(MeliError::new(format!( - "Invalid email filename: {:?}", - self - )))? + 3; + let idx: usize = path + .rfind(":2,") + .ok_or_else(|| MeliError::new(format!("Invalid email filename: {:?}", self)))? + + 3; let mut new_name: String = path[..idx].to_string(); let mut flags = self.fetch_flags(); if !(flags & *f).is_empty() { @@ -212,24 +211,24 @@ impl MailBackend for MaildirType { match rx.recv() { Ok(event) => match event { DebouncedEvent::Create(mut pathbuf) - | DebouncedEvent::Remove(mut pathbuf) => { - if pathbuf.is_dir() { - if pathbuf.ends_with("cur") | pathbuf.ends_with("new") { - pathbuf.pop(); - } - } else { + | DebouncedEvent::Remove(mut pathbuf) => { + if pathbuf.is_dir() { + if pathbuf.ends_with("cur") | pathbuf.ends_with("new") { pathbuf.pop(); - pathbuf.pop(); - }; - eprintln!(" got event in {}", pathbuf.display()); + } + } else { + pathbuf.pop(); + pathbuf.pop(); + }; + eprintln!(" got event in {}", pathbuf.display()); - let mut hasher = DefaultHasher::new(); - pathbuf.hash(&mut hasher); - sender.send(RefreshEvent { - folder: format!("{}", pathbuf.display()), - hash: hasher.finish(), - }); - } + let mut hasher = DefaultHasher::new(); + pathbuf.hash(&mut hasher); + sender.send(RefreshEvent { + folder: format!("{}", pathbuf.display()), + hash: hasher.finish(), + }); + } _ => {} }, Err(e) => eprintln!("watch error: {:?}", e), @@ -261,7 +260,7 @@ impl MaildirType { path.to_str().unwrap().to_string(), path.file_name().unwrap().to_str().unwrap().to_string(), path_children, - ) { + ) { folders.push(f); children.push(folders.len() - 1); } @@ -277,7 +276,7 @@ impl MaildirType { path.to_str().unwrap().to_string(), path.file_name().unwrap().to_str().unwrap().to_string(), Vec::with_capacity(0), - ) { + ) { folders.push(f); } } @@ -285,7 +284,10 @@ impl MaildirType { MaildirType { name: f.name().to_string(), folders, - hash_index: Arc::new(Mutex::new(FnvHashMap::with_capacity_and_hasher(0, Default::default()))), + hash_index: Arc::new(Mutex::new(FnvHashMap::with_capacity_and_hasher( + 0, + Default::default(), + ))), path: f.root_folder().to_string(), } } @@ -342,28 +344,33 @@ impl MaildirType { let s = scope.builder().name(name.clone()).spawn(move || { let len = chunk.len(); let size = if len <= 100 { 100 } else { (len / 100) * 100 }; - let mut local_r: Vec = Vec::with_capacity(chunk.len()); + let mut local_r: Vec< + Envelope, + > = Vec::with_capacity(chunk.len()); for c in chunk.chunks(size) { let map = map.clone(); let len = c.len(); for file in c { - let ri = file.rfind("/").unwrap() + 1; + let ri = file.rfind('/').unwrap() + 1; let file_name = &file[ri..]; - if let Some(cached) = cache_dir.find_cache_file(file_name) { + if let Some(cached) = + cache_dir.find_cache_file(file_name) + { // TODO:: error checking - let reader = io::BufReader::new(fs::File::open(cached).unwrap()); + let reader = io::BufReader::new( + fs::File::open(cached).unwrap(), + ); let env: Envelope = bincode::deserialize_from(reader).unwrap(); - { - let mut map = map.lock().unwrap(); - let hash = env.hash(); - if (*map).contains_key(&hash) { - continue; - } - (*map).insert(hash, (0, file.to_string())); - local_r.push(env); + { + let mut map = map.lock().unwrap(); + let hash = env.hash(); + if (*map).contains_key(&hash) { continue; } - + (*map).insert(hash, (0, file.to_string())); + local_r.push(env); + continue; + } } let e_copy = file.to_string(); /* @@ -376,41 +383,48 @@ impl MaildirType { */ { let mut hasher = DefaultHasher::new(); - let hash = { - let mut buf = Vec::new(); - let mut f = fs::File::open(&e_copy).expect(&format!("Can't open {}", e_copy)); - f.read_to_end(&mut buf).expect(&format!("Can't read {}", e_copy)); - /* Unwrap is safe since we use ? above. */ - hasher.write(&buf); - hasher.finish() - }; - { - let mut map = map.lock().unwrap(); - if (*map).contains_key(&hash) { - continue; - } - (*map).insert(hash, (0, e_copy)); - } - // TODO: Check cache - let op = Box::new(MaildirOp::new(hash, map.clone())); - if let Some(mut e) = Envelope::from_token(op, hash) { - if let Ok(cached) = cache_dir.place_cache_file(file_name) { - let f = match fs::File::create(cached) { - Ok(f) => f, - Err(e) => { - panic!("{}",e); - } + let hash = { + let mut buf = Vec::new(); + let mut f = fs::File::open(&e_copy) + .unwrap_or_else(|_| { + panic!("Can't open {}", e_copy) + }); + f.read_to_end(&mut buf).unwrap_or_else(|_| { + panic!("Can't read {}", e_copy) + }); + /* Unwrap is safe since we use ? above. */ + hasher.write(&buf); + hasher.finish() }; - let writer = io::BufWriter::new(f); - bincode::serialize_into(writer, &e).unwrap(); - } - local_r.push(e); - - - } else { + { + let mut map = map.lock().unwrap(); + if (*map).contains_key(&hash) { continue; } - + (*map).insert(hash, (0, e_copy)); + } + // TODO: Check cache + let op = + Box::new(MaildirOp::new(hash, map.clone())); + if let Some(mut e) = Envelope::from_token(op, hash) + { + if let Ok(cached) = + cache_dir.place_cache_file(file_name) + { + let f = match fs::File::create(cached) { + Ok(f) => f, + Err(e) => { + panic!("{}", e); + } + }; + let writer = io::BufWriter::new(f); + bincode::serialize_into(writer, &e) + .unwrap(); + } + local_r.push(e); + } else { + continue; + } } } tx.send(AsyncStatus::ProgressReport(len)); @@ -429,16 +443,15 @@ impl MaildirType { for (idx, e) in r.iter().enumerate() { let mut y = (*map)[&e.hash()].clone(); y.0 = idx; - (*map).insert(e.hash(),y); + (*map).insert(e.hash(), y); } tx.send(AsyncStatus::Finished); Ok(r) }) - .unwrap() + .unwrap() }; w.build(handle) } - } #[derive(Debug, Default)] @@ -459,7 +472,7 @@ impl MaildirFolder { hash: h.finish(), name: file_name, path: pathbuf, - children: children, + children, }; ret.is_valid()?; Ok(ret) @@ -474,9 +487,9 @@ impl MaildirFolder { p.push(d); if !p.is_dir() { return Err(MeliError::new(format!( - "{} is not a valid maildir folder", - path.display() - ))); + "{} is not a valid maildir folder", + path.display() + ))); } p.pop(); } diff --git a/melib/src/mailbox/backends/mod.rs b/melib/src/mailbox/backends/mod.rs index 31f93c9c..bd3205c7 100644 --- a/melib/src/mailbox/backends/mod.rs +++ b/melib/src/mailbox/backends/mod.rs @@ -44,6 +44,12 @@ pub struct Backends { map: FnvHashMap BackendCreator>>, } +impl Default for Backends { + fn default() -> Self { + Backends::new() + } +} + impl Backends { pub fn new() -> Self { let mut b = Backends { diff --git a/melib/src/mailbox/email/attachment_types.rs b/melib/src/mailbox/email/attachment_types.rs index d4c3c770..e4946955 100644 --- a/melib/src/mailbox/email/attachment_types.rs +++ b/melib/src/mailbox/email/attachment_types.rs @@ -1,5 +1,5 @@ -use mailbox::email::parser::BytesExt; use mailbox::email::attachments::Attachment; +use mailbox::email::parser::BytesExt; use std::fmt::{Display, Formatter, Result as FmtResult}; use std::str; @@ -20,13 +20,11 @@ impl SliceBuild { //fn length(&self) -> usize { // self.end - self.offset + 1 //} - pub fn get<'a>(&self, slice:&'a [u8]) -> &'a [u8] { + pub fn get<'a>(&self, slice: &'a [u8]) -> &'a [u8] { &slice[self.offset..self.end] } } - - #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub enum Charset { Ascii, @@ -72,7 +70,7 @@ impl<'a> From<&'a [u8]> for Charset { _ => { eprintln!("unknown tag is {:?}", str::from_utf8(b)); Charset::Ascii - }, + } } } } @@ -102,10 +100,19 @@ impl Display for MultipartType { #[derive(Clone, Debug, Serialize, Deserialize)] pub enum ContentType { - Text { kind: Text, charset: Charset }, - Multipart { boundary: SliceBuild, kind: MultipartType, subattachments: Vec}, + Text { + kind: Text, + charset: Charset, + }, + Multipart { + boundary: SliceBuild, + kind: MultipartType, + subattachments: Vec, + }, MessageRfc822, - Unsupported { tag: Vec }, + Unsupported { + tag: Vec, + }, } impl Default for ContentType { @@ -137,7 +144,10 @@ impl ContentType { } } pub fn is_text_html(&self) -> bool { - if let ContentType::Text { kind: Text::Html, .. } = self { + if let ContentType::Text { + kind: Text::Html, .. + } = self + { true } else { false diff --git a/melib/src/mailbox/email/attachments.rs b/melib/src/mailbox/email/attachments.rs index e050c72a..6ce3d13b 100644 --- a/melib/src/mailbox/email/attachments.rs +++ b/melib/src/mailbox/email/attachments.rs @@ -19,9 +19,9 @@ * along with meli. If not, see . */ use data_encoding::BASE64_MIME; -use mailbox::email::EnvelopeWrapper; use mailbox::email::parser; use mailbox::email::parser::BytesExt; +use mailbox::email::EnvelopeWrapper; use std::fmt; use std::str; @@ -84,7 +84,7 @@ impl AttachmentBuilder { let offset = (_boundary.as_ptr() as usize).wrapping_sub(value.as_ptr() as usize); let boundary = SliceBuild::new(offset, _boundary.len()); let subattachments = Self::subattachments(&self.raw, boundary.get(&value)); - assert!(subattachments.len() > 0); + assert!(!subattachments.is_empty()); self.content_type = ContentType::Multipart { boundary, kind: if cst.eq_ignore_ascii_case(b"mixed") { @@ -96,7 +96,7 @@ impl AttachmentBuilder { } else { Default::default() }, - subattachments + subattachments, }; } else if ct.eq_ignore_ascii_case(b"text") { self.content_type = ContentType::Text { @@ -105,28 +105,28 @@ impl AttachmentBuilder { }; for (n, v) in params { if n.eq_ignore_ascii_case(b"charset") { - match self.content_type { - ContentType::Text { charset: ref mut c, .. } => { - *c = Charset::from(v); - }, - _ => {}, + if let ContentType::Text { + charset: ref mut c, .. + } = self.content_type + { + *c = Charset::from(v); } - break; + break; } } if cst.eq_ignore_ascii_case(b"html") { - match self.content_type { - ContentType::Text { kind: ref mut k, .. } => { - *k = Text::Html; - }, - _ => {}, + if let ContentType::Text { + kind: ref mut k, .. + } = self.content_type + { + *k = Text::Html; } } else if !cst.eq_ignore_ascii_case(b"plain") { - match self.content_type { - ContentType::Text { kind: ref mut k, .. } => { - *k = Text::Other { tag: cst.into() }; - }, - _ => {}, + if let ContentType::Text { + kind: ref mut k, .. + } = self.content_type + { + *k = Text::Other { tag: cst.into() }; } } } else if ct.eq_ignore_ascii_case(b"message") && cst.eq_ignore_ascii_case(b"rfc822") { @@ -136,9 +136,7 @@ impl AttachmentBuilder { tag.extend(ct); tag.push(b'/'); tag.extend(cst); - self.content_type = ContentType::Unsupported { - tag - }; + self.content_type = ContentType::Unsupported { tag }; }, Err(v) => { eprintln!("parsing error in content_type: {:?} {:?}", value, v); @@ -197,8 +195,7 @@ impl AttachmentBuilder { } pub fn subattachments(raw: &[u8], boundary: &[u8]) -> Vec { - match parser::attachments(raw, boundary).to_full_result() - { + match parser::attachments(raw, boundary).to_full_result() { Ok(attachments) => { let mut vec = Vec::with_capacity(attachments.len()); for a in attachments { @@ -246,37 +243,29 @@ impl AttachmentBuilder { impl fmt::Display for Attachment { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.content_type { - ContentType::MessageRfc822 => { - match EnvelopeWrapper::new(self.bytes().to_vec()) { - Ok(wrapper) => write!(f, "message/rfc822: {} - {} - {}", wrapper.date(), wrapper.from_to_string(), wrapper.subject()), - Err(e) => write!(f, "{}", e), - } + ContentType::MessageRfc822 => match EnvelopeWrapper::new(self.bytes().to_vec()) { + Ok(wrapper) => write!( + f, + "message/rfc822: {} - {} - {}", + wrapper.date(), + wrapper.field_from_to_string(), + wrapper.subject() + ), + Err(e) => write!(f, "{}", e), }, ContentType::Unsupported { .. } => { write!(f, "Data attachment of type {}", self.mime_type()) } - ContentType::Text { .. } => { - write!(f, "Text attachment of type {}", self.mime_type()) - } + ContentType::Text { .. } => write!(f, "Text attachment of type {}", self.mime_type()), ContentType::Multipart { - kind: ref multipart_type, subattachments: ref sub_att_vec, .. - } => if *multipart_type == MultipartType::Alternative { - write!( - f, - "{} attachment with {} subs", - self.mime_type(), - sub_att_vec.len() - ) - } else { - write!( - f, - "{} attachment with {} subs", - self.mime_type(), - sub_att_vec.len() - ) - }, + } => write!( + f, + "{} attachment with {} subs", + self.mime_type(), + sub_att_vec.len() + ), } } } @@ -297,20 +286,23 @@ impl Attachment { } => match *multipart_type { MultipartType::Alternative => { for a in sub_att_vec { - if let ContentType::Text { kind: Text::Plain, .. } = a.content_type { + if let ContentType::Text { + kind: Text::Plain, .. + } = a.content_type + { a.get_text_recursive(text); break; } } - }, + } MultipartType::Mixed | MultipartType::Digest => { for a in sub_att_vec { a.get_text_recursive(text); text.extend_from_slice(b"\n\n"); } - }, - } - _ => {}, + } + }, + _ => {} } } pub fn text(&self) -> String { @@ -356,7 +348,9 @@ impl Attachment { } pub fn is_html(&self) -> bool { match self.content_type { - ContentType::Text { kind: Text::Html, .. } => true, + ContentType::Text { + kind: Text::Html, .. + } => true, _ => false, } } @@ -369,13 +363,13 @@ pub fn interpret_format_flowed(_t: &str) -> String { fn decode_rfc822(_raw: &[u8]) -> Attachment { let builder = AttachmentBuilder::new(b""); - return builder.build(); + builder.build() /* - eprintln!("raw is\n{:?}", str::from_utf8(raw).unwrap()); + eprintln!("raw is\n{:?}", str::from_utf8(raw).unwrap()); let e = match Envelope::from_bytes(raw) { Some(e) => e, - None => { + None => { eprintln!("error in parsing mail"); let error_msg = b"Mail cannot be shown because of errors."; let mut builder = AttachmentBuilder::new(error_msg); @@ -384,10 +378,11 @@ fn decode_rfc822(_raw: &[u8]) -> Attachment { }; e.body(None) */ - } -fn decode_rec_helper(a: &Attachment, filter: &Option) -> ()>>) -> Vec { +type Filter = Box) -> ()>; + +fn decode_rec_helper(a: &Attachment, filter: &Option) -> Vec { let mut ret = match a.content_type { ContentType::Unsupported { .. } => Vec::new(), ContentType::Text { .. } => decode_helper(a, filter), @@ -398,7 +393,10 @@ fn decode_rec_helper(a: &Attachment, filter: &Option if *multipart_type == MultipartType::Alternative { for a in sub_att_vec { - if let ContentType::Text { kind: Text::Plain, .. } = a.content_type { + if let ContentType::Text { + kind: Text::Plain, .. + } = a.content_type + { return decode_helper(a, filter); } } @@ -417,10 +415,10 @@ fn decode_rec_helper(a: &Attachment, filter: &Option) -> ()>>) -> Vec { +pub fn decode_rec(a: &Attachment, filter: Option) -> Vec { decode_rec_helper(a, &filter) } -fn decode_helper(a: &Attachment, filter: &Option) -> ()>>) -> Vec { +fn decode_helper(a: &Attachment, filter: &Option) -> Vec { let charset = match a.content_type { ContentType::Text { charset: c, .. } => c, _ => Default::default(), @@ -449,12 +447,11 @@ fn decode_helper(a: &Attachment, filter: &Option) -> ()>>) -> Vec { +pub fn decode(a: &Attachment, filter: Option) -> Vec { decode_helper(a, &filter) } diff --git a/melib/src/mailbox/email/mod.rs b/melib/src/mailbox/email/mod.rs index 481c8f88..37a5c937 100644 --- a/melib/src/mailbox/email/mod.rs +++ b/melib/src/mailbox/email/mod.rs @@ -129,10 +129,10 @@ impl StrBuilder { let offset = self.offset; let length = self.length; String::from_utf8(s[offset..offset + length].to_vec()).unwrap() - } + } #[cfg(test)] fn display_bytes<'a>(&self, b: &'a [u8]) -> &'a [u8] { - &b[self.offset..(self.offset+self.length)] + &b[self.offset..(self.offset + self.length)] } } @@ -146,7 +146,7 @@ impl StrBuild for MessageID { MessageID( string.to_owned(), StrBuilder { - offset: offset, + offset, length: slice.len() + 1, }, ) @@ -197,12 +197,12 @@ struct References { bitflags! { #[derive(Default, Serialize, Deserialize)] pub struct Flag: u8 { - const PASSED = 0b00000001; - const REPLIED = 0b00000010; - const SEEN = 0b00000100; - const TRASHED = 0b00001000; - const DRAFT = 0b00010000; - const FLAGGED = 0b00100000; + const PASSED = 0b0000_0001; + const REPLIED = 0b0000_0010; + const SEEN = 0b0000_0100; + const TRASHED = 0b0000_1000; + const DRAFT = 0b0001_0000; + const FLAGGED = 0b0010_0000; } } @@ -212,7 +212,6 @@ pub struct EnvelopeWrapper { buffer: Vec, } - use std::ops::Deref; impl Deref for EnvelopeWrapper { @@ -317,7 +316,6 @@ impl Envelope { self.hash } pub fn populate_headers(&mut self, bytes: &[u8]) -> Result<()> { - let (headers, _) = match parser::mail(bytes).to_full_result() { Ok(v) => v, Err(e) => { @@ -372,13 +370,13 @@ impl Envelope { self.set_in_reply_to(value); in_reply_to = Some(value); } else if name.eq_ignore_ascii_case(b"date") { - let parse_result = parser::phrase(value); - if parse_result.is_done() { - let value = parse_result.to_full_result().unwrap(); - self.set_date(value.as_slice()); - } else { - self.set_date(value); - } + let parse_result = parser::phrase(value); + if parse_result.is_done() { + let value = parse_result.to_full_result().unwrap(); + self.set_date(value.as_slice()); + } else { + self.set_date(value); + } } } /* @@ -400,24 +398,21 @@ impl Envelope { Ok(()) } - pub fn populate_headers_from_token(&mut self, mut operation: Box) -> Result<()> { - { - let headers = operation.fetch_headers()?; - return self.populate_headers(headers); - } + let headers = operation.fetch_headers()?; + self.populate_headers(headers) } pub fn date(&self) -> u64 { self.timestamp } pub fn datetime(&self) -> chrono::DateTime { - if let Some(d) = parser::date(&self.date.as_bytes()) { - return d; - } - chrono::FixedOffset::west(0) - .ymd(1970, 1, 1) - .and_hms(0, 0, 0) + if let Some(d) = parser::date(&self.date.as_bytes()) { + return d; + } + chrono::FixedOffset::west(0) + .ymd(1970, 1, 1) + .and_hms(0, 0, 0) } pub fn date_as_str(&self) -> &str { &self.date @@ -426,14 +421,14 @@ impl Envelope { &self.from } - pub fn from_to_string(&self) -> String { + pub fn field_from_to_string(&self) -> String { let _strings: Vec = self.from.iter().map(|a| format!("{}", a)).collect(); _strings.join(", ") } pub fn to(&self) -> &Vec
{ &self.to } - pub fn to_to_string(&self) -> String { + pub fn field_to_to_string(&self) -> String { let _strings: Vec = self.to.iter().map(|a| format!("{}", a)).collect(); _strings.join(", ") } @@ -504,7 +499,7 @@ impl Envelope { } pub fn in_reply_to_raw(&self) -> Cow { match self.in_reply_to { - Some(ref s) => String::from_utf8_lossy(s.raw()).into(), + Some(ref s) => String::from_utf8_lossy(s.raw()), _ => Cow::from(String::new()), } } diff --git a/melib/src/mailbox/email/parser.rs b/melib/src/mailbox/email/parser.rs index 9a2052e6..6b0e0d03 100644 --- a/melib/src/mailbox/email/parser.rs +++ b/melib/src/mailbox/email/parser.rs @@ -114,12 +114,11 @@ fn quoted_printable_byte(input: &[u8]) -> IResult<&[u8], u8> { fn header_value(input: &[u8]) -> IResult<&[u8], &[u8]> { let input_len = input.len(); for (i, x) in input.iter().enumerate() { - if *x == b'\n' { - if ((i + 1) < input_len && input[i + 1] != b' ' && input[i + 1] != b'\t') - || i + 1 == input_len - { - return IResult::Done(&input[(i + 1)..], &input[0..i]); - } + if *x == b'\n' + && (((i + 1) < input_len && input[i + 1] != b' ' && input[i + 1] != b'\t') + || i + 1 == input_len) + { + return IResult::Done(&input[(i + 1)..], &input[0..i]); } } IResult::Incomplete(Needed::Unknown) @@ -146,7 +145,7 @@ pub fn headers_raw(input: &[u8]) -> IResult<&[u8], &[u8]> { return IResult::Done(&input[(i + 1)..], &input[0..i + 1]); } } - return IResult::Error(error_code!(ErrorKind::Custom(43))); + IResult::Error(error_code!(ErrorKind::Custom(43))) } named!(pub body_raw<&[u8]>, @@ -337,9 +336,9 @@ fn display_addr(input: &[u8]) -> IResult<&[u8], Address> { IResult::Done( rest, Address::Mailbox(MailboxAddress { - raw: raw, - display_name: display_name, - address_spec: address_spec, + raw, + display_name, + address_spec, }), ) } @@ -414,12 +413,11 @@ fn group(input: &[u8]) -> IResult<&[u8], Address> { } match mailbox_list(&input[dlength..]) { - IResult::Error(e) => { - return IResult::Error(e); - } + IResult::Error(e) => IResult::Error(e), IResult::Done(rest, vec) => { - let size: usize = (rest.as_ptr() as usize).wrapping_sub((&input[0..] as &[u8]).as_ptr() as usize); - return IResult::Done( + let size: usize = + (rest.as_ptr() as usize).wrapping_sub((&input[0..] as &[u8]).as_ptr() as usize); + IResult::Done( rest, Address::Group(GroupAddress { raw: input[0..size].into(), @@ -429,11 +427,9 @@ fn group(input: &[u8]) -> IResult<&[u8], Address> { }, mailbox_list: vec, }), - ); - } - IResult::Incomplete(i) => { - return IResult::Incomplete(i); + ) } + IResult::Incomplete(i) => IResult::Incomplete(i), } } @@ -559,7 +555,7 @@ fn attachments_f<'a>(input: &'a [u8], boundary: &[u8]) -> IResult<&'a [u8], Vec< return IResult::Error(error_code!(ErrorKind::Custom(43))); } } - return IResult::Done(input, ret); + IResult::Done(input, ret) } named_args!(pub attachments<'a>(boundary: &'a [u8]) < Vec<&'this_is_probably_unique_i_hope_please [u8]> >, @@ -603,13 +599,11 @@ named!( acc += x.len(); acc }); - let bytes = list - .iter() + list.iter() .fold(Vec::with_capacity(list_len), |mut acc, x| { acc.append(&mut x.clone()); acc - }); - bytes + }) }) )) ); @@ -685,7 +679,7 @@ pub fn phrase(input: &[u8]) -> IResult<&[u8], Vec> { acc.push(b' '); } } - return IResult::Done(&[], acc); + IResult::Done(&[], acc) } #[cfg(test)] diff --git a/melib/src/mailbox/mod.rs b/melib/src/mailbox/mod.rs index eff564b2..5e31c62b 100644 --- a/melib/src/mailbox/mod.rs +++ b/melib/src/mailbox/mod.rs @@ -32,7 +32,7 @@ pub mod backends; use error::Result; use mailbox::backends::{folder_default, Folder}; pub mod thread; -pub use mailbox::thread::{build_threads, Container, Threads, SortOrder, SortField}; +pub use mailbox::thread::{build_threads, Container, SortField, SortOrder, Threads}; use std::option::Option; @@ -74,10 +74,13 @@ impl Mailbox { let threads = build_threads(&mut collection, sent_folder); Ok(Mailbox { folder: (*folder).clone(), - collection: collection, - threads: threads, + collection, + threads, }) } + pub fn is_empty(&self) -> bool { + self.collection.is_empty() + } pub fn len(&self) -> usize { self.collection.len() } diff --git a/melib/src/mailbox/thread.rs b/melib/src/mailbox/thread.rs index 8ac29650..5fd8064a 100644 --- a/melib/src/mailbox/thread.rs +++ b/melib/src/mailbox/thread.rs @@ -30,11 +30,11 @@ use mailbox::Mailbox; extern crate fnv; use self::fnv::FnvHashMap; use std::borrow::Cow; -use std::ops::{Index, }; -use std::str::FromStr; -use std::result::Result as StdResult; use std::cell::{Ref, RefCell}; use std::cmp::Ordering; +use std::ops::Index; +use std::result::Result as StdResult; +use std::str::FromStr; #[derive(Debug, Clone, PartialEq, Copy)] pub enum SortOrder { @@ -122,7 +122,6 @@ impl ContainerTree { } } - #[derive(Clone, Debug, Default)] pub struct Threads { containers: Vec, @@ -136,10 +135,10 @@ pub struct Threads { pub struct ThreadIterator<'a> { pos: usize, stack: Vec, - tree: Ref<'a ,Vec>, + tree: Ref<'a, Vec>, } impl<'a> Iterator for ThreadIterator<'a> { - type Item = usize; + type Item = usize; fn next(&mut self) -> Option { { let mut tree = &(*self.tree); @@ -163,7 +162,7 @@ impl<'a> Iterator for ThreadIterator<'a> { return Some(ret); } } - return self.next(); + self.next() } } @@ -172,25 +171,28 @@ impl<'a> IntoIterator for &'a Threads { type IntoIter = ThreadIterator<'a>; fn into_iter(self) -> Self::IntoIter { - ThreadIterator { pos: 0, stack: Vec::new(), tree: self.tree.borrow() } + ThreadIterator { + pos: 0, + stack: Vec::new(), + tree: self.tree.borrow(), + } } } - pub struct RootIterator<'a> { pos: usize, - tree: Ref<'a ,Vec>, + tree: Ref<'a, Vec>, } impl<'a> Iterator for RootIterator<'a> { - type Item = (usize, usize, bool); + type Item = (usize, usize, bool); fn next(&mut self) -> Option<(usize, usize, bool)> { if self.pos == self.tree.len() { return None; } let node = &self.tree[self.pos]; self.pos += 1; - return Some((node.id, node.len, node.has_unseen)); + Some((node.id, node.len, node.has_unseen)) } } @@ -201,8 +203,11 @@ impl Threads { pub fn root_set(&self) -> &Vec { &self.root_set } - pub fn root_set_iter(&self) -> RootIterator { - RootIterator { pos: 0, tree: self.tree.borrow() } + pub fn root_set_iter(&self) -> RootIterator { + RootIterator { + pos: 0, + tree: self.tree.borrow(), + } } pub fn thread_to_mail(&self, i: usize) -> usize { let thread = self.containers[self.threaded_collection[i]]; @@ -219,8 +224,8 @@ impl Threads { let tree = &mut self.tree.borrow_mut(); let containers = &self.containers; for mut t in tree.iter_mut() { - if let Some(ref mut c ) = t.children { - c.sort_by(|a, b| { match subsort { + if let Some(ref mut c) = t.children { + c.sort_by(|a, b| match subsort { (SortField::Date, SortOrder::Desc) => { let a = containers[a.id]; let b = containers[b.id]; @@ -253,7 +258,6 @@ impl Threads { let mb = &collection[b.unwrap()]; mb.subject().cmp(&ma.subject()) } - } }); } } @@ -262,12 +266,11 @@ impl Threads { fn inner_sort_by(&self, sort: (SortField, SortOrder), collection: &[Envelope]) { let tree = &mut self.tree.borrow_mut(); let containers = &self.containers; - tree.sort_by(|a, b| { match sort { + tree.sort_by(|a, b| match sort { (SortField::Date, SortOrder::Desc) => { let a = containers[a.id]; let b = containers[b.id]; b.date.cmp(&a.date) - } (SortField::Date, SortOrder::Asc) => { let a = containers[a.id]; @@ -296,10 +299,14 @@ impl Threads { let mb = &collection[b.unwrap()]; mb.subject().cmp(&ma.subject()) } - } }); } - pub fn sort_by(&self, sort: (SortField, SortOrder), subsort: (SortField, SortOrder), collection: &[Envelope]) { + pub fn sort_by( + &self, + sort: (SortField, SortOrder), + subsort: (SortField, SortOrder), + collection: &[Envelope], + ) { if *self.sort.borrow() != sort { self.inner_sort_by(sort, collection); *self.sort.borrow_mut() = sort; @@ -308,7 +315,6 @@ impl Threads { self.inner_subsort_by(subsort, collection); *self.subsort.borrow_mut() = subsort; } - } pub fn build_collection(&mut self, collection: &[Envelope]) { @@ -320,7 +326,7 @@ impl Threads { i: usize, root_subject_idx: usize, collection: &[Envelope], - ) { + ) { let thread = containers[i]; if let Some(msg_idx) = containers[root_subject_idx].message() { let root_subject = collection[msg_idx].subject(); @@ -333,9 +339,9 @@ impl Threads { if subject == root_subject || subject.starts_with("Re: ") && subject.as_ref().ends_with(root_subject.as_ref()) - { - containers[i].set_show_subject(false); - } + { + containers[i].set_show_subject(false); + } } } if thread.has_parent() && !containers[thread.parent().unwrap()].has_message() { @@ -360,7 +366,15 @@ impl Threads { loop { let mut new_child_tree = ContainerTree::new(fc); - build_threaded(&mut new_child_tree, containers, indentation, threaded, fc, i, collection); + build_threaded( + &mut new_child_tree, + containers, + indentation, + threaded, + fc, + i, + collection, + ); tree.has_unseen |= new_child_tree.has_unseen; child_vec.push(new_child_tree); let thread_ = containers[fc]; @@ -384,7 +398,7 @@ impl Threads { *i, *i, collection, - ); + ); tree.push(tree_node); } self.tree.replace(tree); @@ -397,11 +411,12 @@ impl Index for Threads { type Output = Container; fn index(&self, index: usize) -> &Container { - self.containers.get(index).expect("thread index out of bounds") + self.containers + .get(index) + .expect("thread index out of bounds") } } - impl Container { pub fn date(&self) -> UnixTimestamp { self.date @@ -474,7 +489,7 @@ fn build_collection( threads: &mut Vec, id_table: &mut FnvHashMap, usize>, collection: &mut [Envelope], - ) -> () { +) -> () { for (i, x) in collection.iter_mut().enumerate() { let x_index; /* x's index in threads */ let m_id = x.message_id_raw().into_owned(); @@ -529,7 +544,7 @@ fn build_collection( let parent_id = if id_table.contains_key(&r) { let p = id_table[r.as_ref()]; if !(threads[p].is_descendant(threads, &threads[curr_ref]) - || threads[curr_ref].is_descendant(threads, &threads[p])) + || threads[curr_ref].is_descendant(threads, &threads[p])) { threads[curr_ref].parent = Some(p); if threads[p].first_child.is_none() { @@ -589,7 +604,7 @@ fn build_collection( pub fn build_threads( collection: &mut Vec, sent_folder: &Option>, - ) -> Threads { +) -> Threads { /* To reconstruct thread information from the mails we need: */ /* a vector to hold thread members */ @@ -623,77 +638,77 @@ pub fn build_threads( if id_table.contains_key(&m_id) || (!x.in_reply_to_raw().is_empty() && id_table.contains_key(&x.in_reply_to_raw())) + { + let mut x: Envelope = (*x).clone(); + if id_table.contains_key(&m_id) { + let c = id_table[&m_id]; + if threads[c].message.is_some() { + /* skip duplicate message-id, but this should be handled instead */ + continue; + } + threads[c].message = Some(idx); + assert!(threads[c].has_children()); + threads[c].date = x.date(); + x.set_thread(c); + } else if !x.in_reply_to_raw().is_empty() + && id_table.contains_key(&x.in_reply_to_raw()) { - let mut x: Envelope = (*x).clone(); - if id_table.contains_key(&m_id) { - let c = id_table[&m_id]; - if threads[c].message.is_some() { - /* skip duplicate message-id, but this should be handled instead */ - continue; + let p = id_table[&x_r_id]; + let c = if id_table.contains_key(&m_id) { + id_table[&m_id] + } else { + threads.push(Container { + message: Some(idx), + id: tidx, + parent: Some(p), + first_child: None, + next_sibling: None, + date: x.date(), + indentation: 0, + show_subject: true, + }); + id_table.insert(Cow::from(m_id.into_owned()), tidx); + x.set_thread(tidx); + tidx += 1; + tidx - 1 + }; + threads[c].parent = Some(p); + if threads[p].is_descendant(&threads, &threads[c]) + || threads[c].is_descendant(&threads, &threads[p]) + { + continue; + } + if threads[p].first_child.is_none() { + threads[p].first_child = Some(c); + } else { + let mut fc = threads[p].first_child.unwrap(); + while threads[fc].next_sibling.is_some() { + threads[fc].parent = Some(p); + fc = threads[fc].next_sibling.unwrap(); } - threads[c].message = Some(idx); - assert!(threads[c].has_children()); - threads[c].date = x.date(); - x.set_thread(c); - } else if !x.in_reply_to_raw().is_empty() - && id_table.contains_key(&x.in_reply_to_raw()) - { - let p = id_table[&x_r_id]; - let c = if id_table.contains_key(&m_id) { - id_table[&m_id] - } else { - threads.push(Container { - message: Some(idx), - id: tidx, - parent: Some(p), - first_child: None, - next_sibling: None, - date: x.date(), - indentation: 0, - show_subject: true, - }); - id_table.insert(Cow::from(m_id.into_owned()), tidx); - x.set_thread(tidx); - tidx += 1; - tidx - 1 - }; - threads[c].parent = Some(p); - if threads[p].is_descendant(&threads, &threads[c]) - || threads[c].is_descendant(&threads, &threads[p]) - { - continue; - } - if threads[p].first_child.is_none() { - threads[p].first_child = Some(c); - } else { - let mut fc = threads[p].first_child.unwrap(); - while threads[fc].next_sibling.is_some() { - threads[fc].parent = Some(p); - fc = threads[fc].next_sibling.unwrap(); - } - threads[fc].next_sibling = Some(c); - threads[fc].parent = Some(p); + threads[fc].next_sibling = Some(c); + threads[fc].parent = Some(p); + } + /* update thread date */ + let mut parent_iter = p; + 'date: loop { + let p = &mut threads[parent_iter]; + if p.date < x.date() { + p.date = x.date(); + } + match p.parent { + Some(p) => { + parent_iter = p; } - /* update thread date */ - let mut parent_iter = p; - 'date: loop { - let p = &mut threads[parent_iter]; - if p.date < x.date() { - p.date = x.date(); - } - match p.parent { - Some(p) => { - parent_iter = p; - } - None => { - break 'date; - } - } + None => { + break 'date; } } - collection.push(x); - idx += 1; + } } + collection.push(x); + idx += 1; + } } } } @@ -704,14 +719,14 @@ pub fn build_threads( if threads[*v].parent.is_none() { if !threads[*v].has_message() && threads[*v].has_children() - && !threads[threads[*v].first_child.unwrap()].has_sibling() - { - /* Do not promote the children if doing so would promote them to the root set - * -- unless there is only one child, in which case, do. */ - root_set.push(threads[*v].first_child.unwrap()); + && !threads[threads[*v].first_child.unwrap()].has_sibling() + { + /* Do not promote the children if doing so would promote them to the root set + * -- unless there is only one child, in which case, do. */ + root_set.push(threads[*v].first_child.unwrap()); - continue 'root_set; - } + continue 'root_set; + } root_set.push(*v); } } diff --git a/scripts/pre-commit b/scripts/pre-commit old mode 100644 new mode 100755 index b6bc60a9..9fe9134d --- a/scripts/pre-commit +++ b/scripts/pre-commit @@ -1,7 +1,8 @@ #!/bin/zsh # -exec find . -name "*rs" -exec rustfmt {} \; +exec git diff --name-only HEAD | grep ".*\.rs" | xargs rustfmt +#exec find . -name "*rs" -exec rustfmt {} \; exec cargo +nightly clippy # If there are whitespace errors, print the offending file names and fail. exec git diff-index --check --cached $against -- diff --git a/src/bin.rs b/src/bin.rs index b800441a..47f66658 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -35,7 +35,6 @@ extern crate ui; pub use melib::*; pub use ui::*; - #[macro_use] extern crate chan; extern crate chan_signal; @@ -56,7 +55,6 @@ fn main() { /* Catch SIGWINCH to handle terminal resizing */ let signal = chan_signal::notify(&[Signal::WINCH]); - /* Create the application State. This is the 'System' part of an ECS architecture */ let mut state = State::new(); diff --git a/ui/src/components/mail/compose.rs b/ui/src/components/mail/compose.rs index edb30be7..3996cbe1 100644 --- a/ui/src/components/mail/compose.rs +++ b/ui/src/components/mail/compose.rs @@ -65,7 +65,7 @@ impl Component for Composer { let width = width!(area); let mid = if width > 80 { let width = width - 80; - let mid = width / 2;; + let mid = width / 2; if self.dirty { for i in get_y(upper_left)..=get_y(bottom_right) { @@ -78,17 +78,22 @@ impl Component for Composer { } } mid - } else { 0 }; + } else { + 0 + }; if self.dirty { - for i in get_x(upper_left)+ mid + 1..=get_x(upper_left) + mid + 79 { + for i in get_x(upper_left) + mid + 1..=get_x(upper_left) + mid + 79 { grid[(i, header_height)].set_ch(HORZ_BOUNDARY); grid[(i, header_height)].set_fg(Color::Default); grid[(i, header_height)].set_bg(Color::Default); } } - let body_area = ((mid + 1, header_height+2), (mid + 78, get_y(bottom_right))); + let body_area = ( + (mid + 1, header_height + 2), + (mid + 78, get_y(bottom_right)), + ); if self.dirty { context.dirty_areas.push_back(area); @@ -97,8 +102,7 @@ impl Component for Composer { match self.mode { ViewMode::Overview => { self.pager.draw(grid, body_area, context); - - }, + } } } @@ -134,12 +138,12 @@ impl Component for Composer { .expect("failed to execute process"); let result = f.read_to_string(); self.buffer = result.clone(); - self.pager.update_from_string(result); + self.pager.update_from_str(result.as_str()); context.restore_input(); self.dirty = true; return true; - }, - _ => {}, + } + _ => {} } false } diff --git a/ui/src/components/mail/listing/compact.rs b/ui/src/components/mail/listing/compact.rs index 96ab3d94..c9e3edd1 100644 --- a/ui/src/components/mail/listing/compact.rs +++ b/ui/src/components/mail/listing/compact.rs @@ -67,14 +67,14 @@ impl CompactListing { &CompactListing::format_date(e), e.subject(), len - ) + ) } else { format!( "{} {} {:.85}", idx, &CompactListing::format_date(e), e.subject(), - ) + ) } } @@ -86,7 +86,7 @@ impl CompactListing { length: 0, sort: (Default::default(), Default::default()), subsort: (Default::default(), Default::default()), - content: content, + content, dirty: true, unfocused: false, view: None, @@ -110,7 +110,10 @@ impl CompactListing { // loop { // TODO: Show progress visually - if let Ok(_) = context.accounts[self.cursor_pos.0].status(self.cursor_pos.1) { + if context.accounts[self.cursor_pos.0] + .status(self.cursor_pos.1) + .is_ok() + { break; } } @@ -118,7 +121,6 @@ impl CompactListing { .as_ref() .unwrap(); - self.length = mailbox.threads.root_len(); self.content = CellBuffer::new(MAX_COLS, self.length + 1, Cell::with_char(' ')); if self.length == 0 { @@ -139,9 +141,9 @@ impl CompactListing { let i = if let Some(i) = container.message() { i } else { - threads.containers()[ - container.first_child().unwrap() - ].message().unwrap() + threads.containers()[container.first_child().unwrap()] + .message() + .unwrap() }; let root_envelope: &Envelope = &mailbox.collection[i]; let fg_color = if has_unseen { @@ -163,16 +165,13 @@ impl CompactListing { bg_color, ((0, idx), (MAX_COLS - 1, idx)), false, - ); + ); for x in x..MAX_COLS { self.content[(x, idx)].set_ch(' '); self.content[(x, idx)].set_bg(bg_color); } - - } - } fn highlight_line(&self, grid: &mut CellBuffer, area: Area, idx: usize, context: &Context) { @@ -185,9 +184,9 @@ impl CompactListing { let i = if let Some(i) = container.message() { i } else { - threads.containers()[ - container.first_child().unwrap() - ].message().unwrap() + threads.containers()[container.first_child().unwrap()] + .message() + .unwrap() }; let root_envelope: &Envelope = &mailbox.collection[i]; let fg_color = if !root_envelope.is_seen() { @@ -303,11 +302,7 @@ impl Component for CompactListing { return; } self.view = Some(ThreadView::new(self.cursor_pos, context)); - self.view.as_mut().unwrap().draw( - grid, - area, - context, - ); + self.view.as_mut().unwrap().draw(grid, area, context); self.dirty = false; } } @@ -440,8 +435,7 @@ impl Component for CompactListing { self.dirty = true; self.refresh_mailbox(context); return true; - } - // _ => {} + } // _ => {} }, _ => {} } @@ -451,7 +445,9 @@ impl Component for CompactListing { self.dirty || self.view.as_ref().map(|p| p.is_dirty()).unwrap_or(false) } fn set_dirty(&mut self) { - self.view.as_mut().map(|p| p.set_dirty()); + if let Some(p) = self.view.as_mut() { + p.set_dirty(); + } self.dirty = true; } } diff --git a/ui/src/components/mail/listing/mod.rs b/ui/src/components/mail/listing/mod.rs index 132f4408..b109c599 100644 --- a/ui/src/components/mail/listing/mod.rs +++ b/ui/src/components/mail/listing/mod.rs @@ -79,7 +79,7 @@ impl MailListing { local_collection: Vec::new(), sort: (Default::default(), Default::default()), subsort: (Default::default(), Default::default()), - content: content, + content, dirty: true, unfocused: false, view: None, @@ -107,7 +107,10 @@ impl MailListing { // loop { // TODO: Show progress visually - if let Ok(_) = context.accounts[self.cursor_pos.0].status(self.cursor_pos.1) { + if context.accounts[self.cursor_pos.0] + .status(self.cursor_pos.1) + .is_ok() + { break; } } @@ -162,7 +165,6 @@ impl MailListing { continue; } - match iter.peek() { Some(&x) if threads[x].indentation() == indentation => { indentations.pop(); @@ -198,7 +200,7 @@ impl MailListing { container, &indentations, len, - // context.accounts[self.cursor_pos.0].backend.operation(envelope.hash()) + // context.accounts[self.cursor_pos.0].backend.operation(envelope.hash()) ), &mut self.content, fg_color, @@ -522,9 +524,7 @@ impl Component for MailListing { .threaded(); let account = &mut context.accounts[self.cursor_pos.0]; let (hash, is_seen) = { - let mailbox = &mut account[self.cursor_pos.1] - .as_mut() - .unwrap(); + let mailbox = &mut account[self.cursor_pos.1].as_mut().unwrap(); let envelope: &mut Envelope = if threaded { let i = mailbox.threaded_mail(idx); &mut mailbox.collection[i] @@ -538,9 +538,7 @@ impl Component for MailListing { let backend = &account.backend; backend.operation(hash) }; - let mailbox = &mut account[self.cursor_pos.1] - .as_mut() - .unwrap(); + let mailbox = &mut account[self.cursor_pos.1].as_mut().unwrap(); let envelope: &mut Envelope = if threaded { let i = mailbox.threaded_mail(idx); &mut mailbox.collection[i] @@ -598,9 +596,7 @@ impl Component for MailListing { .conf() .threaded(); let account = &context.accounts[self.cursor_pos.0]; - let mailbox = &account[self.cursor_pos.1] - .as_ref() - .unwrap(); + let mailbox = &account[self.cursor_pos.1].as_ref().unwrap(); let mut coordinates = self.cursor_pos; coordinates.2 = if threaded { mailbox.threaded_mail(self.cursor_pos.2) @@ -792,8 +788,7 @@ impl Component for MailListing { self.dirty = true; self.refresh_mailbox(context); return true; - } - // _ => {} + } // _ => {} }, _ => {} } @@ -803,7 +798,9 @@ impl Component for MailListing { self.dirty || self.view.as_ref().map(|p| p.is_dirty()).unwrap_or(false) } fn set_dirty(&mut self) { - self.view.as_mut().map(|p| p.set_dirty()); + if let Some(p) = self.view.as_mut() { + p.set_dirty(); + }; self.dirty = true; } } diff --git a/ui/src/components/mail/mod.rs b/ui/src/components/mail/mod.rs index 24d1890d..5def2bbd 100644 --- a/ui/src/components/mail/mod.rs +++ b/ui/src/components/mail/mod.rs @@ -65,10 +65,8 @@ impl AccountMenu { index: i, entries: { let mut entries = Vec::with_capacity(a.len()); - let mut idx = 0; - for acc in a.list_folders() { + for (idx, acc) in a.list_folders().into_iter().enumerate() { entries.push((idx, acc)); - idx += 1; } entries }, diff --git a/ui/src/components/mail/view/envelope.rs b/ui/src/components/mail/view/envelope.rs index 8f043612..2a809d08 100644 --- a/ui/src/components/mail/view/envelope.rs +++ b/ui/src/components/mail/view/envelope.rs @@ -68,7 +68,7 @@ impl EnvelopeView { wrapper: EnvelopeWrapper, pager: Option, subview: Option>, - ) -> Self { + ) -> Self { EnvelopeView { pager, subview, @@ -81,33 +81,34 @@ impl EnvelopeView { } /// Returns the string to be displayed in the Viewer - fn attachment_to_text(&self, body: Attachment) -> String { + fn attachment_to_text(&self, body: &Attachment) -> String { let finder = LinkFinder::new(); let body_text = String::from_utf8_lossy(&decode_rec( - &body, - Some(Box::new(|a: &Attachment, v: &mut Vec| { - if a.content_type().is_text_html() { - use std::io::Write; - use std::process::{Command, Stdio}; + &body, + Some(Box::new(|a: &Attachment, v: &mut Vec| { + if a.content_type().is_text_html() { + use std::io::Write; + use std::process::{Command, Stdio}; - let mut html_filter = Command::new("w3m") - .args(&["-I", "utf-8", "-T", "text/html"]) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() - .expect("Failed to start html filter process"); + let mut html_filter = Command::new("w3m") + .args(&["-I", "utf-8", "-T", "text/html"]) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .expect("Failed to start html filter process"); - html_filter - .stdin - .as_mut() - .unwrap() - .write_all(&v) - .expect("Failed to write to w3m stdin"); - *v = b"Text piped through `w3m`. Press `v` to open in web browser. \n\n".to_vec(); - v.extend(html_filter.wait_with_output().unwrap().stdout); - } - })), - )).into_owned(); + html_filter + .stdin + .as_mut() + .unwrap() + .write_all(&v) + .expect("Failed to write to w3m stdin"); + *v = b"Text piped through `w3m`. Press `v` to open in web browser. \n\n" + .to_vec(); + v.extend(html_filter.wait_with_output().unwrap().stdout); + } + })), + )).into_owned(); match self.mode { ViewMode::Normal | ViewMode::Subview => { let mut t = body_text.to_string(); @@ -158,7 +159,7 @@ impl EnvelopeView { } } } - pub fn plain_text_to_buf(s: &String, highlight_urls: bool) -> CellBuffer { + pub fn plain_text_to_buf(s: &str, highlight_urls: bool) -> CellBuffer { let mut buf = CellBuffer::from(s); if highlight_urls { @@ -197,7 +198,7 @@ impl Component for EnvelopeView { let upper_left = upper_left!(area); let bottom_right = bottom_right!(area); - let y :usize = { + let y: usize = { let envelope: &Envelope = &self.wrapper; if self.mode == ViewMode::Raw { @@ -219,7 +220,7 @@ impl Component for EnvelopeView { grid[(x, y)].set_fg(Color::Default); } let (x, y) = write_string_to_grid( - &format!("From: {}", envelope.from_to_string()), + &format!("From: {}", envelope.field_from_to_string()), grid, Color::Byte(33), Color::Default, @@ -232,7 +233,7 @@ impl Component for EnvelopeView { grid[(x, y)].set_fg(Color::Default); } let (x, y) = write_string_to_grid( - &format!("To: {}", envelope.to_to_string()), + &format!("To: {}", envelope.field_to_to_string()), grid, Color::Byte(33), Color::Default, @@ -293,7 +294,7 @@ impl Component for EnvelopeView { } _ => { let buf = { - let text = self.attachment_to_text(body); + let text = self.attachment_to_text(&body); // URL indexes must be colored (ugh..) EnvelopeView::plain_text_to_buf(&text, self.mode == ViewMode::Url) }; @@ -344,7 +345,9 @@ impl Component for EnvelopeView { self.dirty = true; return true; } - UIEventType::Input(Key::Char('r')) if self.mode.is_attachment() || self.mode == ViewMode::Subview => { + UIEventType::Input(Key::Char('r')) + if self.mode.is_attachment() || self.mode == ViewMode::Subview => + { self.mode = ViewMode::Normal; self.subview.take(); self.dirty = true; @@ -358,12 +361,19 @@ impl Component for EnvelopeView { { let envelope: &Envelope = self.wrapper.envelope(); - if let Some(u) = envelope.body_bytes(self.wrapper.buffer()).attachments().get(lidx) { + if let Some(u) = envelope + .body_bytes(self.wrapper.buffer()) + .attachments() + .get(lidx) + { match u.content_type() { ContentType::MessageRfc822 => { self.mode = ViewMode::Subview; - self.subview = Some(Box::new(Pager::from_str(&String::from_utf8_lossy(&decode_rec(u, None)).to_string(), None))); - }, + self.subview = Some(Box::new(Pager::from_str( + &String::from_utf8_lossy(&decode_rec(u, None)).to_string(), + None, + ))); + } ContentType::Text { .. } => { self.mode = ViewMode::Attachment(lidx); @@ -416,7 +426,7 @@ impl Component for EnvelopeView { } }; return true; - }, + } UIEventType::Input(Key::Char('g')) if !self.cmd_buf.is_empty() && self.mode == ViewMode::Url => { @@ -425,7 +435,10 @@ impl Component for EnvelopeView { let url = { let envelope: &Envelope = self.wrapper.envelope(); let finder = LinkFinder::new(); - let mut t = envelope.body_bytes(self.wrapper.buffer()).text().to_string(); + let mut t = envelope + .body_bytes(self.wrapper.buffer()) + .text() + .to_string(); let links: Vec = finder.links(&t).collect(); if let Some(u) = links.get(lidx) { u.as_str().to_string() diff --git a/ui/src/components/mail/view/html.rs b/ui/src/components/mail/view/html.rs index bb308a0f..a9dbc717 100644 --- a/ui/src/components/mail/view/html.rs +++ b/ui/src/components/mail/view/html.rs @@ -70,31 +70,28 @@ impl Component for HtmlView { if self.pager.process_event(event, context) { return true; } - match event.event_type { - UIEventType::Input(Key::Char('v')) => { - // TODO: Optional filter that removes outgoing resource requests (images and - // scripts) - let binary = query_default_app("text/html"); - if let Ok(binary) = binary { - let mut p = create_temp_file(&self.bytes, None); - Command::new(&binary) - .arg(p.path()) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() - .unwrap_or_else(|_| panic!("Failed to start {}", binary.display())); - context.temp_files.push(p); - } else { - context.replies.push_back(UIEvent { - id: 0, - event_type: UIEventType::StatusNotification(format!( - "Couldn't find a default application for html files." - )), - }); - } - return true; + if let UIEventType::Input(Key::Char('v')) = event.event_type { + // TODO: Optional filter that removes outgoing resource requests (images and + // scripts) + let binary = query_default_app("text/html"); + if let Ok(binary) = binary { + let mut p = create_temp_file(&self.bytes, None); + Command::new(&binary) + .arg(p.path()) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .unwrap_or_else(|_| panic!("Failed to start {}", binary.display())); + context.temp_files.push(p); + } else { + context.replies.push_back(UIEvent { + id: 0, + event_type: UIEventType::StatusNotification( + "Couldn't find a default application for html files.".to_string(), + ), + }); } - _ => {} + return true; } false } diff --git a/ui/src/components/mail/view/mod.rs b/ui/src/components/mail/view/mod.rs index e830bd02..f5344718 100644 --- a/ui/src/components/mail/view/mod.rs +++ b/ui/src/components/mail/view/mod.rs @@ -82,7 +82,7 @@ impl MailView { coordinates: (usize, usize, usize), pager: Option, subview: Option>, - ) -> Self { + ) -> Self { MailView { coordinates, pager, @@ -95,33 +95,34 @@ impl MailView { } /// Returns the string to be displayed in the Viewer - fn attachment_to_text(&self, body: Attachment) -> String { + fn attachment_to_text(&self, body: &Attachment) -> String { let finder = LinkFinder::new(); let body_text = String::from_utf8_lossy(&decode_rec( - &body, - Some(Box::new(|a: &Attachment, v: &mut Vec| { - if a.content_type().is_text_html() { - use std::io::Write; - use std::process::{Command, Stdio}; + &body, + Some(Box::new(|a: &Attachment, v: &mut Vec| { + if a.content_type().is_text_html() { + use std::io::Write; + use std::process::{Command, Stdio}; - let mut html_filter = Command::new("w3m") - .args(&["-I", "utf-8", "-T", "text/html"]) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() - .expect("Failed to start html filter process"); + let mut html_filter = Command::new("w3m") + .args(&["-I", "utf-8", "-T", "text/html"]) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .expect("Failed to start html filter process"); - html_filter - .stdin - .as_mut() - .unwrap() - .write_all(&v) - .expect("Failed to write to w3m stdin"); - *v = b"Text piped through `w3m`. Press `v` to open in web browser. \n\n".to_vec(); - v.extend(html_filter.wait_with_output().unwrap().stdout); - } - })), - )).into_owned(); + html_filter + .stdin + .as_mut() + .unwrap() + .write_all(&v) + .expect("Failed to write to w3m stdin"); + *v = b"Text piped through `w3m`. Press `v` to open in web browser. \n\n" + .to_vec(); + v.extend(html_filter.wait_with_output().unwrap().stdout); + } + })), + )).into_owned(); match self.mode { ViewMode::Normal | ViewMode::Subview => { let mut t = body_text.to_string(); @@ -172,7 +173,7 @@ impl MailView { } } } - pub fn plain_text_to_buf(s: &String, highlight_urls: bool) -> CellBuffer { + pub fn plain_text_to_buf(s: &str, highlight_urls: bool) -> CellBuffer { let mut buf = CellBuffer::from(s); if highlight_urls { @@ -237,7 +238,7 @@ impl Component for MailView { grid[(x, y)].set_fg(Color::Default); } let (x, y) = write_string_to_grid( - &format!("From: {}", envelope.from_to_string()), + &format!("From: {}", envelope.field_from_to_string()), grid, Color::Byte(33), Color::Default, @@ -250,7 +251,7 @@ impl Component for MailView { grid[(x, y)].set_fg(Color::Default); } let (x, y) = write_string_to_grid( - &format!("To: {}", envelope.to_to_string()), + &format!("To: {}", envelope.field_to_to_string()), grid, Color::Byte(33), Color::Default, @@ -302,7 +303,9 @@ impl Component for MailView { .as_ref() .unwrap(); let envelope: &Envelope = &mailbox.collection[mailbox_idx.2]; - let op = context.accounts[mailbox_idx.0].backend.operation(envelope.hash()); + let op = context.accounts[mailbox_idx.0] + .backend + .operation(envelope.hash()); let body = envelope.body(op); match self.mode { ViewMode::Attachment(aidx) if body.attachments()[aidx].is_html() => { @@ -317,7 +320,7 @@ impl Component for MailView { } _ => { let buf = { - let text = self.attachment_to_text(body); + let text = self.attachment_to_text(&body); // URL indexes must be colored (ugh..) MailView::plain_text_to_buf(&text, self.mode == ViewMode::Url) }; @@ -365,7 +368,9 @@ impl Component for MailView { }; self.dirty = true; } - UIEventType::Input(Key::Char('r')) if self.mode.is_attachment() || self.mode == ViewMode::Subview => { + UIEventType::Input(Key::Char('r')) + if self.mode.is_attachment() || self.mode == ViewMode::Subview => + { self.mode = ViewMode::Normal; self.subview.take(); self.dirty = true; @@ -383,26 +388,30 @@ impl Component for MailView { .unwrap(); let envelope: &Envelope = &mailbox.collection[self.coordinates.2]; - let op = context.accounts[self.coordinates.0].backend.operation(envelope.hash()); + let op = context.accounts[self.coordinates.0] + .backend + .operation(envelope.hash()); if let Some(u) = envelope.body(op).attachments().get(lidx) { match u.content_type() { ContentType::MessageRfc822 => { self.mode = ViewMode::Subview; match EnvelopeWrapper::new(u.bytes().to_vec()) { Ok(wrapper) => { - self.subview = Some(Box::new(EnvelopeView::new(wrapper, None, None))); - }, + self.subview = + Some(Box::new(EnvelopeView::new(wrapper, None, None))); + } Err(e) => { context.replies.push_back(UIEvent { id: 0, - event_type: UIEventType::StatusNotification( - format!("{}", e) - ), + event_type: UIEventType::StatusNotification(format!( + "{}", + e + )), }); } } return true; - }, + } ContentType::Text { .. } => { self.mode = ViewMode::Attachment(lidx); @@ -468,7 +477,9 @@ impl Component for MailView { let envelope: &Envelope = &mailbox.collection[self.coordinates.2]; let finder = LinkFinder::new(); - let op = context.accounts[self.coordinates.0].backend.operation(envelope.hash()); + let op = context.accounts[self.coordinates.0] + .backend + .operation(envelope.hash()); let mut t = envelope.body(op).text().to_string(); let links: Vec = finder.links(&t).collect(); if let Some(u) = links.get(lidx) { @@ -500,7 +511,9 @@ impl Component for MailView { } self.dirty = true; } - _ => { return false; } + _ => { + return false; + } } true } diff --git a/ui/src/components/mail/view/thread.rs b/ui/src/components/mail/view/thread.rs index e00c0724..6fa105bc 100644 --- a/ui/src/components/mail/view/thread.rs +++ b/ui/src/components/mail/view/thread.rs @@ -31,7 +31,6 @@ struct ThreadEntry { msg_idx: usize, } - #[derive(Debug, Default)] pub struct ThreadView { new_cursor_pos: usize, @@ -49,7 +48,9 @@ pub struct ThreadView { impl ThreadView { pub fn new(coordinates: (usize, usize, usize), context: &Context) -> Self { let mut stack: Vec<(usize, usize)> = Vec::with_capacity(32); - let mailbox = &context.accounts[coordinates.0][coordinates.1].as_ref().unwrap(); + let mailbox = &context.accounts[coordinates.0][coordinates.1] + .as_ref() + .unwrap(); let threads = &mailbox.threads; let container = &threads.containers()[threads.root_set()[coordinates.2]]; @@ -66,7 +67,7 @@ impl ThreadView { entries: Vec::new(), cursor_pos: 1, new_cursor_pos: 0, - .. Default::default() + ..Default::default() }; let mut line = 0; let mut max_ind = 0; @@ -87,22 +88,28 @@ impl ThreadView { view.new_expanded_pos = view.entries.len() - 1; view.expanded_pos = view.new_expanded_pos + 1; - let height = 2*view.entries.len(); + let height = 2 * view.entries.len(); let mut width = 0; let mut strings: Vec = Vec::with_capacity(view.entries.len()); - for e in &view.entries { let envelope: &Envelope = &mailbox.collection[e.msg_idx]; - strings.push(format!(" {}{} - {}", " ".repeat(e.index.0 * 4), envelope.date_as_str(), envelope.from_to_string())); - width = cmp::max(width, e.index.0 + strings.last().as_ref().unwrap().len() + 1); - + strings.push(format!( + " {}{} - {}", + " ".repeat(e.index.0 * 4), + envelope.date_as_str(), + envelope.field_from_to_string() + )); + width = cmp::max( + width, + e.index.0 + strings.last().as_ref().unwrap().len() + 1, + ); } - let mut content = CellBuffer::new(width, height, Cell::default()); + let mut content = CellBuffer::new(width, height, Cell::default()); for (y, e) in view.entries.iter().enumerate() { - if y > 0 && content.get_mut(e.index.0 * 4, 2*y - 1).is_some() { - let index = (e.index.0 * 4, 2*y - 1); + if y > 0 && content.get_mut(e.index.0 * 4, 2 * y - 1).is_some() { + let index = (e.index.0 * 4, 2 * y - 1); if content[index].ch() == ' ' { let mut ctr = 1; while content[(e.index.0 * 4 + ctr, 2 * y - 1)].ch() == ' ' { @@ -120,14 +127,14 @@ impl ThreadView { &mut content, Color::Default, Color::Default, - ((e.index.0 + 1, 2*y), (width - 1, height - 1)), + ((e.index.0 + 1, 2 * y), (width - 1, height - 1)), true, - ); - content[(e.index.0 * 4, 2*y)].set_ch(VERT_BOUNDARY); + ); + content[(e.index.0 * 4, 2 * y)].set_ch(VERT_BOUNDARY); for i in (e.index.0 * 4)..width { - content[(i, 2*y + 1)].set_ch(HORZ_BOUNDARY); + content[(i, 2 * y + 1)].set_ch(HORZ_BOUNDARY); } - content[(e.index.0 *4, 2*y + 1)].set_ch(LIGHT_UP_AND_HORIZONTAL); + content[(e.index.0 * 4, 2 * y + 1)].set_ch(LIGHT_UP_AND_HORIZONTAL); } //view.mailview = MailView::new((view.coordinates.0, view.coordinates.1, view.entries[view.expanded_pos].msg_idx), None, None); view.content = content; @@ -144,23 +151,28 @@ impl ThreadView { let msg_idx = if let Some(i) = container.message() { i } else { - mailbox.threads.containers()[ - container.first_child().unwrap() - ].message().unwrap() + mailbox.threads.containers()[container.first_child().unwrap()] + .message() + .unwrap() }; let envelope: &Envelope = &mailbox.collection[msg_idx]; - let op = context.accounts[self.coordinates.0].backend.operation(envelope.hash()); + let op = context.accounts[self.coordinates.0] + .backend + .operation(envelope.hash()); let body = envelope.body(op); let mut body_text: String = " \n".repeat(6); body_text.push_str(&String::from_utf8_lossy(&decode_rec(&body, None))); - let mut buf = CellBuffer::from(&body_text).split_newlines(); - + let mut buf = CellBuffer::from(body_text.as_str()).split_newlines(); let date = format!("Date: {}\n", envelope.date_as_str()); - let from = format!("From: {}\n", envelope.from_to_string()); + let from = format!("From: {}\n", envelope.field_from_to_string()); let message_id = &format!("Message-ID: <{}>\n\n", envelope.message_id_raw()); - let mut width = [date.len(), from.len(), message_id.len(), buf.size().0].iter().map(|&v| v).max().unwrap_or(1); + let mut width = [date.len(), from.len(), message_id.len(), buf.size().0] + .iter() + .cloned() + .max() + .unwrap_or(1); let height = buf.size().1; if width > buf.size().0 { buf.resize(width, height, Cell::default()); @@ -176,7 +188,7 @@ impl ThreadView { Color::Default, ((ind, 0), (width, height)), true, - ); + ); write_string_to_grid( &from, &mut buf, @@ -184,7 +196,7 @@ impl ThreadView { Color::Default, ((ind, 1), (width, height)), true, - ); + ); write_string_to_grid( &message_id, &mut buf, @@ -192,7 +204,7 @@ impl ThreadView { Color::Default, ((ind, 2), (width, height)), true, - ); + ); ThreadEntry { index: (ind, idx, order), @@ -237,8 +249,8 @@ impl ThreadView { self.cursor_pos = self.new_cursor_pos; for &idx in &[old_cursor_pos, self.new_cursor_pos] { let new_area = ( - set_y(upper_left, get_y(upper_left) + 2*(idx % rows)), - set_y(bottom_right, get_y(upper_left) + 2*(idx % rows)), + set_y(upper_left, get_y(upper_left) + 2 * (idx % rows)), + set_y(bottom_right, get_y(upper_left) + 2 * (idx % rows)), ); self.highlight_line(grid, new_area, idx); context.dirty_areas.push_back(new_area); @@ -253,13 +265,16 @@ impl ThreadView { grid, &self.content, area, - ((0, 2*top_idx), (width - 1, height - 1)), + ((0, 2 * top_idx), (width - 1, height - 1)), ); self.highlight_line( grid, ( - set_y(upper_left, get_y(upper_left) + 2*(self.cursor_pos % rows)), - set_y(bottom_right, get_y(upper_left) + 2*(self.cursor_pos % rows)), + set_y(upper_left, get_y(upper_left) + 2 * (self.cursor_pos % rows)), + set_y( + bottom_right, + get_y(upper_left) + 2 * (self.cursor_pos % rows), + ), ), self.cursor_pos, ); @@ -292,22 +307,25 @@ impl Component for ThreadView { let mid = get_y(upper_left) + total_rows - bottom_entity_rows; if !self.dirty { - self.mailview.draw(grid, (set_y(upper_left, mid + 1), bottom_right), context); + self.mailview + .draw(grid, (set_y(upper_left, mid + 1), bottom_right), context); return; } self.dirty = false; let y = { - let mailbox = &mut context.accounts[self.coordinates.0][self.coordinates.1].as_ref().unwrap(); + let mailbox = &mut context.accounts[self.coordinates.0][self.coordinates.1] + .as_ref() + .unwrap(); let threads = &mailbox.threads; let container = &threads.containers()[threads.root_set()[self.coordinates.2]]; let i = if let Some(i) = container.message() { i } else { - threads.containers()[ - container.first_child().unwrap() - ].message().unwrap() + threads.containers()[container.first_child().unwrap()] + .message() + .unwrap() }; let envelope: &Envelope = &mailbox.collection[i]; @@ -318,7 +336,7 @@ impl Component for ThreadView { Color::Default, area, true, - ); + ); for x in x..=get_x(bottom_right) { grid[(x, y)].set_ch(' '); grid[(x, y)].set_bg(Color::Default); @@ -341,7 +359,7 @@ impl Component for ThreadView { &self.content, (set_y(upper_left, y), set_y(bottom_right, mid - 1)), ((0, 0), (width - 1, height - 1)), - ); + ); for x in get_x(upper_left)..=get_x(bottom_right) { grid[(x, mid)].set_ch(HORZ_BOUNDARY); } @@ -356,10 +374,23 @@ impl Component for ThreadView { if self.new_expanded_pos != self.expanded_pos { self.expanded_pos = self.new_expanded_pos; - self.mailview = MailView::new((self.coordinates.0, self.coordinates.1, self.entries[self.expanded_pos].msg_idx), None, None); + self.mailview = MailView::new( + ( + self.coordinates.0, + self.coordinates.1, + self.entries[self.expanded_pos].msg_idx, + ), + None, + None, + ); } - self.draw_list(grid, (set_y(upper_left, y), set_y(bottom_right, mid - 1)), context); - self.mailview.draw(grid, (set_y(upper_left, mid + 1), bottom_right), context); + self.draw_list( + grid, + (set_y(upper_left, y), set_y(bottom_right, mid - 1)), + context, + ); + self.mailview + .draw(grid, (set_y(upper_left, mid + 1), bottom_right), context); } fn process_event(&mut self, event: &UIEvent, context: &mut Context) -> bool { if self.mailview.process_event(event, context) { @@ -372,7 +403,7 @@ impl Component for ThreadView { self.dirty = true; } return true; - }, + } UIEventType::Input(Key::Down) => { let height = self.entries.len(); if height > 0 && self.cursor_pos + 1 < height { @@ -385,10 +416,10 @@ impl Component for ThreadView { self.new_expanded_pos = self.cursor_pos; self.dirty = true; return true; - }, + } UIEventType::Resize => { self.dirty = true; - }, + } _ => {} } false diff --git a/ui/src/components/mod.rs b/ui/src/components/mod.rs index d4ecb6d5..179f989c 100644 --- a/ui/src/components/mod.rs +++ b/ui/src/components/mod.rs @@ -36,7 +36,7 @@ pub mod utilities; pub use self::utilities::*; use std::fmt; -use std::fmt::{Display, Debug}; +use std::fmt::{Debug, Display}; use std::ops::Deref; use super::{Key, UIEvent, UIEventType}; @@ -76,7 +76,6 @@ impl Display for Entity { } } - impl Deref for Entity { type Target = Box; @@ -227,22 +226,22 @@ fn write_string_to_grid( eprintln!(" Invalid area with string {} and area {:?}", s, area); return (x, y); } - 'char: for c in s.chars() { - grid[(x, y)].set_ch(c); - grid[(x, y)].set_fg(fg_color); - grid[(x, y)].set_bg(bg_color); - x += 1; + 'char: for c in s.chars() { + grid[(x, y)].set_ch(c); + grid[(x, y)].set_fg(fg_color); + grid[(x, y)].set_bg(bg_color); + x += 1; - if x == (get_x(bottom_right)) + 1 || x > get_x(bounds) { - x = get_x(upper_left); - y += 1; - if y > (get_y(bottom_right)) || y > get_y(bounds) { - return (x, y - 1); - } - if !line_break { - break 'char; - } + if x == (get_x(bottom_right)) + 1 || x > get_x(bounds) { + x = get_x(upper_left); + y += 1; + if y > (get_y(bottom_right)) || y > get_y(bounds) { + return (x, y - 1); } + if !line_break { + break 'char; + } + } } (x, y) } diff --git a/ui/src/components/utilities.rs b/ui/src/components/utilities.rs index de9bd0d6..5691fbc3 100644 --- a/ui/src/components/utilities.rs +++ b/ui/src/components/utilities.rs @@ -65,7 +65,9 @@ impl Component for HSplit { for i in get_x(upper_left)..=get_x(bottom_right) { grid[(i, mid)].set_ch('─'); } - context.dirty_areas.push_back(((get_x(upper_left), mid), (get_x(bottom_right), mid))); + context + .dirty_areas + .push_back(((get_x(upper_left), mid), (get_x(bottom_right), mid))); } self.top.component.draw( @@ -154,14 +156,13 @@ impl Component for VSplit { .get(mid, get_y(bottom_right) - 1) .map(|a| a.ch()) .unwrap_or_else(|| ' '); - match c { - HORZ_BOUNDARY => { - grid[(mid, get_y(bottom_right) + 1)].set_ch(LIGHT_UP_AND_HORIZONTAL); - } - _ => {} + if let HORZ_BOUNDARY = c { + grid[(mid, get_y(bottom_right) + 1)].set_ch(LIGHT_UP_AND_HORIZONTAL); } } - context.dirty_areas.push_back(((mid, get_y(upper_left)), (mid, get_y(bottom_right)))); + context + .dirty_areas + .push_back(((mid, get_y(upper_left)), (mid, get_y(bottom_right)))); } self.left .component @@ -209,13 +210,13 @@ impl fmt::Display for Pager { } impl Pager { - pub fn update_from_string(&mut self, text: String) -> () { + pub fn update_from_str(&mut self, text: &str) -> () { let lines: Vec<&str> = text.trim().split('\n').collect(); let height = lines.len() + 1; let width = lines.iter().map(|l| l.len()).max().unwrap_or(0); let mut content = CellBuffer::new(width, height, Cell::with_char(' ')); //interpret_format_flowed(&text); - Pager::print_string(&mut content, &text); + Pager::print_string(&mut content, text); self.content = content; self.height = height; self.width = width; @@ -256,11 +257,11 @@ impl Pager { Pager::print_string(&mut content, &text); Pager { cursor_pos: cursor_pos.unwrap_or(0), - height: height, - width: width, + height, + width, dirty: true, - content: content, - .. Default::default() + content, + ..Default::default() } } pub fn from_str(s: &str, cursor_pos: Option) -> Self { @@ -275,7 +276,7 @@ impl Pager { width, dirty: true, content, - .. Default::default() + ..Default::default() } } pub fn from_buf(content: CellBuffer, cursor_pos: Option) -> Self { @@ -286,7 +287,7 @@ impl Pager { width, dirty: true, content, - .. Default::default() + ..Default::default() } } pub fn print_string(content: &mut CellBuffer, s: &str) { @@ -327,14 +328,14 @@ impl Component for Pager { match mvm { PagerMovement::PageUp => { self.cursor_pos = self.cursor_pos.saturating_sub(height); - }, + } PagerMovement::PageDown => { - if self.cursor_pos + 2*height + 1 < self.height { + if self.cursor_pos + 2 * height + 1 < self.height { self.cursor_pos += height; } else { self.cursor_pos = self.height.saturating_sub(height).saturating_sub(1); } - }, + } } } @@ -394,7 +395,9 @@ impl Component for Pager { self.dirty = true; return false; } - _ => { return false; } + _ => { + return false; + } } true } @@ -586,7 +589,7 @@ impl Component for StatusBar { } _ => {} } - return false; + false } fn is_dirty(&self) -> bool { self.dirty || self.container.component.is_dirty() @@ -617,7 +620,9 @@ impl fmt::Display for TextBox { impl Component for TextBox { fn draw(&mut self, _grid: &mut CellBuffer, _area: Area, _context: &mut Context) {} - fn process_event(&mut self, _event: &UIEvent, _context: &mut Context) -> bool { false } + fn process_event(&mut self, _event: &UIEvent, _context: &mut Context) -> bool { + false + } fn set_dirty(&mut self) {} } @@ -669,7 +674,7 @@ impl Component for Progress { unimplemented!() } fn process_event(&mut self, _event: &UIEvent, _context: &mut Context) -> bool { - return false; + false } fn set_dirty(&mut self) {} } @@ -751,13 +756,10 @@ impl Component for Tabbed { } } fn process_event(&mut self, event: &UIEvent, context: &mut Context) -> bool { - match &event.event_type { - UIEventType::Input(Key::Char('T')) => { - self.cursor_pos = (self.cursor_pos + 1) % self.children.len(); - self.children[self.cursor_pos].set_dirty(); - return true; - } - _ => {} + if let UIEventType::Input(Key::Char('T')) = event.event_type { + self.cursor_pos = (self.cursor_pos + 1) % self.children.len(); + self.children[self.cursor_pos].set_dirty(); + return true; } self.children[self.cursor_pos].process_event(event, context) } diff --git a/ui/src/conf/mod.rs b/ui/src/conf/mod.rs index 69fe3746..9fe82090 100644 --- a/ui/src/conf/mod.rs +++ b/ui/src/conf/mod.rs @@ -117,10 +117,13 @@ impl Settings { sent_folder, }; - s.insert(id, AccountConf { - account: acc, - conf: x - }); + s.insert( + id, + AccountConf { + account: acc, + conf: x, + }, + ); } Settings { diff --git a/ui/src/execute/actions.rs b/ui/src/execute/actions.rs index 3fd12033..ff4154e4 100644 --- a/ui/src/execute/actions.rs +++ b/ui/src/execute/actions.rs @@ -23,14 +23,13 @@ * User actions that need to be handled by the UI */ -pub use melib::mailbox::{SortOrder, SortField}; +pub use melib::mailbox::{SortField, SortOrder}; #[derive(Debug, Clone)] pub enum MailListingAction { ToggleThreaded, } - #[derive(Debug, Clone)] pub enum Action { MailListing(MailListingAction), diff --git a/ui/src/state.rs b/ui/src/state.rs index 978793f5..0ba38263 100644 --- a/ui/src/state.rs +++ b/ui/src/state.rs @@ -32,8 +32,8 @@ use super::*; use chan::{Receiver, Sender}; use fnv::FnvHashMap; use std::io::Write; -use std::thread; use std::result; +use std::thread; use std::time; use termion::raw::IntoRawMode; use termion::screen::AlternateScreen; @@ -60,9 +60,9 @@ impl InputHandler { tx.send(ThreadEvent::UIEvent(UIEventType::ChangeMode(UIMode::Fork))); }, &rx, - ) + ) }) - .unwrap(); + .unwrap(); } fn kill(&self) { self.tx.send(false); @@ -100,23 +100,33 @@ impl Context { } pub fn account_status(&mut self, idx_a: usize, idx_m: usize) -> result::Result { let s = self.accounts[idx_a].status(idx_m)?; - if let Some(Some(event)) = s { - eprintln!("setting up notification"); - let (idx_a, idx_m) = self.mailbox_hashes[&event.folder]; - let subjects = { - let mut ret = Vec::with_capacity(event.index.len()); - eprintln!("index is {:?}", &event.index); - for &i in &event.index { - ret.push(self.accounts[idx_a][idx_m].as_ref().unwrap().collection[i].subject()); - } - ret - }; - self.replies.push_back(UIEvent { id: 0, event_type: UIEventType::Notification(format!("Update in {}/{}, indexes {:?}", self.accounts[idx_a].name(), self.accounts[idx_a][idx_m].as_ref().unwrap().folder.name(), subjects)) }); - Ok(true) - } else if let Some(None) = s { - Ok(true) - } else { - Ok(false) + match s { + LoadMailboxResult::New(event) => { + eprintln!("setting up notification"); + let (idx_a, idx_m) = self.mailbox_hashes[&event.folder]; + let subjects = { + let mut ret = Vec::with_capacity(event.index.len()); + eprintln!("index is {:?}", &event.index); + for &i in &event.index { + ret.push( + self.accounts[idx_a][idx_m].as_ref().unwrap().collection[i].subject(), + ); + } + ret + }; + self.replies.push_back(UIEvent { + id: 0, + event_type: UIEventType::Notification(format!( + "Update in {}/{}, indexes {:?}", + self.accounts[idx_a].name(), + self.accounts[idx_a][idx_m].as_ref().unwrap().folder.name(), + subjects + )), + }); + Ok(true) + } + LoadMailboxResult::Loaded => Ok(true), + LoadMailboxResult::Refresh => Ok(false), } } } @@ -154,6 +164,12 @@ impl Drop for State { } } +impl Default for State { + fn default() -> Self { + Self::new() + } +} + impl State { pub fn new() -> Self { /* Create a channel to communicate with other threads. The main process is the sole receiver. @@ -236,8 +252,10 @@ impl State { startup_thread: Some(startup_tx.clone()), threads: FnvHashMap::with_capacity_and_hasher(1, Default::default()), }; - s.threads - .insert(startup_thread.thread().id(), (startup_tx.clone(), startup_thread)); + s.threads.insert( + startup_thread.thread().id(), + (startup_tx.clone(), startup_thread), + ); write!( s.stdout(), "{}{}{}", @@ -290,13 +308,16 @@ impl State { thread::sleep(dur); } }) - .expect("Failed to spawn startup-thread in hash_to_folder()") + .expect("Failed to spawn startup-thread in hash_to_folder()") }; self.startup_thread = Some(startup_tx.clone()); self.threads .insert(startup_thread.thread().id(), (startup_tx, startup_thread)); } else { - eprintln!("BUG: mailbox with hash {} not found in mailbox_hashes.", hash); + eprintln!( + "BUG: mailbox with hash {} not found in mailbox_hashes.", + hash + ); } } diff --git a/ui/src/types/accounts.rs b/ui/src/types/accounts.rs index 855a2dce..fe490190 100644 --- a/ui/src/types/accounts.rs +++ b/ui/src/types/accounts.rs @@ -25,12 +25,18 @@ use async::*; use conf::AccountConf; -use melib::error::Result; -use mailbox::backends::{MailBackend, Folder, Backends, RefreshEventConsumer}; +use mailbox::backends::{Backends, Folder, MailBackend, RefreshEventConsumer}; use mailbox::*; +use melib::error::Result; +use std::mem; use std::ops::{Index, IndexMut}; use std::result; -use std::mem; + +pub enum LoadMailboxResult { + New(NewMailEvent), + Refresh, + Loaded, +} pub struct NewMailEvent { pub folder: u64, @@ -68,15 +74,13 @@ impl Account { workers.push(Some(handle)); } Account { - name: name, - folders: folders, - workers: workers, - - sent_folder: sent_folder, - + name, + folders, + workers, + sent_folder, settings: settings.clone(), runtime_settings: settings, - backend: backend, + backend, } } pub fn reload(&mut self, idx: usize) { @@ -91,6 +95,9 @@ impl Account { pub fn len(&self) -> usize { self.folders.len() } + pub fn is_empty(&self) -> bool { + self.folders.is_empty() + } pub fn list_folders(&self) -> Vec { let mut folders = self.backend.folders(); if let Some(folder_renames) = self.settings.conf().folders() { @@ -109,8 +116,13 @@ impl Account { pub fn workers(&mut self) -> &mut Vec { &mut self.workers } - fn load_mailbox(&mut self, index: usize, envelopes: Result>) -> Option> { - let mut ret: Option> = None; + + fn load_mailbox( + &mut self, + index: usize, + envelopes: Result>, + ) -> LoadMailboxResult { + let mut ret: LoadMailboxResult = LoadMailboxResult::Refresh; // TODO: Cleanup this function let folders = self.backend.folders(); @@ -118,22 +130,50 @@ impl Account { if self.sent_folder.is_some() { let id = self.sent_folder.unwrap(); if id == index { - /* ======================== */ - let old_m = mem::replace(&mut self.folders[index], Some(Mailbox::new(folder, &None, envelopes))); + /* ======================== */ + let old_m = mem::replace( + &mut self.folders[index], + Some(Mailbox::new(folder, &None, envelopes)), + ); if let Some(old_m) = old_m { if self.folders[index].is_some() && old_m.is_ok() { - let diff = self.folders[index].as_ref().map(|v| v.as_ref().unwrap().collection.len()).unwrap_or(0).saturating_sub(old_m.as_ref().map(|v| v.collection.len()).unwrap_or(0)); + let diff = self.folders[index] + .as_ref() + .map(|v| v.as_ref().unwrap().collection.len()) + .unwrap_or(0) + .saturating_sub( + old_m.as_ref().map(|v| v.collection.len()).unwrap_or(0), + ); if diff > 0 { - let mut index = old_m.as_ref().unwrap().collection.iter().zip(&self.folders[index].as_ref().unwrap().as_ref().unwrap().collection).count(); - ret = Some(Some(NewMailEvent { + let mut index = old_m + .as_ref() + .unwrap() + .collection + .iter() + .zip( + &self.folders[index] + .as_ref() + .unwrap() + .as_ref() + .unwrap() + .collection, + ) + .count(); + ret = LoadMailboxResult::New(NewMailEvent { folder: folder.hash(), - index: (index.saturating_sub(1)..(self.folders[index].as_ref().unwrap().as_ref().unwrap().collection.len().saturating_sub(1))).collect(), - })); - + index: (index.saturating_sub(1) + ..(self.folders[index] + .as_ref() + .unwrap() + .as_ref() + .unwrap() + .collection + .len() + .saturating_sub(1))) + .collect(), + }); } } - } else { - ret = Some(None); } /* ======================== */ } else { @@ -151,54 +191,98 @@ impl Account { if sent[0].is_none() { sent[0] = Some(Mailbox::new(sent_path, &None, envelopes.clone())); } - /* ======================== */ - let old_m = mem::replace(&mut cur[0], Some(Mailbox::new(folder, &sent[0], envelopes))); + /* ======================== */ + let old_m = + mem::replace(&mut cur[0], Some(Mailbox::new(folder, &sent[0], envelopes))); if let Some(old_m) = old_m { if cur[0].is_some() && old_m.is_ok() { - let diff = cur[0].as_ref().map(|v| v.as_ref().unwrap().collection.len()).unwrap_or(0).saturating_sub(old_m.as_ref().map(|v| v.collection.len()).unwrap_or(0)); + let diff = cur[0] + .as_ref() + .map(|v| v.as_ref().unwrap().collection.len()) + .unwrap_or(0) + .saturating_sub( + old_m.as_ref().map(|v| v.collection.len()).unwrap_or(0), + ); if diff > 0 { - let mut index = old_m.as_ref().unwrap().collection.iter().zip(&cur[0].as_ref().unwrap().as_ref().unwrap().collection).count(); - ret = Some(Some(NewMailEvent { + let mut index = old_m + .as_ref() + .unwrap() + .collection + .iter() + .zip(&cur[0].as_ref().unwrap().as_ref().unwrap().collection) + .count(); + ret = LoadMailboxResult::New(NewMailEvent { folder: folder.hash(), - index: (index.saturating_sub(1)..(cur[0].as_ref().unwrap().as_ref().unwrap().collection.len()).saturating_sub(1)).collect(), - })); - + index: (index.saturating_sub(1) + ..(cur[0] + .as_ref() + .unwrap() + .as_ref() + .unwrap() + .collection + .len()) + .saturating_sub(1)) + .collect(), + }); } - } - } else { - ret = Some(None); } - /* ======================== */ + /* ======================== */ } } else { /* ======================== */ - let old_m = mem::replace(&mut self.folders[index], Some(Mailbox::new(folder, &None, envelopes))); - if let Some(old_m) = old_m { - if self.folders[index].is_some() && old_m.is_ok() { - let diff = self.folders[index].as_ref().map(|v| v.as_ref().unwrap().collection.len()).unwrap_or(0).saturating_sub(old_m.as_ref().map(|v| v.collection.len()).unwrap_or(0)); - if diff > 0 { - let mut index = old_m.as_ref().unwrap().collection.iter().zip(&self.folders[index].as_ref().unwrap().as_ref().unwrap().collection).count(); - ret = Some(Some(NewMailEvent { - folder: folder.hash(), - index: (index.saturating_sub(1)..(self.folders[index].as_ref().unwrap().as_ref().unwrap().collection.len().saturating_sub(1))).collect(), - })); - - } + let old_m = mem::replace( + &mut self.folders[index], + Some(Mailbox::new(folder, &None, envelopes)), + ); + if let Some(old_m) = old_m { + if self.folders[index].is_some() && old_m.is_ok() { + let diff = self.folders[index] + .as_ref() + .map(|v| v.as_ref().unwrap().collection.len()) + .unwrap_or(0) + .saturating_sub(old_m.as_ref().map(|v| v.collection.len()).unwrap_or(0)); + if diff > 0 { + let mut index = old_m + .as_ref() + .unwrap() + .collection + .iter() + .zip( + &self.folders[index] + .as_ref() + .unwrap() + .as_ref() + .unwrap() + .collection, + ) + .count(); + ret = LoadMailboxResult::New(NewMailEvent { + folder: folder.hash(), + index: (index.saturating_sub(1) + ..(self.folders[index] + .as_ref() + .unwrap() + .as_ref() + .unwrap() + .collection + .len() + .saturating_sub(1))) + .collect(), + }); } - } else { - ret = Some(None); } + } /* ======================== */ }; ret } - pub fn status(&mut self, index: usize) -> result::Result>, usize> { + pub fn status(&mut self, index: usize) -> result::Result { match self.workers[index].as_mut() { None => { - return Ok(None); + return Ok(LoadMailboxResult::Loaded); } Some(ref mut w) => match w.poll() { Ok(AsyncStatus::NoUpdate) => { diff --git a/ui/src/types/cells.rs b/ui/src/types/cells.rs index 7a1e96fe..53fdcd94 100644 --- a/ui/src/types/cells.rs +++ b/ui/src/types/cells.rs @@ -106,13 +106,22 @@ pub struct CellBuffer { impl fmt::Debug for CellBuffer { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "CellBuffer {{ cols: {}, rows: {}, buf: {} cells", self.cols, self.rows, self.buf.len()) + write!( + f, + "CellBuffer {{ cols: {}, rows: {}, buf: {} cells", + self.cols, + self.rows, + self.buf.len() + ) } } impl CellBuffer { pub fn area(&self) -> Area { - ((0, 0), (self.cols.saturating_sub(1), self.rows.saturating_sub(1))) + ( + (0, 0), + (self.cols.saturating_sub(1), self.rows.saturating_sub(1)), + ) } pub fn set_cols(&mut self, new_cols: usize) { self.cols = new_cols; @@ -216,13 +225,13 @@ impl Default for CellBuffer { } } -impl<'a> From<&'a String> for CellBuffer { - fn from(s: &'a String) -> Self { +impl<'a> From<&'a str> for CellBuffer { + fn from(s: &'a str) -> Self { let lines: Vec<&str> = s.lines().map(|l| l.trim_right()).collect(); let len = s.len() + lines.len(); let mut buf = CellBuffer::new(len, 1, Cell::default()); let mut x = 0; - for l in lines.iter() { + for l in &lines { for (idx, c) in l.chars().enumerate() { buf[(x + idx, 0)].set_ch(c); } diff --git a/ui/src/types/helpers.rs b/ui/src/types/helpers.rs index 6b437e2a..5de577d0 100644 --- a/ui/src/types/helpers.rs +++ b/ui/src/types/helpers.rs @@ -22,7 +22,7 @@ use std; use std::fs; use std::fs::OpenOptions; -use std::io::{Write, Read}; +use std::io::{Read, Write}; use std::path::PathBuf; use uuid::Uuid; @@ -52,10 +52,11 @@ impl File { &self.path } pub fn read_to_string(&self) -> String { - let mut buf = Vec::new(); - let mut f = fs::File::open(&self.path).expect(&format!("Can't open {}", &self.path.display())); - f.read_to_end(&mut buf).expect(&format!("Can't read {}", &self.path.display())); + let mut f = fs::File::open(&self.path) + .unwrap_or_else(|_| panic!("Can't open {}", &self.path.display())); + f.read_to_end(&mut buf) + .unwrap_or_else(|_| panic!("Can't read {}", &self.path.display())); String::from_utf8(buf).unwrap() } } diff --git a/ui/src/types/mod.rs b/ui/src/types/mod.rs index 8dcc76de..eb4f04b3 100644 --- a/ui/src/types/mod.rs +++ b/ui/src/types/mod.rs @@ -20,7 +20,7 @@ */ pub mod accounts; -pub use self::accounts::Account; +pub use self::accounts::{Account, LoadMailboxResult}; #[macro_use] mod position; #[macro_use] diff --git a/ui/src/types/position.rs b/ui/src/types/position.rs index 88c91f40..61ebb79a 100644 --- a/ui/src/types/position.rs +++ b/ui/src/types/position.rs @@ -87,7 +87,7 @@ macro_rules! height { /// # } /// ``` #[macro_export] -macro_rules! width{ +macro_rules! width { ($a:expr) => { (get_x(bottom_right!($a))).saturating_sub(get_x(upper_left!($a))) };