From 64019fa5eca3ebf40ce5eda3c84c3d3aa2a021c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Tue, 16 Mar 2021 23:39:43 +0100 Subject: [PATCH] improve choice after editing msg --- CHANGELOG.md | 2 + src/app.rs | 101 ++++++++++++++++++++++++++++++++++++++++----------- src/input.rs | 53 +++++++++++++++++++++------ 3 files changed, 122 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c87e63..ad5b2b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - IDLE support [#29] +- Improve choice after editing msg [#30] ### Changed @@ -80,6 +81,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#22]: https://github.com/soywod/himalaya/issues/22 [#25]: https://github.com/soywod/himalaya/issues/25 [#29]: https://github.com/soywod/himalaya/issues/29 +[#30]: https://github.com/soywod/himalaya/issues/30 [#32]: https://github.com/soywod/himalaya/issues/32 [#38]: https://github.com/soywod/himalaya/issues/38 [#39]: https://github.com/soywod/himalaya/issues/39 diff --git a/src/app.rs b/src/app.rs index e72e340..4acc644 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,6 +1,6 @@ use clap::{self, Arg, SubCommand}; use error_chain::error_chain; -use std::fs; +use std::{env, fs}; use crate::{ config::{self, Config}, @@ -332,14 +332,33 @@ impl<'a> App<'a> { let mut imap_conn = ImapConnector::new(&account)?; let tpl = Msg::build_new_tpl(&config, &account)?; let content = input::open_editor_with_tpl(tpl.to_string().as_bytes())?; - let msg = Msg::from(content); + let mut msg = Msg::from(content); - input::ask_for_confirmation("Send the message?")?; - - println!("Sending…"); - smtp::send(&account, &msg.to_sendable_msg()?)?; - imap_conn.append_msg("Sent", &msg.to_vec()?)?; - println!("Done!"); + loop { + match input::post_edit_choice() { + Ok(choice) => match choice { + input::Choice::Send => { + println!("Sending…"); + smtp::send(&account, &msg.to_sendable_msg()?)?; + imap_conn.append_msg("Sent", &msg.to_vec()?)?; + println!("Done!"); + break; + } + input::Choice::Draft => { + println!("Saving to draft…"); + imap_conn.append_msg("Drafts", &msg.to_vec()?)?; + println!("Done!"); + break; + } + input::Choice::Edit => { + let content = input::open_editor_with_draft()?; + msg = Msg::from(content); + } + input::Choice::Quit => break, + }, + Err(err) => eprintln!("{}", err), + } + } imap_conn.logout(); } @@ -395,14 +414,33 @@ impl<'a> App<'a> { }; let content = input::open_editor_with_tpl(&tpl.to_string().as_bytes())?; - let msg = Msg::from(content); + let mut msg = Msg::from(content); - input::ask_for_confirmation("Send the message?")?; - - println!("Sending…"); - smtp::send(&account, &msg.to_sendable_msg()?)?; - imap_conn.append_msg("Sent", &msg.to_vec()?)?; - println!("Done!"); + loop { + match input::post_edit_choice() { + Ok(choice) => match choice { + input::Choice::Send => { + println!("Sending…"); + smtp::send(&account, &msg.to_sendable_msg()?)?; + imap_conn.append_msg("Sent", &msg.to_vec()?)?; + println!("Done!"); + break; + } + input::Choice::Draft => { + println!("Saving to draft…"); + imap_conn.append_msg("Drafts", &msg.to_vec()?)?; + println!("Done!"); + break; + } + input::Choice::Edit => { + let content = input::open_editor_with_draft()?; + msg = Msg::from(content); + } + input::Choice::Quit => break, + }, + Err(err) => eprintln!("{}", err), + } + } imap_conn.logout(); } @@ -418,14 +456,33 @@ impl<'a> App<'a> { let msg = Msg::from(imap_conn.read_msg(&mbox, &uid)?); let tpl = msg.build_forward_tpl(&config, &account)?; let content = input::open_editor_with_tpl(&tpl.to_string().as_bytes())?; - let msg = Msg::from(content); + let mut msg = Msg::from(content); - input::ask_for_confirmation("Send the message?")?; - - println!("Sending…"); - smtp::send(&account, &msg.to_sendable_msg()?)?; - imap_conn.append_msg("Sent", &msg.to_vec()?)?; - println!("Done!"); + loop { + match input::post_edit_choice() { + Ok(choice) => match choice { + input::Choice::Send => { + println!("Sending…"); + smtp::send(&account, &msg.to_sendable_msg()?)?; + imap_conn.append_msg("Sent", &msg.to_vec()?)?; + println!("Done!"); + break; + } + input::Choice::Draft => { + println!("Saving to draft…"); + imap_conn.append_msg("Drafts", &msg.to_vec()?)?; + println!("Done!"); + break; + } + input::Choice::Edit => { + let content = input::open_editor_with_draft()?; + msg = Msg::from(content); + } + input::Choice::Quit => break, + }, + Err(err) => eprintln!("{}", err), + } + } imap_conn.logout(); } diff --git a/src/input.rs b/src/input.rs index 7848a53..22e0655 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,7 +1,7 @@ use error_chain::error_chain; use std::{ env, - fs::{remove_file, File}, + fs::File, io::{self, Read, Write}, process::Command, }; @@ -29,23 +29,52 @@ pub fn open_editor_with_tpl(tpl: &[u8]) -> Result { .chain_err(|| format!("Cannot open file `{}`", draft_path.to_string_lossy()))? .read_to_string(&mut draft) .chain_err(|| format!("Cannot read file `{}`", draft_path.to_string_lossy()))?; - remove_file(&draft_path) - .chain_err(|| format!("Cannot remove file `{}`", draft_path.to_string_lossy()))?; Ok(draft) } -pub fn ask_for_confirmation(prompt: &str) -> Result<()> { - print!("{} (y/n) ", prompt); +pub fn open_editor_with_draft() -> Result { + // Creates draft file + let mut draft_path = env::temp_dir(); + draft_path.push("himalaya-draft.mail"); + + // Opens editor and saves user input to draft file + Command::new(env::var("EDITOR").chain_err(|| "Cannot find `EDITOR` env var")?) + .arg(&draft_path) + .status() + .chain_err(|| "Cannot start editor")?; + + // Extracts draft file content + let mut draft = String::new(); + File::open(&draft_path) + .chain_err(|| format!("Cannot open file `{}`", draft_path.to_string_lossy()))? + .read_to_string(&mut draft) + .chain_err(|| format!("Cannot read file `{}`", draft_path.to_string_lossy()))?; + + Ok(draft) +} + +pub enum Choice { + Send, + Draft, + Edit, + Quit, +} + +pub fn post_edit_choice() -> Result { + print!("(s)end, (d)raft, (e)dit or (q)uit? "); io::stdout().flush().chain_err(|| "Cannot flush stdout")?; - match io::stdin() - .bytes() - .next() - .and_then(|res| res.ok()) - .map(|bytes| bytes as char) - { - Some('y') | Some('Y') => Ok(()), + let mut buf = String::new(); + io::stdin() + .read_line(&mut buf) + .chain_err(|| "Cannot read stdin")?; + + match buf.bytes().next().map(|bytes| bytes as char) { + Some('s') => Ok(Choice::Send), + Some('d') => Ok(Choice::Draft), + Some('e') => Ok(Choice::Edit), + Some('q') => Ok(Choice::Quit), Some(choice) => Err(format!("Invalid choice `{}`", choice).into()), None => Err("Empty choice".into()), }