diff --git a/examples/README.md b/examples/README.md index ca95b684..a2087dee 100644 --- a/examples/README.md +++ b/examples/README.md @@ -12,6 +12,7 @@ - Topics: - Subcommands - External subcommands + - Default subcommands - pacman-like interface: [builder](pacman.md) - Topics: - Flag subcommands diff --git a/examples/git-derive.md b/examples/git-derive.md index d33ce19b..ea507fc0 100644 --- a/examples/git-derive.md +++ b/examples/git-derive.md @@ -22,6 +22,7 @@ SUBCOMMANDS: clone Clones repos help Print this message or the help of the given subcommand(s) push pushes things + stash $ git-derive help git @@ -38,6 +39,7 @@ SUBCOMMANDS: clone Clones repos help Print this message or the help of the given subcommand(s) push pushes things + stash $ git-derive help add git-derive[EXE]-add @@ -75,6 +77,61 @@ Adding ["Cargo.toml", "Cargo.lock"] ``` +Default subcommand: +```console +$ git-derive stash -h +git-derive[EXE]-stash + +USAGE: + git-derive stash [OPTIONS] + git-derive stash + +OPTIONS: + -h, --help Print help information + -m, --message + +SUBCOMMANDS: + apply + help Print this message or the help of the given subcommand(s) + pop + push + +$ git-derive stash push -h +git-derive[EXE]-stash-push + +USAGE: + git-derive stash push [OPTIONS] + +OPTIONS: + -h, --help Print help information + -m, --message + +$ git-derive stash pop -h +git-derive[EXE]-stash-pop + +USAGE: + git-derive stash pop [STASH] + +ARGS: + + +OPTIONS: + -h, --help Print help information + +$ git-derive stash -m "Prototype" +Pushing StashPush { message: Some("Prototype") } + +$ git-derive stash pop +Popping None + +$ git-derive stash push -m "Prototype" +Pushing StashPush { message: Some("Prototype") } + +$ git-derive stash pop +Popping None + +``` + External subcommands: ```console $ git-derive custom-tool arg1 --foo bar diff --git a/examples/git-derive.rs b/examples/git-derive.rs index 28cc593e..7e44edb1 100644 --- a/examples/git-derive.rs +++ b/examples/git-derive.rs @@ -3,10 +3,10 @@ use std::ffi::OsString; use std::path::PathBuf; -use clap::{Parser, Subcommand}; +use clap::{Args, Parser, Subcommand}; /// A fictional versioning CLI -#[derive(Parser)] +#[derive(Debug, Parser)] #[clap(name = "git")] #[clap(about = "A fictional versioning CLI", long_about = None)] struct Cli { @@ -14,7 +14,7 @@ struct Cli { command: Commands, } -#[derive(Subcommand)] +#[derive(Debug, Subcommand)] enum Commands { /// Clones repos #[clap(arg_required_else_help = true)] @@ -35,14 +35,38 @@ enum Commands { #[clap(required = true, parse(from_os_str))] path: Vec, }, + Stash(Stash), #[clap(external_subcommand)] External(Vec), } +#[derive(Debug, Args)] +#[clap(args_conflicts_with_subcommands = true)] +struct Stash { + #[clap(subcommand)] + command: Option, + + #[clap(flatten)] + push: StashPush, +} + +#[derive(Debug, Subcommand)] +enum StashCommands { + Push(StashPush), + Pop { stash: Option }, + Apply { stash: Option }, +} + +#[derive(Debug, Args)] +struct StashPush { + #[clap(short, long)] + message: Option, +} + fn main() { let args = Cli::parse(); - match &args.command { + match args.command { Commands::Clone { remote } => { println!("Cloning {}", remote); } @@ -52,6 +76,20 @@ fn main() { Commands::Add { path } => { println!("Adding {:?}", path); } + Commands::Stash(stash) => { + let stash_cmd = stash.command.unwrap_or(StashCommands::Push(stash.push)); + match stash_cmd { + StashCommands::Push(push) => { + println!("Pushing {:?}", push); + } + StashCommands::Pop { stash } => { + println!("Popping {:?}", stash); + } + StashCommands::Apply { stash } => { + println!("Applying {:?}", stash); + } + } + } Commands::External(args) => { println!("Calling out to {:?} with {:?}", &args[0], &args[1..]); } diff --git a/examples/git.md b/examples/git.md index 64c2f941..e3cea460 100644 --- a/examples/git.md +++ b/examples/git.md @@ -20,6 +20,7 @@ SUBCOMMANDS: clone Clones repos help Print this message or the help of the given subcommand(s) push pushes things + stash $ git help git @@ -36,6 +37,7 @@ SUBCOMMANDS: clone Clones repos help Print this message or the help of the given subcommand(s) push pushes things + stash $ git help add git[EXE]-add @@ -73,6 +75,61 @@ Adding ["Cargo.toml", "Cargo.lock"] ``` +Default subcommand: +```console +$ git stash -h +git[EXE]-stash + +USAGE: + git stash [OPTIONS] + git stash + +OPTIONS: + -h, --help Print help information + -m, --message + +SUBCOMMANDS: + apply + help Print this message or the help of the given subcommand(s) + pop + push + +$ git stash push -h +git[EXE]-stash-push + +USAGE: + git stash push [OPTIONS] + +OPTIONS: + -h, --help Print help information + -m, --message + +$ git stash pop -h +git[EXE]-stash-pop + +USAGE: + git stash pop [STASH] + +ARGS: + + +OPTIONS: + -h, --help Print help information + +$ git stash -m "Prototype" +Pushing Some("Prototype") + +$ git stash pop +Popping None + +$ git stash push -m "Prototype" +Pushing Some("Prototype") + +$ git stash pop +Popping None + +``` + External subcommands: ```console $ git custom-tool arg1 --foo bar diff --git a/examples/git.rs b/examples/git.rs index 4bcd1954..1ced54a9 100644 --- a/examples/git.rs +++ b/examples/git.rs @@ -4,8 +4,8 @@ use std::path::PathBuf; use clap::{arg, Command}; -fn main() { - let matches = Command::new("git") +fn cli() -> Command<'static> { + Command::new("git") .about("A fictional versioning CLI") .subcommand_required(true) .arg_required_else_help(true) @@ -29,7 +29,22 @@ fn main() { .arg_required_else_help(true) .arg(arg!( ... "Stuff to add").allow_invalid_utf8(true)), ) - .get_matches(); + .subcommand( + Command::new("stash") + .args_conflicts_with_subcommands(true) + .args(push_args()) + .subcommand(Command::new("push").args(push_args())) + .subcommand(Command::new("pop").arg(arg!([STASH]))) + .subcommand(Command::new("apply").arg(arg!([STASH]))), + ) +} + +fn push_args() -> Vec> { + vec![arg!(-m --message ).required(false)] +} + +fn main() { + let matches = cli().get_matches(); match matches.subcommand() { Some(("clone", sub_matches)) => { @@ -52,6 +67,26 @@ fn main() { .collect::>(); println!("Adding {:?}", paths); } + Some(("stash", sub_matches)) => { + let stash_command = sub_matches.subcommand().unwrap_or(("push", sub_matches)); + match stash_command { + ("apply", sub_matches) => { + let stash = sub_matches.value_of("STASH"); + println!("Applying {:?}", stash); + } + ("pop", sub_matches) => { + let stash = sub_matches.value_of("STASH"); + println!("Popping {:?}", stash); + } + ("push", sub_matches) => { + let message = sub_matches.value_of("message"); + println!("Pushing {:?}", message); + } + (name, _) => { + unreachable!("Unsupported subcommand `{}`", name) + } + } + } Some((ext, sub_matches)) => { let args = sub_matches .values_of_os("")