rust 52 lines · 10 steps

Building a CLI with clap's derive macros

clap turns annotated Rust structs and enums into a full command-line parser with subcommands, validation, and defaults.

Explained by highlit
1use std::path::PathBuf;
2 
3use clap::{Parser, Subcommand, ValueEnum};
4 
5#[derive(Parser)]
6#[command(name = "imgtool", version, about = "Batch image processor")]
7struct Cli {
8 #[arg(short, long, global = true, action = clap::ArgAction::Count)]
9 verbose: u8,
10 
11 #[arg(long, value_name = "FILE", global = true)]
12 config: Option<PathBuf>,
13 
14 #[command(subcommand)]
15 command: Command,
16}
17 
18#[derive(Subcommand)]
19enum Command {
20 Convert {
21 #[arg(required = true)]
22 inputs: Vec<PathBuf>,
23 
24 #[arg(short, long)]
25 output_dir: PathBuf,
26 
27 #[arg(short, long, value_enum, default_value_t = Format::Png)]
28 format: Format,
29 
30 #[arg(short, long, value_parser = clap::value_parser!(u8).range(1..=100), default_value_t = 85)]
31 quality: u8,
32 },
33 Resize {
34 input: PathBuf,
35 
36 #[arg(short = 'W', long)]
37 width: Option<u32>,
38 
39 #[arg(short = 'H', long)]
40 height: Option<u32>,
41 
42 #[arg(long, conflicts_with_all = ["width", "height"])]
43 scale: Option<f32>,
44 },
45}
46 
47#[derive(Copy, Clone, ValueEnum)]
48enum Format {
49 Png,
50 Jpeg,
51 Webp,
52}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Deriving Parser and Subcommand lets clap generate parsing, help, and validation from your type definitions.
  2. 2Attribute options like global, conflicts_with_all, and value_parser encode CLI rules declaratively instead of hand-written checks.
  3. 3Modeling optional flags as Option and choices as ValueEnum makes invalid states hard to represent.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Building a CLI with clap's derive macros — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code