add list accounts command (#244)

This commit is contained in:
Clément DOUIN 2022-03-03 17:29:39 +01:00
parent e5164a2ce3
commit 736641bf77
No known key found for this signature in database
GPG key ID: 353E4A18EE0FAB72
21 changed files with 416 additions and 111 deletions

View file

@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Flowed format support [#206]
- List accounts command [#244]
### Changed
@ -448,11 +449,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#199]: https://github.com/soywod/himalaya/issues/199
[#204]: https://github.com/soywod/himalaya/issues/204
[#205]: https://github.com/soywod/himalaya/issues/205
[#206]: https://github.com/soywod/himalaya/issues/206
[#215]: https://github.com/soywod/himalaya/issues/215
[#220]: https://github.com/soywod/himalaya/issues/220
[#227]: https://github.com/soywod/himalaya/issues/227
[#228]: https://github.com/soywod/himalaya/issues/228
[#229]: https://github.com/soywod/himalaya/issues/229
[#244]: https://github.com/soywod/himalaya/issues/244
[#249]: https://github.com/soywod/himalaya/issues/249
[#256]: https://github.com/soywod/himalaya/issues/256
[#259]: https://github.com/soywod/himalaya/issues/259
@ -471,3 +474,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#305]: https://github.com/soywod/himalaya/issues/305
[#308]: https://github.com/soywod/himalaya/issues/308
[#309]: https://github.com/soywod/himalaya/issues/309
[#321]: https://github.com/soywod/himalaya/issues/321

View file

@ -5,5 +5,5 @@
//!
//! [clap's docs.rs website]: https://docs.rs/clap/2.33.3/clap/enum.Shell.html
pub mod compl_arg;
pub mod compl_handler;
pub mod compl_args;
pub mod compl_handlers;

107
src/config/account.rs Normal file
View file

@ -0,0 +1,107 @@
//! Account module.
//!
//! This module contains the definition of the printable account,
//! which is only used by the "accounts" command to list all available
//! accounts from the config file.
use anyhow::Result;
use serde::Serialize;
use std::{
collections::hash_map::Iter,
fmt::{self, Display},
ops::Deref,
};
use crate::{
config::DeserializedAccountConfig,
output::{PrintTable, PrintTableOpts, WriteColor},
ui::{Cell, Row, Table},
};
/// Represents the list of printable accounts.
#[derive(Debug, Default, Serialize)]
pub struct Accounts(pub Vec<Account>);
impl Deref for Accounts {
type Target = Vec<Account>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl PrintTable for Accounts {
fn print_table(&self, writter: &mut dyn WriteColor, opts: PrintTableOpts) -> Result<()> {
writeln!(writter)?;
Table::print(writter, self, opts)?;
writeln!(writter)?;
Ok(())
}
}
/// Represents the printable account.
#[derive(Debug, Default, PartialEq, Eq, Serialize)]
pub struct Account {
/// Represents the account name.
pub name: String,
/// Represents the backend name of the account.
pub backend: String,
/// Represents the defaultness state of the account.
pub default: bool,
}
impl Account {
pub fn new(name: &str, backend: &str, default: bool) -> Self {
Self {
name: name.into(),
backend: backend.into(),
default,
}
}
}
impl Display for Account {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name)
}
}
impl Table for Account {
fn head() -> Row {
Row::new()
.cell(Cell::new("NAME").shrinkable().bold().underline().white())
.cell(Cell::new("BACKEND").bold().underline().white())
.cell(Cell::new("DEFAULT").bold().underline().white())
}
fn row(&self) -> Row {
let default = if self.default { "yes" } else { "" };
Row::new()
.cell(Cell::new(&self.name).shrinkable().green())
.cell(Cell::new(&self.backend).blue())
.cell(Cell::new(default).white())
}
}
impl From<Iter<'_, String, DeserializedAccountConfig>> for Accounts {
fn from(map: Iter<'_, String, DeserializedAccountConfig>) -> Self {
let mut accounts: Vec<_> = map
.map(|(name, config)| match config {
DeserializedAccountConfig::Imap(config) => {
Account::new(name, "imap", config.default.unwrap_or_default())
}
DeserializedAccountConfig::Maildir(config) => {
Account::new(name, "maildir", config.default.unwrap_or_default())
}
#[cfg(feature = "notmuch")]
DeserializedAccountConfig::Maildir(config) => {
Account::new(name, "notmuch", config.default.unwrap_or_default())
}
})
.collect();
accounts.sort_by(|a, b| b.name.partial_cmp(&a.name).unwrap());
Self(accounts)
}
}

View file

@ -1,9 +1,52 @@
//! This module provides arguments related to the user account config.
use clap::Arg;
use anyhow::Result;
use clap::{App, Arg, ArgMatches, SubCommand};
use log::{debug, info};
use crate::ui::table_arg;
type MaxTableWidth = Option<usize>;
/// Represents the account commands.
#[derive(Debug, PartialEq, Eq)]
pub enum Cmd {
/// Represents the list accounts command.
List(MaxTableWidth),
}
/// Represents the account command matcher.
pub fn matches(m: &ArgMatches) -> Result<Option<Cmd>> {
info!(">> account command matcher");
let cmd = if let Some(m) = m.subcommand_matches("accounts") {
info!("accounts command matched");
let max_table_width = m
.value_of("max-table-width")
.and_then(|width| width.parse::<usize>().ok());
debug!("max table width: {:?}", max_table_width);
Some(Cmd::List(max_table_width))
} else {
None
};
info!("<< account command matcher");
Ok(cmd)
}
/// Represents the account subcommands.
pub fn subcmds<'a>() -> Vec<App<'a, 'a>> {
vec![SubCommand::with_name("accounts")
.aliases(&["account", "acc", "a"])
.about("Lists accounts")
.arg(table_arg::max_width())]
}
/// Represents the user account name argument.
/// This argument allows the user to select a different account than the default one.
/// This argument allows the user to select a different account than
/// the default one.
pub fn name_arg<'a>() -> Arg<'a, 'a> {
Arg::with_name("account")
.long("account")

View file

@ -0,0 +1,135 @@
//! Account handlers module.
//!
//! This module gathers all account actions triggered by the CLI.
use anyhow::Result;
use log::{info, trace};
use crate::{
config::{AccountConfig, Accounts, DeserializedConfig},
output::{PrintTableOpts, PrinterService},
};
/// Lists all accounts.
pub fn list<'a, P: PrinterService>(
max_width: Option<usize>,
config: &DeserializedConfig,
account_config: &AccountConfig,
printer: &mut P,
) -> Result<()> {
info!(">> account list handler");
let accounts: Accounts = config.accounts.iter().into();
trace!("accounts: {:?}", accounts);
printer.print_table(
Box::new(accounts),
PrintTableOpts {
format: &account_config.format,
max_width,
},
)?;
info!("<< account list handler");
Ok(())
}
#[cfg(test)]
mod tests {
use std::{collections::HashMap, fmt::Debug, io, iter::FromIterator};
use termcolor::ColorSpec;
use crate::{
config::{DeserializedAccountConfig, DeserializedImapAccountConfig},
output::{Print, PrintTable, WriteColor},
};
use super::*;
#[test]
fn it_should_match_cmds_accounts() {
#[derive(Debug, Default, Clone)]
struct StringWritter {
content: String,
}
impl io::Write for StringWritter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.content
.push_str(&String::from_utf8(buf.to_vec()).unwrap());
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
self.content = String::default();
Ok(())
}
}
impl termcolor::WriteColor for StringWritter {
fn supports_color(&self) -> bool {
false
}
fn set_color(&mut self, _spec: &ColorSpec) -> io::Result<()> {
io::Result::Ok(())
}
fn reset(&mut self) -> io::Result<()> {
io::Result::Ok(())
}
}
impl WriteColor for StringWritter {}
#[derive(Debug, Default)]
struct PrinterServiceTest {
pub writter: StringWritter,
}
impl PrinterService for PrinterServiceTest {
fn print_table<T: Debug + PrintTable + erased_serde::Serialize + ?Sized>(
&mut self,
data: Box<T>,
opts: PrintTableOpts,
) -> Result<()> {
data.print_table(&mut self.writter, opts)?;
Ok(())
}
fn print<T: serde::Serialize + Print>(&mut self, _data: T) -> Result<()> {
unimplemented!()
}
fn is_json(&self) -> bool {
unimplemented!()
}
}
struct TestBackend;
let config = DeserializedConfig {
accounts: HashMap::from_iter([(
"account-1".into(),
DeserializedAccountConfig::Imap(DeserializedImapAccountConfig {
default: Some(true),
..DeserializedImapAccountConfig::default()
}),
)]),
..DeserializedConfig::default()
};
let account_config = AccountConfig::default();
let mut printer = PrinterServiceTest::default();
let mut backend = TestBackend {};
assert!(list(None, &config, &account_config, &mut printer).is_ok());
assert_eq!(
concat![
"\n",
"NAME │BACKEND │DEFAULT \n",
"account-1 │imap │true \n",
"\n"
],
printer.writter.content
);
}
}

View file

@ -2,26 +2,26 @@ pub mod mbox {
pub mod mbox;
pub use mbox::*;
pub mod mbox_arg;
pub mod mbox_handler;
pub mod mbox_args;
pub mod mbox_handlers;
}
pub mod msg {
pub mod envelope;
pub use envelope::*;
pub mod msg_arg;
pub mod msg_args;
pub mod msg_handler;
pub mod msg_handlers;
pub mod msg_utils;
pub mod flag_arg;
pub mod flag_handler;
pub mod flag_args;
pub mod flag_handlers;
pub mod tpl_arg;
pub use tpl_arg::TplOverride;
pub mod tpl_args;
pub use tpl_args::TplOverride;
pub mod tpl_handler;
pub mod tpl_handlers;
pub mod msg_entity;
pub use msg_entity::*;
@ -41,12 +41,12 @@ pub mod backends {
pub use id_mapper::*;
pub mod imap {
pub mod imap_arg;
pub mod imap_args;
pub mod imap_backend;
pub use imap_backend::*;
pub mod imap_handler;
pub mod imap_handlers;
pub mod imap_mbox;
pub use imap_mbox::*;
@ -100,16 +100,23 @@ pub mod smtp {
}
pub mod config {
pub mod config_args;
pub mod deserialized_config;
pub use deserialized_config::*;
pub mod account_args;
pub mod account_config;
pub use account_config::*;
pub mod deserialized_account_config;
pub use deserialized_account_config::*;
pub mod config_args;
pub mod account_args;
pub mod account_handlers;
pub mod account;
pub use account::*;
pub mod account_config;
pub use account_config::*;
pub mod format;
pub use format::*;
}

View file

@ -3,15 +3,15 @@ use std::{convert::TryFrom, env};
use url::Url;
use himalaya::{
backends::{imap_arg, imap_handler, Backend, ImapBackend, MaildirBackend},
compl::{compl_arg, compl_handler},
backends::{imap_args, imap_handlers, Backend, ImapBackend, MaildirBackend},
compl::{compl_args, compl_handlers},
config::{
account_args, config_args, AccountConfig, BackendConfig, DeserializedConfig,
DEFAULT_INBOX_FOLDER,
account_args, account_handlers, config_args, AccountConfig, BackendConfig,
DeserializedConfig, DEFAULT_INBOX_FOLDER,
},
mbox::{mbox_arg, mbox_handler},
msg::{flag_arg, flag_handler, msg_arg, msg_handler, tpl_arg, tpl_handler},
output::{output_arg, OutputFmt, StdoutPrinter},
mbox::{mbox_args, mbox_handlers},
msg::{flag_args, flag_handlers, msg_args, msg_handlers, tpl_args, tpl_handlers},
output::{output_args, OutputFmt, StdoutPrinter},
smtp::LettreService,
};
@ -26,12 +26,13 @@ fn create_app<'a>() -> clap::App<'a, 'a> {
.global_setting(clap::AppSettings::GlobalVersion)
.arg(&config_args::path_arg())
.arg(&account_args::name_arg())
.args(&output_arg::args())
.arg(mbox_arg::source_arg())
.subcommands(compl_arg::subcmds())
.subcommands(imap_arg::subcmds())
.subcommands(mbox_arg::subcmds())
.subcommands(msg_arg::subcmds())
.args(&output_args::args())
.arg(mbox_args::source_arg())
.subcommands(compl_args::subcmds())
.subcommands(imap_args::subcmds())
.subcommands(account_args::subcmds())
.subcommands(mbox_args::subcmds())
.subcommands(msg_args::subcmds())
}
#[allow(clippy::single_match)]
@ -75,7 +76,7 @@ fn main() -> Result<()> {
}
};
return msg_handler::mailto(&url, &account_config, &mut printer, backend, &mut smtp);
return msg_handlers::mailto(&url, &account_config, &mut printer, backend, &mut smtp);
}
let app = create_app();
@ -83,9 +84,9 @@ fn main() -> Result<()> {
// Check completion command BEFORE entities and services initialization.
// Related issue: https://github.com/soywod/himalaya/issues/115.
match compl_arg::matches(&m)? {
Some(compl_arg::Command::Generate(shell)) => {
return compl_handler::generate(create_app(), shell);
match compl_args::matches(&m)? {
Some(compl_args::Command::Generate(shell)) => {
return compl_handlers::generate(create_app(), shell);
}
_ => (),
}
@ -130,38 +131,46 @@ fn main() -> Result<()> {
// Check IMAP commands.
if let BackendConfig::Imap(ref imap_config) = backend_config {
let mut imap = ImapBackend::new(&account_config, imap_config);
match imap_arg::matches(&m)? {
Some(imap_arg::Command::Notify(keepalive)) => {
return imap_handler::notify(keepalive, mbox, &mut imap);
match imap_args::matches(&m)? {
Some(imap_args::Command::Notify(keepalive)) => {
return imap_handlers::notify(keepalive, mbox, &mut imap);
}
Some(imap_arg::Command::Watch(keepalive)) => {
return imap_handler::watch(keepalive, mbox, &mut imap);
Some(imap_args::Command::Watch(keepalive)) => {
return imap_handlers::watch(keepalive, mbox, &mut imap);
}
_ => (),
}
}
// Check account commands.
match account_args::matches(&m)? {
Some(account_args::Cmd::List(max_width)) => {
return account_handlers::list(max_width, &config, &account_config, &mut printer);
}
_ => (),
}
// Check mailbox commands.
match mbox_arg::matches(&m)? {
Some(mbox_arg::Cmd::List(max_width)) => {
return mbox_handler::list(max_width, &account_config, &mut printer, backend);
match mbox_args::matches(&m)? {
Some(mbox_args::Cmd::List(max_width)) => {
return mbox_handlers::list(max_width, &account_config, &mut printer, backend);
}
_ => (),
}
// Check message commands.
match msg_arg::matches(&m)? {
Some(msg_arg::Cmd::Attachments(seq)) => {
return msg_handler::attachments(seq, mbox, &account_config, &mut printer, backend);
match msg_args::matches(&m)? {
Some(msg_args::Cmd::Attachments(seq)) => {
return msg_handlers::attachments(seq, mbox, &account_config, &mut printer, backend);
}
Some(msg_arg::Cmd::Copy(seq, mbox_dst)) => {
return msg_handler::copy(seq, mbox, mbox_dst, &mut printer, backend);
Some(msg_args::Cmd::Copy(seq, mbox_dst)) => {
return msg_handlers::copy(seq, mbox, mbox_dst, &mut printer, backend);
}
Some(msg_arg::Cmd::Delete(seq)) => {
return msg_handler::delete(seq, mbox, &mut printer, backend);
Some(msg_args::Cmd::Delete(seq)) => {
return msg_handlers::delete(seq, mbox, &mut printer, backend);
}
Some(msg_arg::Cmd::Forward(seq, attachment_paths, encrypt)) => {
return msg_handler::forward(
Some(msg_args::Cmd::Forward(seq, attachment_paths, encrypt)) => {
return msg_handlers::forward(
seq,
attachment_paths,
encrypt,
@ -172,8 +181,8 @@ fn main() -> Result<()> {
&mut smtp,
);
}
Some(msg_arg::Cmd::List(max_width, page_size, page)) => {
return msg_handler::list(
Some(msg_args::Cmd::List(max_width, page_size, page)) => {
return msg_handlers::list(
max_width,
page_size,
page,
@ -183,14 +192,14 @@ fn main() -> Result<()> {
backend,
);
}
Some(msg_arg::Cmd::Move(seq, mbox_dst)) => {
return msg_handler::move_(seq, mbox, mbox_dst, &mut printer, backend);
Some(msg_args::Cmd::Move(seq, mbox_dst)) => {
return msg_handlers::move_(seq, mbox, mbox_dst, &mut printer, backend);
}
Some(msg_arg::Cmd::Read(seq, text_mime, raw)) => {
return msg_handler::read(seq, text_mime, raw, mbox, &mut printer, backend);
Some(msg_args::Cmd::Read(seq, text_mime, raw)) => {
return msg_handlers::read(seq, text_mime, raw, mbox, &mut printer, backend);
}
Some(msg_arg::Cmd::Reply(seq, all, attachment_paths, encrypt)) => {
return msg_handler::reply(
Some(msg_args::Cmd::Reply(seq, all, attachment_paths, encrypt)) => {
return msg_handlers::reply(
seq,
all,
attachment_paths,
@ -202,11 +211,11 @@ fn main() -> Result<()> {
&mut smtp,
);
}
Some(msg_arg::Cmd::Save(raw_msg)) => {
return msg_handler::save(mbox, raw_msg, &mut printer, backend);
Some(msg_args::Cmd::Save(raw_msg)) => {
return msg_handlers::save(mbox, raw_msg, &mut printer, backend);
}
Some(msg_arg::Cmd::Search(query, max_width, page_size, page)) => {
return msg_handler::search(
Some(msg_args::Cmd::Search(query, max_width, page_size, page)) => {
return msg_handlers::search(
query,
max_width,
page_size,
@ -217,8 +226,8 @@ fn main() -> Result<()> {
backend,
);
}
Some(msg_arg::Cmd::Sort(criteria, query, max_width, page_size, page)) => {
return msg_handler::sort(
Some(msg_args::Cmd::Sort(criteria, query, max_width, page_size, page)) => {
return msg_handlers::sort(
criteria,
query,
max_width,
@ -230,11 +239,11 @@ fn main() -> Result<()> {
backend,
);
}
Some(msg_arg::Cmd::Send(raw_msg)) => {
return msg_handler::send(raw_msg, &account_config, &mut printer, backend, &mut smtp);
Some(msg_args::Cmd::Send(raw_msg)) => {
return msg_handlers::send(raw_msg, &account_config, &mut printer, backend, &mut smtp);
}
Some(msg_arg::Cmd::Write(atts, encrypt)) => {
return msg_handler::write(
Some(msg_args::Cmd::Write(atts, encrypt)) => {
return msg_handlers::write(
atts,
encrypt,
&account_config,
@ -243,24 +252,24 @@ fn main() -> Result<()> {
&mut smtp,
);
}
Some(msg_arg::Cmd::Flag(m)) => match m {
Some(flag_arg::Cmd::Set(seq_range, flags)) => {
return flag_handler::set(seq_range, mbox, &flags, &mut printer, backend);
Some(msg_args::Cmd::Flag(m)) => match m {
Some(flag_args::Cmd::Set(seq_range, flags)) => {
return flag_handlers::set(seq_range, mbox, &flags, &mut printer, backend);
}
Some(flag_arg::Cmd::Add(seq_range, flags)) => {
return flag_handler::add(seq_range, mbox, &flags, &mut printer, backend);
Some(flag_args::Cmd::Add(seq_range, flags)) => {
return flag_handlers::add(seq_range, mbox, &flags, &mut printer, backend);
}
Some(flag_arg::Cmd::Remove(seq_range, flags)) => {
return flag_handler::remove(seq_range, mbox, &flags, &mut printer, backend);
Some(flag_args::Cmd::Remove(seq_range, flags)) => {
return flag_handlers::remove(seq_range, mbox, &flags, &mut printer, backend);
}
_ => (),
},
Some(msg_arg::Cmd::Tpl(m)) => match m {
Some(tpl_arg::Cmd::New(tpl)) => {
return tpl_handler::new(tpl, &account_config, &mut printer);
Some(msg_args::Cmd::Tpl(m)) => match m {
Some(tpl_args::Cmd::New(tpl)) => {
return tpl_handlers::new(tpl, &account_config, &mut printer);
}
Some(tpl_arg::Cmd::Reply(seq, all, tpl)) => {
return tpl_handler::reply(
Some(tpl_args::Cmd::Reply(seq, all, tpl)) => {
return tpl_handlers::reply(
seq,
all,
tpl,
@ -270,8 +279,8 @@ fn main() -> Result<()> {
backend,
);
}
Some(tpl_arg::Cmd::Forward(seq, tpl)) => {
return tpl_handler::forward(
Some(tpl_args::Cmd::Forward(seq, tpl)) => {
return tpl_handlers::forward(
seq,
tpl,
mbox,
@ -280,11 +289,11 @@ fn main() -> Result<()> {
backend,
);
}
Some(tpl_arg::Cmd::Save(atts, tpl)) => {
return tpl_handler::save(mbox, &account_config, atts, tpl, &mut printer, backend);
Some(tpl_args::Cmd::Save(atts, tpl)) => {
return tpl_handlers::save(mbox, &account_config, atts, tpl, &mut printer, backend);
}
Some(tpl_arg::Cmd::Send(atts, tpl)) => {
return tpl_handler::send(
Some(tpl_args::Cmd::Send(atts, tpl)) => {
return tpl_handlers::send(
mbox,
&account_config,
atts,

View file

@ -7,7 +7,7 @@ use anyhow::Result;
use clap::{self, App, AppSettings, Arg, ArgMatches, SubCommand};
use log::{debug, info};
use crate::msg::msg_arg;
use crate::msg::msg_args;
type SeqRange<'a> = &'a str;
type Flags = String;
@ -89,21 +89,21 @@ pub fn subcmds<'a>() -> Vec<App<'a, 'a>> {
SubCommand::with_name("add")
.aliases(&["a"])
.about("Adds flags to a message")
.arg(msg_arg::seq_range_arg())
.arg(msg_args::seq_range_arg())
.arg(flags_arg()),
)
.subcommand(
SubCommand::with_name("set")
.aliases(&["s", "change", "c"])
.about("Replaces all message flags")
.arg(msg_arg::seq_range_arg())
.arg(msg_args::seq_range_arg())
.arg(flags_arg()),
)
.subcommand(
SubCommand::with_name("remove")
.aliases(&["rem", "rm", "r", "delete", "del", "d"])
.about("Removes flags from a message")
.arg(msg_arg::seq_range_arg())
.arg(msg_args::seq_range_arg())
.arg(flags_arg()),
)]
}

View file

@ -7,8 +7,8 @@ use clap::{self, App, Arg, ArgMatches, SubCommand};
use log::{debug, info, trace};
use crate::{
mbox::mbox_arg,
msg::{flag_arg, msg_arg, tpl_arg},
mbox::mbox_args,
msg::{flag_args, msg_args, tpl_args},
ui::table_arg,
};
@ -43,8 +43,8 @@ pub enum Cmd<'a> {
Send(RawMsg<'a>),
Write(AttachmentPaths<'a>, Encrypt),
Flag(Option<flag_arg::Cmd<'a>>),
Tpl(Option<tpl_arg::Cmd<'a>>),
Flag(Option<flag_args::Cmd<'a>>),
Tpl(Option<tpl_args::Cmd<'a>>),
}
/// Message command matcher.
@ -262,11 +262,11 @@ pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Cmd<'a>>> {
}
if let Some(m) = m.subcommand_matches("template") {
return Ok(Some(Cmd::Tpl(tpl_arg::matches(m)?)));
return Ok(Some(Cmd::Tpl(tpl_args::matches(m)?)));
}
if let Some(m) = m.subcommand_matches("flag") {
return Ok(Some(Cmd::Flag(flag_arg::matches(m)?)));
return Ok(Some(Cmd::Flag(flag_args::matches(m)?)));
}
info!("default list command matched");
@ -338,13 +338,13 @@ pub fn encrypt_arg<'a>() -> Arg<'a, 'a> {
/// Message subcommands.
pub fn subcmds<'a>() -> Vec<App<'a, 'a>> {
vec![
flag_arg::subcmds(),
tpl_arg::subcmds(),
flag_args::subcmds(),
tpl_args::subcmds(),
vec![
SubCommand::with_name("attachments")
.aliases(&["attachment", "att", "a"])
.about("Downloads all message attachments")
.arg(msg_arg::seq_arg()),
.arg(msg_args::seq_arg()),
SubCommand::with_name("list")
.aliases(&["lst", "l"])
.about("Lists all messages")
@ -442,12 +442,12 @@ pub fn subcmds<'a>() -> Vec<App<'a, 'a>> {
.aliases(&["cp", "c"])
.about("Copies a message to the targetted mailbox")
.arg(seq_arg())
.arg(mbox_arg::target_arg()),
.arg(mbox_args::target_arg()),
SubCommand::with_name("move")
.aliases(&["mv"])
.about("Moves a message to the targetted mailbox")
.arg(seq_arg())
.arg(mbox_arg::target_arg()),
.arg(mbox_args::target_arg()),
SubCommand::with_name("delete")
.aliases(&["del", "d", "remove", "rm"])
.about("Deletes a message")

View file

@ -6,7 +6,7 @@ use anyhow::Result;
use clap::{self, App, AppSettings, Arg, ArgMatches, SubCommand};
use log::{debug, info, trace};
use crate::msg::msg_arg;
use crate::msg::msg_args;
type Seq<'a> = &'a str;
type ReplyAll = bool;
@ -169,27 +169,27 @@ pub fn subcmds<'a>() -> Vec<App<'a, 'a>> {
SubCommand::with_name("reply")
.aliases(&["rep", "re", "r"])
.about("Generates a reply message template")
.arg(msg_arg::seq_arg())
.arg(msg_arg::reply_all_arg())
.arg(msg_args::seq_arg())
.arg(msg_args::reply_all_arg())
.args(&tpl_args()),
)
.subcommand(
SubCommand::with_name("forward")
.aliases(&["fwd", "fw", "f"])
.about("Generates a forward message template")
.arg(msg_arg::seq_arg())
.arg(msg_args::seq_arg())
.args(&tpl_args()),
)
.subcommand(
SubCommand::with_name("save")
.about("Saves a message based on the given template")
.arg(&msg_arg::attachment_arg())
.arg(&msg_args::attachment_arg())
.arg(Arg::with_name("template").raw(true)),
)
.subcommand(
SubCommand::with_name("send")
.about("Sends a message based on the given template")
.arg(&msg_arg::attachment_arg())
.arg(&msg_args::attachment_arg())
.arg(Arg::with_name("template").raw(true)),
)]
}

View file

@ -1,6 +1,6 @@
//! Module related to output formatting and printing.
pub mod output_arg;
pub mod output_args;
pub mod output_utils;
pub use output_utils::*;