Skip to content

Commit

Permalink
refactor man and completion with clap derive api
Browse files Browse the repository at this point in the history
  • Loading branch information
soywod committed Dec 5, 2023
1 parent 7a10a7f commit d230822
Show file tree
Hide file tree
Showing 22 changed files with 270 additions and 233 deletions.
30 changes: 27 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ version = "0.4.24"

[dependencies.clap]
version = "4.0"
features = ["derive"]

[dependencies.clap_complete]
version = "4.0"
Expand All @@ -80,7 +81,7 @@ version = "4.0.0"
version = "0.2.4"

[dependencies.env_logger]
version = "0.8"
version = "0.10"

[dependencies.erased-serde]
version = "0.3"
Expand Down
64 changes: 40 additions & 24 deletions src/account/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,20 @@ pub enum Cmd {
/// Represents the account command matcher.
pub fn matches(m: &ArgMatches) -> Result<Option<Cmd>> {
let cmd = if let Some(m) = m.subcommand_matches(CMD_ACCOUNT) {
if let Some(m) = m.subcommand_matches(CMD_SYNC) {
if let Some(m) = m.subcommand_matches(CMD_CONFIGURE) {
info!("configure account subcommand matched");
let reset = parse_reset_flag(m);
Some(Cmd::Configure(reset))
} else if let Some(m) = m.subcommand_matches(CMD_LIST) {
info!("list accounts subcommand matched");
let max_table_width = table::args::parse_max_width(m);
Some(Cmd::List(max_table_width))
} else if let Some(m) = m.subcommand_matches(CMD_SYNC) {
info!("sync account subcommand matched");
let dry_run = parse_dry_run_arg(m);
let include = folder::args::parse_include_arg(m);
let exclude = folder::args::parse_exclude_arg(m);
let folders_strategy = if let Some(folder) = folder::args::parse_source_arg(m) {
let folders_strategy = if let Some(folder) = folder::args::parse_global_source_arg(m) {
Some(FolderSyncStrategy::Include(HashSet::from_iter([
folder.to_owned()
])))
Expand All @@ -52,17 +60,8 @@ pub fn matches(m: &ArgMatches) -> Result<Option<Cmd>> {
None
};
Some(Cmd::Sync(folders_strategy, dry_run))
} else if let Some(m) = m.subcommand_matches(CMD_LIST) {
info!("list accounts subcommand matched");
let max_table_width = table::args::parse_max_width(m);
Some(Cmd::List(max_table_width))
} else if let Some(m) = m.subcommand_matches(CMD_CONFIGURE) {
info!("configure account subcommand matched");
let reset = parse_reset_flag(m);
Some(Cmd::Configure(reset))
} else {
info!("no account subcommand matched, falling back to subcommand list");
Some(Cmd::List(None))
None
}
} else {
None
Expand All @@ -75,10 +74,26 @@ pub fn matches(m: &ArgMatches) -> Result<Option<Cmd>> {
pub fn subcmd() -> Command {
Command::new(CMD_ACCOUNT)
.about("Subcommand to manage accounts")
.subcommands([
.long_about("Subcommand to manage accounts like configure, list or sync")
.aliases(["accounts", "acc"])
.subcommand_required(true)
.arg_required_else_help(true)
.subcommand(
Command::new(CMD_CONFIGURE)
.about("Configure the given account")
.aliases(["config", "conf", "cfg"])
.arg(reset_flag())
.arg(folder::args::source_arg(
"Define the account to be configured",
)),
)
.subcommand(
Command::new(CMD_LIST)
.about("List all accounts from the config file")
.about("List all accounts")
.long_about("List all accounts that are set up in the configuration file")
.arg(table::args::max_width()),
)
.subcommand(
Command::new(CMD_SYNC)
.about("Synchronize the given account locally")
.arg(folder::args::all_arg("Synchronize all folders"))
Expand All @@ -89,26 +104,27 @@ pub fn subcmd() -> Command {
"Synchronize all folders except the given ones",
))
.arg(dry_run()),
Command::new(CMD_CONFIGURE)
.about("Configure the current selected account")
.aliases(["config", "conf", "cfg"])
.arg(reset_flag()),
])
)
}

/// Represents the user account name argument. This argument allows
/// the user to select a different account than the default one.
pub fn arg() -> Arg {
Arg::new(ARG_ACCOUNT)
.help("Set the account")
pub fn global_args() -> impl IntoIterator<Item = Arg> {
[Arg::new(ARG_ACCOUNT)
.help("Override the default account")
.long_help(
"Override the default account
The given account will be used by default for all other commands (when applicable).",
)
.long("account")
.short('a')
.global(true)
.value_name("STRING")
.value_name("name")]
}

/// Represents the user account name argument parser.
pub fn parse_arg(matches: &ArgMatches) -> Option<&str> {
pub fn parse_global_arg(matches: &ArgMatches) -> Option<&str> {
matches.get_one::<String>(ARG_ACCOUNT).map(String::as_str)
}

Expand Down
17 changes: 11 additions & 6 deletions src/cache/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,24 @@ const ARG_DISABLE_CACHE: &str = "disable-cache";

/// Represents the disable cache flag argument. This argument allows
/// the user to disable any sort of cache.
pub fn arg() -> Arg {
Arg::new(ARG_DISABLE_CACHE)
pub fn global_args() -> impl IntoIterator<Item = Arg> {
[Arg::new(ARG_DISABLE_CACHE)
.help("Disable any sort of cache")
.long_help(
"Disable any sort of cache. The action depends on
the command it applies on.",
"Disable any sort of cache.
The action depends on commands it apply on. For example, when listing
envelopes using the IMAP backend, this flag will ensure that envelopes
are fetched from the IMAP server and not from the synchronized local
Maildir.",
)
.long("disable-cache")
.alias("no-cache")
.global(true)
.action(ArgAction::SetTrue)
.action(ArgAction::SetTrue)]
}

/// Represents the disable cache flag parser.
pub fn parse_disable_cache_flag(m: &ArgMatches) -> bool {
pub fn parse_disable_cache_arg(m: &ArgMatches) -> bool {
m.get_flag(ARG_DISABLE_CACHE)
}
39 changes: 0 additions & 39 deletions src/completion/args.rs

This file was deleted.

10 changes: 10 additions & 0 deletions src/completion/command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use clap::{value_parser, Parser};
use clap_complete::Shell;

/// Print completion script for the given shell to stdout
#[derive(Debug, Parser)]
pub struct Generate {
/// Shell that completion script should be generated for
#[arg(value_parser = value_parser!(Shell))]
pub shell: Shell,
}
18 changes: 18 additions & 0 deletions src/completion/handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use anyhow::Result;
use clap::Command;
use clap_complete::Shell;
use std::io::stdout;

use crate::printer::Printer;

pub fn generate(printer: &mut impl Printer, mut cmd: Command, shell: Shell) -> Result<()> {
let name = cmd.get_name().to_string();

clap_complete::generate(shell, &mut cmd, name, &mut stdout());

printer.print(format!(
"Shell script successfully generated for shell {shell}!"
))?;

Ok(())
}
15 changes: 0 additions & 15 deletions src/completion/handlers.rs

This file was deleted.

10 changes: 2 additions & 8 deletions src/completion/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,2 @@
//! Module related to shell completion.
//!
//! This module allows users to generate autocompletion scripts for
//! their shells. You can see the list of available shells directly on
//! the clap's [docs.rs](https://docs.rs/clap/2.33.3/clap/enum.Shell.html).
pub mod args;
pub mod handlers;
pub mod command;
pub mod handler;
15 changes: 10 additions & 5 deletions src/config/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,21 @@ const ARG_CONFIG: &str = "config";

/// Represents the config file path argument. This argument allows the
/// user to customize the config file path.
pub fn arg() -> Arg {
Arg::new(ARG_CONFIG)
.help("Set a custom configuration file path")
pub fn global_args() -> impl IntoIterator<Item = Arg> {
[Arg::new(ARG_CONFIG)
.help("Override the configuration file path")
.long_help(
"Override the configuration file path
If the file under the given path does not exist, the wizard will propose to create it.",
)
.long("config")
.short('c')
.global(true)
.value_name("PATH")
.value_name("path")]
}

/// Represents the config file path argument parser.
pub fn parse_arg(matches: &ArgMatches) -> Option<&str> {
pub fn parse_global_arg(matches: &ArgMatches) -> Option<&str> {
matches.get_one::<String>(ARG_CONFIG).map(String::as_str)
}
3 changes: 2 additions & 1 deletion src/email/envelope/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ pub fn matches(m: &ArgMatches) -> Result<Option<Cmd>> {
/// Represents the envelope subcommand.
pub fn subcmd() -> Command {
Command::new(CMD_ENVELOPE)
.about("Manage envelopes")
.about("Subcommand to manage envelopes")
.long_about("Subcommand to manage envelopes like list")
.subcommands([Command::new(CMD_LIST)
.alias("lst")
.about("List envelopes")
Expand Down
3 changes: 2 additions & 1 deletion src/email/envelope/flag/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ pub fn matches(m: &ArgMatches) -> Result<Option<Cmd>> {
/// Represents the flag subcommand.
pub fn subcmd() -> Command {
Command::new(CMD_FLAG)
.about("Manage flags")
.about("Subcommand to manage flags")
.long_about("Subcommand to manage flags like add, set or remove")
.subcommand_required(true)
.arg_required_else_help(true)
.subcommand(
Expand Down
3 changes: 2 additions & 1 deletion src/email/message/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ pub fn matches(m: &ArgMatches) -> Result<Option<Cmd>> {
/// Represents the email subcommands.
pub fn subcmd() -> Command {
Command::new(CMD_MESSAGE)
.about("Manage messages")
.about("Subcommand to manage messages")
.long_about("Subcommand to manage messages like read, write, reply or send")
.aliases(["msg"])
.subcommand_required(true)
.arg_required_else_help(true)
Expand Down
3 changes: 2 additions & 1 deletion src/email/message/template/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Cmd<'a>>> {
pub fn subcmd() -> Command {
Command::new(CMD_TPL)
.alias("tpl")
.about("Manage templates")
.about("Subcommand to manage templates")
.long_about("Subcommand to manage templates like write, reply, send or save")
.subcommand_required(true)
.arg_required_else_help(true)
.subcommand(
Expand Down
Loading

0 comments on commit d230822

Please sign in to comment.