use clap::{Args, Parser, Subcommand, ValueEnum, ValueHint};
#[derive(Debug, Parser)]
#[command(
name = "reserve",
version,
about = "Find a domain name you can actually buy",
long_about = "Check one or more names across grouped domain extensions.\n\n\
Pick extensions by industry, region, or popularity, filter and sort\n\
the list, and sweep it. Every answer comes from the registry itself, and a\n\
lookup that cannot be answered is reported as unknown rather than guessed.",
after_help = "EXAMPLES:\n \
reserve example open the picker and choose extensions\n \
reserve example --group tech sweep the technology extensions\n \
reserve example -g shop -g finance extensions marketed for selling\n \
reserve example -g top-50 --sort popularity the fifty most used\n \
reserve groups list every group you can pick\n\n\
Full documentation: https://reserve.devops.bd",
disable_help_subcommand = true,
infer_subcommands = false,
propagate_version = true,
max_term_width = 100
)]
pub(crate) struct Cli {
#[arg(value_name = "NAME", value_hint = ValueHint::Other)]
pub names: Vec<String>,
#[arg(long, value_name = "PATH", value_hint = ValueHint::FilePath)]
pub names_from: Option<String>,
#[command(flatten)]
pub select: SelectArgs,
#[command(flatten)]
pub view: ListingArgs,
#[command(flatten)]
pub pacing: PacingArgs,
#[command(flatten)]
pub output: OutputArgs,
#[command(flatten)]
pub global: GlobalArgs,
#[command(subcommand)]
pub command: Option<Command>,
}
#[derive(Debug, Subcommand)]
#[allow(
clippy::large_enum_variant,
reason = "clap derive requires argument structs by value on each variant"
)]
pub(crate) enum Command {
Groups {
#[arg(short, long, value_enum, value_name = "FAMILY")]
family: Option<FamilyArg>,
#[arg(long)]
json: bool,
},
Extensions {
#[command(flatten)]
select: SelectArgs,
#[command(flatten)]
view: ListingArgs,
#[arg(long)]
json: bool,
},
Config {
#[command(subcommand)]
action: ConfigAction,
},
Doctor {
#[arg(long)]
json: bool,
},
Completions {
#[arg(value_enum)]
shell: ShellArg,
},
}
#[derive(Debug, Subcommand)]
pub(crate) enum ConfigAction {
Show {
#[arg(long)]
json: bool,
},
Path,
}
#[derive(Debug, Clone, Default, Args)]
#[command(next_help_heading = "Choosing extensions")]
pub(crate) struct SelectArgs {
#[arg(
short,
long,
value_name = "GROUP",
value_delimiter = ',',
num_args = 1..
)]
pub group: Vec<String>,
#[arg(
short = 't',
long = "tld",
value_name = "EXT",
value_delimiter = ',',
num_args = 1..
)]
pub tld: Vec<String>,
#[arg(
short = 'x',
long,
value_name = "EXT",
value_delimiter = ',',
num_args = 1..
)]
pub exclude: Vec<String>,
#[arg(short, long, value_name = "TEXT")]
pub search: Option<String>,
#[arg(long, value_name = "KEY", value_delimiter = ',', num_args = 1..)]
pub industry: Vec<String>,
#[arg(long, value_name = "KEY", value_delimiter = ',', num_args = 1..)]
pub region: Vec<String>,
#[arg(long)]
pub cctld: bool,
#[arg(long, value_enum, value_name = "DEPTH", default_value_t = DepthArg::Any)]
pub depth: DepthArg,
#[arg(long, value_name = "SPEC")]
pub length: Option<String>,
#[arg(long, value_name = "PATH", value_hint = ValueHint::FilePath)]
pub tlds_from: Option<String>,
#[arg(long)]
pub include_restricted: bool,
}
#[derive(Debug, Clone, Args)]
#[command(next_help_heading = "Ordering and paging")]
pub(crate) struct ListingArgs {
#[arg(long, value_enum, value_name = "FIELD", default_value_t = SortFieldArg::Popularity)]
pub sort: SortFieldArg,
#[arg(long, value_enum, value_name = "ORDER")]
pub order: Option<SortOrderArg>,
#[arg(long, value_name = "N", default_value_t = 1)]
pub page: usize,
#[arg(long, value_name = "N")]
pub page_size: Option<usize>,
#[arg(long, conflicts_with = "page")]
pub all_pages: bool,
}
impl Default for ListingArgs {
fn default() -> Self {
Self {
sort: SortFieldArg::Popularity,
order: None,
page: 1,
page_size: None,
all_pages: false,
}
}
}
#[derive(Debug, Clone, Args)]
#[command(next_help_heading = "Pacing")]
pub(crate) struct PacingArgs {
#[arg(short = 'c', long, value_name = "N", env = "RESERVE_CONCURRENCY")]
pub concurrency: Option<usize>,
#[arg(long, value_name = "N")]
pub per_registry: Option<usize>,
#[arg(long, value_name = "N")]
pub rate: Option<u32>,
#[arg(long, value_name = "SECS", env = "RESERVE_TIMEOUT")]
pub timeout: Option<u64>,
#[arg(long, conflicts_with_all = ["concurrency", "rate"])]
pub cautious: bool,
#[arg(long, value_enum, value_name = "SOURCE", default_value_t = SourceArg::Auto)]
pub source: SourceArg,
#[arg(long)]
pub refresh: bool,
#[arg(long, value_name = "PATH", value_hint = ValueHint::FilePath)]
pub registry_servers: Option<String>,
#[arg(long, value_name = "PATH", value_hint = ValueHint::FilePath)]
pub text_servers: Option<String>,
#[arg(long)]
pub servers_replace: bool,
#[arg(long)]
pub no_referral: bool,
}
#[derive(Debug, Clone, Default, Args)]
#[command(next_help_heading = "Output")]
pub(crate) struct OutputArgs {
#[arg(long)]
pub json: bool,
#[arg(short = 'a', long)]
pub available_only: bool,
#[arg(long)]
pub details: bool,
#[arg(long)]
pub responder: bool,
#[arg(long)]
pub dns: bool,
#[arg(long)]
pub where_to_buy: bool,
#[arg(long, conflicts_with_all = ["details", "responder", "dns", "where_to_buy"])]
pub full: bool,
#[arg(short, long, value_name = "DIR", value_hint = ValueHint::DirPath)]
pub out: Option<String>,
#[arg(long)]
pub save: bool,
#[arg(long)]
pub append: bool,
}
#[derive(Debug, Args)]
pub(crate) struct GlobalArgs {
#[arg(long, value_enum, value_name = "WHEN", default_value_t = ColorArg::Auto, global = true)]
pub color: ColorArg,
#[arg(long, value_name = "N", global = true, env = "RESERVE_WIDTH")]
pub width: Option<u16>,
#[arg(long, global = true, env = "RESERVE_NO_INPUT")]
pub no_input: bool,
#[arg(long, conflicts_with = "no_input", global = true)]
pub interactive: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub(crate) enum ColorArg {
Auto,
Always,
Never,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, ValueEnum)]
pub(crate) enum DepthArg {
#[default]
Any,
Second,
Third,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub(crate) enum SortFieldArg {
Name,
Popularity,
Length,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub(crate) enum SortOrderArg {
Asc,
Desc,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub(crate) enum SourceArg {
Auto,
Registry,
Text,
Dns,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub(crate) enum FamilyArg {
Industry,
Region,
Popularity,
Curated,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub(crate) enum ShellArg {
Bash,
Elvish,
Fish,
PowerShell,
Zsh,
}
#[cfg(test)]
mod tests {
use clap::CommandFactory as _;
use super::*;
#[test]
fn the_command_tree_carries_no_conflicting_definition() {
Cli::command().debug_assert();
}
}