Skip to content

Commit

Permalink
refactor flag with clap derive api
Browse files Browse the repository at this point in the history
  • Loading branch information
soywod committed Dec 7, 2023
1 parent 2c33dd2 commit 5e1a03e
Show file tree
Hide file tree
Showing 9 changed files with 254 additions and 76 deletions.
12 changes: 9 additions & 3 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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),
Expand All @@ -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,
}
Expand Down
51 changes: 51 additions & 0 deletions src/email/envelope/flag/arg/ids_and_flags.rs
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions src/email/envelope/flag/arg/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod ids_and_flags;
48 changes: 48 additions & 0 deletions src/email/envelope/flag/command/add.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 39 additions & 0 deletions src/email/envelope/flag/command/mod.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 48 additions & 0 deletions src/email/envelope/flag/command/remove.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 48 additions & 0 deletions src/email/envelope/flag/command/set.rs
Original file line number Diff line number Diff line change
@@ -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!"))
}
}
4 changes: 3 additions & 1 deletion src/email/envelope/flag/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
pub mod arg;
pub mod args;
pub mod command;
pub mod config;
pub mod handlers;

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,
Expand Down
Loading

0 comments on commit 5e1a03e

Please sign in to comment.