Command Line Argument Parser for Rust
Dual-licensed under Apache 2.0 or MIT.
Create your command-line parser, with all of the bells and whistles, declaratively or procedurally.
For more details, see:
A full featured, fast Command Line Argument Parser for Rust
Home Page: docs.rs/clap
License: Apache License 2.0
Command Line Argument Parser for Rust
Dual-licensed under Apache 2.0 or MIT.
Create your command-line parser, with all of the bells and whistles, declaratively or procedurally.
For more details, see:
The order is displayed correctly everywhere except "suggested usage" (i.e. when a typo is made and the usage string is re-generated for current usage). In this string it appears in alphabetical order which can be confusing.
Working on an app that should be able to operate on either STDIN or a file, I was trying to use -
as the file name to indicate STDIN (as is the convention used in the app I'm porting, and elsewhere), but that causes an index out of bounds panic.
% ./target/debug/signing-participants -
thread '<main>' panicked at 'index out of bounds: the len is 0 but the index is 0', /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/libcore/str/mod.rs:1685
So, I thought I'd try the common --
to indicate "only positional arguments follow", but that fails as well but much more gracefully.
% ./target/debug/signing-participants -- -
Argument -- isn't valid
USAGE:
signing-participants [FLAGS] [OPTIONS] <INPUT>
For more information try --help
In v0.8.0, text coloring was introduced which I generally am a great fan of. Having it in usage strings seems like something I definitely want to have.
The first implementation of it applies it to the entire output of the usage string, which doesn't help one to focus on what's actually the problem.
Therefore I would recommend to use color (and/or bold text) only to highlight portions of it, like the required parameters that were missing. This could also be used to highlight suggestions in a friendly color.
Of course, a disclaimer shall be placed here that this is a somewhat cosmetical issue which is to some extend subjective. This issue is nothing more than a suggestion.
As a side-note, thanks for implementing everything with dependencies in a feature-gated fashion to allow an opt-out, which is what I chose as an intermediate solution in my case. Generally, that's a great practice that I will adopt were adequate as well.
I need to support an optional argument like the one noted in the subject, but was unable to achieve this. Apparently there is no support for multiple arguments of a single flag. docopt
can do this though, and I believe its a useful feature to have.
A workaround I tried was to use the Arg::requires()
method to enforce flags to appear together. However, a doubly-linked requires definition doesn't seem to work. For example, in the following excerpt I want -u
to appear with -f
and vice-versa.
โ google-apis-rs git:(clap) โ make groupsmigration1-cli-cargo ARGS="run -- archive insert groupid -h"
cd gen/groupsmigration1-cli && cargo run -- archive insert groupid -h
Running `target/debug/groupsmigration1 archive insert groupid -h`
groupsmigration1-archive-insert
Inserts a new mail into the archive of the Google group.
USAGE:
groupsmigration1 archive insert [FLAGS] [OPTIONS] <group-id>
FLAGS:
-h, --help Prints help information
-v, --version Prints version information
OPTIONS:
-f <file> The file to upload
-u <mode> Specify which file to upload [values: resumable simple]
-o <out> Specify the file into which to write the programs output
-p <v>... Set various fields of the request structure
POSITIONAL ARGUMENTS:
group-id The group ID
In code, this looks like this (example is manufactured, and not actual code, might not compile)
let mut uarg = Arg::with_name("u").required(false).takes_value(true);
uarg = uarg.requires("file");
farg = Arg::with_name("file")
.short("f")
.required(false)
.requires("u")
.takes_value(true));
Maybe I am doing it wrong though. The code above results in runtime errors like this:
โ google-apis-rs git:(clap) โ make groupsmigration1-cli-cargo ARGS="run -- archive insert groupid -u simple -f file"
cd gen/groupsmigration1-cli && cargo run -- archive insert groupid -u simple -f file
Running `target/debug/groupsmigration1 archive insert groupid -u simple -f file`
One or more required arguments were not supplied
USAGE:
groupsmigration1 archive insert [FLAGS] [OPTIONS] -f <file> <group-id>
For more information try --help
In any case, it would be very helpful to print which dependencies are actually missing :).
Thanks for your help !
It's here: https://github.com/kbknapp/clap-rs/blob/master/src/args/arg.rs#L332
I am pretty new to the whole github thing--corporate work will do that to you!--so, if I'm doing this wrong, lemme know... I submitted a PR that fixes this, but, honestly, it's mostly just a proof of concept. There's no telling what errors it causes because I don't know what functions that assertion performed.
That said, it passes all the tests. :P
This will be implemented via feature
as it will incur an additional dep.
This is for spelling mistakes, for example if we had an application with --file <file>
option and we ran
$ myprog --flie words.txt
--flie isn't a valid argument for myprog
Did you mean --file?
USAGE:
myprog [FLAGS] [OPTIONS]
For more information try --help
Initial implementation will be longs and subcommnds only, but should be able to add values from .possible_values()
later.
Currently only one sub-command may be used per match. For example:
Assume myapp
has two subcommands one
and two
, and each of those has subone
and subtwo
respectively.
myapp
|-one
| |-subone
|-two
|-subtwo
Meaning currently you can only run the following permutations
$ myapp one
$ myapp one subone
$ myapp two
$ myapp two subtwo
This issue proposes using a ..
syntax to mean "Back up one level" meaning you could then add these additional permutations to valid uses
$ myapp one ..two
$ myapp two ..one
$ myapp two subtwo ..one
$ myapp two subtwo ..one subone
$ myapp two ..one subone
$ myapp one ..two subtwo
$ myapp one subone ..two
$ myapp one subone ..two subtwo
This could also lead to ....
meaning up three levels or any multiple of ..
adding an additional level.
This will be labeled maybe
because I'm unsure of why would need something like this other than combining multiple invocations of a program into a single call... I'll think on this one for a bit and see how it turns out.
To allow something like
Arg::from_usage("[myopt] -o --opt <mode> <file> 'some help text'")
This would parse as
Name: myopt
Short: o
Long: opt
Values: <mode> <file>
Multiple: false
Required: false
Number of Values: 2
Some items to be determined are how to parse when an explicit name does not precede the values (Required true
, or false
, use the first value for determining? Use Long as name? etc.)
So, I went to do a bit more dynamic generation (this time with the help text of one of my app's arguments), and ran into the same static lifetime issue as #28.
I can provide a more concrete example if you'd like, but I wanted to file this before I forgot.
6669f0a introduces shorthand parsing for multiple values. However, this causes subcommands to be parsed as flag-values, thus making it impossible to properly call the program.
For example, calls like this ...
groupsmigration1 --scope foobar archive insert group -u simple README.md
... now fail as -u
is not a valid argument. This is as --scope <url>...
has eaten all arguments until the first -flag
, then -u
is interpreted as top-level flag which it is not. Usually archive
and insert
are subcommands, and group
as well as -u
are required flags of insert
.
I have made a quick-fix (notes) which might not be ready for a PR, and I am unsure whether I am fit to fix this properly. Clearly we would want to add a few tests to assure this truly works and to protect from regression.
Initially support Int
, and Float
. Implementation should allow additions down the road as well, based on usage, maybe a File
or Directory
too...
Such as "-c some -c other -c again"
Need to add better and more comprehensive examples of the various options and how to use them.
If you misspell --help you do not get a suggestion.
See #44
When specifying an argument like this:
Arg::with_name("url")
.long("scope")
.help("Specify the authentication a method should be executed in. Each scope requires the user to grant this application permission to use it.If unset, it defaults to the shortest scope url for a particular method.")
.multiple(true)
.takes_value(true))
The auto-generated grammar shows up like this --scope <url>...
:
groupsmigration1 0.2.0
Sebastian Thiel <[email protected]>
Groups Migration Api.
USAGE:
groupsmigration1 [FLAGS] [OPTIONS] [SUBCOMMANDS]
FLAGS:
--debug Output all server communication to standard error. `tx` and `rx` are placed into the same stream.
--debug-auth Output all communication related to authentication to standard error. `tx` and `rx` are placed into the same stream.
-h, --help Prints help information
-v, --version Prints version information
OPTIONS:
--config-dir <folder> A directory into which we will store our persistent data. Defaults to a user-writable directory that we will create during the first invocation.[default: ~/.google-service-cli
--scopes <url>... Specify the authentication a method should be executed in. Each scope requires the user to grant this application permission to use it.If unset, it defaults to the shortest scope url for a particular method.
SUBCOMMANDS:
archive
help Prints this message
All documentation details can be found at http://byron.github.io/google-apis-rs/google_groupsmigration1_cli
This grammar was used similarly by docopt
, but meant you could call it like program --scope url1 url2
. However, with clap
it only works if the flag is repeated: program --scope url1 --scope url2
which should be resulting in a different grammar, more along the lines of [--scope <url>]...
.
I believe this inconsistency should be reviewed, either docopt has an issue there, or clap :).
In any case, it would be great if the expected number of arguments could be +
(one or more) as I also have the case where I specify -r <value>...
, which previously allowed me to make calls like -r v1 v2 v3 v4
, which is very convenient. With clap
, I will now have to write -r v1 -r v2 -r v3 -r v4
, resulting in much more noise.
This one might be related to #88, which requests a fixed amount of arguments. When thinking about python's argparse
module, I remember that they have the notion of num_args
, which is either +
, *
or an explicit number. Implementing it this way would probably be a breaking change as takes_value(true|false)
would be more like takes_value(Values::ZeroOrMore|Values::OneOrMore|Values::Exactly(5)|Values::None)
.
I'm working on a command that allows a user to specify an arbitrary number of files/directories on the command line (Ex: dupe-finder /path/to/dir1 /path/to/dir2 /path/to/dir3
). I know I could do this currently, if I changed the form to use an option that allowed multiple values (dupe-finder -d /path/to/dir1 -d /path/to/dir2 -d /path/to/dir3
), but it would be handy to be able to have a positional argument that captured any positional arguments at & after its index into a vector.
Currently, if an argument is "required by" a "required by default" argument it will not be shown in the usage string.
i.e. If I set up two positional arguments "input" and "output" mark only input as required(true)
, but specify requires("output")
on the input argument, "output" will not be listed in the usage string which can be confusing to users:
$ myprog infile.txt
One or more required arguments weren't specified
USAGE:
myprog [FLAGS] <INPUT>
[...]
It SHOULD display:
USAGE:
myprog [FLAGS] <INPUT> <OUTPUT>
With a program exhibiting the following grammar ...
$ groupsmigration1 archive insert --help`
groupsmigration1-archive-insert
Inserts a new mail into the archive of the Google group.
USAGE:
groupsmigration1 archive insert <group-id> [FLAGS] [OPTIONS] [ -u <mode> <file> ]
FLAGS:
-h, --help Prints help information
-v, --version Prints version information
OPTIONS:
-m <mime> The file's mime time, like 'application/octet-stream'
-u <mode> <file> Specify the upload protocol (simple|resumable) and the file to upload
-o <out> Specify the file into which to write the programs output
-p <v>... Set various fields of the request structure
POSITIONAL ARGUMENTS:
group-id The group ID
... I would expect a partial invocation like groupsmigration1 archive insert
to yield a usage more along the lines of ...
One or more required arguments were not supplied: <group-id>, '-u <mode> <file>'
USAGE:
groupsmigration1 archive insert <group-id> -u <mode> <file>
For more information try --help
... but what you get is just as follows:
One or more required arguments were not supplied
USAGE:
groupsmigration1 archive insert
For more information try --help
Another example for missing required parameters is groupsmigration1 archive insert -u simple README.md
where <group-id>
is missing. However, this is not actually said in the resulting usage text:
$ groupsmigration1 archive insert -u simple README.md
One or more required arguments were not supplied
USAGE:
groupsmigration1 archive insert [ -u <mode> <file> ]
For more information try --help
What I would expect here is something like this:
One or more required arguments were not supplied: <group-id>
USAGE:
groupsmigration1 archive insert <group-id> -u simple README.md
For more information try --help
In a call like groupsmigration1 archive insert group
one will see a usage string like this:
One or more required arguments were not supplied
USAGE:
groupsmigration1 archive insert <group-id>
For more information try --help
and I think think it would be much better to get something like that:
One or more required arguments were not supplied: -u <mode> <file>
USAGE:
groupsmigration1 archive insert group -u <mode> <file>
For more information try --help
Once the usage is improved, clap
will finally be top-of-the-line when it comes to usability I think, and I really want it to be there :).
Thanks for taking care.
Allow slices in the _all(&[&str])
methods instead of a _all(Vec<&str>)
to not require an extra allocation.
Usage strings, if possible should be re-generated upon error for the current usage case. For example if you have a non-required by default argument which requires another argument, and the user fails to supply the third argument (which is required by proxy), the usage string is generic - yet the error message says a required argument is missing...which argument?
let m = App::new("app")
.arg(Arg::from_usage("--reqs").requires("input"))
.arg_from_usage("[input] 'some input'")
.get_matches();
Run with app --reqs
and the usage does not identify [input]
as a requirement, yet states a generic "required argument missing"
Now this does happen in certain instances, but I want to implement it in all instances.
Windows 7 64 bit
Rust 1.0.0-beta 64 bit (9854143cb)
clap 0.5.11
Invoking --help many times results in randomly ordered flags
I.e.
parent_group: "arg1", "arg2", "arg3", "group2"
group2: "arg4", "arg5"
If parent_group
needed to be displayed in the usage it would only show arg4, arg5
not arg1, arg2, arg3, arg4, arg5
Adds a feature
and an additional dep, which is not included by default.
To be released this should support the following methods of App
, Arg
, and ArgGroup
App::new
(i.e. setting the name)App::version
App::author
App::bin_name
App::about
App::after_help
App::usage
App::help
App::help_short
App::version_short
App::setting(s)
App::arg(s)
App::arg_group(s)
App::subcommand(s)
The following will not be implemented, yet.
App::arg(s)_from_usage
App::setting(s)
Arg::with_name
Arg::short
Arg::long
Arg::help
Arg::required
Arg::takes_value
Arg::index
Arg::multiple
Arg::global
Arg::empty_values
Arg::group
Arg::number_of_values
Arg::max_values
Arg::min_values
Arg::value_name
Arg::value_names
Arg::conflicts_with
Arg::requires
Arg::mutually_overrides_with
Arg::possible_values
The following will not be implemented, yet.
Arg::validator
Arg::*_all
(These because the functionality is implemented in the single method)Arg::from_usage
ArgGroup::with_name
(i.e. setting the name)ArgGroup::add
ArgGroup::required
ArgGroup::requires
ArgGroup::conflicts_with
The following will not be implemented, yet.
ArgGroup::*_all
(These because the functionality is implemented in the single method)In trying to get the version string to automatically populate based on the version I specify in my Cargo.toml
using something like:
...
let version = format!("{}.{}.{}{}",
env!("CARGO_PKG_VERSION_MAJOR"),
env!("CARGO_PKG_VERSION_MINOR"),
env!("CARGO_PKG_VERSION_PATCH"),
option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""));
let matches = App::new("signing-participants")
.version(&version[..])
...
However, this fails with:
% cargo build
Compiling signing-participants v0.0.1 (file:///Users/jacobhelwig/btsync/projects/signing-participants)
src/main.rs:27:19: 27:26 error: `version` does not live long enough
src/main.rs:27 .version(&version[..])
^~~~~~~
note: reference must be valid for the static lifetime...
src/main.rs:24:78: 93:2 note: ...but borrowed value is only valid for the block suffix following statement 1 at 24:77
src/main.rs:24 option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""));
src/main.rs:25
src/main.rs:26 let matches = App::new("signing-participants")
src/main.rs:27 .version(&version[..])
src/main.rs:28 .author("Jacob Helwig <[email protected]")
src/main.rs:29 .about("Generate a list for key-signing parties")
...
error: aborting due to previous error
Could not compile `signing-participants`.
To learn more, run the command again with --verbose.
I can get it to work if I don't care about the prerelease marker, and switch to concat!
(haven't been able to get concat!
to play nicely with option_env!
):
let version = concat!(env!("CARGO_PKG_VERSION_MAJOR"), ".",
env!("CARGO_PKG_VERSION_MINOR"), ".",
env!("CARGO_PKG_VERSION_PATCH"));
let matches = App::new("signing-participants")
.version(&version)
% cargo run -- --version
Compiling signing-participants v0.0.1 (file:///Users/jacobhelwig/btsync/projects/signing-participants)
Running `target/debug/signing-participants --version`
signing-participants 0.0.1
Sticking with format!
so I can use option_env!
is really not nice (as it involves unsafe code provided by dougxxx in the #rust IRC channel):
#![feature(collections)]
use std::mem::forget;
use std::mem::transmute;
unsafe fn as_static(v:&str) -> &'static str {
let tmp = String::from_str(v);
let boxed = Box::new(tmp);
let rtn: *const str = &**boxed as *const str;
forget(boxed);
return transmute(rtn);
}
fn awkward_function(v:&'static str) {
println!("{}", v);
}
fn main() {
let foo = String::from_str("Hello World");
unsafe { awkward_function(as_static(&*foo)); }
}
Is there a way the elements of the App struct could be changed to not require static lifetimes on its elements? I haven't looked at what the implications of this would be with the rest of the code, but allowing the format!
trick I initially tried for defining the version seems like reasonable usage of the library.
Even though this issue is not due to a bug in clap
, I thought I might post it here for your information only.
For more information, please have a look at the respective question on stackoverflow.
Currently creating simple arguments (those without relational rules) is just as verbose as more complex configurations. Adding something like a Arg::from_usage()
would greatly simplify building simple arguments.
Example:
Arg::from_usage("[name] -f --flag 'a flag used for something'");
// Or a required option that allows multiple occurrences
Arg::from_usage("--some-opt <name>... 'An option that takes multiple values and is required'");
Currently if an argument is mutually excluded by another argument and appears before the argument that declared the exclusion, the error message only states "a required argument wasn't supplied" but it should state that the specific argument is excluded by another (which it correctly does when the excluded argument appears after the one declaring the exclusion).
Add something like a .possible_values(Vec<&str>)
to Arg which denotes all the possible values for an option or positional argument, and at runtime ensures one of those values was used, or fails with a usage string.
This is a slightly breaking change - not enough to warrant a label.
Currently, using named values -f <file> <mode>
requires you to set multiple(true)
...but this isn't correct logic. By this token, someone could legally do:
$ myprog -f some.txt fast -f other.txt slow
This may, or may not, be what the developer wanted. Setting multiple(true)
shouldn't be a requirement for named values...only for unnamed multiple values. This allows the developer to decide which style of argument he wants, multiple allowances, or multiple values.
While creating #5 I've noticed that you use tabs. https://github.com/rust-lang/rust-guidelines/blob/master/style/whitespace.md suggests that this is discouraged. Would you consider switching to that guideline?
Splitting from #80 to track separately. Same method though, via a feature
due to additional toml-rs
dep.
let m = App::new("app").arg(Arg::from_usage("--reqs"))
.get_matches();
Drops the s
from --reqs
Currently it enforces the usage of Vec<&str>
, which makes it harder to use for people who prefer different means of passing this information. They could have a statically allocated array for instance, which contains enumerations, which in turn implement AsRef<str>
to allow a light conversion.
I suggest to have a look at this method's signature which uses an iterator over items that convert into a &str
, allowing all sorts of inputs. Internally, you can still easily create the Vec
you require by using Iterator::collect()
Current API is quite verbose, I'm considering using common short names to save some key strokes and cut back on the the verbosity. Things such as value
-> val
, etc. There are also several method names which have several synonyms that would fit. Once this is stabilized I will start considering a 1.0 release (along with a Rust 1.0).
This would ultimately be a breaking change (if names are changed), but legacy methods will be left in until a proper deprecation period has passed.
If anyone has ideas of overly verbose method names that should be changed, let's here it :)
Main methods I'm considering are those of ArgMatches
but those of Arg
and App
could also change if needed. I'm also not apposed to leaving all method names as is, I believe being too verbose is better than too short.
Currently application names with a hyphen '-' get replaced with a space ' ' when displaying usage strings. This is ideal for determining subcommands, but the original application name, or subcommand name should allow '-'s.
via a feature
probably using rust-ansi-term or term
Currently if you have several positional arguments, and one of the latter ones is required, the preceding ones are not added to the required list, which can make for a confusing error message (i.e. you're putting all the required arguments in according to the usage statement, but still getting "one or more required arguments not supplied")
I see you're using travis-cargo but had the forethought to fork it and hence avoid breaking changes. In any case, I thought I should inform you anyway, to ensure you don't get a nasty surprise in future. See http://huonw.github.io/blog/2015/05/travis-on-the-train-part-2/ for more details.
Argument assertions to determine if incompatible options have been used are currently evaluated inside arg.rs within the individual method. This allows for certain assertions to pass, that shouldn't, depending on the order in which argument options are listed.
Although assertions should normally be evaluated as soon as possible, all options must first be present. Thus assertions need to be moved to app.rs inside the arg()
method.
Currently if you use arg_enum!
to create possible values into an enum, you must either allow non-camel-case enum variants (to suppress the warning), or force users to start their possible values with an upper case character. For example, if you had a --mode
which accepted an arg_enum!
of
arg_enum! {
enum {
Vi,
Emacs
}
}
The user must use $ myprog --mode Vi
which isn't optimal. This enum should be able to match vi
or Vi
.
Simply converting to lowercase is also a very tricky subject if utf-8
is to be supported. But being, I don't use any non-ascii characters on a regular basis, I'm unfamiliar with capital/lowercase unicode graphemes.
In addition to #72 something akin to validating numeric ranges goes along nicely with Specific Value Sets. Perhaps a type of Range
? Thinking out loud...
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.