Squashed 'libs/CommService/' content from commit 7ccc0fc
git-subtree-dir: libs/CommService git-subtree-split: 7ccc0fce88bbc5969df060058cf0fb57abe3bcf9
This commit is contained in:
152
libs/CLI11/book/chapters/advanced-topics.md
Normal file
152
libs/CLI11/book/chapters/advanced-topics.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# Advanced topics
|
||||
|
||||
## Environment variables
|
||||
|
||||
Environment variables can be used to fill in the value of an option:
|
||||
|
||||
```cpp
|
||||
std::string opt;
|
||||
app.add_option("--my_option", opt)->envname("MY_OPTION");
|
||||
```
|
||||
|
||||
If not given on the command line, the environment variable will be checked and
|
||||
read from if it exists. All the standard tools, like default and required, work
|
||||
as expected. If passed on the command line, this will ignore the environment
|
||||
variable.
|
||||
|
||||
## Needs/excludes
|
||||
|
||||
You can set a network of requirements. For example, if flag a needs flag b but
|
||||
cannot be given with flag c, that would be:
|
||||
|
||||
```cpp
|
||||
auto a = app.add_flag("-a");
|
||||
auto b = app.add_flag("-b");
|
||||
auto c = app.add_flag("-c");
|
||||
|
||||
a->needs(b);
|
||||
a->excludes(c);
|
||||
```
|
||||
|
||||
CLI11 will make sure your network of requirements makes sense, and will throw an
|
||||
error immediately if it does not.
|
||||
|
||||
## Custom option callbacks
|
||||
|
||||
You can make a completely generic option with a custom callback. For example, if
|
||||
you wanted to add a complex number (already exists, so please don't actually do
|
||||
this):
|
||||
|
||||
```cpp
|
||||
CLI::Option *
|
||||
add_option(CLI::App &app, std::string name, cx &variable, std::string description = "", bool defaulted = false) {
|
||||
CLI::callback_t fun = [&variable](CLI::results_t res) {
|
||||
double x, y;
|
||||
bool worked = CLI::detail::lexical_cast(res[0], x) && CLI::detail::lexical_cast(res[1], y);
|
||||
if(worked)
|
||||
variable = cx(x, y);
|
||||
return worked;
|
||||
};
|
||||
|
||||
CLI::Option *opt = app.add_option(name, fun, description, defaulted);
|
||||
opt->set_custom_option("COMPLEX", 2);
|
||||
if(defaulted) {
|
||||
std::stringstream out;
|
||||
out << variable;
|
||||
opt->set_default_str(out.str());
|
||||
}
|
||||
return opt;
|
||||
}
|
||||
```
|
||||
|
||||
Then you could use it like this:
|
||||
|
||||
```cpp
|
||||
std::complex<double> comp{0, 0};
|
||||
add_option(app, "-c,--complex", comp);
|
||||
```
|
||||
|
||||
## Custom converters
|
||||
|
||||
You can add your own converters to allow CLI11 to accept more option types in
|
||||
the standard calls. These can only be used for "single" size options (so
|
||||
complex, vector, etc. are a separate topic). If you set up a custom
|
||||
`istringstream& operator <<` overload before include CLI11, you can support
|
||||
different conversions. If you place this in the CLI namespace, you can even keep
|
||||
this from affecting the rest of your code. Here's how you could add
|
||||
`boost::optional` for a compiler that does not have `__has_include`:
|
||||
|
||||
```cpp
|
||||
// CLI11 already does this if __has_include is defined
|
||||
#ifndef __has_include
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
// Use CLI namespace to avoid the conversion leaking into your other code
|
||||
namespace CLI {
|
||||
|
||||
template <typename T> std::istringstream &operator>>(std::istringstream &in, boost::optional<T> &val) {
|
||||
T v;
|
||||
in >> v;
|
||||
val = v;
|
||||
return in;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#include <CLI11.hpp>
|
||||
```
|
||||
|
||||
This is an example of how to use the system only; if you are just looking for a
|
||||
way to activate `boost::optional` support on older compilers, you should define
|
||||
`CLI11_BOOST_OPTIONAL` before including a CLI11 file, you'll get the
|
||||
`boost::optional` support.
|
||||
|
||||
## Custom converters and type names: std::chrono example
|
||||
|
||||
An example of adding a custom converter and typename for `std::chrono` follows:
|
||||
|
||||
```cpp
|
||||
namespace CLI
|
||||
{
|
||||
template <typename T, typename R>
|
||||
std::istringstream &operator>>(std::istringstream &in, std::chrono::duration<T,R> &val)
|
||||
{
|
||||
T v;
|
||||
in >> v;
|
||||
val = std::chrono::duration<T,R>(v);
|
||||
return in;
|
||||
}
|
||||
|
||||
template <typename T, typename R>
|
||||
std::stringstream &operator<<(std::stringstream &in, std::chrono::duration<T,R> &val)
|
||||
{
|
||||
in << val.count();
|
||||
return in;
|
||||
}
|
||||
}
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
|
||||
namespace CLI
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <>
|
||||
constexpr const char *type_name<std::chrono::hours>()
|
||||
{
|
||||
return "TIME [H]";
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr const char *type_name<std::chrono::minutes>()
|
||||
{
|
||||
return "TIME [MIN]";
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Thanks to Olivier Hartmann for the example.
|
||||
39
libs/CLI11/book/chapters/an-advanced-example.md
Normal file
39
libs/CLI11/book/chapters/an-advanced-example.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Making a git clone
|
||||
|
||||
Let's try our hand at a little `git` clone, called `geet`. It will just print
|
||||
it's intent, rather than running actual code, since it's just a demonstration.
|
||||
Let's start by adding an app and requiring 1 subcommand to run:
|
||||
|
||||
[include:"Intro"](../code/geet.cpp)
|
||||
|
||||
Now, let's define the first subcommand, `add`, along with a few options:
|
||||
|
||||
[include:"Add"](../code/geet.cpp)
|
||||
|
||||
Now, let's add `commit`:
|
||||
|
||||
[include:"Commit"](../code/geet.cpp)
|
||||
|
||||
All that's need now is the parse call. We'll print a little message after the
|
||||
code runs, and then return:
|
||||
|
||||
[include:"Parse"](../code/geet.cpp)
|
||||
|
||||
[Source code](https://github.com/CLIUtils/CLI11/tree/main/book/code/geet.cpp)
|
||||
|
||||
If you compile and run:
|
||||
|
||||
```term
|
||||
gitbook:examples $ c++ -std=c++11 geet.cpp -o geet
|
||||
```
|
||||
|
||||
You'll see it behaves pretty much like `git`.
|
||||
|
||||
## Multi-file App parse code
|
||||
|
||||
This example could be made much nicer if it was split into files, one per
|
||||
subcommand. If you simply use shared pointers instead of raw values in the
|
||||
lambda capture, you can tie the lifetime to the lambda function lifetime. CLI11
|
||||
has a
|
||||
[multifile example](https://github.com/CLIUtils/CLI11/tree/main/examples/subcom_in_files)
|
||||
in its example folder.
|
||||
39
libs/CLI11/book/chapters/basics.md
Normal file
39
libs/CLI11/book/chapters/basics.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# The Basics
|
||||
|
||||
The simplest CLI11 program looks like this:
|
||||
|
||||
[include](../code/simplest.cpp)
|
||||
|
||||
The first line includes the library; this explicitly uses the single file
|
||||
edition (see [Selecting an edition](/chapters/installation)).
|
||||
|
||||
After entering the main function, you'll see that a `CLI::App` object is
|
||||
created. This is the basis for all interactions with the library. You could
|
||||
optionally provide a description for your app here.
|
||||
|
||||
A normal CLI11 application would define some flags and options next. This is a
|
||||
simplest possible example, so we'll go on.
|
||||
|
||||
The macro `CLI11_PARSE` just runs five simple lines. This internally runs
|
||||
`app.parse(argc, argv)`, which takes the command line info from C++ and parses
|
||||
it. If there is an error, it throws a `ParseError`; if you catch it, you can use
|
||||
`app.exit` with the error as an argument to print a nice message and produce the
|
||||
correct return code for your application.
|
||||
|
||||
If you just use `app.parse` directly, your application will still work, but the
|
||||
stack will not be correctly unwound since you have an uncaught exception, and
|
||||
the command line output will be cluttered, especially for help.
|
||||
|
||||
For this (and most of the examples in this book) we will assume that we have the
|
||||
`CLI11.hpp` file in the current directory and that we are creating an output
|
||||
executable `a.out` on a macOS or Linux system. The commands to compile and test
|
||||
this example would be:
|
||||
|
||||
```term
|
||||
gitbook:examples $ g++ -std=c++11 simplest.cpp
|
||||
gitbook:examples $ ./a.out -h
|
||||
Usage: ./a.out [OPTIONS]
|
||||
|
||||
Options:
|
||||
-h,--help Print this help message and exit
|
||||
```
|
||||
340
libs/CLI11/book/chapters/config.md
Normal file
340
libs/CLI11/book/chapters/config.md
Normal file
@@ -0,0 +1,340 @@
|
||||
# Accepting configure files
|
||||
|
||||
## Reading a configure file
|
||||
|
||||
You can tell your app to allow configure files with `set_config("--config")`.
|
||||
There are arguments: the first is the option name. If empty, it will clear the
|
||||
config flag. The second item is the default file name. If that is specified, the
|
||||
config will try to read that file. The third item is the help string, with a
|
||||
reasonable default, and the final argument is a boolean (default: false) that
|
||||
indicates that the configuration file is required and an error will be thrown if
|
||||
the file is not found and this is set to true.
|
||||
|
||||
### Adding a default path
|
||||
|
||||
if it is desired that config files be searched for a in a default path the
|
||||
`CLI::FileOnDefaultPath` transform can be used.
|
||||
|
||||
```cpp
|
||||
app.set_config("--config")->transform(CLI::FileOnDefaultPath("/default_path/"));
|
||||
```
|
||||
|
||||
This will allow specified files to either exist as given or on a specified
|
||||
default path.
|
||||
|
||||
```cpp
|
||||
app.set_config("--config")
|
||||
->transform(CLI::FileOnDefaultPath("/default_path/"))
|
||||
->transform(CLI::FileOnDefaultPath("/default_path2/",false));
|
||||
```
|
||||
|
||||
Multiple default paths can be specified through this mechanism. The last
|
||||
transform given is executed first so the error return must be disabled so it can
|
||||
be chained to the first. The same effect can be achieved though the or(`|`)
|
||||
operation with validators
|
||||
|
||||
```cpp
|
||||
app.set_config("--config")
|
||||
->transform(CLI::FileOnDefaultPath("/default_path2/") | CLI::FileOnDefaultPath("/default_path/"));
|
||||
```
|
||||
|
||||
### Extra fields
|
||||
|
||||
Sometimes configuration files are used for multiple purposes so CLI11 allows
|
||||
options on how to deal with extra fields
|
||||
|
||||
```cpp
|
||||
app.allow_config_extras(true);
|
||||
```
|
||||
|
||||
will allow capture the extras in the extras field of the app. (NOTE: This also
|
||||
sets the `allow_extras` in the app to true)
|
||||
|
||||
```cpp
|
||||
app.allow_config_extras(false);
|
||||
```
|
||||
|
||||
will generate an error if there are any extra fields for slightly finer control
|
||||
there is a scoped enumeration of the modes or
|
||||
|
||||
```cpp
|
||||
app.allow_config_extras(CLI::config_extras_mode::ignore);
|
||||
```
|
||||
|
||||
will completely ignore extra parameters in the config file. This mode is the
|
||||
default.
|
||||
|
||||
```cpp
|
||||
app.allow_config_extras(CLI::config_extras_mode::capture);
|
||||
```
|
||||
|
||||
will store the unrecognized options in the app extras fields. This option is the
|
||||
closest equivalent to `app.allow_config_extras(true);` with the exception that
|
||||
it does not also set the `allow_extras` flag so using this option without also
|
||||
setting `allow_extras(true)` will generate an error which may or may not be the
|
||||
desired behavior.
|
||||
|
||||
```cpp
|
||||
app.allow_config_extras(CLI::config_extras_mode::error);
|
||||
```
|
||||
|
||||
is equivalent to `app.allow_config_extras(false);`
|
||||
|
||||
```cpp
|
||||
app.allow_config_extras(CLI::config_extras_mode::ignore_all);
|
||||
```
|
||||
|
||||
will completely ignore any mismatches, extras, or other issues with the config
|
||||
file
|
||||
|
||||
### Getting the used configuration file name
|
||||
|
||||
If it is needed to get the configuration file name used this can be obtained via
|
||||
`app.get_config_ptr()->as<std::string>()` or
|
||||
`app["--config"]->as<std::string>()` assuming `--config` was the configuration
|
||||
option name.
|
||||
|
||||
## Configure file format
|
||||
|
||||
Here is an example configuration file, in
|
||||
[TOML](https://github.com/toml-lang/toml) format:
|
||||
|
||||
```ini
|
||||
# Comments are supported, using a #
|
||||
# The default section is [default], case insensitive
|
||||
|
||||
value = 1
|
||||
str = "A string"
|
||||
vector = [1,2,3]
|
||||
|
||||
# Section map to subcommands
|
||||
[subcommand]
|
||||
in_subcommand = Wow
|
||||
[subcommand.sub]
|
||||
subcommand = true # could also be give as sub.subcommand=true
|
||||
```
|
||||
|
||||
Spaces before and after the name and argument are ignored. Multiple arguments
|
||||
are separated by spaces. One set of quotes will be removed, preserving spaces
|
||||
(the same way the command line works). Boolean options can be `true`, `on`, `1`,
|
||||
`y`, `t`, `+`, `yes`, `enable`; or `false`, `off`, `0`, `no`, `n`, `f`, `-`,
|
||||
`disable`, (case insensitive). Sections (and `.` separated names) are treated as
|
||||
subcommands (note: this does not necessarily mean that subcommand was passed, it
|
||||
just sets the "defaults". If a subcommand is set to `configurable` then passing
|
||||
the subcommand using `[sub]` in a configuration file will trigger the
|
||||
subcommand.)
|
||||
|
||||
CLI11 also supports configuration file in INI format.
|
||||
|
||||
```ini
|
||||
; Comments are supported, using a ;
|
||||
; The default section is [default], case insensitive
|
||||
|
||||
value = 1
|
||||
str = "A string"
|
||||
vector = 1 2 3
|
||||
|
||||
; Section map to subcommands
|
||||
[subcommand]
|
||||
in_subcommand = Wow
|
||||
sub.subcommand = true
|
||||
```
|
||||
|
||||
The main differences are in vector notation and comment character. Note: CLI11
|
||||
is not a full TOML parser as it just reads values as strings. It is possible
|
||||
(but not recommended) to mix notation.
|
||||
|
||||
## Multiple configuration files
|
||||
|
||||
If it is desired that multiple configuration be allowed. Use
|
||||
|
||||
```cpp
|
||||
app.set_config("--config")->expected(1, X);
|
||||
```
|
||||
|
||||
Where X is some positive integer and will allow up to `X` configuration files to
|
||||
be specified by separate `--config` arguments.
|
||||
|
||||
## Writing out a configure file
|
||||
|
||||
To print a configuration file from the passed arguments, use
|
||||
`.config_to_str(default_also=false, write_description=false)`, where
|
||||
`default_also` will also show any defaulted arguments, and `write_description`
|
||||
will include option descriptions and the App description
|
||||
|
||||
```cpp
|
||||
CLI::App app;
|
||||
app.add_option(...);
|
||||
// several other options
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
//the config printout should be after the parse to capture the given arguments
|
||||
std::cout<<app.config_to_str(true,true);
|
||||
```
|
||||
|
||||
if a prefix is needed to print before the options, for example to print a config
|
||||
for just a subcommand, the config formatter can be obtained directly.
|
||||
|
||||
```cpp
|
||||
auto fmtr=app.get_config_formatter();
|
||||
//std::string to_config(const App *app, bool default_also, bool write_description, std::string prefix)
|
||||
fmtr->to_config(&app,true,true,"sub.");
|
||||
//prefix can be used to set a prefix before each argument, like "sub."
|
||||
```
|
||||
|
||||
### Customization of configure file output
|
||||
|
||||
The default config parser/generator has some customization points that allow
|
||||
variations on the TOML format. The default formatter has a base configuration
|
||||
that matches the TOML format. It defines 5 characters that define how different
|
||||
aspects of the configuration are handled. You must use
|
||||
`get_config_formatter_base()` to have access to these fields
|
||||
|
||||
```cpp
|
||||
/// the character used for comments
|
||||
char commentChar = '#';
|
||||
/// the character used to start an array '\0' is a default to not use
|
||||
char arrayStart = '[';
|
||||
/// the character used to end an array '\0' is a default to not use
|
||||
char arrayEnd = ']';
|
||||
/// the character used to separate elements in an array
|
||||
char arraySeparator = ',';
|
||||
/// the character used separate the name from the value
|
||||
char valueDelimiter = '=';
|
||||
/// the character to use around strings
|
||||
char stringQuote = '"';
|
||||
/// the character to use around single characters
|
||||
char characterQuote = '\'';
|
||||
/// the maximum number of layers to allow
|
||||
uint8_t maximumLayers{255};
|
||||
/// the separator used to separator parent layers
|
||||
char parentSeparatorChar{'.'};
|
||||
/// Specify the configuration index to use for arrayed sections
|
||||
uint16_t configIndex{0};
|
||||
/// Specify the configuration section that should be used
|
||||
std::string configSection;
|
||||
```
|
||||
|
||||
These can be modified via setter functions
|
||||
|
||||
- `ConfigBase *comment(char cchar)`: Specify the character to start a comment
|
||||
block
|
||||
- `ConfigBase *arrayBounds(char aStart, char aEnd)`: Specify the start and end
|
||||
characters for an array
|
||||
- `ConfigBase *arrayDelimiter(char aSep)`: Specify the delimiter character for
|
||||
an array
|
||||
- `ConfigBase *valueSeparator(char vSep)`: Specify the delimiter between a name
|
||||
and value
|
||||
- `ConfigBase *quoteCharacter(char qString, char qChar)` :specify the characters
|
||||
to use around strings and single characters
|
||||
- `ConfigBase *maxLayers(uint8_t layers)` : specify the maximum number of parent
|
||||
layers to process. This is useful to limit processing for larger config files
|
||||
- `ConfigBase *parentSeparator(char sep)` : specify the character to separate
|
||||
parent layers from options
|
||||
- `ConfigBase *section(const std::string §ionName)` : specify the section
|
||||
name to use to get the option values, only this section will be processed
|
||||
- `ConfigBase *index(uint16_t sectionIndex)` : specify an index section to use
|
||||
for processing if multiple TOML sections of the same name are present
|
||||
`[[section]]`
|
||||
|
||||
For example, to specify reading a configure file that used `:` to separate name
|
||||
and values:
|
||||
|
||||
```cpp
|
||||
auto config_base=app.get_config_formatter_base();
|
||||
config_base->valueSeparator(':');
|
||||
```
|
||||
|
||||
The default configuration file will read INI files, but will write out files in
|
||||
the TOML format. To specify outputting INI formatted files use
|
||||
|
||||
```cpp
|
||||
app.config_formatter(std::make_shared<CLI::ConfigINI>());
|
||||
```
|
||||
|
||||
which makes use of a predefined modification of the ConfigBase class which TOML
|
||||
also uses. If a custom formatter is used that is not inheriting from the from
|
||||
ConfigBase class `get_config_formatter_base() will return a nullptr if RTTI is
|
||||
on (usually the default), or garbage if RTTI is off, so some care must be
|
||||
exercised in its use with custom configurations.
|
||||
|
||||
## Custom formats
|
||||
|
||||
You can invent a custom format and set that instead of the default INI
|
||||
formatter. You need to inherit from `CLI::Config` and implement the following
|
||||
two functions:
|
||||
|
||||
```cpp
|
||||
std::string to_config(const CLI::App *app, bool default_also, bool, std::string) const;
|
||||
std::vector<CLI::ConfigItem> from_config(std::istream &input) const;
|
||||
```
|
||||
|
||||
The `CLI::ConfigItem`s that you return are simple structures with a name, a
|
||||
vector of parents, and a vector of results. A optionally customizable `to_flag`
|
||||
method on the formatter lets you change what happens when a ConfigItem turns
|
||||
into a flag.
|
||||
|
||||
Finally, set your new class as new config formatter:
|
||||
|
||||
```cpp
|
||||
app.config_formatter(std::make_shared<NewConfig>());
|
||||
```
|
||||
|
||||
See
|
||||
[`examples/json.cpp`](https://github.com/CLIUtils/CLI11/blob/main/examples/json.cpp)
|
||||
for a complete JSON config example.
|
||||
|
||||
### Trivial JSON configuration example
|
||||
|
||||
```JSON
|
||||
{
|
||||
"test": 56,
|
||||
"testb": "test",
|
||||
"flag": true
|
||||
}
|
||||
```
|
||||
|
||||
The parser can handle these structures with only a minor tweak
|
||||
|
||||
```cpp
|
||||
app.get_config_formatter_base()->valueSeparator(':');
|
||||
```
|
||||
|
||||
The open and close brackets must be on a separate line and the comma gets
|
||||
interpreted as an array separator but since no values are after the comma they
|
||||
get ignored as well. This will not support multiple layers or sections or any
|
||||
other moderately complex JSON, but can work if the input file is simple.
|
||||
|
||||
## Triggering Subcommands
|
||||
|
||||
Configuration files can be used to trigger subcommands if a subcommand is set to
|
||||
configure. By default configuration file just set the default values of a
|
||||
subcommand. But if the `configure()` option is set on a subcommand then the if
|
||||
the subcommand is utilized via a `[subname]` block in the configuration file it
|
||||
will act as if it were called from the command line. Subsubcommands can be
|
||||
triggered via `[subname.subsubname]`. Using the `[[subname]]` will be as if the
|
||||
subcommand were triggered multiple times from the command line. This
|
||||
functionality can allow the configuration file to act as a scripting file.
|
||||
|
||||
For custom configuration files this behavior can be triggered by specifying the
|
||||
parent subcommands in the structure and `++` as the name to open a new
|
||||
subcommand scope and `--` to close it. These names trigger the different
|
||||
callbacks of configurable subcommands.
|
||||
|
||||
## Stream parsing
|
||||
|
||||
In addition to the regular parse functions a
|
||||
`parse_from_stream(std::istream &input)` is available to directly parse a stream
|
||||
operator. For example to process some arguments in an already open file stream.
|
||||
The stream is fed directly in the config parser so bypasses the normal command
|
||||
line parsing.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The config file input works with any form of the option given: Long, short,
|
||||
positional, or the environment variable name. When generating a config file it
|
||||
will create an option name in following priority.
|
||||
|
||||
1. First long name
|
||||
2. Positional name
|
||||
3. First short name
|
||||
4. Environment name
|
||||
167
libs/CLI11/book/chapters/flags.md
Normal file
167
libs/CLI11/book/chapters/flags.md
Normal file
@@ -0,0 +1,167 @@
|
||||
# Adding Flags
|
||||
|
||||
The most basic addition to a command line program is a flag. This is simply
|
||||
something that does not take any arguments. Adding a flag in CLI11 is done in
|
||||
one of three ways.
|
||||
|
||||
## Boolean flags
|
||||
|
||||
The simplest way to add a flag is probably a boolean flag:
|
||||
|
||||
```cpp
|
||||
bool my_flag{false};
|
||||
app.add_flag("-f", my_flag, "Optional description");
|
||||
```
|
||||
|
||||
This will bind the flag `-f` to the boolean `my_flag`. After the parsing step,
|
||||
`my_flag` will be `false` if the flag was not found on the command line, or
|
||||
`true` if it was. By default, it will be allowed any number of times, but if you
|
||||
explicitly\[^1\] request `->take_last(false)`, it will only be allowed once;
|
||||
passing something like `./my_app -f -f` or `./my_app -ff` will throw a
|
||||
`ParseError` with a nice help description. A flag name may start with any
|
||||
character except ('-', ' ', '\n', and '!'). For long flags, after the first
|
||||
character all characters are allowed except ('=',':','{',' ', '\n'). Names are
|
||||
given as a comma separated string, with the dash or dashes. An flag can have as
|
||||
many names as you want, and afterward, using `count`, you can use any of the
|
||||
names, with dashes as needed.
|
||||
|
||||
## Integer flags
|
||||
|
||||
If you want to allow multiple flags and count their value, simply use any
|
||||
integral variables instead of a bool:
|
||||
|
||||
```cpp
|
||||
int my_flag{0};
|
||||
app.add_flag("-f", my_flag, "Optional description");
|
||||
```
|
||||
|
||||
After the parsing step, `my_flag` will contain the number of times this flag was
|
||||
found on the command line, including 0 if not found.
|
||||
|
||||
This behavior can also be controlled manually via
|
||||
`->multi_option_policy(CLI::MultiOptionPolicy::Sum)` as of version 2.2.
|
||||
|
||||
## Arbitrary type flags
|
||||
|
||||
CLI11 allows the type of the variable to assign to in the `add_flag` function to
|
||||
be any supported type. This is particularly useful in combination with
|
||||
specifying default values for flags. The allowed types include bool, int, float,
|
||||
vector, enum, or string-like.
|
||||
|
||||
### Default Flag Values
|
||||
|
||||
Flag options specified through the `add_flag*` functions allow a syntax for the
|
||||
option names to default particular options to a false value or any other value
|
||||
if some flags are passed. For example:
|
||||
|
||||
```cpp
|
||||
app.add_flag("--flag,!--no-flag",result,"help for flag");
|
||||
```
|
||||
|
||||
specifies that if `--flag` is passed on the command line result will be true or
|
||||
contain a value of 1. If `--no-flag` is passed `result` will contain false or -1
|
||||
if `result` is a signed integer type, or 0 if it is an unsigned type. An
|
||||
alternative form of the syntax is more explicit: `"--flag,--no-flag{false}"`;
|
||||
this is equivalent to the previous example. This also works for short form
|
||||
options `"-f,!-n"` or `"-f,-n{false}"`. If `variable_to_bind_to` is anything but
|
||||
an integer value the default behavior is to take the last value given, while if
|
||||
`variable_to_bind_to` is an integer type the behavior will be to sum all the
|
||||
given arguments and return the result. This can be modified if needed by
|
||||
changing the `multi_option_policy` on each flag (this is not inherited). The
|
||||
default value can be any value. For example if you wished to define a numerical
|
||||
flag:
|
||||
|
||||
```cpp
|
||||
app.add_flag("-1{1},-2{2},-3{3}",result,"numerical flag")
|
||||
```
|
||||
|
||||
using any of those flags on the command line will result in the specified number
|
||||
in the output. Similar things can be done for string values, and enumerations,
|
||||
as long as the default value can be converted to the given type.
|
||||
|
||||
## Pure flags
|
||||
|
||||
Every command that starts with `add_`, such as the flag commands, return a
|
||||
pointer to the internally stored `CLI::Option` that describes your addition. If
|
||||
you prefer, you can capture this pointer and use it, and that allows you to skip
|
||||
adding a variable to bind to entirely:
|
||||
|
||||
```cpp
|
||||
CLI::Option* my_flag = app.add_flag("-f", "Optional description");
|
||||
```
|
||||
|
||||
After parsing, you can use `my_flag->count()` to count the number of times this
|
||||
was found. You can also directly use the value (`*my_flag`) as a bool.
|
||||
`CLI::Option` will be discussed in more detail later.
|
||||
|
||||
## Callback flags
|
||||
|
||||
If you want to define a callback that runs when you make a flag, you can use
|
||||
`add_flag_function` (C++11 or newer) or `add_flag` (C++14 or newer only) to add
|
||||
a callback function. The function should have the signature `void(std::size_t)`.
|
||||
This could be useful for a version printout, etc.
|
||||
|
||||
```cpp
|
||||
auto callback = [](int count){std::cout << "This was called " << count << " times";};
|
||||
app.add_flag_function("-c", callback, "Optional description");
|
||||
```
|
||||
|
||||
## Aliases
|
||||
|
||||
The name string, the first item of every `add_` method, can contain as many
|
||||
short and long names as you want, separated by commas. For example,
|
||||
`"-a,--alpha,-b,--beta"` would allow any of those to be recognized on the
|
||||
command line. If you use the same name twice, or if you use the same name in
|
||||
multiple flags, CLI11 will immediately throw a `CLI::ConstructionError`
|
||||
describing your problem (it will not wait until the parsing step).
|
||||
|
||||
If you want to make an option case insensitive, you can use the
|
||||
`->ignore_case()` method on the `CLI::Option` to do that. For example,
|
||||
|
||||
```cpp
|
||||
bool flag{false};
|
||||
app.add_flag("--flag", flag)
|
||||
->ignore_case();
|
||||
```
|
||||
|
||||
would allow the following to count as passing the flag:
|
||||
|
||||
```term
|
||||
gitbook $ ./my_app --fLaG
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
The following program will take several flags:
|
||||
|
||||
[include:"define"](../code/flags.cpp)
|
||||
|
||||
The values would be used like this:
|
||||
|
||||
[include:"usage"](../code/flags.cpp)
|
||||
|
||||
[Source code](https://github.com/CLIUtils/CLI11/tree/main/book/code/flags.cpp)
|
||||
|
||||
If you compile and run:
|
||||
|
||||
```term
|
||||
gitbook:examples $ g++ -std=c++11 flags.cpp
|
||||
gitbook:examples $ ./a.out -h
|
||||
Flag example program
|
||||
Usage: ./a.out [OPTIONS]
|
||||
|
||||
Options:
|
||||
-h,--help Print this help message and exit
|
||||
-b,--bool This is a bool flag
|
||||
-i,--int This is an int flag
|
||||
-p,--plain This is a plain flag
|
||||
|
||||
gitbook:examples $ ./a.out -bii --plain -i
|
||||
The flags program
|
||||
Bool flag passed
|
||||
Flag int: 3
|
||||
Flag plain: 1
|
||||
```
|
||||
|
||||
\[^1\]: It will not inherit this from the parent defaults, since this is often
|
||||
useful even if you don't want all options to allow multiple passed options.
|
||||
86
libs/CLI11/book/chapters/formatting.md
Normal file
86
libs/CLI11/book/chapters/formatting.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# Formatting help output
|
||||
|
||||
{% hint style='info' %} New in CLI11 1.6 {% endhint %}
|
||||
|
||||
## Customizing an existing formatter
|
||||
|
||||
In CLI11, you can control the output of the help printout in full or in part.
|
||||
The default formatter was written in such a way as to be customizable. You can
|
||||
use `app.get_formatter()` to get the current formatter. The formatter you set
|
||||
will be inherited by subcommands that are created after you set the formatter.
|
||||
|
||||
There are several configuration options that you can set:
|
||||
|
||||
| Set method | Description | Availability |
|
||||
| --------------------- | -------------------------------- | ------------ |
|
||||
| `column_width(width)` | The width of the columns | Both |
|
||||
| `label(key, value)` | Set a label to a different value | Both |
|
||||
|
||||
Labels will map the built in names and type names from key to value if present.
|
||||
For example, if you wanted to change the width of the columns to 40 and the
|
||||
`REQUIRED` label from `(REQUIRED)` to `(MUST HAVE)`:
|
||||
|
||||
```cpp
|
||||
app.get_formatter()->column_width(40);
|
||||
app.get_formatter()->label("REQUIRED", "(MUST HAVE)");
|
||||
```
|
||||
|
||||
## Subclassing
|
||||
|
||||
You can further configure pieces of the code while still keeping most of the
|
||||
formatting intact by subclassing either formatter and replacing any of the
|
||||
methods with your own. The formatters use virtual functions most places, so you
|
||||
are free to add or change anything about them. For example, if you wanted to
|
||||
remove the info that shows up between the option name and the description:
|
||||
|
||||
```cpp
|
||||
class MyFormatter : public CLI::Formatter {
|
||||
public:
|
||||
std::string make_option_opts(const CLI::Option *) const override {return "";}
|
||||
};
|
||||
app.formatter(std::make_shared<MyFormatter>());
|
||||
```
|
||||
|
||||
Look at the class definitions in `FormatterFwd.hpp` or the method definitions in
|
||||
`Formatter.hpp` to see what methods you have access to and how they are put
|
||||
together.
|
||||
|
||||
## Anatomy of a help message
|
||||
|
||||
This is a normal printout, with `<>` indicating the methods used to produce each
|
||||
line.
|
||||
|
||||
```text
|
||||
<make_description(app)>
|
||||
<make_usage(app)>
|
||||
<make_positionals(app)>
|
||||
<make_group(app, "Positionals", true, filter>
|
||||
<make_groups(app, mode)>
|
||||
<make_group(app, "Option Group 1"), false, filter>
|
||||
<make_group(app, "Option Group 2"), false, filter>
|
||||
...
|
||||
<make_subcommands(app)>
|
||||
<make_subcommand(sub1, Mode::Normal)>
|
||||
<make_subcommand(sub2, Mode::Normal)>
|
||||
<make_footer(app)>
|
||||
```
|
||||
|
||||
`make_usage` calls `make_option_usage(opt)` on all the positionals to build that
|
||||
part of the line. `make_subcommand` passes the subcommand as the app pointer.
|
||||
|
||||
The `make_groups` print the group name then call `make_option(o)` on the options
|
||||
listed in that group. The normal printout for an option looks like this:
|
||||
|
||||
```text
|
||||
make_option_opts(o)
|
||||
┌───┴────┐
|
||||
-n,--name (REQUIRED) This is a description
|
||||
└────┬────┘ └──────────┬──────────┘
|
||||
make_option_name(o,p) make_option_desc(o)
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `*1`: This signature depends on whether the call is from a positional or
|
||||
optional.
|
||||
- `o` is opt pointer, `p` is true if positional.
|
||||
114
libs/CLI11/book/chapters/installation.md
Normal file
114
libs/CLI11/book/chapters/installation.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# Installation
|
||||
|
||||
## Single file edition
|
||||
|
||||
```cpp
|
||||
#include <CLI11.hpp>
|
||||
```
|
||||
|
||||
This example uses the single file edition of CLI11. You can download `CLI11.hpp`
|
||||
from the latest release and put it into the same folder as your source code,
|
||||
then compile this with C++ enabled. For a larger project, you can just put this
|
||||
in an include folder and you are set.
|
||||
|
||||
## Full edition
|
||||
|
||||
```cpp
|
||||
#include <CLI/CLI.hpp>
|
||||
```
|
||||
|
||||
If you want to use CLI11 in its full form, you can also use the original
|
||||
multiple file edition. This has an extra utility (`Timer`), and is does not
|
||||
require that you use a release. The only change to your code would be the
|
||||
include shown above.
|
||||
|
||||
### CMake support for the full edition
|
||||
|
||||
If you use CMake 3.4+ for your project (highly recommended), CLI11 comes with a
|
||||
powerful CMakeLists.txt file that was designed to also be used with
|
||||
`add_subproject`. You can add the repository to your code (preferably as a git
|
||||
submodule), then add the following line to your project (assuming your folder is
|
||||
called CLI11):
|
||||
|
||||
```cmake
|
||||
add_subdirectory(CLI11)
|
||||
```
|
||||
|
||||
Then, you will have a target `CLI11::CLI11` that you can link to with
|
||||
`target_link_libraries`. It will provide the include paths you need for the
|
||||
library. This is the way [GooFit](https://github.com/GooFit/GooFit) uses CLI11,
|
||||
for example.
|
||||
|
||||
You can also configure and optionally install CLI11, and CMake will create the
|
||||
necessary `lib/cmake/CLI11/CLI11Config.cmake` files, so
|
||||
`find_package(CLI11 CONFIG REQUIRED)` also works.
|
||||
|
||||
If you use conan.io, CLI11 supports that too.
|
||||
|
||||
### Running tests on the full edition
|
||||
|
||||
CLI11 has examples and tests that can be accessed using a CMake build on any
|
||||
platform. Simply build and run ctest to run the 200+ tests to ensure CLI11 works
|
||||
on your system.
|
||||
|
||||
As an example of the build system, the following code will download and test
|
||||
CLI11 in a simple Alpine Linux docker container [^1]:
|
||||
|
||||
```term
|
||||
gitbook:~ $ docker run -it alpine
|
||||
root:/ # apk add --no-cache g++ cmake make git
|
||||
fetch ...
|
||||
root:/ # git clone https://github.com/CLIUtils/CLI11.git
|
||||
Cloning into 'CLI11' ...
|
||||
root:/ # cd CLI11
|
||||
root:CLI11 # mkdir build
|
||||
root:CLI11 # cd build
|
||||
root:build # cmake ..
|
||||
-- The CXX compiler identification is GNU 6.3.0 ...
|
||||
root:build # make
|
||||
Scanning dependencies ...
|
||||
root:build # make test
|
||||
[warning]Running tests...
|
||||
Test project /CLI11/build
|
||||
Start 1: HelpersTest
|
||||
1/10 Test #1: HelpersTest ...................... Passed 0.01 sec
|
||||
Start 2: IniTest
|
||||
2/10 Test #2: IniTest .......................... Passed 0.01 sec
|
||||
Start 3: SimpleTest
|
||||
3/10 Test #3: SimpleTest ....................... Passed 0.01 sec
|
||||
Start 4: AppTest
|
||||
4/10 Test #4: AppTest .......................... Passed 0.02 sec
|
||||
Start 5: CreationTest
|
||||
5/10 Test #5: CreationTest ..................... Passed 0.01 sec
|
||||
Start 6: SubcommandTest
|
||||
6/10 Test #6: SubcommandTest ................... Passed 0.01 sec
|
||||
Start 7: HelpTest
|
||||
7/10 Test #7: HelpTest ......................... Passed 0.01 sec
|
||||
Start 8: NewParseTest
|
||||
8/10 Test #8: NewParseTest ..................... Passed 0.01 sec
|
||||
Start 9: TimerTest
|
||||
9/10 Test #9: TimerTest ........................ Passed 0.24 sec
|
||||
Start 10: link_test_2
|
||||
10/10 Test #10: link_test_2 ...................... Passed 0.00 sec
|
||||
|
||||
100% tests passed, 0 tests failed out of 10
|
||||
|
||||
Total Test time (real) = 0.34 sec
|
||||
```
|
||||
|
||||
For the curious, the CMake options and defaults are listed below. Most options
|
||||
default to off if CLI11 is used as a subdirectory in another project.
|
||||
|
||||
| Option | Description |
|
||||
| ----------------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| `CLI11_SINGLE_FILE=ON` | Build the `CLI11.hpp` file from the sources. Requires Python (version 3 or 2.7). |
|
||||
| `CLI11_SINGLE_FILE_TESTS=OFF` | Run the tests on the generated single file version as well |
|
||||
| `CLI11_EXAMPLES=ON` | Build the example programs. |
|
||||
| `CLI11_TESTING=ON` | Build the tests. |
|
||||
| `CLI11_CLANG_TIDY=OFF` | Run `clang-tidy` on the examples and headers. Requires CMake 3.6+. |
|
||||
| `CLI11_CLANG_TIDY_OPTIONS=""` | Options to pass to `clang-tidy`, such as `-fix` (single threaded build only if applying fixes!) |
|
||||
|
||||
[^1]:
|
||||
Docker is being used to create a pristine disposable environment; there is
|
||||
nothing special about this container. Alpine is being used because it is
|
||||
small, modern, and fast. Commands are similar on any other platform.
|
||||
54
libs/CLI11/book/chapters/internals.md
Normal file
54
libs/CLI11/book/chapters/internals.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# CLI11 Internals
|
||||
|
||||
## Callbacks
|
||||
|
||||
The library was designed to bind to existing variables without requiring typed
|
||||
classes or inheritance. This is accomplished through lambda functions.
|
||||
|
||||
This looks like:
|
||||
|
||||
```cpp
|
||||
Option* add_option(string name, T item) {
|
||||
this->function = [&item](string value){
|
||||
item = detail::lexical_cast<T>(value);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Obviously, you can't access `T` after the `add_` method is over, so it stores
|
||||
the string representation of the default value if it receives the special `true`
|
||||
value as the final argument (not shown above).
|
||||
|
||||
## Parsing
|
||||
|
||||
Parsing follows the following procedure:
|
||||
|
||||
1. `_validate`: Make sure the defined options and subcommands are self
|
||||
consistent.
|
||||
2. `_parse`: Main parsing routine. See below.
|
||||
3. `_run_callback`: Run an App callback if present.
|
||||
|
||||
The parsing phase is the most interesting:
|
||||
|
||||
1. `_parse_single`: Run on each entry on the command line and fill the
|
||||
options/subcommands.
|
||||
2. `_process`: Run the procedure listed below.
|
||||
3. `_process_extra`: This throws an error if needed on extra arguments that
|
||||
didn't fit in the parse.
|
||||
|
||||
The `_process` procedure runs the following steps; each step is recursive and
|
||||
completes all subcommands before moving to the next step (new in 1.7). This
|
||||
ensures that interactions between options and subcommand options is consistent.
|
||||
|
||||
1. `_process_ini`: This reads an INI file and fills/changes options as needed.
|
||||
2. `_process_env`: Look for environment variables.
|
||||
3. `_process_callbacks`: Run the callback functions - this fills out the
|
||||
variables.
|
||||
4. `_process_help_flags`: Run help flags if present (and quit).
|
||||
5. `_process_requirements`: Make sure needs/excludes, required number of options
|
||||
present.
|
||||
|
||||
## Exceptions
|
||||
|
||||
The library immediately returns a C++ exception when it detects a problem, such
|
||||
as an incorrect construction or a malformed command line.
|
||||
459
libs/CLI11/book/chapters/options.md
Normal file
459
libs/CLI11/book/chapters/options.md
Normal file
@@ -0,0 +1,459 @@
|
||||
# Options
|
||||
|
||||
## Simple options
|
||||
|
||||
The most versatile addition to a command line program is an option. This is like
|
||||
a flag, but it takes an argument. CLI11 handles all the details for many types
|
||||
of options for you, based on their type. To add an option:
|
||||
|
||||
```cpp
|
||||
int int_option{0};
|
||||
app.add_option("-i", int_option, "Optional description");
|
||||
```
|
||||
|
||||
This will bind the option `-i` to the integer `int_option`. On the command line,
|
||||
a single value that can be converted to an integer will be expected. Non-integer
|
||||
results will fail. If that option is not given, CLI11 will not touch the initial
|
||||
value. This allows you to set up defaults by simply setting your value
|
||||
beforehand. If you want CLI11 to display your default value, you can add
|
||||
`->capture_default_str()` after the option.
|
||||
|
||||
```cpp
|
||||
int int_option{0};
|
||||
app.add_option("-i", int_option, "Optional description")->capture_default_str();
|
||||
```
|
||||
|
||||
You can use any C++ int-like type, not just `int`. CLI11 understands the
|
||||
following categories of types:
|
||||
|
||||
| Type | CLI11 |
|
||||
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| number like | Integers, floats, bools, or any type that can be constructed from an integer or floating point number. Accepts common numerical strings like `0xFF` as well as octal, and decimal |
|
||||
| string-like | std::string, or anything that can be constructed from or assigned a std::string |
|
||||
| char | For a single char, single string values are accepted, otherwise longer strings are treated as integral values and a conversion is attempted |
|
||||
| complex-number | std::complex or any type which has a real(), and imag() operations available, will allow 1 or 2 string definitions like "1+2j" or two arguments "1","2" |
|
||||
| enumeration | any enum or enum class type is supported through conversion from the underlying type(typically int, though it can be specified otherwise) |
|
||||
| container-like | a container(like vector) of any available types including other containers |
|
||||
| wrapper | any other object with a `value_type` static definition where the type specified by `value_type` is one of the type in this list, including `std::atomic<>` |
|
||||
| tuple | a tuple, pair, or array, or other type with a tuple size and tuple_type operations defined and the members being a type contained in this list |
|
||||
| function | A function that takes an array of strings and returns a string that describes the conversion failure or empty for success. May be the empty function. (`{}`) |
|
||||
| streamable | any other type with a `<<` operator will also work |
|
||||
|
||||
By default, CLI11 will assume that an option is optional, and one value is
|
||||
expected if you do not use a vector. You can change this on a specific option
|
||||
using option modifiers. An option name may start with any character except ('-',
|
||||
' ', '\n', and '!'). For long options, after the first character all characters
|
||||
are allowed except ('=',':','{',' ', '\n'). Names are given as a comma separated
|
||||
string, with the dash or dashes. An option can have as many names as you want,
|
||||
and afterward, using `count`, you can use any of the names, with dashes as
|
||||
needed, to count the options. One of the names is allowed to be given without
|
||||
proceeding dash(es); if present the option is a positional option, and that name
|
||||
will be used on the help line for its positional form.
|
||||
|
||||
## Positional options and aliases
|
||||
|
||||
When you give an option on the command line without a name, that is a positional
|
||||
option. Positional options are accepted in the same order they are defined. So,
|
||||
for example:
|
||||
|
||||
```term
|
||||
gitbook:examples $ ./a.out one --two three four
|
||||
```
|
||||
|
||||
The string `one` would have to be the first positional option. If `--two` is a
|
||||
flag, then the remaining two strings are positional. If `--two` is a
|
||||
one-argument option, then `four` is the second positional. If `--two` accepts
|
||||
two or more arguments, then there are no more positionals.
|
||||
|
||||
To make a positional option, you simply give CLI11 one name that does not start
|
||||
with a dash. You can have as many (non-overlapping) names as you want for an
|
||||
option, but only one positional name. So the following name string is valid:
|
||||
|
||||
```cpp
|
||||
"-a,-b,--alpha,--beta,mypos"
|
||||
```
|
||||
|
||||
This would make two short option aliases, two long option alias, and the option
|
||||
would be also be accepted as a positional.
|
||||
|
||||
## Containers of options
|
||||
|
||||
If you use a vector or other container instead of a plain option, you can accept
|
||||
more than one value on the command line. By default, a container accepts as many
|
||||
options as possible, until the next value that could be a valid option name. You
|
||||
can specify a set number using an option modifier `->expected(N)`. (The default
|
||||
unlimited behavior on vectors is restored with `N=-1`) CLI11 does not
|
||||
differentiate between these two methods for unlimited acceptance options.
|
||||
|
||||
| Separate names | Combined names |
|
||||
| ----------------- | -------------- |
|
||||
| `--vec 1 --vec 2` | `--vec 1 2` |
|
||||
|
||||
It is also possible to specify a minimum and maximum number through
|
||||
`->expected(Min,Max)`. It is also possible to specify a min and max type size
|
||||
for the elements of the container. It most cases these values will be
|
||||
automatically determined but a user can manually restrict them.
|
||||
|
||||
An example of setting up a vector option:
|
||||
|
||||
```cpp
|
||||
std::vector<int> int_vec;
|
||||
app.add_option("--vec", int_vec, "My vector option");
|
||||
```
|
||||
|
||||
Vectors will be replaced by the parsed content if the option is given on the
|
||||
command line.
|
||||
|
||||
A definition of a container for purposes of CLI11 is a type with a `end()`,
|
||||
`insert(...)`, `clear()` and `value_type` definitions. This includes `vector`,
|
||||
`set`, `deque`, `list`, `forward_iist`, `map`, `unordered_map` and a few others
|
||||
from the standard library, and many other containers from the boost library.
|
||||
|
||||
### Empty containers
|
||||
|
||||
By default a container will never return an empty container. If it is desired to
|
||||
allow an empty container to be returned, then the option must be modified with a
|
||||
0 as the minimum expected value
|
||||
|
||||
```cpp
|
||||
std::vector<int> int_vec;
|
||||
app.add_option("--vec", int_vec, "Empty vector allowed")->expected(0,-1);
|
||||
```
|
||||
|
||||
An empty vector can than be specified on the command line as `--vec {}`
|
||||
|
||||
To allow an empty vector from config file, the default must be set in addition
|
||||
to the above modification.
|
||||
|
||||
```cpp
|
||||
std::vector<int> int_vec;
|
||||
app.add_option("--vec", int_vec, "Empty vector allowed")->expected(0,-1)->default_str("{}");
|
||||
```
|
||||
|
||||
Then in the file
|
||||
|
||||
```toml
|
||||
vec={}
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```toml
|
||||
vec=[]
|
||||
```
|
||||
|
||||
will generate an empty vector in `int_vec`.
|
||||
|
||||
### Containers of containers
|
||||
|
||||
Containers of containers are also supported.
|
||||
|
||||
```cpp
|
||||
std::vector<std::vector<int>> int_vec;
|
||||
app.add_option("--vec", int_vec, "My vector of vectors option");
|
||||
```
|
||||
|
||||
CLI11 inserts a separator sequence at the start of each argument call to
|
||||
separate the vectors. So unless the separators are injected as part of the
|
||||
command line each call of the option on the command line will result in a
|
||||
separate element of the outer vector. This can be manually controlled via
|
||||
`inject_separator(true|false)` but in nearly all cases this should be left to
|
||||
the defaults. To insert of a separator from the command line add a `%%` where
|
||||
the separation should occur.
|
||||
|
||||
```bash
|
||||
cmd --vec_of_vec 1 2 3 4 %% 1 2
|
||||
```
|
||||
|
||||
would then result in a container of size 2 with the first element containing 4
|
||||
values and the second 2.
|
||||
|
||||
This separator is also the only way to get values into something like
|
||||
|
||||
```cpp
|
||||
std::pair<std::vector<int>,std::vector<int>> two_vecs;
|
||||
app.add_option("--vec", two_vecs, "pair of vectors");
|
||||
```
|
||||
|
||||
without calling the argument twice.
|
||||
|
||||
Further levels of nesting containers should compile but intermediate layers will
|
||||
only have a single element in the container, so is probably not that useful.
|
||||
|
||||
### Nested types
|
||||
|
||||
Types can be nested. For example:
|
||||
|
||||
```cpp
|
||||
std::map<int, std::pair<int,std::string>> map;
|
||||
app.add_option("--dict", map, "map of pairs");
|
||||
```
|
||||
|
||||
will require 3 arguments for each invocation, and multiple sets of 3 arguments
|
||||
can be entered for a single invocation on the command line.
|
||||
|
||||
```cpp
|
||||
std::map<int, std::pair<int,std::vector<std::string>>> map;
|
||||
app.add_option("--dict", map, "map of pairs");
|
||||
```
|
||||
|
||||
will result in a requirement for 2 integers on each invocation and absorb an
|
||||
unlimited number of strings including 0.
|
||||
|
||||
## Option modifiers
|
||||
|
||||
When you call `add_option`, you get a pointer to the added option. You can use
|
||||
that to add option modifiers. A full listing of the option modifiers:
|
||||
|
||||
| Modifier | Description |
|
||||
| ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `->required()` | The program will quit if this option is not present. This is `mandatory` in Plumbum, but required options seems to be a more standard term. For compatibility, `->mandatory()` also works. |
|
||||
| `->expected(N)` | Take `N` values instead of as many as possible, mainly for vector args. |
|
||||
| `->expected(Nmin,Nmax)` | Take between `Nmin` and `Nmax` values. |
|
||||
| `->type_size(N)` | specify that each block of values would consist of N elements |
|
||||
| `->type_size(Nmin,Nmax)` | specify that each block of values would consist of between Nmin and Nmax elements |
|
||||
| `->needs(opt)` | This option requires another option to also be present, opt is an `Option` pointer or a string with the name of the option. Can be removed with `->remove_needs(opt)` |
|
||||
| `->excludes(opt)` | This option cannot be given with `opt` present, opt is an `Option` pointer or a string with the name of the option. Can be removed with `->remove_excludes(opt)` |
|
||||
| `->envname(name)` | Gets the value from the environment if present and not passed on the command line. |
|
||||
| `->group(name)` | The help group to put the option in. No effect for positional options. Defaults to `"Options"`. `"Hidden"` will not show up in the help print. |
|
||||
| `->description(string)` | Set/change the description |
|
||||
| `->ignore_case()` | Ignore the case on the command line (also works on subcommands, does not affect arguments). |
|
||||
| `->ignore_underscore()` | Ignore any underscores on the command line (also works on subcommands, does not affect arguments). |
|
||||
| `->allow_extra_args()` | Allow extra argument values to be included when an option is passed. Enabled by default for vector options. |
|
||||
| `->disable_flag_override()` | specify that flag options cannot be overridden on the command line use `=<newval>` |
|
||||
| `->delimiter('<CH>')` | specify a character that can be used to separate elements in a command line argument, default is <none>, common values are ',', and ';' |
|
||||
| `->multi_option_policy( CLI::MultiOptionPolicy::Throw)` | Sets the policy for handling multiple arguments if the option was received on the command line several times. `Throw`ing an error is the default, but `TakeLast`, `TakeFirst`, `TakeAll`, `Join`, and `Sum` are also available. See the next four lines for shortcuts to set this more easily. |
|
||||
| `->take_last()` | Only use the last option if passed several times. This is always true by default for bool options, regardless of the app default, but can be set to false explicitly with `->multi_option_policy()`. |
|
||||
| `->take_first()` | sets `->multi_option_policy(CLI::MultiOptionPolicy::TakeFirst)` |
|
||||
| `->take_all()` | sets `->multi_option_policy(CLI::MultiOptionPolicy::TakeAll)` |
|
||||
| `->join()` | sets `->multi_option_policy(CLI::MultiOptionPolicy::Join)`, which uses newlines or the specified delimiter to join all arguments into a single string output. |
|
||||
| `->join(delim)` | sets `->multi_option_policy(CLI::MultiOptionPolicy::Join)`, which uses `delim` to join all arguments into a single string output. this also sets the delimiter |
|
||||
| `->check(Validator)` | perform a check on the returned results to verify they meet some criteria. See [Validators](./validators.md) for more info |
|
||||
| `->transform(Validator)` | Run a transforming validator on each value passed. See [Validators](./validators.md) for more info |
|
||||
| `->each(void(std::string))` | Run a function on each parsed value, _in order_. |
|
||||
| `->default_str(string)` | set a default string for use in the help and as a default value if no arguments are passed and a value is requested |
|
||||
| `->default_function(std::string())` | Advanced: Change the function that `capture_default_str()` uses. |
|
||||
| `->default_val(value)` | Generate the default string from a value and validate that the value is also valid. For options that assign directly to a value type the value in that type is also updated. Value must be convertible to a string(one of known types or have a stream operator). |
|
||||
| `->capture_default_str()` | Store the current value attached and display it in the help string. |
|
||||
| `->always_capture_default()` | Always run `capture_default_str()` when creating new options. Only useful on an App's `option_defaults`. |
|
||||
| `->run_callback_for_default()` | Force the option callback to be executed or the variable set when the `default_val` is used. |
|
||||
| `->force_callback()` | Force the option callback to be executed regardless of whether the option was used or not. Will use the default_str if available, if no default is given the callback will be executed with an empty string as an argument, which will translate to a default initialized value, which can be compiler dependent |
|
||||
| `->trigger_on_parse()` | Have the option callback be triggered when the value is parsed vs. at the end of all parsing, the option callback can potentially be executed multiple times. Generally only useful if you have a user defined callback or validation check. Or potentially if a vector input is given multiple times as it will clear the results when a repeat option is given via command line. It will trigger the callbacks once per option call on the command line |
|
||||
| `->option_text(string)` | Sets the text between the option name and description. |
|
||||
|
||||
The `->check(...)` and `->transform(...)` modifiers can also take a callback
|
||||
function of the form `bool function(std::string)` that runs on every value that
|
||||
the option receives, and returns a value that tells CLI11 whether the check
|
||||
passed or failed.
|
||||
|
||||
## Using the `CLI::Option` pointer
|
||||
|
||||
Each of the option creation mechanisms returns a pointer to the internally
|
||||
stored option. If you save that pointer, you can continue to access the option,
|
||||
and change setting on it later. The Option object can also be converted to a
|
||||
bool to see if it was passed, or `->count()` can be used to see how many times
|
||||
the option was passed. Since flags are also options, the same methods work on
|
||||
them.
|
||||
|
||||
```cpp
|
||||
CLI::Option* opt = app.add_flag("--opt");
|
||||
|
||||
CLI11_PARSE(app, argv, argc);
|
||||
|
||||
if(* opt)
|
||||
std::cout << "Flag received " << opt->count() << " times." << std::endl;
|
||||
```
|
||||
|
||||
## Inheritance of defaults
|
||||
|
||||
One of CLI11's systems to allow customizability without high levels of verbosity
|
||||
is the inheritance system. You can set default values on the parent `App`, and
|
||||
all options and subcommands created from it remember the default values at the
|
||||
point of creation. The default value for Options, specifically, are accessible
|
||||
through the `option_defaults()` method. There are a number of settings that can
|
||||
be set and inherited:
|
||||
|
||||
- `group`: The group name starts as "Options"
|
||||
- `required`: If the option must be given. Defaults to `false`. Is ignored for
|
||||
flags.
|
||||
- `multi_option_policy`: What to do if several copies of an option are passed
|
||||
and one value is expected. Defaults to `CLI::MultiOptionPolicy::Throw`. This
|
||||
is also used for bool flags, but they always are created with the value
|
||||
`CLI::MultiOptionPolicy::TakeLast` or `CLI::MultiOptionPolicy::Sum` regardless
|
||||
of the default, so that multiple bool flags does not cause an error. But you
|
||||
can override that setting by calling the `multi_option_policy` directly.
|
||||
- `ignore_case`: Allow any mixture of cases for the option or flag name
|
||||
- `ignore_underscore`: Allow any number of underscores in the option or flag
|
||||
name
|
||||
- `configurable`: Specify whether an option can be configured through a config
|
||||
file
|
||||
- `disable_flag_override`: do not allow flag values to be overridden on the
|
||||
command line
|
||||
- `always_capture_default`: specify that the default values should be
|
||||
automatically captured.
|
||||
- `delimiter`: A delimiter to use for capturing multiple values in a single
|
||||
command line string (e.g. --flag="flag,-flag2,flag3")
|
||||
|
||||
An example of usage:
|
||||
|
||||
```cpp
|
||||
app.option_defaults()->ignore_case()->group("Required");
|
||||
|
||||
app.add_flag("--CaSeLeSs");
|
||||
app.get_group() // is "Required"
|
||||
```
|
||||
|
||||
Groups are mostly for visual organization, but an empty string for a group name
|
||||
will hide the option.
|
||||
|
||||
### Windows style options
|
||||
|
||||
You can also set the app setting `app->allow_windows_style_options()` to allow
|
||||
windows style options to also be recognized on the command line:
|
||||
|
||||
- `/a` (flag)
|
||||
- `/f filename` (option)
|
||||
- `/long` (long flag)
|
||||
- `/file filename` (space)
|
||||
- `/file:filename` (colon)
|
||||
- `/long_flag:false` (long flag with : to override the default value)
|
||||
|
||||
Windows style options do not allow combining short options or values not
|
||||
separated from the short option like with `-` options. You still specify option
|
||||
names in the same manner as on Linux with single and double dashes when you use
|
||||
the `add_*` functions, and the Linux style on the command line will still work.
|
||||
If a long and a short option share the same name, the option will match on the
|
||||
first one defined.
|
||||
|
||||
## Parse configuration
|
||||
|
||||
How an option and its arguments are parsed depends on a set of controls that are
|
||||
part of the option structure. In most circumstances these controls are set
|
||||
automatically based on the type or function used to create the option and the
|
||||
type the arguments are parsed into. The variables define the size of the
|
||||
underlying type (essentially how many strings make up the type), the expected
|
||||
size (how many groups are expected) and a flag indicating if multiple groups are
|
||||
allowed with a single option. And these interact with the `multi_option_policy`
|
||||
when it comes time to parse.
|
||||
|
||||
### Examples
|
||||
|
||||
How options manage this is best illustrated through some examples.
|
||||
|
||||
```cpp
|
||||
std::string val;
|
||||
app.add_option("--opt",val,"description");
|
||||
```
|
||||
|
||||
creates an option that assigns a value to a `std::string` When this option is
|
||||
constructed it sets a type_size min and max of 1. Meaning that the assignment
|
||||
uses a single string. The Expected size is also set to 1 by default, and
|
||||
`allow_extra_args` is set to false. meaning that each time this option is called
|
||||
1 argument is expected. This would also be the case if val were a `double`,
|
||||
`int` or any other single argument types.
|
||||
|
||||
now for example
|
||||
|
||||
```cpp
|
||||
std::pair<int, std::string> val;
|
||||
app.add_option("--opt",val,"description");
|
||||
```
|
||||
|
||||
In this case the typesize is automatically detected to be 2 instead of 1, so the
|
||||
parsing would expect 2 arguments associated with the option.
|
||||
|
||||
```cpp
|
||||
std::vector<int> val;
|
||||
app.add_option("--opt",val,"description");
|
||||
```
|
||||
|
||||
detects a type size of 1, since the underlying element type is a single string,
|
||||
so the minimum number of strings is 1. But since it is a vector the expected
|
||||
number can be very big. The default for a vector is (1<<30), and the
|
||||
allow_extra_args is set to true. This means that at least 1 argument is expected
|
||||
to follow the option, but arbitrary numbers of arguments may follow. These are
|
||||
checked if they have the form of an option but if not they are added to the
|
||||
argument.
|
||||
|
||||
```cpp
|
||||
std::vector<std::tuple<int, double, std::string>> val;
|
||||
app.add_option("--opt",val,"description");
|
||||
```
|
||||
|
||||
gets into the complicated cases where the type size is now 3. and the expected
|
||||
max is set to a large number and `allow_extra_args` is set to true. In this case
|
||||
at least 3 arguments are required to follow the option, and subsequent groups
|
||||
must come in groups of three, otherwise an error will result.
|
||||
|
||||
```cpp
|
||||
bool val{false};
|
||||
app.add_flag("--opt",val,"description");
|
||||
```
|
||||
|
||||
Using the add_flag methods for creating options creates an option with an
|
||||
expected size of 0, implying no arguments can be passed.
|
||||
|
||||
```cpp
|
||||
std::complex<double> val;
|
||||
app.add_option("--opt",val,"description");
|
||||
```
|
||||
|
||||
triggers the complex number type which has a min of 1 and max of 2, so 1 or 2
|
||||
strings can be passed. Complex number conversion supports arguments of the form
|
||||
"1+2j" or "1","2", or "1" "2i". The imaginary number symbols `i` and `j` are
|
||||
interchangeable in this context.
|
||||
|
||||
```cpp
|
||||
std::vector<std::vector<int>> val;
|
||||
app.add_option("--opt",val,"description");
|
||||
```
|
||||
|
||||
has a type size of 1 to (1<<30).
|
||||
|
||||
### Customization
|
||||
|
||||
The `type_size(N)`, `type_size(Nmin, Nmax)`, `expected(N)`,
|
||||
`expected(Nmin,Nmax)`, and `allow_extra_args()` can be used to customize an
|
||||
option. For example
|
||||
|
||||
```cpp
|
||||
std::string val;
|
||||
auto opt=app.add_flag("--opt{vvv}",val,"description");
|
||||
opt->expected(0,1);
|
||||
```
|
||||
|
||||
will create a hybrid option, that can exist on its own in which case the value
|
||||
"vvv" is used or if a value is given that value will be used.
|
||||
|
||||
There are some additional options that can be specified to modify an option for
|
||||
specific cases:
|
||||
|
||||
- `->run_callback_for_default()` will specify that the callback should be
|
||||
executed when a default_val is set. This is set automatically when appropriate
|
||||
though it can be turned on or off and any user specified callback for an
|
||||
option will be executed when the default value for an option is set.
|
||||
|
||||
- `->force_callback()` will for the callback/value assignment to run at the
|
||||
conclusion of parsing regardless of whether the option was supplied or not.
|
||||
This can be used to force the default or execute some code.
|
||||
|
||||
- `->trigger_on_parse()` will trigger the callback or value assignment each time
|
||||
the argument is passed. The value is reset if the option is supplied multiple
|
||||
times.
|
||||
|
||||
## Unusual circumstances
|
||||
|
||||
There are a few cases where some things break down in the type system managing
|
||||
options and definitions. Using the `add_option` method defines a lambda function
|
||||
to extract a default value if required. In most cases this is either
|
||||
straightforward or a failure is detected automatically and handled. But in a few
|
||||
cases a streaming template is available that several layers down may not
|
||||
actually be defined. This results in CLI11 not being able to detect this
|
||||
circumstance automatically and will result in compile error. One specific known
|
||||
case is `boost::optional` if the boost optional_io header is included. This
|
||||
header defines a template for all boost optional values even if they do not
|
||||
actually have a streaming operator. For example `boost::optional<std::vector>`
|
||||
does not have a streaming operator but one is detected since it is part of a
|
||||
template. For these cases a secondary method `app->add_option_no_stream(...)` is
|
||||
provided that bypasses this operation completely and should compile in these
|
||||
cases.
|
||||
194
libs/CLI11/book/chapters/subcommands.md
Normal file
194
libs/CLI11/book/chapters/subcommands.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# Subcommands and the App
|
||||
|
||||
Subcommands are keyword that invoke a new set of options and features. For
|
||||
example, the `git` command has a long series of subcommands, like `add` and
|
||||
`commit`. Each can have its own options and implementations. This chapter will
|
||||
focus on implementations that are contained in the same C++ application, though
|
||||
the system git uses to extend the main command by calling other commands in
|
||||
separate executables is supported too; that's called "Prefix commands" and is
|
||||
included at the end of this chapter.
|
||||
|
||||
## The parent App
|
||||
|
||||
We'll start by discussing the parent `App`. You've already used it quite a bit,
|
||||
to create options and set option defaults. There are several other things you
|
||||
can do with an `App`, however.
|
||||
|
||||
You are given a lot of control the help output. You can set a footer with
|
||||
`app.footer("My Footer")`. You can replace the default help print when a
|
||||
`ParseError` is thrown with
|
||||
`app.set_failure_message(CLI::FailureMessage::help)`. The default is
|
||||
`CLI:::FailureMessage::simple`, and you can easily define a new one. Just make a
|
||||
(lambda) function that takes an App pointer and a reference to an error code
|
||||
(even if you don't use them), and returns a string.
|
||||
|
||||
## Adding a subcommand
|
||||
|
||||
Subcommands can be added just like an option:
|
||||
|
||||
```cpp
|
||||
CLI::App* sub = app.add_subcommand("sub", "This is a subcommand");
|
||||
```
|
||||
|
||||
The subcommand should have a name as the first argument, and a little
|
||||
description for the second argument. A pointer to the internally stored
|
||||
subcommand is provided; you usually will be capturing that pointer and using it
|
||||
later (though you can use callbacks if you prefer). As always, feel free to use
|
||||
`auto sub = ...` instead of naming the type.
|
||||
|
||||
You can check to see if the subcommand was received on the command line several
|
||||
ways:
|
||||
|
||||
```cpp
|
||||
if(*sub) ...
|
||||
if(sub->parsed()) ...
|
||||
if(app.got_subcommand(sub)) ...
|
||||
if(app.got_subcommand("sub")) ...
|
||||
```
|
||||
|
||||
You can also get a list of subcommands with `get_subcommands()`, and they will
|
||||
be in parsing order.
|
||||
|
||||
There are a lot of options that you can set on a subcommand; in fact,
|
||||
subcommands have exactly the same options as your main app, since they are
|
||||
actually the same class of object (as you may have guessed from the type above).
|
||||
This has the pleasant side affect of making subcommands infinitely nestable.
|
||||
|
||||
## Required subcommands
|
||||
|
||||
Each App has controls to set the number of subcommands you expect. This is
|
||||
controlled by:
|
||||
|
||||
```cpp
|
||||
app.require_subcommand(/* min */ 0, /* max */ 1);
|
||||
```
|
||||
|
||||
If you set the max to 0, CLI11 will allow an unlimited number of subcommands.
|
||||
After the (non-unlimited) maximum is reached, CLI11 will stop trying to match
|
||||
subcommands. So the if you pass "`one two`" to a command, and both `one` and
|
||||
`two` are subcommands, it will depend on the maximum number as to whether the
|
||||
"`two`" is a subcommand or an argument to the "`one`" subcommand.
|
||||
|
||||
As a shortcut, you can also call the `require_subcommand` method with one
|
||||
argument; that will be the fixed number of subcommands if positive, it will be
|
||||
the maximum number if negative. Calling it without an argument will set the
|
||||
required subcommands to 1 or more.
|
||||
|
||||
The maximum number of subcommands is inherited by subcommands. This allows you
|
||||
to set the maximum to 1 once at the beginning on the parent app if you only want
|
||||
single subcommands throughout your app. You should keep this in mind, if you are
|
||||
dealing with lots of nested subcommands.
|
||||
|
||||
## Using callbacks
|
||||
|
||||
You've already seen how to check to see what subcommands were given. It's often
|
||||
much easier, however, to just define the code you want to run when you are
|
||||
making your parser, and not run a bunch of code after `CLI11_PARSE` to analyse
|
||||
the state (Procedural! Yuck!). You can do that with lambda functions. A
|
||||
`std::function<void()>` callback `.callback()` is provided, and CLI11 ensures
|
||||
that all options are prepared and usable by reference capture before entering
|
||||
the callback. An example is shown below in the `geet` program.
|
||||
|
||||
## Inheritance of defaults
|
||||
|
||||
The following values are inherited when you add a new subcommand. This happens
|
||||
at the point the subcommand is created:
|
||||
|
||||
- The name and description for the help flag
|
||||
- The footer
|
||||
- The failure message printer function
|
||||
- Option defaults
|
||||
- Allow extras
|
||||
- Prefix command
|
||||
- Ignore case
|
||||
- Ignore underscore
|
||||
- Allow Windows style options
|
||||
- Fallthrough
|
||||
- Group name
|
||||
- Max required subcommands
|
||||
- validate positional arguments
|
||||
- validate optional arguments
|
||||
|
||||
## Special modes
|
||||
|
||||
There are several special modes for Apps and Subcommands.
|
||||
|
||||
### Allow extras
|
||||
|
||||
Normally CLI11 throws an error if you don't match all items given on the command
|
||||
line. However, you can enable `allow_extras()` to instead store the extra values
|
||||
in `.remaining()`. You can get all remaining options including those in
|
||||
contained subcommands recursively in the original order with `.remaining(true)`.
|
||||
`.remaining_size()` is also provided; this counts the size but ignores the `--`
|
||||
special separator if present.
|
||||
|
||||
### Fallthrough
|
||||
|
||||
Fallthrough allows an option that does not match in a subcommand to "fall
|
||||
through" to the parent command; if that parent allows that option, it matches
|
||||
there instead. This was added to allow CLI11 to represent models:
|
||||
|
||||
```term
|
||||
gitbook:code $ ./my_program my_model_1 --model_flag --shared_flag
|
||||
```
|
||||
|
||||
Here, `--shared_flag` was set on the main app, and on the command line it "falls
|
||||
through" `my_model_1` to match on the main app.
|
||||
|
||||
### Prefix command
|
||||
|
||||
This is a special mode that allows "prefix" commands, where the parsing
|
||||
completely stops when it gets to an unknown option. Further unknown options are
|
||||
ignored, even if they could match. Git is the traditional example for prefix
|
||||
commands; if you run git with an unknown subcommand, like "`git thing`", it then
|
||||
calls another command called "`git-thing`" with the remaining options intact.
|
||||
|
||||
### Silent subcommands
|
||||
|
||||
Subcommands can be modified by using the `silent` option. This will prevent the
|
||||
subcommand from showing up in the get_subcommands list. This can be used to make
|
||||
subcommands into modifiers. For example, a help subcommand might look like
|
||||
|
||||
```c++
|
||||
auto sub1 = app.add_subcommand("help")->silent();
|
||||
sub1->parse_complete_callback([]() { throw CLI::CallForHelp(); });
|
||||
```
|
||||
|
||||
This would allow calling help such as:
|
||||
|
||||
```bash
|
||||
./app help
|
||||
./app help sub1
|
||||
```
|
||||
|
||||
### Positional Validation
|
||||
|
||||
Some arguments supplied on the command line may be legitamately applied to more
|
||||
than 1 positional argument. In this context enabling `positional_validation` on
|
||||
the application or subcommand will check any validators before applying the
|
||||
command line argument to the positional option. It is not an error to fail
|
||||
validation in this context, positional arguments not matching any validators
|
||||
will go into the `extra_args` field which may generate an error depending on
|
||||
settings.
|
||||
|
||||
### Optional Argument Validation
|
||||
|
||||
Similar to positional validation, there are occasional contexts in which case it
|
||||
might be ambiguous whether an argument should be applied to an option or a
|
||||
positional option.
|
||||
|
||||
```c++
|
||||
std::vector<std::string> vec;
|
||||
std::vector<int> ivec;
|
||||
app.add_option("pos", vec);
|
||||
app.add_option("--args", ivec)->check(CLI::Number);
|
||||
app.validate_optional_arguments();
|
||||
```
|
||||
|
||||
In this case a sequence of integers is expected for the argument and remaining
|
||||
strings go to the positional string vector. Without the
|
||||
`validate_optional_arguments()` active it would be impossible get any later
|
||||
arguments into the positional if the `--args` option is used. The validator in
|
||||
this context is used to make sure the optional arguments match with what the
|
||||
argument is expecting and if not the `-args` option is closed, and remaining
|
||||
arguments fall into the positional.
|
||||
40
libs/CLI11/book/chapters/toolkits.md
Normal file
40
libs/CLI11/book/chapters/toolkits.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Using CLI11 in a Toolkit
|
||||
|
||||
CLI11 was designed to be integrate into a toolkit, providing a native experience
|
||||
for users. This was used in GooFit to provide `GooFit::Application`, an class
|
||||
designed to make ROOT users feel at home.
|
||||
|
||||
## Custom namespace
|
||||
|
||||
If you want to provide CLI11 in a custom namespace, you'll want to at least put
|
||||
`using CLI::App` in your namespace. You can also include Option, some errors,
|
||||
and validators. You can also put `using namespace CLI` inside your namespace to
|
||||
import everything.
|
||||
|
||||
You may also want to make your own copy of the `CLI11_PARSE` macro. Something
|
||||
like:
|
||||
|
||||
```cpp
|
||||
#define MYPACKAGE_PARSE(app, argv, argc) \
|
||||
try { \
|
||||
app.parse(argv, argc); \
|
||||
} catch(const CLI::ParseError &e) { \
|
||||
return app.exit(e); \
|
||||
}
|
||||
```
|
||||
|
||||
## Subclassing App
|
||||
|
||||
If you subclass `App`, you'll just need to do a few things. You'll need a
|
||||
constructor; calling the base `App` constructor is a good idea, but not
|
||||
necessary (it just sets a description and adds a help flag.
|
||||
|
||||
You can call anything you would like to configure in the constructor, like
|
||||
`option_defaults()->take_last()` or `fallthrough()`, and it will be set on all
|
||||
user instances. You can add flags and options, as well.
|
||||
|
||||
## Virtual functions provided
|
||||
|
||||
You are given a few virtual functions that you can change (only on the main
|
||||
App). `pre_callback` runs right before the callbacks run, letting you print out
|
||||
custom messages at the top of your app.
|
||||
66
libs/CLI11/book/chapters/validators.md
Normal file
66
libs/CLI11/book/chapters/validators.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Validators
|
||||
|
||||
There are two forms of validators:
|
||||
|
||||
- `transform` validators: mutating
|
||||
- `check` validators: non-mutating (recommended unless the parsed string must be
|
||||
mutated)
|
||||
|
||||
A transform validator comes in one form, a function with the signature
|
||||
`std::string(std::string)`. The function will take a string and return the
|
||||
modified version of the string. If there is an error, the function should throw
|
||||
a `CLI::ValidationError` with the appropriate reason as a message.
|
||||
|
||||
However, `check` validators come in two forms; either a simple function with the
|
||||
const version of the above signature, `std::string(const std::string &)`, or a
|
||||
subclass of `struct CLI::Validator`. This structure has two members that a user
|
||||
should set; one (`func_`) is the function to add to the Option (exactly matching
|
||||
the above function signature, since it will become that function), and the other
|
||||
is `name_`, and is the type name to set on the Option (unless empty, in which
|
||||
case the typename will be left unchanged).
|
||||
|
||||
Validators can be combined with `&` and `|`, and they have an `operator()` so
|
||||
that you can call them as if they were a function. In CLI11, const static
|
||||
versions of the validators are provided so that the user does not have to call a
|
||||
constructor also.
|
||||
|
||||
An example of a custom validator:
|
||||
|
||||
```cpp
|
||||
struct LowerCaseValidator : public Validator {
|
||||
LowerCaseValidator() {
|
||||
name_ = "LOWER";
|
||||
func_ = [](const std::string &str) {
|
||||
if(CLI::detail::to_lower(str) != str)
|
||||
return std::string("String is not lower case");
|
||||
else
|
||||
return std::string();
|
||||
};
|
||||
}
|
||||
};
|
||||
const static LowerCaseValidator Lowercase;
|
||||
```
|
||||
|
||||
If you were not interested in the extra features of Validator, you could simply
|
||||
pass the lambda function above to the `->check()` method of `Option`.
|
||||
|
||||
The built-in validators for CLI11 are:
|
||||
|
||||
| Validator | Description |
|
||||
| ------------------- | ---------------------------------------------------------------------- |
|
||||
| `ExistingFile` | Check for existing file (returns error message if check fails) |
|
||||
| `ExistingDirectory` | Check for an existing directory (returns error message if check fails) |
|
||||
| `ExistingPath` | Check for an existing path |
|
||||
| `NonexistentPath` | Check for an non-existing path |
|
||||
| `Range(min=0, max)` | Produce a range (factory). Min and max are inclusive. |
|
||||
|
||||
And, the protected members that you can set when you make your own are:
|
||||
|
||||
| Type | Member | Description |
|
||||
| ------------------------------------------- | -------------------- | ---------------------------------------------------------------------- |
|
||||
| `std::function<std::string(std::string &)>` | `func_` | Core validation function - modifies input and returns "" if successful |
|
||||
| `std::function<std::string()>` | `desc_function` | Optional description function (uses `description_` instead if not set) |
|
||||
| `std::string` | `name_` | The name for search purposes |
|
||||
| `int` (`-1`) | `application_index_` | The element this validator applies to (-1 for all) |
|
||||
| `bool` (`true`) | `active_` | This can be disabled |
|
||||
| `bool` (`false`) | `non_modifying_` | Specify that this is a Validator instead of a Transformer |
|
||||
Reference in New Issue
Block a user