From bc5f9045ce659793cc86a331f177a8230ad4e897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Thu, 16 Sep 2021 16:43:41 +0200 Subject: [PATCH] improve imap and mbox arg/handler --- src/compl/arg.rs | 22 +++++----- src/domain/imap/{cli.rs => arg.rs} | 68 +++++++++++++++--------------- src/domain/imap/handler.rs | 28 ++++++++++++ src/domain/imap/mod.rs | 5 ++- src/domain/imap/service.rs | 4 ++ src/domain/mbox/arg.rs | 47 +++++++++++++++++++++ src/domain/mbox/cli.rs | 48 --------------------- src/domain/mbox/handler.rs | 25 +++++++++++ src/domain/mbox/mod.rs | 5 ++- src/domain/msg/{cli.rs => arg.rs} | 6 +-- src/domain/msg/mod.rs | 2 +- src/flag/{cli.rs => arg.rs} | 2 +- src/flag/mod.rs | 2 +- src/main.rs | 46 ++++++++++++++------ src/ui/table.rs | 6 +-- 15 files changed, 198 insertions(+), 118 deletions(-) rename src/domain/imap/{cli.rs => arg.rs} (50%) create mode 100644 src/domain/imap/handler.rs create mode 100644 src/domain/mbox/arg.rs delete mode 100644 src/domain/mbox/cli.rs create mode 100644 src/domain/mbox/handler.rs rename src/domain/msg/{cli.rs => arg.rs} (99%) rename src/flag/{cli.rs => arg.rs} (97%) diff --git a/src/compl/arg.rs b/src/compl/arg.rs index d123f93..984b374 100644 --- a/src/compl/arg.rs +++ b/src/compl/arg.rs @@ -1,21 +1,12 @@ //! Module related to completion arguments. //! -//! This module provides subcommands and an argument matcher for the completion command. +//! This module provides subcommands and an argument matcher related to completion. use anyhow::Result; use clap::{self, App, Arg, ArgMatches, Shell, SubCommand}; use log::debug; -/// Subcommands related to the completion generation. -pub fn subcmds<'a>() -> Vec> { - vec![SubCommand::with_name("completion") - .about("Generates the completion script for the given shell") - .args(&[Arg::with_name("shell") - .possible_values(&Shell::variants()[..]) - .required(true)])] -} - -/// Enumeration of all possible completion matches. +/// Enumeration of all possible matches. pub enum Match<'a> { /// Generate completion script for the given shell slice. Generate(&'a str), @@ -32,3 +23,12 @@ pub fn matches<'a>(m: &'a ArgMatches) -> Result>> { Ok(None) } + +/// Completion subcommands. +pub fn subcmds<'a>() -> Vec> { + vec![SubCommand::with_name("completion") + .about("Generates the completion script for the given shell") + .args(&[Arg::with_name("shell") + .possible_values(&Shell::variants()[..]) + .required(true)])] +} diff --git a/src/domain/imap/cli.rs b/src/domain/imap/arg.rs similarity index 50% rename from src/domain/imap/cli.rs rename to src/domain/imap/arg.rs index dce1092..3c47c32 100644 --- a/src/domain/imap/cli.rs +++ b/src/domain/imap/arg.rs @@ -1,10 +1,41 @@ +//! Module related to IMAP arguments. +//! +//! This module provides subcommands and an argument matcher related to IMAP. + use anyhow::Result; -use clap; +use clap::{App, ArgMatches}; use log::debug; -use crate::domain::{config::entity::Config, imap::service::ImapServiceInterface}; +/// Enumeration of all possible matches. +pub enum Match { + /// Start the IMAP notify mode with the give keepalive duration. + Notify(u64), -pub fn subcmds<'a>() -> Vec> { + /// Start the IMAP watch mode with the give keepalive duration. + Watch(u64), +} + +/// IMAP arg matcher. +pub fn matches(m: &ArgMatches) -> Result> { + if let Some(m) = m.subcommand_matches("notify") { + debug!("notify command matched"); + let keepalive = clap::value_t_or_exit!(m.value_of("keepalive"), u64); + debug!("keepalive: {}", keepalive); + return Ok(Some(Match::Notify(keepalive))); + } + + if let Some(m) = m.subcommand_matches("watch") { + debug!("watch command matched"); + let keepalive = clap::value_t_or_exit!(m.value_of("keepalive"), u64); + debug!("keepalive: {}", keepalive); + return Ok(Some(Match::Watch(keepalive))); + } + + Ok(None) +} + +/// IMAP subcommands. +pub fn subcmds<'a>() -> Vec> { vec![ clap::SubCommand::with_name("notify") .about("Notifies when new messages arrive in the given mailbox") @@ -29,34 +60,3 @@ pub fn subcmds<'a>() -> Vec> { ), ] } - -pub fn matches( - arg_matches: &clap::ArgMatches, - config: &Config, - imap: &mut ImapService, -) -> Result { - if let Some(matches) = arg_matches.subcommand_matches("notify") { - debug!("notify command matched"); - - let keepalive = clap::value_t_or_exit!(matches.value_of("keepalive"), u64); - debug!("keepalive: {}", &keepalive); - - imap.notify(&config, keepalive)?; - imap.logout()?; - return Ok(true); - } - - if let Some(matches) = arg_matches.subcommand_matches("watch") { - debug!("watch command matched"); - - let keepalive = clap::value_t_or_exit!(matches.value_of("keepalive"), u64); - debug!("keepalive: {}", &keepalive); - - imap.watch(keepalive)?; - imap.logout()?; - return Ok(true); - } - - debug!("nothing matched"); - Ok(false) -} diff --git a/src/domain/imap/handler.rs b/src/domain/imap/handler.rs new file mode 100644 index 0000000..8aa2545 --- /dev/null +++ b/src/domain/imap/handler.rs @@ -0,0 +1,28 @@ +//! Module related to IMAP handling. +//! +//! This module gathers all IMAP handlers triggered by the CLI. + +use anyhow::Result; + +use crate::domain::{config::entity::Config, imap::service::ImapServiceInterface}; + +/// Notify handler. +pub fn notify( + keepalive: u64, + config: &Config, + imap: &mut ImapService, +) -> Result<()> { + imap.notify(&config, keepalive)?; + imap.logout()?; + Ok(()) +} + +/// Watch handler. +pub fn watch( + keepalive: u64, + imap: &mut ImapService, +) -> Result<()> { + imap.watch(keepalive)?; + imap.logout()?; + Ok(()) +} diff --git a/src/domain/imap/mod.rs b/src/domain/imap/mod.rs index f41d052..c2bd990 100644 --- a/src/domain/imap/mod.rs +++ b/src/domain/imap/mod.rs @@ -1,4 +1,5 @@ -//! Modules related to IMAP. +//! Module related to IMAP. -pub mod cli; +pub mod arg; +pub mod handler; pub mod service; diff --git a/src/domain/imap/service.rs b/src/domain/imap/service.rs index 20bc0f9..5afb494 100644 --- a/src/domain/imap/service.rs +++ b/src/domain/imap/service.rs @@ -1,3 +1,7 @@ +//! Module related to IMAP servicing. +//! +//! This module exposes a service that can interact with IMAP servers. + use anyhow::{anyhow, Context, Result}; use imap; use log::{debug, trace}; diff --git a/src/domain/mbox/arg.rs b/src/domain/mbox/arg.rs new file mode 100644 index 0000000..d615f49 --- /dev/null +++ b/src/domain/mbox/arg.rs @@ -0,0 +1,47 @@ +//! Module related to mailboxes arguments. +//! +//! This module provides subcommands and an argument matcher related to mailboxes. + +use anyhow::Result; +use clap::{App, Arg, ArgMatches, SubCommand}; +use log::debug; + +/// Enumeration of all possible matches. +pub enum Match { + /// List all available mailboxes. + List, +} + +/// Mailboxes arg matcher. +pub fn matches(m: &ArgMatches) -> Result> { + if let Some(_) = m.subcommand_matches("mailboxes") { + debug!("mailboxes command matched"); + return Ok(Some(Match::List)); + } + + Ok(None) +} + +/// Mailboxes subcommands. +pub fn subcmds<'a>() -> Vec> { + vec![SubCommand::with_name("mailboxes") + .aliases(&["mailbox", "mboxes", "mbox", "m"]) + .about("Lists all mailboxes")] +} + +/// Source mailbox arg. +pub fn source_arg<'a>() -> Arg<'a, 'a> { + Arg::with_name("mailbox") + .short("m") + .long("mailbox") + .help("Selects a specific mailbox") + .value_name("MAILBOX") + .default_value("INBOX") +} + +/// Target mailbox arg. +pub fn target_arg<'a>() -> Arg<'a, 'a> { + Arg::with_name("target") + .help("Specifies the targetted mailbox") + .value_name("TARGET") +} diff --git a/src/domain/mbox/cli.rs b/src/domain/mbox/cli.rs deleted file mode 100644 index 90cd0a3..0000000 --- a/src/domain/mbox/cli.rs +++ /dev/null @@ -1,48 +0,0 @@ -use anyhow::Result; -use clap; -use log::{debug, trace}; - -use crate::{ - domain::{imap::service::ImapServiceInterface, mbox::entity::Mboxes}, - output::service::{OutputService, OutputServiceInterface}, -}; - -pub fn subcmds<'a>() -> Vec> { - vec![clap::SubCommand::with_name("mailboxes") - .aliases(&["mailbox", "mboxes", "mbox", "m"]) - .about("Lists all mailboxes")] -} - -pub fn matches( - arg_matches: &clap::ArgMatches, - output: &OutputService, - imap: &mut ImapService, -) -> Result { - if let Some(_) = arg_matches.subcommand_matches("mailboxes") { - debug!("mailboxes command matched"); - let names = imap.list_mboxes()?; - let mboxes = Mboxes::from(&names); - debug!("mboxes len: {}", mboxes.0.len()); - trace!("{:#?}", mboxes); - output.print(mboxes)?; - imap.logout()?; - return Ok(true); - } - - Ok(false) -} - -pub fn source_arg<'a>() -> clap::Arg<'a, 'a> { - clap::Arg::with_name("mailbox") - .short("m") - .long("mailbox") - .help("Selects a specific mailbox") - .value_name("MAILBOX") - .default_value("INBOX") -} - -pub fn mbox_target_arg<'a>() -> clap::Arg<'a, 'a> { - clap::Arg::with_name("target") - .help("Specifies the targetted mailbox") - .value_name("TARGET") -} diff --git a/src/domain/mbox/handler.rs b/src/domain/mbox/handler.rs new file mode 100644 index 0000000..e4348f4 --- /dev/null +++ b/src/domain/mbox/handler.rs @@ -0,0 +1,25 @@ +//! Module related to mailboxes handling. +//! +//! This module gathers all mailboxes actions triggered by the CLI. + +use anyhow::Result; +use log::{debug, trace}; + +use crate::{ + domain::{imap::service::ImapServiceInterface, mbox::entity::Mboxes}, + output::service::{OutputService, OutputServiceInterface}, +}; + +/// List mailboxes. +pub fn list( + output: &OutputService, + imap: &mut ImapService, +) -> Result<()> { + let names = imap.list_mboxes()?; + let mboxes = Mboxes::from(&names); + debug!("mailboxes len: {}", mboxes.0.len()); + trace!("mailboxes: {:#?}", mboxes); + output.print(mboxes)?; + imap.logout()?; + Ok(()) +} diff --git a/src/domain/mbox/mod.rs b/src/domain/mbox/mod.rs index e85c41a..bb656c4 100644 --- a/src/domain/mbox/mod.rs +++ b/src/domain/mbox/mod.rs @@ -1,2 +1,5 @@ -pub mod cli; +//! Module related to mailboxes. + +pub mod arg; pub mod entity; +pub mod handler; diff --git a/src/domain/msg/cli.rs b/src/domain/msg/arg.rs similarity index 99% rename from src/domain/msg/cli.rs rename to src/domain/msg/arg.rs index f1ca704..8d177c3 100644 --- a/src/domain/msg/cli.rs +++ b/src/domain/msg/arg.rs @@ -22,7 +22,7 @@ use crate::{ domain::{ account::entity::Account, imap::service::ImapServiceInterface, - mbox::{cli::mbox_target_arg, entity::Mbox}, + mbox::{arg::target_arg, entity::Mbox}, smtp::service::SmtpServiceInterface, }, flag::model::Flags, @@ -93,12 +93,12 @@ pub fn subcmds<'a>() -> Vec> { .aliases(&["cp"]) .about("Copies a message to the targetted mailbox") .arg(uid_arg()) - .arg(mbox_target_arg()), + .arg(target_arg()), clap::SubCommand::with_name("move") .aliases(&["mv"]) .about("Moves a message to the targetted mailbox") .arg(uid_arg()) - .arg(mbox_target_arg()), + .arg(target_arg()), clap::SubCommand::with_name("delete") .aliases(&["remove", "rm"]) .about("Deletes a message") diff --git a/src/domain/msg/mod.rs b/src/domain/msg/mod.rs index ac0abf9..eb92a3d 100644 --- a/src/domain/msg/mod.rs +++ b/src/domain/msg/mod.rs @@ -18,7 +18,7 @@ /// /// Execute `himalaya help ` where `` is one entry of this list above /// to get more information about them. -pub mod cli; +pub mod arg; /// Here are the two **main structs** of this module: `Msg` and `Msgs` which /// represent a *Mail* or *multiple Mails* in this crate. diff --git a/src/flag/cli.rs b/src/flag/arg.rs similarity index 97% rename from src/flag/cli.rs rename to src/flag/arg.rs index c475d94..326b9b7 100644 --- a/src/flag/cli.rs +++ b/src/flag/arg.rs @@ -3,7 +3,7 @@ use clap; use log::debug; use crate::{ - domain::{imap::service::ImapServiceInterface, msg::cli::uid_arg}, + domain::{imap::service::ImapServiceInterface, msg::arg::uid_arg}, flag::model::Flags, }; diff --git a/src/flag/mod.rs b/src/flag/mod.rs index 9225677..550ac90 100644 --- a/src/flag/mod.rs +++ b/src/flag/mod.rs @@ -1,2 +1,2 @@ -pub mod cli; +pub mod arg; pub mod model; diff --git a/src/main.rs b/src/main.rs index a81a86b..fa44fef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,14 +23,13 @@ fn create_app<'a>() -> clap::App<'a, 'a> { .version(env!("CARGO_PKG_VERSION")) .about(env!("CARGO_PKG_DESCRIPTION")) .author(env!("CARGO_PKG_AUTHORS")) - .setting(clap::AppSettings::InferSubcommands) .args(&output_args()) .args(&config_args()) - .arg(mbox::cli::source_arg()) - .subcommands(flag::cli::subcmds()) - .subcommands(imap::cli::subcmds()) - .subcommands(mbox::cli::subcmds()) - .subcommands(msg::cli::subcmds()) + .arg(mbox::arg::source_arg()) + .subcommands(flag::arg::subcmds()) + .subcommands(imap::arg::subcmds()) + .subcommands(mbox::arg::subcmds()) + .subcommands(msg::arg::subcmds()) .subcommands(compl::arg::subcmds()) } @@ -57,9 +56,13 @@ fn main() -> Result<()> { let app = create_app(); let m = app.get_matches(); - // Check shell completion BEFORE any entity or service initialization. - if let Some(compl::arg::Match::Generate(shell)) = compl::arg::matches(&m)? { - return compl::handler::generate(shell, create_app()); + // Check completion match BEFORE any entity or service initialization. + // See https://github.com/soywod/himalaya/issues/115. + match compl::arg::matches(&m)? { + Some(compl::arg::Match::Generate(shell)) => { + return compl::handler::generate(shell, create_app()); + } + _ => (), } let mbox = Mbox::try_from(m.value_of("mailbox"))?; @@ -69,11 +72,28 @@ fn main() -> Result<()> { let mut imap = ImapService::from((&account, &mbox)); let mut smtp = SmtpService::from(&account); + // Check IMAP matches. + match imap::arg::matches(&m)? { + Some(imap::arg::Match::Notify(keepalive)) => { + return imap::handler::notify(keepalive, &config, &mut imap); + } + Some(imap::arg::Match::Watch(keepalive)) => { + return imap::handler::watch(keepalive, &mut imap); + } + _ => (), + } + + // Check mailbox matches. + match mbox::arg::matches(&m)? { + Some(mbox::arg::Match::List) => { + return mbox::handler::list(&output, &mut imap); + } + _ => (), + } + // TODO: use same system as compl - let _matched = mbox::cli::matches(&m, &output, &mut imap)? - || flag::cli::matches(&m, &mut imap)? - || imap::cli::matches(&m, &config, &mut imap)? - || msg::cli::matches(&m, &mbox, &account, &output, &mut imap, &mut smtp)?; + let _matched = flag::arg::matches(&m, &mut imap)? + || msg::arg::matches(&m, &mbox, &account, &output, &mut imap, &mut smtp)?; Ok(()) } diff --git a/src/ui/table.rs b/src/ui/table.rs index 944d65a..54bab6f 100644 --- a/src/ui/table.rs +++ b/src/ui/table.rs @@ -4,7 +4,7 @@ //! //! [builder design pattern]: https://refactoring.guru/design-patterns/builder -use log::{debug, trace}; +use log::trace; use std::fmt; use terminal_size; use unicode_width::UnicodeWidthStr; @@ -228,12 +228,12 @@ where table .iter_mut() .map(|row| { - debug!("processing row: {:?}", row); + trace!("processing row: {:?}", row); row.0 .iter_mut() .enumerate() .map(|(i, cell)| { - debug!("processing cell: {:?}", cell); + trace!("processing cell: {:?}", cell); trace!("table_width: {}", table_width); trace!("max_width: {}", Self::max_width());