mirror of
https://github.com/soywod/himalaya.git
synced 2025-04-17 06:43:37 +00:00
refactor flag with clap derive api
This commit is contained in:
parent
2c33dd2f9f
commit
5e1a03e3c1
9 changed files with 254 additions and 76 deletions
12
src/cli.rs
12
src/cli.rs
|
@ -7,6 +7,7 @@ use crate::{
|
|||
completion::command::CompletionGenerateCommand,
|
||||
config::{self, TomlConfig},
|
||||
envelope::command::EnvelopeSubcommand,
|
||||
flag::command::FlagSubcommand,
|
||||
folder::command::FolderSubcommand,
|
||||
manual::command::ManualGenerateCommand,
|
||||
output::{ColorFmt, OutputFmt},
|
||||
|
@ -90,17 +91,21 @@ pub struct Cli {
|
|||
#[derive(Subcommand, Debug)]
|
||||
pub enum HimalayaCommand {
|
||||
/// Subcommand to manage accounts
|
||||
#[command(subcommand)]
|
||||
#[command(subcommand, alias = "accounts")]
|
||||
Account(AccountSubcommand),
|
||||
|
||||
/// Subcommand to manage folders
|
||||
#[command(subcommand)]
|
||||
#[command(subcommand, alias = "folders")]
|
||||
Folder(FolderSubcommand),
|
||||
|
||||
/// Subcommand to manage envelopes
|
||||
#[command(subcommand)]
|
||||
#[command(subcommand, alias = "envelopes")]
|
||||
Envelope(EnvelopeSubcommand),
|
||||
|
||||
/// Subcommand to manage flags
|
||||
#[command(subcommand, alias = "flags")]
|
||||
Flag(FlagSubcommand),
|
||||
|
||||
/// Generate manual pages to a directory
|
||||
#[command(arg_required_else_help = true)]
|
||||
Manual(ManualGenerateCommand),
|
||||
|
@ -116,6 +121,7 @@ impl HimalayaCommand {
|
|||
Self::Account(cmd) => cmd.execute(printer, config).await,
|
||||
Self::Folder(cmd) => cmd.execute(printer, config).await,
|
||||
Self::Envelope(cmd) => cmd.execute(printer, config).await,
|
||||
Self::Flag(cmd) => cmd.execute(printer, config).await,
|
||||
Self::Manual(cmd) => cmd.execute(printer).await,
|
||||
Self::Completion(cmd) => cmd.execute(printer).await,
|
||||
}
|
||||
|
|
51
src/email/envelope/flag/arg/ids_and_flags.rs
Normal file
51
src/email/envelope/flag/arg/ids_and_flags.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
use clap::Parser;
|
||||
use email::flag::{Flag, Flags};
|
||||
use log::debug;
|
||||
|
||||
/// The ids and/or flags arguments parser
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct IdsAndFlagsArgs {
|
||||
/// The list of ids and/or flags
|
||||
///
|
||||
/// Every argument that can be parsed as an integer is considered
|
||||
/// an id, otherwise it is considered as a flag.
|
||||
#[arg(value_name = "ID-OR-FLAG", required = true)]
|
||||
pub ids_and_flags: Vec<IdOrFlag>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum IdOrFlag {
|
||||
Id(String),
|
||||
Flag(Flag),
|
||||
}
|
||||
|
||||
impl From<&str> for IdOrFlag {
|
||||
fn from(value: &str) -> Self {
|
||||
value
|
||||
.parse::<usize>()
|
||||
.map(|_| Self::Id(value.to_owned()))
|
||||
.unwrap_or_else(|err| {
|
||||
let flag = Flag::from(value);
|
||||
debug!("cannot parse {value} as usize, parsing it as flag {flag}");
|
||||
debug!("{err:?}");
|
||||
Self::Flag(flag)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_tuple<'a>(ids_and_flags: &'a [IdOrFlag]) -> (Vec<&'a str>, Flags) {
|
||||
ids_and_flags.iter().fold(
|
||||
(Vec::default(), Flags::default()),
|
||||
|(mut ids, mut flags), arg| {
|
||||
match arg {
|
||||
IdOrFlag::Id(id) => {
|
||||
ids.push(id.as_str());
|
||||
}
|
||||
IdOrFlag::Flag(flag) => {
|
||||
flags.insert(flag.to_owned());
|
||||
}
|
||||
};
|
||||
(ids, flags)
|
||||
},
|
||||
)
|
||||
}
|
1
src/email/envelope/flag/arg/mod.rs
Normal file
1
src/email/envelope/flag/arg/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod ids_and_flags;
|
48
src/email/envelope/flag/command/add.rs
Normal file
48
src/email/envelope/flag/command/add.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
|
||||
use crate::{
|
||||
account::arg::name::AccountNameFlag,
|
||||
backend::Backend,
|
||||
cache::arg::disable::DisableCacheFlag,
|
||||
config::TomlConfig,
|
||||
flag::arg::ids_and_flags::{to_tuple, IdsAndFlagsArgs},
|
||||
folder::arg::name::FolderNameArg,
|
||||
printer::Printer,
|
||||
};
|
||||
|
||||
/// Add flag(s) to an envelope
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct FlagAddCommand {
|
||||
#[command(flatten)]
|
||||
pub folder: FolderNameArg,
|
||||
|
||||
#[command(flatten)]
|
||||
pub args: IdsAndFlagsArgs,
|
||||
|
||||
#[command(flatten)]
|
||||
pub account: AccountNameFlag,
|
||||
|
||||
#[command(flatten)]
|
||||
pub cache: DisableCacheFlag,
|
||||
}
|
||||
|
||||
impl FlagAddCommand {
|
||||
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
||||
info!("executing flag add command");
|
||||
|
||||
let folder = &self.folder.name;
|
||||
let account = self.account.name.as_ref().map(String::as_str);
|
||||
let cache = self.cache.disable;
|
||||
|
||||
let (toml_account_config, account_config) =
|
||||
config.clone().into_account_configs(account, cache)?;
|
||||
let backend = Backend::new(toml_account_config, account_config.clone(), false).await?;
|
||||
|
||||
let (ids, flags) = to_tuple(&self.args.ids_and_flags);
|
||||
backend.add_flags(folder, &ids, &flags).await?;
|
||||
|
||||
printer.print(format!("Flag(s) {flags} successfully added!"))
|
||||
}
|
||||
}
|
39
src/email/envelope/flag/command/mod.rs
Normal file
39
src/email/envelope/flag/command/mod.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
mod add;
|
||||
mod remove;
|
||||
mod set;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Subcommand;
|
||||
|
||||
use crate::{config::TomlConfig, printer::Printer};
|
||||
|
||||
use self::{add::FlagAddCommand, remove::FlagRemoveCommand, set::FlagSetCommand};
|
||||
|
||||
/// Subcommand to manage flags
|
||||
#[derive(Debug, Subcommand)]
|
||||
pub enum FlagSubcommand {
|
||||
/// Add flag(s) to an envelope
|
||||
#[command(arg_required_else_help = true)]
|
||||
#[command(alias = "create")]
|
||||
Add(FlagAddCommand),
|
||||
|
||||
/// Replace flag(s) of an envelope
|
||||
#[command(arg_required_else_help = true)]
|
||||
#[command(aliases = ["update", "change", "replace"])]
|
||||
Set(FlagSetCommand),
|
||||
|
||||
/// Remove flag(s) from an envelope
|
||||
#[command(arg_required_else_help = true)]
|
||||
#[command(aliases = ["rm", "delete", "del"])]
|
||||
Remove(FlagRemoveCommand),
|
||||
}
|
||||
|
||||
impl FlagSubcommand {
|
||||
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
||||
match self {
|
||||
Self::Add(cmd) => cmd.execute(printer, config).await,
|
||||
Self::Set(cmd) => cmd.execute(printer, config).await,
|
||||
Self::Remove(cmd) => cmd.execute(printer, config).await,
|
||||
}
|
||||
}
|
||||
}
|
48
src/email/envelope/flag/command/remove.rs
Normal file
48
src/email/envelope/flag/command/remove.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
|
||||
use crate::{
|
||||
account::arg::name::AccountNameFlag,
|
||||
backend::Backend,
|
||||
cache::arg::disable::DisableCacheFlag,
|
||||
config::TomlConfig,
|
||||
flag::arg::ids_and_flags::{to_tuple, IdsAndFlagsArgs},
|
||||
folder::arg::name::FolderNameArg,
|
||||
printer::Printer,
|
||||
};
|
||||
|
||||
/// Remove flag(s) from an envelope
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct FlagRemoveCommand {
|
||||
#[command(flatten)]
|
||||
pub folder: FolderNameArg,
|
||||
|
||||
#[command(flatten)]
|
||||
pub args: IdsAndFlagsArgs,
|
||||
|
||||
#[command(flatten)]
|
||||
pub account: AccountNameFlag,
|
||||
|
||||
#[command(flatten)]
|
||||
pub cache: DisableCacheFlag,
|
||||
}
|
||||
|
||||
impl FlagRemoveCommand {
|
||||
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
||||
info!("executing flag remove command");
|
||||
|
||||
let folder = &self.folder.name;
|
||||
let account = self.account.name.as_ref().map(String::as_str);
|
||||
let cache = self.cache.disable;
|
||||
|
||||
let (toml_account_config, account_config) =
|
||||
config.clone().into_account_configs(account, cache)?;
|
||||
let backend = Backend::new(toml_account_config, account_config.clone(), false).await?;
|
||||
|
||||
let (ids, flags) = to_tuple(&self.args.ids_and_flags);
|
||||
backend.remove_flags(folder, &ids, &flags).await?;
|
||||
|
||||
printer.print(format!("Flag(s) {flags} successfully removed!"))
|
||||
}
|
||||
}
|
48
src/email/envelope/flag/command/set.rs
Normal file
48
src/email/envelope/flag/command/set.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
|
||||
use crate::{
|
||||
account::arg::name::AccountNameFlag,
|
||||
backend::Backend,
|
||||
cache::arg::disable::DisableCacheFlag,
|
||||
config::TomlConfig,
|
||||
flag::arg::ids_and_flags::{to_tuple, IdsAndFlagsArgs},
|
||||
folder::arg::name::FolderNameArg,
|
||||
printer::Printer,
|
||||
};
|
||||
|
||||
/// Replace flag(s) of an envelope
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct FlagSetCommand {
|
||||
#[command(flatten)]
|
||||
pub folder: FolderNameArg,
|
||||
|
||||
#[command(flatten)]
|
||||
pub args: IdsAndFlagsArgs,
|
||||
|
||||
#[command(flatten)]
|
||||
pub account: AccountNameFlag,
|
||||
|
||||
#[command(flatten)]
|
||||
pub cache: DisableCacheFlag,
|
||||
}
|
||||
|
||||
impl FlagSetCommand {
|
||||
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
||||
info!("executing flag set command");
|
||||
|
||||
let folder = &self.folder.name;
|
||||
let account = self.account.name.as_ref().map(String::as_str);
|
||||
let cache = self.cache.disable;
|
||||
|
||||
let (toml_account_config, account_config) =
|
||||
config.clone().into_account_configs(account, cache)?;
|
||||
let backend = Backend::new(toml_account_config, account_config.clone(), false).await?;
|
||||
|
||||
let (ids, flags) = to_tuple(&self.args.ids_and_flags);
|
||||
backend.set_flags(folder, &ids, &flags).await?;
|
||||
|
||||
printer.print(format!("Flag(s) {flags} successfully set!"))
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
pub mod arg;
|
||||
pub mod args;
|
||||
pub mod command;
|
||||
pub mod config;
|
||||
pub mod handlers;
|
||||
|
||||
|
@ -6,7 +8,7 @@ use serde::Serialize;
|
|||
use std::{collections::HashSet, ops};
|
||||
|
||||
/// Represents the flag variants.
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize)]
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Ord, PartialOrd, Serialize)]
|
||||
pub enum Flag {
|
||||
Seen,
|
||||
Answered,
|
||||
|
|
79
src/main.rs
79
src/main.rs
|
@ -2,9 +2,16 @@ use anyhow::Result;
|
|||
use clap::Parser;
|
||||
use env_logger::{Builder as LoggerBuilder, Env, DEFAULT_FILTER_ENV};
|
||||
use himalaya::{cli::Cli, config::TomlConfig, printer::StdoutPrinter};
|
||||
use log::{debug, warn};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
if let Err((_, err)) = coredump::register_panic_handler() {
|
||||
warn!("cannot register custom panic handler: {err}");
|
||||
debug!("{err:?}");
|
||||
}
|
||||
|
||||
LoggerBuilder::new()
|
||||
.parse_env(Env::new().filter_or(DEFAULT_FILTER_ENV, "warn"))
|
||||
.format_timestamp(None)
|
||||
|
@ -20,30 +27,12 @@ async fn main() -> Result<()> {
|
|||
|
||||
// fn create_app() -> clap::Command {
|
||||
// clap::Command::new(env!("CARGO_PKG_NAME"))
|
||||
// .version(env!("CARGO_PKG_VERSION"))
|
||||
// .about(env!("CARGO_PKG_DESCRIPTION"))
|
||||
// .author(env!("CARGO_PKG_AUTHORS"))
|
||||
// .propagate_version(true)
|
||||
// .infer_subcommands(true)
|
||||
// .args(cache::args::global_args())
|
||||
// .args(output::args::global_args())
|
||||
// .subcommand(envelope::args::subcmd())
|
||||
// .subcommand(flag::args::subcmd())
|
||||
// .subcommand(message::args::subcmd())
|
||||
// .subcommand(template::args::subcmd())
|
||||
// }
|
||||
|
||||
// #[tokio::main]
|
||||
// async fn main() -> Result<()> {
|
||||
// #[cfg(not(target_os = "windows"))]
|
||||
// if let Err((_, err)) = coredump::register_panic_handler() {
|
||||
// warn!("cannot register custom panic handler: {err}");
|
||||
// debug!("cannot register custom panic handler: {err:?}");
|
||||
// }
|
||||
|
||||
// let default_env_filter = env_logger::DEFAULT_FILTER_ENV;
|
||||
// env_logger::init_from_env(env_logger::Env::default().filter_or(default_env_filter, "off"));
|
||||
|
||||
// // check mailto command before app initialization
|
||||
// let raw_args: Vec<String> = env::args().collect();
|
||||
// if raw_args.len() > 1 && raw_args[1].starts_with("mailto:") {
|
||||
|
@ -59,58 +48,6 @@ async fn main() -> Result<()> {
|
|||
// return message::handlers::mailto(&account_config, &backend, &mut printer, &url).await;
|
||||
// }
|
||||
|
||||
// let app = _create_app();
|
||||
// let m = app.get_matches();
|
||||
|
||||
// let some_config_path = config::args::parse_global_arg(&m);
|
||||
// let some_account_name = account::command::parse_global_arg(&m);
|
||||
// let disable_cache = cache::args::parse_disable_cache_arg(&m);
|
||||
|
||||
// let toml_config = TomlConfig::from_some_path_or_default(some_config_path).await?;
|
||||
|
||||
// let mut printer = StdoutPrinter::try_from(&m)?;
|
||||
|
||||
// let (toml_account_config, account_config) = toml_config
|
||||
// .clone()
|
||||
// .into_account_configs(some_account_name, disable_cache)?;
|
||||
|
||||
// match envelope::args::matches(&m)? {
|
||||
// Some(envelope::args::Cmd::List(max_width, page_size, page)) => {
|
||||
// let folder = folder.unwrap_or(DEFAULT_INBOX_FOLDER);
|
||||
// let backend = Backend::new(toml_account_config, account_config.clone(), false).await?;
|
||||
// return envelope::handlers::list(
|
||||
// &account_config,
|
||||
// &mut printer,
|
||||
// &backend,
|
||||
// &folder,
|
||||
// max_width,
|
||||
// page_size,
|
||||
// page,
|
||||
// )
|
||||
// .await;
|
||||
// }
|
||||
// _ => (),
|
||||
// }
|
||||
|
||||
// match flag::args::matches(&m)? {
|
||||
// Some(flag::args::Cmd::Set(ids, ref flags)) => {
|
||||
// let folder = folder.unwrap_or(DEFAULT_INBOX_FOLDER);
|
||||
// let backend = Backend::new(toml_account_config, account_config.clone(), false).await?;
|
||||
// return flag::handlers::set(&mut printer, &backend, &folder, ids, flags).await;
|
||||
// }
|
||||
// Some(flag::args::Cmd::Add(ids, ref flags)) => {
|
||||
// let folder = folder.unwrap_or(DEFAULT_INBOX_FOLDER);
|
||||
// let backend = Backend::new(toml_account_config, account_config.clone(), false).await?;
|
||||
// return flag::handlers::add(&mut printer, &backend, &folder, ids, flags).await;
|
||||
// }
|
||||
// Some(flag::args::Cmd::Remove(ids, ref flags)) => {
|
||||
// let folder = folder.unwrap_or(DEFAULT_INBOX_FOLDER);
|
||||
// let backend = Backend::new(toml_account_config, account_config.clone(), false).await?;
|
||||
// return flag::handlers::remove(&mut printer, &backend, &folder, ids, flags).await;
|
||||
// }
|
||||
// _ => (),
|
||||
// }
|
||||
|
||||
// match message::args::matches(&m)? {
|
||||
// Some(message::args::Cmd::Attachments(ids)) => {
|
||||
// let folder = folder.unwrap_or(DEFAULT_INBOX_FOLDER);
|
||||
|
@ -259,6 +196,4 @@ async fn main() -> Result<()> {
|
|||
// }
|
||||
// _ => (),
|
||||
// }
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
|
Loading…
Add table
Reference in a new issue