style: add mdlint

This commit is contained in:
Henry Schreiner
2021-07-19 12:16:51 -04:00
committed by Henry Schreiner
parent f27f6f2070
commit 4698131216
15 changed files with 390 additions and 363 deletions

View File

@@ -1,6 +1,5 @@
# Advanced topics
## Environment variables
Environment variables can be used to fill in the value of an option:
@@ -9,6 +8,7 @@ Environment variables can be used to fill in the value of an option:
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.
@@ -55,7 +55,7 @@ add_option(CLI::App &app, std::string name, cx &variable, std::string descriptio
Then you could use it like this:
```
```cpp
std::complex<double> comp{0, 0};
add_option(app, "-c,--complex", comp);
```
@@ -89,7 +89,6 @@ template <typename T> std::istringstream &operator>>(std::istringstream &in, boo
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:
@@ -97,40 +96,40 @@ 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::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;
}
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]";
}
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]";
}
template <>
constexpr const char *type_name<std::chrono::minutes>()
{
return "TIME [MIN]";
}
}
}
```

View File

@@ -1,7 +1,5 @@
# 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)

View File

@@ -5,36 +5,42 @@
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.
### 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
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);`
### 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.
@@ -93,7 +99,6 @@ Where X is some positive integer and will allow up to `X` configuration files to
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
@@ -105,7 +110,6 @@ To print a configuration file from the passed arguments, use `.config_to_str(def
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.");
@@ -113,7 +117,9 @@ if a prefix is needed to print before the options, for example to print a config
```
### 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
```cpp
/// the character used for comments
char commentChar = '#';
@@ -129,12 +135,12 @@ char valueDelimiter = '=';
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 *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
For example to specify reading a configure file that used `:` to separate name and values
For example, to specify reading a configure file that used `:` to separate name and values:
```cpp
auto config_base=app.get_config_formatter_base();
@@ -142,9 +148,11 @@ 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
@@ -166,16 +174,17 @@ app.config_formatter(std::make_shared<NewConfig>());
See [`examples/json.cpp`](https://github.com/CLIUtils/CLI11/blob/master/examples/json.cpp) for a complete JSON config example.
## 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.
## 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 a name in following priority.
1. First long name
2. Positional name
3. First short name
4. Environment name
1. First long name
2. Positional name
3. First short name
4. Environment name

View File

@@ -13,7 +13,6 @@ 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.
## Integer flags
If you want to allow multiple flags, simply use any integer-like instead of a bool:
@@ -70,7 +69,6 @@ auto callback = [](int count){std::cout << "This was called " << count << " time
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).
@@ -122,5 +120,4 @@ 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.

View File

@@ -4,13 +4,12 @@
New in CLI11 1.6
{% endhint %}
## Customizing an existing formatter
## 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 |
@@ -60,7 +59,7 @@ This is a normal printout, with `<>` indicating the methods used to produce each
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

View File

@@ -1,8 +1,8 @@
# Options
## Simple options
The most versatile addition to a command line program is a 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:
The most versatile addition to a command line program is a 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};
@@ -73,6 +73,7 @@ Vectors will be replaced by the parsed content if the option is given on the com
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.
### Containers of containers
Containers of containers are also supported.
```cpp
@@ -85,6 +86,7 @@ CLI11 inserts a separator sequence at the start of each argument call to separat
```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
@@ -99,7 +101,9 @@ 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
Types can be nested. For example:
```cpp
std::map<int, std::pair<int,std::string>> map;
app.add_option("--dict", map, "map of pairs");
@@ -111,6 +115,7 @@ will require 3 arguments for each invocation, and multiple sets of 3 arguments c
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
@@ -166,19 +171,19 @@ if(* opt)
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` regardless of the default, so that multiple bool flags does not cause an error. But you can override that flag by flag.
* `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")
* `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` regardless of the default, so that multiple bool flags does not cause an error. But you can override that flag by flag.
* `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");
@@ -187,17 +192,16 @@ 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)
* `/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.
@@ -205,15 +209,19 @@ Windows style options do not allow combining short options or values not separat
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
### 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");
@@ -232,6 +240,7 @@ detects a type size of 1, since the underlying element type is a single string,
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
@@ -248,11 +257,11 @@ 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
@@ -264,10 +273,13 @@ 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.
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.
## 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 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. The conditions in CLI11 cannot 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 no 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.

View File

@@ -53,6 +53,7 @@ Each App has controls to set the number of subcommands you expect. This is contr
```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

View File

@@ -2,7 +2,7 @@
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
## 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.
@@ -17,14 +17,12 @@ You may also want to make your own copy of the `CLI11_PARSE` macro. Something li
}
```
# Subclassing App
## 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
## 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.

View File

@@ -49,7 +49,6 @@ The built-in validators for CLI11 are:
| `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 |