Skip to content

Commit

Permalink
Merge pull request #143 from kbknapp/issue-140
Browse files Browse the repository at this point in the history
Issue #140 , #141 , and #85
  • Loading branch information
kbknapp committed Jun 30, 2015
2 parents bf5fa2b + ff149a2 commit 853d62f
Show file tree
Hide file tree
Showing 13 changed files with 142 additions and 188 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ Command Line Argument Parser for Rust

It is a simple to use, efficient, and full featured library for parsing command line arguments and subcommands when writing console, or terminal applications.

## What's New

If you're already familiar with `clap` but just want to see some new highlights as of **1.0.0-beta**

* **Deprecated Functions Removed** - In an effort to start a 1.x all deprecated functions have been removed, see the deprecations sections below to update your code (very minimal)
* **Can fully override help** - This allows you fully override the auto-generated help if you so choose
* **Can wait for user input on error** - This is helpful mainly on Windows if a user mistakenly opens your application via double-click, or you'd like to provide a GUI shortcut to run your application

For full details see the [changelog](https://github.com/kbknapp/clap-rs/blob/master/CHANGELOG.md)

## About

`clap` is used to parse *and validate* the string of command line arguments provided by the user at runtime. You provide the list of valid possibilities, and `clap` handles the rest. This means you focus on your *applications* functionality, and less on the parsing and validating of arguments.
Expand Down
6 changes: 3 additions & 3 deletions clap-tests/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ fn main() {
.arg(Arg::from_usage("-f --flag... 'tests flags'")
.global(true))
.args(vec![
Arg::from_usage("[flag2] -F 'tests flags with exclusions'").mutually_excludes("flag").requires("option2"),
Arg::from_usage("--long-option-2 [option2] 'tests long options with exclusions'").mutually_excludes("option").requires("positional2"),
Arg::from_usage("[flag2] -F 'tests flags with exclusions'").conflicts_with("flag").requires("option2"),
Arg::from_usage("--long-option-2 [option2] 'tests long options with exclusions'").conflicts_with("option").requires("positional2"),
Arg::from_usage("[positional2] 'tests positionals with exclusions'"),
Arg::from_usage("-O --Option [option3] 'tests options with specific value sets'").possible_values(&opt3_vals),
Arg::from_usage("[positional3]... 'tests positionals with specific values'").possible_values(&pos3_vals),
Expand All @@ -29,7 +29,7 @@ fn main() {
Arg::from_usage("--minvals2 [minvals]... 'Tests 2 min vals'").min_values(2),
Arg::from_usage("--maxvals3 [maxvals]... 'Tests 3 max vals'").max_values(3)
])
.subcommand(SubCommand::new("subcmd")
.subcommand(SubCommand::with_name("subcmd")
.about("tests subcommands")
.version("0.1")
.author("Kevin K. <kbknapp@gmail.com>")
Expand Down
2 changes: 1 addition & 1 deletion examples/01a_QuickExample.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fn main() {
.args_from_usage("-c --config=[conf] 'Sets a custom config file'
[output] 'Sets an optional output file'
[debug]... -d 'Turn debugging information on'")
.subcommand(SubCommand::new("test")
.subcommand(SubCommand::with_name("test")
.about("does testing things")
.arg_from_usage("[list] -l 'lists test values'"))
.get_matches();
Expand Down
2 changes: 1 addition & 1 deletion examples/01b_QuickExample.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ fn main() {
.short("d")
.multiple(true)
.help("Turn debugging information on"))
.subcommand(SubCommand::new("test")
.subcommand(SubCommand::with_name("test")
.about("does testing things")
.arg(Arg::with_name("list")
.short("l")
Expand Down
2 changes: 1 addition & 1 deletion examples/05_FlagArgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ fn main() {
// also use this other 'config' arg too"
// Can also specifiy a list using
// requires_all(Vec<&str>)
.mutually_excludes("output") // Opposite of requires(), says "if the
.conflicts_with("output") // Opposite of requires(), says "if the
// user uses -a, they CANNOT use 'output'"
// also has a mutually_excludes_all(Vec<&str>)
)
Expand Down
2 changes: 1 addition & 1 deletion examples/06_PositionalArgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fn main() {
// also use this other 'config' arg too"
// Can also specifiy a list using
// requires_all(Vec<&str>)
.mutually_excludes("output") // Opposite of requires(), says "if the
.conflicts_with("output") // Opposite of requires(), says "if the
// user uses -a, they CANNOT use 'output'"
// also has a mutually_excludes_all(Vec<&str>)
.required(true) // By default this argument MUST be present
Expand Down
6 changes: 3 additions & 3 deletions examples/07_OptionArgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ fn main() {
// also use this other 'config' arg too"
// Can also specifiy a list using
// requires_all(Vec<&str>)
.mutually_excludes("output") // Opposite of requires(), says "if the
.conflicts_with("output") // Opposite of requires(), says "if the
// user uses -a, they CANNOT use 'output'"
// also has a mutually_excludes_all(Vec<&str>)
// also has a conflicts_with_all(Vec<&str>)
)
// NOTE: In order to compile this example, comment out mutually_excludes()
// NOTE: In order to compile this example, comment out conflicts_with()
// and requires() because we have not defined an "output" or "config"
// argument.
.get_matches();
Expand Down
2 changes: 1 addition & 1 deletion examples/08_SubCommands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fn main() {
// In the following example assume we wanted an application which
// supported an "add" subcommand, this "add" subcommand also took
// one positional argument of a file to add:
.subcommand(SubCommand::new("add") // The name we call argument with
.subcommand(SubCommand::with_name("add") // The name we call argument with
.about("Adds files to myapp") // The message displayed in "myapp -h"
// or "myapp help"
.version("0.1") // Subcommands can have independent version
Expand Down
104 changes: 82 additions & 22 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::collections::HashSet;
use std::collections::HashMap;
use std::collections::VecDeque;
use std::env;
use std::io::{self, BufRead};
use std::path::Path;
use std::vec::IntoIter;
use std::process;
Expand Down Expand Up @@ -120,7 +121,9 @@ pub struct App<'a, 'v, 'ab, 'u, 'h, 'ar> {
groups: HashMap<&'ar str, ArgGroup<'ar, 'ar>>,
global_args: Vec<Arg<'ar, 'ar, 'ar, 'ar, 'ar, 'ar>>,
no_sc_error: bool,
wait_on_error: bool,
help_on_no_args: bool,
help_str: Option<&'u str>,
help_on_no_sc: bool
}

Expand Down Expand Up @@ -166,6 +169,8 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
subcmds_neg_reqs: false,
global_args: vec![],
no_sc_error: false,
help_str: None,
wait_on_error: false,
help_on_no_args: false,
help_on_no_sc: false
}
Expand Down Expand Up @@ -259,25 +264,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
self
}

/// **WARNING:** This method is deprecated. Use `.subcommand_required(true)` instead.
///
/// Allows specifying that if no subcommand is present at runtime, error and exit gracefully
///
/// **NOTE:** This defaults to false (subcommands do *not* need to be present)
///
/// # Example
///
/// ```no_run
/// # use clap::App;
/// App::new("myprog")
/// .subcommands_negate_reqs(true)
/// # ;
/// ```
pub fn error_on_no_subcommand(mut self, n: bool) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> {
self.no_sc_error = n;
self
}

/// Allows specifying that if no subcommand is present at runtime, error and exit gracefully
///
/// **NOTE:** This defaults to false (subcommands do *not* need to be present)
Expand Down Expand Up @@ -337,6 +323,45 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
self
}

/// Sets a custom help message and overrides the auto-generated one. This should only be used
/// when the auto-gererated message does not suffice.
///
/// This will be displayed to the user when they use the defailt `--help` or `-h`
///
/// **NOTE:** This replaces the **entire** help message, so nothing will be auto-gererated.
///
/// **NOTE:** This **only** replaces the help message for the current command, meaning if you
/// are using subcommands, those help messages will still be auto-gererated unless you
/// specify a `.help()` for them as well.
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// App::new("myapp")
/// .help("myapp v1.0\n\
/// Does awesome things\n\
/// (C) me@mail.com\n\n\
///
/// USAGE: myapp <opts> <comamnd>\n\n\
///
/// Options:\n\
/// -h, --helpe Dispay this message\n\
/// -V, --version Display version info\n\
/// -s <stuff> Do something with stuff\n\
/// -v Be verbose\n\n\
///
/// Commmands:\n\
/// help Prints this message\n\
/// work Do some work")
/// # ;
/// ```
pub fn help(mut self, h: &'u str) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> {
self.help_str = Some(h);
self
}

/// Sets the short version of the `help` argument without the preceding `-`.
///
/// By default `clap` automatically assigns `h`, but this can be overridden
Expand Down Expand Up @@ -402,6 +427,31 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
self
}

/// Will display a message "Press [ENTER]/[RETURN] to continue..." and wait user before
/// exiting
///
/// This is most useful when writing an application which is run from a GUI shortcut, or on
/// Windows where a user tries to open the binary by double-clicking instead of using the
/// command line (i.e. set `.arg_required_else_help(true)` and `.wait_on_error(true)` to
/// display the help in such a case).
///
/// **NOTE:** This setting is **not** recursive with subcommands, meaning if you wish this
/// behavior for all subcommands, you must set this on each command (needing this is extremely
/// rare)
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// App::new("myprog")
/// .arg_required_else_help(true)
/// # ;
/// ```
pub fn wait_on_error(mut self, w: bool) -> App<'a, 'v, 'ab, 'u, 'h, 'ar> {
self.wait_on_error = w;
self
}

/// Specifies that the help text sould be displayed (and then exit gracefully), if no
/// subcommands are present at runtime (i.e. an empty run such as, `$ myprog`.
///
Expand Down Expand Up @@ -877,7 +927,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
/// ```no_run
/// # use clap::{App, Arg, SubCommand};
/// # App::new("myprog")
/// .subcommand(SubCommand::new("config")
/// .subcommand(SubCommand::with_name("config")
/// .about("Controls configuration features")
/// .arg_from_usage("<config> 'Required configuration file to use'"))
/// // Additional subcommand configuration goes here, such as other arguments...
Expand All @@ -899,9 +949,9 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
/// # use clap::{App, Arg, SubCommand};
/// # App::new("myprog")
/// .subcommands( vec![
/// SubCommand::new("config").about("Controls configuration functionality")
/// SubCommand::with_name("config").about("Controls configuration functionality")
/// .arg(Arg::with_name("config_file").index(1)),
/// SubCommand::new("debug").about("Controls debug functionality")])
/// SubCommand::with_name("debug").about("Controls debug functionality")])
/// # ;
/// ```
pub fn subcommands(mut self, subcmds: Vec<App<'a, 'v, 'ab, 'u, 'h, 'ar>>)
Expand Down Expand Up @@ -1161,6 +1211,10 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{

// Prints the full help message to the user
fn print_help(&self) {
if let Some(h) = self.help_str {
println!("{}", h);
return
}
self.print_version(false);
let flags = !self.flags.is_empty();
let pos = !self.positionals_idx.is_empty();
Expand Down Expand Up @@ -1357,6 +1411,12 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
// Exits with a status code passed to the OS
// This is legacy from before std::process::exit() and may be removed evenutally
fn exit(&self, status: i32) {
if self.wait_on_error {
println!("\nPress [ENTER] / [RETURN] to continue...");
let mut s = String::new();
let i = io::stdin();
i.lock().read_line(&mut s).unwrap();
}
process::exit(status);
}

Expand Down
Loading

0 comments on commit 853d62f

Please sign in to comment.