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