Loading page…
Rust walkthroughs
Loading page…
Command-line argument parsing is essential for CLI tools. The clap crate (Command Line Argument Parser) provides a robust, ergonomic API for building feature-rich CLIs with automatic help generation, shell completions, and validation.
Clap offers multiple API styles:
We'll focus on the Derive API, which is the most idiomatic for typical applications.
# Cargo.toml
[dependencies]
clap = { version = "4", features = ["derive"] }use clap::{Parser, Subcommand, ValueEnum};
use std::path::PathBuf;
/// A fictional versioning CLI tool
#[derive(Parser, Debug)]
#[command(name = "mycli")]
#[command(author = "Your Name <you@example.com>")]
#[command(version = "1.0")]
#[command(about = "A CLI tool demonstrating clap features", long_about = None)]
struct Cli {
/// Turn debugging information on
#[arg(short, long, action = clap::ArgAction::Count)]
verbose: u8,
/// Configuration file path
#[arg(short, long, value_name = "FILE")]
config: Option<PathBuf>,
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand, Debug)]
enum Commands {
/// Add a file to the index
Add {
/// Files to add
#[arg(required = true)]
files: Vec<PathBuf>,
/// Force add ignored files
#[arg(short, long)]
force: bool,
},
/// Commit changes
Commit {
/// Commit message
#[arg(short, long)]
message: Option<String>,
/// Open editor for commit message
#[arg(long)]
edit: bool,
},
/// Push changes to remote
Push {
/// Remote name
#[arg(default_value = "origin")]
remote: String,
/// Branch name
branch: Option<String>,
},
/// Pull changes from remote
Pull {
/// Remote name
remote: Option<String>,
},
}
#[derive(Parser, Debug)]
struct SearchArgs {
/// Search pattern
pattern: String,
/// Search path
#[arg(default_value = ".")]
path: PathBuf,
/// Case insensitive search
#[arg(short, long)]
ignore_case: bool,
/// Number of results to show
#[arg(short = 'n', long = "limit", default_value = "10")]
max_results: usize,
}
fn main() {
let cli = Cli::parse();
// Handle verbosity
match cli.verbose {
0 => println!("Normal output"),
1 => println!("Verbose output"),
2 => println!("More verbose output"),
_ => println!("Maximum verbosity!"),
}
// Handle config file
if let Some(config_path) = cli.config {
println!("Using config file: {:?}", config_path);
}
// Handle subcommands
match cli.command {
Commands::Add { files, force } => {
println!("Adding files: {:?}, force: {}", files, force);
}
Commands::Commit { message, edit } => {
if edit {
println!("Opening editor...");
}
println!("Committing with message: {:?}", message);
}
Commands::Push { remote, branch } => {
println!("Pushing to {} (branch: {:?})", remote, branch);
}
Commands::Pull { remote } => {
println!("Pulling from {:?}", remote);
}
}
}use clap::{Parser, ValueEnum};
#[derive(Parser, Debug)]
struct FormatArgs {
/// Output format
#[arg(value_enum)]
format: OutputFormat,
/// Sort order
#[arg(short, long, value_enum, default_value = "asc")]
sort: SortOrder,
}
#[derive(Clone, Debug, ValueEnum)]
enum OutputFormat {
Json,
Yaml,
Toml,
Text,
}
#[derive(Clone, Debug, ValueEnum)]
enum SortOrder {
Asc,
Desc,
}
fn main() {
let args = FormatArgs::parse();
println!("Format: {:?}, Sort: {:?}", args.format, args.sort);
}use clap::Parser;
fn validate_port(port: &str) -> Result<u16, String> {
let port: u16 = port.parse().map_err(|_| "Invalid port number")?;
if port < 1024 {
return Err("Port must be >= 1024".to_string());
}
Ok(port)
}
#[derive(Parser, Debug)]
struct ServerArgs {
/// Port to listen on (must be >= 1024)
#[arg(short, long, value_parser = validate_port)]
port: u16,
/// Host address
#[arg(long, default_value = "127.0.0.1")]
host: String,
}
fn main() {
let args = ServerArgs::parse();
println!("Server listening on {}:{{}}", args.host, args.port);
}# Show help
mycli --help
mycli add --help
# Basic usage
mycli add src/main.rs src/lib.rs
mycli add --force src/hidden.rs
mycli commit -m "Initial commit"
mycli push origin main
# With flags
mycli -v add src/main.rs
mycli -vv commit -m "Commit message"
mycli --config ./mycli.toml push
# With enum values
mycli search "pattern" --format json --sort desc
mycli search "pattern" -i -n 20#[derive(Parser)] on a struct to define arguments; Parser::parse() reads from std::env::args()#[arg(short, long)] creates both short (-f) and long (--flag) versions#[command(subcommand)] enables subcommands with an enum marked with #[derive(Subcommand)]Option<T> for optional arguments; Vec<T> for multiple values; defaults with default_value#[derive(ValueEnum)] for arguments that accept a fixed set of valuesvalue_parser function that returns Result<T, String>-h (short help) and --help (long help) from your doc commentsaction = clap::ArgAction::Count pattern enables -v, -vv, -vvv style verbosity flags