Hello i'm using clap to build a cli
What I want to achieve is simple:
I have 2 groups of args fruits
and vegetables
I have a subcommand create
to create a new fruit or vegetable
I could have 2 sepetate commands to create fruit and vegetables but I prefer to have only one command and pass an arg to create a fruit (--fruit) or a vegetable (--vegetable)
my_cli create --fruit // will create a fruit
my_cli create --vegetable // will create a vegetable
there are required args to create a fruit --weight --country there are required args to create a vegetable --type --destination
If I run my_cli create --fruit --type "root vegetable"
it should pop an error because --fruit will conflicts with all args from vegetable group, same for --vegetable with args from fruit group
There is my code
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
/// Apply command on fruit
#[arg(
short,
long,
global = true,
conflicts_with = "vegetable",
default_value = "true",
default_value_if("vegetable", "true", "false"),
display_order = 0
)]
pub fruit: bool,
/// Apply command on vegetable
#[arg(
short,
long,
global = true,
conflicts_with = "fruit",
default_value = "false",
default_value_if("fruit", "true", "false"),
display_order = 0
)]
pub vegetable: bool,
}
#[derive(Subcommand)]
pub enum Commands {
/// Create a new fruit or vegetable
Create(CreateArgs),
}
#[derive(Args, Debug)]
pub struct CreateArgs {
/// Type
#[arg(long, display_order = 1, group = "vegetable_group")]
pub type: Option<String>,
/// Destination
#[arg(long, display_order = 1, group = "vegetable_group")]
pub destination: Option<String>,
/// Weight
#[arg(long, display_order = 1, group = "fruit_group")]
pub weight: Option<String>,
/// Country
#[arg(long, display_order = 1, group = "fruit_group")]
pub country: Option<String>,
}
How to make a group of args conflicts with an other?
I could do something like this for all args but with a lot of args this is not relevant
/// Destination
#[arg(long, display_order = 1, group = "vegetable_group", conflicts_with_all(["weight", "country"])]
pub destination: Option<String>,
Clap subcommands names can contain dashes, so the solution is simple (if tricky):
use clap::{Parser, Subcommand};
#[derive(Parser)]
struct Cli {
#[command(subcommand)]
command: CreateCommand,
}
#[derive(Subcommand)]
enum CreateCommand {
Create {
#[command(subcommand)]
fruit: FruitCommands,
},
}
#[derive(Subcommand)]
enum FruitCommands {
#[command(name = "--fruit")]
Fruit {
#[arg(long)]
weight: u32,
#[arg(long)]
country: String,
},
#[command(name = "--vegetable")]
Vegetable {
#[arg(long)]
r#type: String,
#[arg(long)]
destination: String,
},
}