Working Code
The clap crate provides derive macros that let you define even complex CLIs declaratively:
use clap::{Parser, Subcommand};
#[derive(Parser, Debug)]
#[command(name = "todo", version, about = "A small, fast CLI TODO app", long_about = None)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand, Debug)]
enum Commands {
/// Add a new task
Add {
#[arg(value_name = "TEXT")]
text: String,
},
/// Mark a task as done
Done {
#[arg(value_name = "ID")]
id: u32,
},
/// List tasks
List {
#[arg(long, help = "Include completed tasks")]
all: bool,
},
}
fn main() {
let cli = Cli::parse();
match cli.command {
Commands::Add { text } => println!("Adding: {text}"),
Commands::Done { id } => println!("Marking done: #{id}"),
Commands::List { all } => println!("Listing (all={all})"),
}
}
Cli::parse()automatically readsstd::env::args(), validates them, and fills the struct.- Adding
#[command(version)]gives you a--versionflag; filling inaboutadds a description to--help.
Help and Error Messages
$ todo --help
Usage: todo <COMMAND>
Commands:
add Add a new task
done Mark a task as done
list List tasks
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help (see more with '--help')
-V, --version Print version
Invalid input produces a helpful message and a non-zero exit code:
$ todo add
? failed to parse argument: TEXT is required but missing
Try It Yourself
- Test that
todo list --allsetsallto true and omitting it sets it to false. - Add another subcommand that mixes long and short options, like
todo done --id 3. - Use
clap::Parser::command().long_about("...")to add a detailed README-level help description.
- Environment variables — Use
#[arg(env = "TODO_PATH")]so the storage path can also be set via an environment variable. - Exit codes — Add a pattern that prints a message with
eprintln!and exits withstd::process::exit(1)on abnormal conditions. - Config subcommand — Design a
todo config set --key theme --value darksubcommand and connect it to serde-based config file storage.