use clap::{CommandFactory, Parser, Subcommand, ValueEnum};
use clap_complete::{generate, Shell};
use clap_complete_nushell::Nushell;
#[derive(Parser)]
#[command(name = "cargo-fresh")]
#[command(about = "Check and update globally installed Cargo packages")]
#[command(version)]
pub struct Cli {
#[arg(short, long)]
pub verbose: bool,
#[arg(short, long)]
pub updates_only: bool,
#[arg(long)]
pub no_interactive: bool,
#[arg(long)]
pub include_prerelease: bool,
#[arg(long)]
pub batch: bool,
#[arg(long)]
pub filter: Option<String>,
#[arg(long, action = clap::ArgAction::Append)]
pub exclude: Vec<String>,
#[arg(long)]
pub dry_run: bool,
#[arg(long, value_name = "URL")]
pub registry_url: Option<String>,
#[arg(long, value_enum, default_value_t = OutputFormat::Human, value_name = "FORMAT")]
pub format: OutputFormat,
#[arg(long)]
pub no_cargo_search_fallback: bool,
#[arg(long)]
pub install_binstall: bool,
#[arg(long)]
pub check_binstall: bool,
#[command(subcommand)]
pub command: Option<Commands>,
}
#[derive(Subcommand)]
pub enum Commands {
Completion {
#[arg(value_enum)]
shell: ShellType,
#[arg(long)]
cargo_fresh: bool,
},
Man,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
pub enum OutputFormat {
Human,
Json,
}
#[derive(Clone, ValueEnum)]
pub enum ShellType {
Bash,
Zsh,
Fish,
Powershell,
Elvish,
Nushell,
}
impl Cli {
fn generate_completion_for_shell(shell: ShellType, cmd: &mut clap::Command, name: &str) {
let shell_type = match shell {
ShellType::Bash => Shell::Bash,
ShellType::Zsh => Shell::Zsh,
ShellType::Fish => Shell::Fish,
ShellType::Powershell => Shell::PowerShell,
ShellType::Elvish => Shell::Elvish,
ShellType::Nushell => return generate(Nushell, cmd, name, &mut std::io::stdout()),
};
generate(shell_type, cmd, name, &mut std::io::stdout());
}
pub fn generate_completion(shell: ShellType) {
let mut cmd = Self::command();
Self::generate_completion_for_shell(shell, &mut cmd, "cargo-fresh");
}
pub fn generate_cargo_fresh_completion(shell: ShellType) {
let fresh = Self::command()
.name("fresh")
.about("Check and update globally installed Cargo packages");
let mut cargo_cmd = clap::Command::new("cargo")
.about("Rust's package manager")
.subcommand(fresh);
Self::generate_completion_for_shell(shell, &mut cargo_cmd, "cargo");
}
pub fn generate_man() -> std::io::Result<()> {
let cmd = Self::command();
let man = clap_mangen::Man::new(cmd);
man.render(&mut std::io::stdout())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cli_command_builds() {
Cli::command().debug_assert();
}
#[test]
fn cli_parses_basic_flags() {
let cli = Cli::try_parse_from([
"cargo-fresh",
"--verbose",
"--batch",
"--filter",
"cargo-*",
"--exclude",
"foo",
"--exclude",
"bar",
])
.expect("parse");
assert!(cli.verbose);
assert!(cli.batch);
assert_eq!(cli.filter.as_deref(), Some("cargo-*"));
assert_eq!(cli.exclude, vec!["foo".to_string(), "bar".to_string()]);
}
#[test]
fn cli_completion_subcommand() {
let cli =
Cli::try_parse_from(["cargo-fresh", "completion", "bash", "--cargo-fresh"]).expect("parse");
match cli.command {
Some(Commands::Completion { cargo_fresh, .. }) => assert!(cargo_fresh),
_ => panic!("expected completion subcommand"),
}
}
}