diff --git a/Cargo.lock b/Cargo.lock index c71e299..59f0f14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "ansi_term" version = "0.11.0" diff --git a/Cargo.toml b/Cargo.toml index aa36ff5..7ff3c6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,8 @@ documentation = "https://github.com/untitaker/mates.rs" homepage = "https://github.com/untitaker/mates.rs" repository = "https://github.com/untitaker/mates.rs" +edition = "2018" + [lib] name = "mates" path = "src/mates/lib.rs" diff --git a/src/bin/mates.rs b/src/bin/mates.rs index e34f9f5..651d38a 100644 --- a/src/bin/mates.rs +++ b/src/bin/mates.rs @@ -1,4 +1,6 @@ extern crate mates; use mates::cli; -fn main() { cli::cli_main() } +fn main() { + cli::cli_main() +} diff --git a/src/mates/app.rs b/src/mates/app.rs index 36b79fe..1be1a7c 100644 --- a/src/mates/app.rs +++ b/src/mates/app.rs @@ -1,4 +1,4 @@ -use clap::{App, Arg, AppSettings, SubCommand}; +use clap::{App, AppSettings, Arg, SubCommand}; pub fn app() -> App<'static, 'static> { App::new("mates") @@ -6,20 +6,29 @@ pub fn app() -> App<'static, 'static> { .author("Markus Unterwaditzer") .about("A simple commandline addressbook") .setting(AppSettings::SubcommandRequired) - .subcommand(SubCommand::with_name("index") - .about("Rewrite/create the index")) - .subcommand(SubCommand::with_name("mutt-query") - .about("Search for contact, output is usable for mutt's query_command.") - .arg(Arg::with_name("query").index(1))) - .subcommand(SubCommand::with_name("file-query") - .about("Search for contact, return just the filename.") - .arg(Arg::with_name("query").index(1))) - .subcommand(SubCommand::with_name("email-query") - .about("Search for contact, return \"name \".") - .arg(Arg::with_name("query").index(1))) - .subcommand(SubCommand::with_name("add") - .about("Take mail from stdin, add sender to contacts. Print filename.")) - .subcommand(SubCommand::with_name("edit") - .about("Open contact (given by filepath or search-string) interactively.") - .arg(Arg::with_name("file-or-query").index(1))) + .subcommand(SubCommand::with_name("index").about("Rewrite/create the index")) + .subcommand( + SubCommand::with_name("mutt-query") + .about("Search for contact, output is usable for mutt's query_command.") + .arg(Arg::with_name("query").index(1)), + ) + .subcommand( + SubCommand::with_name("file-query") + .about("Search for contact, return just the filename.") + .arg(Arg::with_name("query").index(1)), + ) + .subcommand( + SubCommand::with_name("email-query") + .about("Search for contact, return \"name \".") + .arg(Arg::with_name("query").index(1)), + ) + .subcommand( + SubCommand::with_name("add") + .about("Take mail from stdin, add sender to contacts. Print filename."), + ) + .subcommand( + SubCommand::with_name("edit") + .about("Open contact (given by filepath or search-string) interactively.") + .arg(Arg::with_name("file-or-query").index(1)), + ) } diff --git a/src/mates/cli.rs b/src/mates/cli.rs index b96f84c..1b25412 100644 --- a/src/mates/cli.rs +++ b/src/mates/cli.rs @@ -1,19 +1,19 @@ use std::borrow::ToOwned; use std::env; use std::error::Error; -use std::fmt;use std::fs; -use std::io::{Read,Write}; +use std::fmt; +use std::fs; use std::io; +use std::io::{Read, Write}; use std::path; use std::process; -use atomicwrites::{AtomicFile,AllowOverwrite}; - -use utils; -use utils::CustomPathExt; -use app; -use editor; +use atomicwrites::{AllowOverwrite, AtomicFile}; +use crate::app; +use crate::editor; +use crate::utils; +use crate::utils::CustomPathExt; #[inline] fn get_pwd() -> path::PathBuf { @@ -37,8 +37,8 @@ fn build_index(outfile: &path::Path, dir: &path::Path) -> MainResult<()> { let af = AtomicFile::new(&outfile, AllowOverwrite); let mut errors = false; - try!(af.write::<(), io::Error, _>(|outf| { - for entry in try!(fs::read_dir(dir)) { + af.write::<(), io::Error, _>(|outf| { + for entry in fs::read_dir(dir)? { let entry = match entry { Ok(x) => x, Err(e) => { @@ -59,23 +59,23 @@ fn build_index(outfile: &path::Path, dir: &path::Path) -> MainResult<()> { Err(e) => { println!("Error while reading {}: {}", pathbuf.display(), e); errors = true; - continue + continue; } }; match utils::index_item_from_contact(&contact) { Ok(index_string) => { - try!(outf.write_all(index_string.as_bytes())); - }, + outf.write_all(index_string.as_bytes())?; + } Err(e) => { println!("Error while indexing {}: {}", pathbuf.display(), e); errors = true; - continue + continue; } }; - }; + } Ok(()) - })); + })?; if errors { Err(MainError::new("Several errors happened while generating the index.").into()) @@ -89,8 +89,8 @@ pub fn cli_main() { Err(e) => { writeln!(&mut io::stderr(), "{}", e).unwrap(); process::exit(1); - }, - _ => () + } + _ => (), }; } @@ -106,47 +106,49 @@ pub fn cli_main_raw() -> MainResult<()> { } }; - let submatches = matches.subcommand_matches(command).expect("Internal error."); + let submatches = matches + .subcommand_matches(command) + .expect("Internal error."); match command { "index" => { - println!("Rebuilding index file \"{}\"...", config.index_path.display()); - try!(build_index(&config.index_path, &config.vdir_path)); - }, + println!( + "Rebuilding index file \"{}\"...", + config.index_path.display() + ); + build_index(&config.index_path, &config.vdir_path)?; + } "mutt-query" => { let query = submatches.value_of("query").unwrap_or(""); - try!(mutt_query(&config, &query[..])); - }, + mutt_query(&config, &query[..])?; + } "file-query" => { let query = submatches.value_of("query").unwrap_or(""); - try!(file_query(&config, &query[..])); - }, + file_query(&config, &query[..])?; + } "email-query" => { let query = submatches.value_of("query").unwrap_or(""); - try!(email_query(&config, &query[..])); - }, + email_query(&config, &query[..])?; + } "add" => { let stdin = io::stdin(); let mut email = String::new(); - try!(stdin.lock().read_to_string(&mut email)); - let contact = try!(utils::add_contact_from_email( - &config.vdir_path, - &email[..] - )); + stdin.lock().read_to_string(&mut email)?; + let contact = utils::add_contact_from_email(&config.vdir_path, &email[..])?; println!("{}", contact.path.display()); - let mut index_fp = try!(fs::OpenOptions::new() - .append(true) - .write(true) - .open(&config.index_path)); + let mut index_fp = fs::OpenOptions::new() + .append(true) + .write(true) + .open(&config.index_path)?; - let index_entry = try!(utils::index_item_from_contact(&contact)); - try!(index_fp.write_all(index_entry.as_bytes())); - }, + let index_entry = utils::index_item_from_contact(&contact)?; + index_fp.write_all(index_entry.as_bytes())?; + } "edit" => { let query = submatches.value_of("file-or-query").unwrap_or(""); - try!(edit_contact(&config, &query[..])); - }, + edit_contact(&config, &query[..])?; + } _ => { return Err(MainError::new(format!("Invalid command: {}", command)).into()); } @@ -158,7 +160,7 @@ fn edit_contact(config: &Configuration, query: &str) -> MainResult<()> { let results = if get_pwd().join(query).is_file() { vec![path::PathBuf::from(query)] } else { - try!(utils::file_query(config, query)).into_iter().collect() + utils::file_query(config, query)?.into_iter().collect() }; if results.len() < 1 { @@ -172,13 +174,13 @@ fn edit_contact(config: &Configuration, query: &str) -> MainResult<()> { let fcontent = { let mut fcontent = String::new(); - let mut file = try!(fs::File::open(fpath)); - try!(file.read_to_string(&mut fcontent)); + let mut file = fs::File::open(fpath)?; + file.read_to_string(&mut fcontent)?; fcontent }; if (&fcontent[..]).trim().len() == 0 { - try!(fs::remove_file(fpath)); + fs::remove_file(fpath)?; return Err(MainError::new("Contact emptied, file removed.").into()); }; @@ -186,38 +188,38 @@ fn edit_contact(config: &Configuration, query: &str) -> MainResult<()> { } fn mutt_query<'a>(config: &Configuration, query: &str) -> MainResult<()> { - println!(""); // For some reason mutt requires an empty line - // We need to ignore errors here, otherwise mutt's UI will glitch + println!(""); // For some reason mutt requires an empty line + // We need to ignore errors here, otherwise mutt's UI will glitch if let Ok(items) = utils::index_query(config, query) { for item in items { if item.email.len() > 0 && item.name.len() > 0 { println!("{}\t{}", item.email, item.name); }; - }; + } }; Ok(()) } fn file_query<'a>(config: &Configuration, query: &str) -> MainResult<()> { - for path in try!(utils::file_query(config, query)).iter() { + for path in utils::file_query(config, query)?.iter() { println!("{}", path.display()); - }; + } Ok(()) } fn email_query<'a>(config: &Configuration, query: &str) -> MainResult<()> { - for item in try!(utils::index_query(config, query)) { + for item in utils::index_query(config, query)? { if item.name.len() > 0 && item.email.len() > 0 { println!("{} <{}>", item.name, item.email); }; - }; + } Ok(()) } pub struct Configuration { pub index_path: path::PathBuf, pub vdir_path: path::PathBuf, - pub grep_cmd: String + pub grep_cmd: String, } impl Configuration { @@ -227,35 +229,39 @@ impl Configuration { Some(x) => path::PathBuf::from(&x), None => match get_envvar("HOME") { Some(home) => get_pwd().join(&home).join(".mates_index"), - None => return Err("Unable to determine user's home directory.".to_owned()) - } + None => return Err("Unable to determine user's home directory.".to_owned()), + }, }, vdir_path: match get_envvar("MATES_DIR") { Some(x) => path::PathBuf::from(&x), - None => return Err("MATES_DIR must be set to your vdir path (directory of vcf-files).".to_owned()) + None => { + return Err( + "MATES_DIR must be set to your vdir path (directory of vcf-files)." + .to_owned(), + ) + } }, grep_cmd: match get_envvar("MATES_GREP") { Some(x) => x, - None => "grep -i".to_owned() - } + None => "grep -i".to_owned(), + }, }) } } - #[derive(PartialEq, Eq, Debug)] pub struct MainError { desc: String, } -pub type MainResult = Result>; +pub type MainResult = Result>; impl Error for MainError { fn description(&self) -> &str { &self.desc[..] } - fn cause(&self) -> Option<&Error> { + fn cause(&self) -> Option<&dyn Error> { None } } @@ -268,8 +274,6 @@ impl fmt::Display for MainError { impl MainError { pub fn new>(desc: T) -> Self { - MainError { - desc: desc.into(), - } + MainError { desc: desc.into() } } } diff --git a/src/mates/editor/mod.rs b/src/mates/editor/mod.rs index 6b37793..cc6526e 100644 --- a/src/mates/editor/mod.rs +++ b/src/mates/editor/mod.rs @@ -1,16 +1,16 @@ use std::fs; -use std::io::{Read,Write}; -use std::process; +use std::io::{Read, Write}; use std::path::Path; +use std::process; use vobject; use atomicwrites; -use cursive::Cursive; use cursive::theme; -use cursive::theme::Color::*; use cursive::theme::BaseColor::*; +use cursive::theme::Color::*; +use cursive::Cursive; mod widgets; @@ -29,7 +29,6 @@ pub fn cli_main>(filename: P) { process::exit(1); } - let (editor, editor_view) = VcardEditor::new(vobj); let mut siv = Cursive::new(); @@ -49,13 +48,14 @@ pub fn cli_main>(filename: P) { title_secondary: Dark(White), highlight: Light(White), highlight_inactive: Dark(Black), - } + }, }); siv.run(); vobj = editor.to_vobject(&mut siv); - drop(siv); // Necessary to be able to write text immediately afterwards + drop(siv); // Necessary to be able to write text immediately afterwards let af = atomicwrites::AtomicFile::new(filename, atomicwrites::AllowOverwrite); - af.write(|mut f| f.write_all(vobject::write_component(&vobj).as_bytes())).unwrap(); + af.write(|f| f.write_all(vobject::write_component(&vobj).as_bytes())) + .unwrap(); } diff --git a/src/mates/editor/widgets.rs b/src/mates/editor/widgets.rs index 24b405b..2953d10 100644 --- a/src/mates/editor/widgets.rs +++ b/src/mates/editor/widgets.rs @@ -1,25 +1,31 @@ use std::ops::Deref; -use cursive::Cursive; use cursive::traits::*; use cursive::views; +use cursive::Cursive; use vobject; struct FormattedNameEditor { - original_prop: Option + original_prop: Option, } impl FormattedNameEditor { - pub fn pop_from_vobject(vobj: &mut vobject::Component) -> (Self, views::IdView) { + pub fn pop_from_vobject( + vobj: &mut vobject::Component, + ) -> (Self, views::IdView) { let prop = vobj.pop("FN"); let content = match prop { Some(ref p) => p.value_as_string(), - None => "".to_owned() + None => "".to_owned(), }; - (FormattedNameEditor { original_prop: prop }, - views::EditView::new().content(content).with_id("FN")) + ( + FormattedNameEditor { + original_prop: prop, + }, + views::EditView::new().content(content).with_id("FN"), + ) } pub fn push_to_vobject(&self, siv: &mut Cursive, vobj: &mut vobject::Component) { @@ -30,14 +36,13 @@ impl FormattedNameEditor { let mut nx = x.clone(); nx.raw_value = vobject::escape_chars(content.as_str()); nx - }, - None => vobject::Property::new("FN", content.as_str()) + } + None => vobject::Property::new("FN", content.as_str()), }; vobj.push(new_prop); } } - fn mprops_to_view(props: Vec) -> views::TextArea { let mut edit_text = String::new(); for prop in props { @@ -52,7 +57,11 @@ fn mprops_to_view(props: Vec) -> views::TextArea { views::TextArea::new().content(edit_text) } -fn view_to_mprops>(v: V, prop_name: &str, vobj: &mut vobject::Component) { +fn view_to_mprops>( + v: V, + prop_name: &str, + vobj: &mut vobject::Component, +) { for line in v.get_content().split('\n') { let mut split = line.rsplitn(2, ' '); let mut prop = match split.next() { @@ -69,7 +78,9 @@ fn view_to_mprops>(v: V, prop_name: &str, vobj: struct EmailsEditor; impl EmailsEditor { - pub fn pop_from_vobject(vobj: &mut vobject::Component) -> (Self, views::IdView) { + pub fn pop_from_vobject( + vobj: &mut vobject::Component, + ) -> (Self, views::IdView) { let props = vobj.props.remove("EMAIL").unwrap_or_else(Vec::new); (EmailsEditor, mprops_to_view(props).with_id("emails")) } @@ -83,7 +94,9 @@ impl EmailsEditor { struct TelEditor; impl TelEditor { - pub fn pop_from_vobject(vobj: &mut vobject::Component) -> (Self, views::IdView) { + pub fn pop_from_vobject( + vobj: &mut vobject::Component, + ) -> (Self, views::IdView) { let props = vobj.props.remove("TEL").unwrap_or_else(Vec::new); (TelEditor, mprops_to_view(props).with_id("tels")) } @@ -98,7 +111,7 @@ pub struct VcardEditor { vobj: vobject::Component, fn_field: FormattedNameEditor, email_field: EmailsEditor, - tel_field: TelEditor + tel_field: TelEditor, } impl VcardEditor { @@ -108,20 +121,28 @@ impl VcardEditor { let (tel_field, tel_view) = TelEditor::pop_from_vobject(&mut vobj); let main_col = views::LinearLayout::vertical() - .child(views::Panel::new(views::LinearLayout::vertical() - .child(views::TextView::new("Formatted Name:")) - .child(fn_view))) - .child(views::Panel::new(views::LinearLayout::vertical() - .child(views::TextView::new("Hit ^C to abort, or ")) - .child(views::Button::new("Save", |s| s.quit())))); + .child(views::Panel::new( + views::LinearLayout::vertical() + .child(views::TextView::new("Formatted Name:")) + .child(fn_view), + )) + .child(views::Panel::new( + views::LinearLayout::vertical() + .child(views::TextView::new("Hit ^C to abort, or ")) + .child(views::Button::new("Save", |s| s.quit())), + )); let props_list = views::LinearLayout::vertical() - .child(views::Panel::new(views::LinearLayout::vertical() - .child(views::TextView::new("Email addresses: (type + email)")) - .child(email_view))) - .child(views::Panel::new(views::LinearLayout::vertical() - .child(views::TextView::new("Telephone numbers: (type + nr)")) - .child(tel_view))); + .child(views::Panel::new( + views::LinearLayout::vertical() + .child(views::TextView::new("Email addresses: (type + email)")) + .child(email_view), + )) + .child(views::Panel::new( + views::LinearLayout::vertical() + .child(views::TextView::new("Telephone numbers: (type + nr)")) + .child(tel_view), + )); let cols = views::LinearLayout::horizontal() .child(main_col) @@ -132,7 +153,7 @@ impl VcardEditor { vobj: vobj, fn_field: fn_field, email_field: email_field, - tel_field: tel_field + tel_field: tel_field, }; (rv, cols) diff --git a/src/mates/lib.rs b/src/mates/lib.rs index 7f52dd7..2dd98e0 100644 --- a/src/mates/lib.rs +++ b/src/mates/lib.rs @@ -1,11 +1,11 @@ -extern crate vobject; -extern crate email; -extern crate uuid; extern crate atomicwrites; extern crate clap; extern crate cursive; +extern crate email; +extern crate uuid; +extern crate vobject; pub mod app; pub mod cli; -mod utils; mod editor; +mod utils; diff --git a/src/mates/utils.rs b/src/mates/utils.rs index 4fb54c8..86bfd11 100644 --- a/src/mates/utils.rs +++ b/src/mates/utils.rs @@ -1,18 +1,18 @@ use std::borrow::ToOwned; use std::collections::HashSet; +use std::convert::AsRef; use std::fs; -use std::io::{Read,Write}; use std::io; +use std::io::{Read, Write}; use std::path; use std::process; -use std::convert::AsRef; -use atomicwrites::{AtomicFile,DisallowOverwrite}; +use atomicwrites::{AtomicFile, DisallowOverwrite}; use email::rfc5322::Rfc5322Parser; use uuid::Uuid; -use vobject::{Component,Property,parse_component,write_component}; +use vobject::{parse_component, write_component, Component, Property}; -use cli::Configuration; +use crate::cli::Configuration; pub trait CustomPathExt { fn metadata(&self) -> io::Result; @@ -23,9 +23,13 @@ pub trait CustomPathExt { } impl CustomPathExt for path::Path { - fn metadata(&self) -> io::Result { fs::metadata(self) } + fn metadata(&self) -> io::Result { + fs::metadata(self) + } - fn exists(&self) -> bool { fs::metadata(self).is_ok() } + fn exists(&self) -> bool { + fs::metadata(self).is_ok() + } fn is_file(&self) -> bool { fs::metadata(self).map(|s| s.is_file()).unwrap_or(false) @@ -40,27 +44,24 @@ impl CustomPathExt for path::Path { } pub fn handle_process(process: &mut process::Child) -> io::Result<()> { - let exitcode = try!(process.wait()); + let exitcode = process.wait()?; if !exitcode.success() { return Err(io::Error::new( io::ErrorKind::Other, - format!("{}", exitcode) + format!("{}", exitcode), )); }; Ok(()) } - pub struct IndexIterator { - linebuffer: Vec + linebuffer: Vec, } impl IndexIterator { fn new(output: &String) -> IndexIterator { let rv = output.split('\n').map(|x| x.to_string()).collect(); - IndexIterator { - linebuffer: rv - } + IndexIterator { linebuffer: rv } } } @@ -70,7 +71,7 @@ impl Iterator for IndexIterator { fn next(&mut self) -> Option { match self.linebuffer.pop() { Some(x) => Some(IndexItem::new(x)), - None => None + None => None, } } } @@ -78,7 +79,7 @@ impl Iterator for IndexIterator { pub struct IndexItem { pub email: String, pub name: String, - pub filepath: Option + pub filepath: Option, } impl IndexItem { @@ -90,35 +91,40 @@ impl IndexItem { name: parts.next().unwrap_or("").to_string(), filepath: match parts.next() { Some(x) => Some(path::PathBuf::from(x)), - None => None - } + None => None, + }, } } } pub struct Contact { pub component: Component, - pub path: path::PathBuf + pub path: path::PathBuf, } impl Contact { pub fn from_file>(path: P) -> io::Result { - let mut contact_file = try!(fs::File::open(&path)); + let mut contact_file = fs::File::open(&path)?; let contact_string = { let mut x = String::new(); - try!(contact_file.read_to_string(&mut x)); + contact_file.read_to_string(&mut x)?; x }; let item = match parse_component(&contact_string[..]) { Ok(x) => x, - Err(e) => return Err(io::Error::new( - io::ErrorKind::Other, - format!("Error while parsing contact: {}", e) - )) + Err(e) => { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("Error while parsing contact: {}", e), + )) + } }; - Ok(Contact { component: item, path: path.as_ref().to_owned() }) + Ok(Contact { + component: item, + path: path.as_ref().to_owned(), + }) } pub fn generate(fullname: Option<&str>, email: Option<&str>, dir: &path::Path) -> Contact { @@ -129,26 +135,26 @@ impl Contact { uid = Uuid::new_v4().hyphenated().to_string(); contact_path = dir.join(&format!("{}.vcf", uid)); if !(*contact_path).exists() { - break + break; } - }; + } (uid, contact_path) }; - Contact { path: contact_path, component: generate_component(uid.into(), fullname, email) } + Contact { + path: contact_path, + component: generate_component(uid.into(), fullname, email), + } } pub fn write_create(&self) -> io::Result<()> { let string = write_component(&self.component); let af = AtomicFile::new(&self.path, DisallowOverwrite); - try!(af.write(|f| { - f.write_all(string.as_bytes()) - })); + af.write(|f| f.write_all(string.as_bytes()))?; Ok(()) } } - fn generate_component(uid: String, fullname: Option<&str>, email: Option<&str>) -> Component { let mut comp = Component::new("VCARD"); @@ -156,39 +162,40 @@ fn generate_component(uid: String, fullname: Option<&str>, email: Option<&str>) match fullname { Some(x) => comp.push(Property::new("FN", x)), - None => () + None => (), }; match email { Some(x) => comp.push(Property::new("EMAIL", x)), - None => () + None => (), }; comp.push(Property::new("UID", &uid[..])); comp } pub fn index_query<'a>(config: &Configuration, query: &str) -> io::Result { - let mut process = try!( - command_from_config(&config.grep_cmd[..]) + let mut process = command_from_config(&config.grep_cmd[..]) .arg(&query[..]) .arg(&config.index_path) .stdin(process::Stdio::piped()) .stdout(process::Stdio::piped()) .stderr(process::Stdio::inherit()) - .spawn()); + .spawn()?; - try!(handle_process(&mut process)); + handle_process(&mut process)?; let stream = match process.stdout.as_mut() { Some(x) => x, - None => return Err(io::Error::new( - io::ErrorKind::Other, - "Failed to get stdout from grep process.", - )) + None => { + return Err(io::Error::new( + io::ErrorKind::Other, + "Failed to get stdout from grep process.", + )) + } }; let mut output = String::new(); - try!(stream.read_to_string(&mut output)); + stream.read_to_string(&mut output)?; Ok(IndexIterator::new(&output)) } @@ -196,26 +203,28 @@ pub fn index_query<'a>(config: &Configuration, query: &str) -> io::Result io::Result> { let mut rv: HashSet = HashSet::new(); - rv.extend( - try!(index_query(config, query)).filter_map(|x| x.filepath) - ); + rv.extend(index_query(config, query)?.filter_map(|x| x.filepath)); Ok(rv) } pub fn index_item_from_contact(contact: &Contact) -> io::Result { let name = match contact.component.get_only("FN") { Some(name) => name.value_as_string(), - None => return Err(io::Error::new( - io::ErrorKind::Other, - "No name found.", - )) + None => return Err(io::Error::new(io::ErrorKind::Other, "No name found.")), }; let emails = contact.component.get_all("EMAIL"); let mut rv = String::new(); for email in emails.iter() { - rv.push_str(&format!("{}\t{}\t{}\n", email.value_as_string(), name, contact.path.display())[..]); - }; + rv.push_str( + &format!( + "{}\t{}\t{}\n", + email.value_as_string(), + name, + contact.path.display() + )[..], + ); + } Ok(rv) } @@ -223,8 +232,8 @@ pub fn index_item_from_contact(contact: &Contact) -> io::Result { pub fn parse_from_header<'a>(s: &'a String) -> (Option<&'a str>, Option<&'a str>) { let mut split = s.rsplitn(2, '<'); let email = match split.next() { - Some(x) => Some(x.trim_right_matches('>')), - None => Some(&s[..]) + Some(x) => Some(x.trim_end_matches('>')), + None => Some(&s[..]), }; let name = split.next(); (name, email) @@ -237,12 +246,12 @@ pub fn read_sender_from_email(email: &str) -> Option { match parser.consume_header() { Some(header) => { if header.name == "From" { - return header.get_value().ok() + return header.get_value().ok(); }; - }, - None => return None + } + None => return None, }; - }; + } None } @@ -250,18 +259,19 @@ pub fn read_sender_from_email(email: &str) -> Option { pub fn add_contact_from_email(contact_dir: &path::Path, email_input: &str) -> io::Result { let from_header = match read_sender_from_email(email_input) { Some(x) => x, - None => return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Couldn't find From-header in email.", - )) + None => { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Couldn't find From-header in email.", + )) + } }; let (fullname, email) = parse_from_header(&from_header); let contact = Contact::generate(fullname, email, contact_dir); - try!(contact.write_create()); + contact.write_create()?; Ok(contact) } - fn command_from_config(config_val: &str) -> process::Command { let mut parts = config_val.split(' '); let main = parts.next().unwrap();