1use clap::error::{Error, ErrorKind};
2use clap::{ArgMatches, Args as _, Command, FromArgMatches, Parser, Subcommand};
3
4#[derive(Parser, Debug)]
5struct AddArgs {
6    name: Vec<String>,
7}
8#[derive(Parser, Debug)]
9struct RemoveArgs {
10    #[arg(short, long)]
11    force: bool,
12    name: Vec<String>,
13}
14
15#[derive(Debug)]
16enum CliSub {
17    Add(AddArgs),
18    Remove(RemoveArgs),
19}
20
21impl FromArgMatches for CliSub {
22    fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> {
23        match matches.subcommand() {
24            Some(("add", args)) => Ok(Self::Add(AddArgs::from_arg_matches(args)?)),
25            Some(("remove", args)) => Ok(Self::Remove(RemoveArgs::from_arg_matches(args)?)),
26            Some((_, _)) => Err(Error::raw(
27                ErrorKind::InvalidSubcommand,
28                "Valid subcommands are `add` and `remove`",
29            )),
30            None => Err(Error::raw(
31                ErrorKind::MissingSubcommand,
32                "Valid subcommands are `add` and `remove`",
33            )),
34        }
35    }
36    fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
37        match matches.subcommand() {
38            Some(("add", args)) => *self = Self::Add(AddArgs::from_arg_matches(args)?),
39            Some(("remove", args)) => *self = Self::Remove(RemoveArgs::from_arg_matches(args)?),
40            Some((_, _)) => {
41                return Err(Error::raw(
42                    ErrorKind::InvalidSubcommand,
43                    "Valid subcommands are `add` and `remove`",
44                ))
45            }
46            None => (),
47        };
48        Ok(())
49    }
50}
51
52impl Subcommand for CliSub {
53    fn augment_subcommands(cmd: Command) -> Command {
54        cmd.subcommand(AddArgs::augment_args(Command::new("add")))
55            .subcommand(RemoveArgs::augment_args(Command::new("remove")))
56            .subcommand_required(true)
57    }
58    fn augment_subcommands_for_update(cmd: Command) -> Command {
59        cmd.subcommand(AddArgs::augment_args(Command::new("add")))
60            .subcommand(RemoveArgs::augment_args(Command::new("remove")))
61            .subcommand_required(true)
62    }
63    fn has_subcommand(name: &str) -> bool {
64        matches!(name, "add" | "remove")
65    }
66}
67
68#[derive(Parser, Debug)]
69struct Cli {
70    #[arg(short, long)]
71    top_level: bool,
72    #[command(subcommand)]
73    subcommand: CliSub,
74}
75
76fn main() {
77    let args = Cli::parse();
78    println!("{args:#?}");
79}
80