-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs(Examples): adds subcommand examples
Closes #766
- Loading branch information
Showing
2 changed files
with
144 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
// Working with subcommands is simple. There are a few key points to remember when working with | ||
// subcommands in clap. First, SubCommands are really just Apps. This means they can have their own | ||
// settings, version, authors, args, and even their own subcommands. The next thing to remember is | ||
// that subcommands are set up in a tree like heirachy. | ||
// | ||
// An ASCII art depiction may help explain this better. Using a fictional version of git as the demo | ||
// subject. Imagine the following are all subcommands of git (note, the author is aware these aren't | ||
// actually all subcommands in the real git interface, but it makes explanation easier) | ||
// | ||
// Top Level App (git) TOP | ||
// | | ||
// ----------------------------------------- | ||
// / | \ \ | ||
// clone push add commit LEVEL 1 | ||
// | / \ / \ | | ||
// url origin remote ref name message LEVEL 2 | ||
// / /\ | ||
// path remote local LEVEL 3 | ||
// | ||
// Given the above fictional subcommand hierarchy, valid runtime uses would be (not an all inclusive | ||
// list): | ||
// | ||
// $ git clone url | ||
// $ git push origin path | ||
// $ git add ref local | ||
// $ git commit message | ||
// | ||
// Notice only one command per "level" may be used. You could not, for example, do: | ||
// | ||
// $ git clone url push origin path | ||
// | ||
// It's also important to know that subcommands each have their own set of matches and may have args | ||
// with the same name as other subcommands in a different part of the tree heirachy (i.e. the arg | ||
// names aren't in a flat namespace). | ||
// | ||
// In order to use subcommands in clap, you only need to know which subcommand you're at in your | ||
// tree, and which args are defined on that subcommand. | ||
// | ||
// Let's make a quick program to illustrate. We'll be using the same example as above but for | ||
// brevity sake we won't implement all of the subcommands, only a few. | ||
|
||
extern crate clap; | ||
|
||
use clap::{App, Arg, SubCommand, AppSettings}; | ||
|
||
fn main() { | ||
|
||
let matches = App::new("git") | ||
.about("A fictional versioning CLI") | ||
.version("1.0") | ||
.author("Me") | ||
.subcommand(SubCommand::with_name("clone") | ||
.about("clones repos") | ||
.arg(Arg::with_name("repo") | ||
.help("The repo to clone") | ||
.required(true))) | ||
.subcommand(SubCommand::with_name("push") | ||
.about("pushes things") | ||
.setting(AppSettings::SubcommandRequiredElseHelp) | ||
.subcommand(SubCommand::with_name("remote") // Subcommands can have thier own subcommands, | ||
// which in turn have their own subcommands | ||
.about("pushes remote things") | ||
.arg(Arg::with_name("repo") | ||
.required(true) | ||
.help("The remote repo to push things to"))) | ||
.subcommand(SubCommand::with_name("local") | ||
.about("pushes local things"))) | ||
.subcommand(SubCommand::with_name("add") | ||
.about("adds things") | ||
.author("Someone Else") // Subcommands can list different authors | ||
.version("v2.0 (I'm versioned differently") // or different version from their parents | ||
.setting(AppSettings::ArgRequiredElseHelp) // They can even have different settings | ||
.arg(Arg::with_name("stuff") | ||
.long("stuff") | ||
.help("Stuff to add") | ||
.takes_value(true) | ||
.multiple(true))) | ||
.get_matches(); | ||
|
||
// At this point, the matches we have point to git. Keep this in mind... | ||
|
||
// You can check if one of git's subcommands was used | ||
if matches.is_present("clone") { | ||
println!("'git clone' was run."); | ||
} | ||
|
||
// You can see which subcommand was used | ||
if let Some(subcommand) = matches.subcommand_name() { | ||
println!("'git {}' was used", subcommand); | ||
|
||
// It's important to note, this *only* check's git's DIRECT children, **NOT** it's | ||
// grandchildren, great grandchildren, etc. | ||
// | ||
// i.e. if the command `git push remove --stuff foo` was run, the above will only print out, | ||
// `git push` was used. We'd need to get push's matches to see futher into the tree | ||
} | ||
|
||
// An alternative to checking the name is matching on known names. Again notice that only the | ||
// direct children are matched here. | ||
match matches.subcommand_name() { | ||
Some("clone") => println!("'git clone' was used"), | ||
Some("push") => println!("'git push' was used"), | ||
Some("add") => println!("'git add' was used"), | ||
None => println!("No subcommand was used"), | ||
_ => unreachable!(), // Assuming you've listed all direct children above, this is unreachable | ||
} | ||
|
||
// You could get the independent subcommand matches, although this is less common | ||
if let Some(clone_matches) = matches.subcommand_matches("clone") { | ||
// Now we have a reference to clone's matches | ||
println!("Cloning repo: {}", clone_matches.value_of("repo").unwrap()); | ||
} | ||
|
||
// The most common way to handle subcommands is via a combined approach using | ||
// `ArgMatches::subcommand` which returns a tuple of both the name and matches | ||
match matches.subcommand() { | ||
("clone", Some(clone_matches)) =>{ | ||
// Now we have a reference to clone's matches | ||
println!("Cloning {}", clone_matches.value_of("repo").unwrap()); | ||
}, | ||
("push", Some(push_matches)) =>{ | ||
// Now we have a reference to push's matches | ||
match push_matches.subcommand() { | ||
("remote", Some(remote_matches)) =>{ | ||
// Now we have a reference to remote's matches | ||
println!("Pushing to {}", remote_matches.value_of("repo").unwrap()); | ||
}, | ||
("local", Some(local_matches)) =>{ | ||
// Now we have a reference to push's matches | ||
println!("'git push local' was used"); | ||
}, | ||
_ => unreachable!(), | ||
} | ||
}, | ||
("add", Some(add_matches)) =>{ | ||
// Now we have a reference to add's matches | ||
println!("Adding {}", add_matches.values_of("stuff").unwrap().collect::<Vec<_>>().join(", ")); | ||
}, | ||
("", None) => println!("No subcommand was used"), // If no subcommand was usd it'll match the tuple ("", None) | ||
_ => unreachable!(), // If all subcommands are defined above, anything else is unreachabe!() | ||
} | ||
|
||
// Continued program logic goes here... | ||
} |
File renamed without changes.