diff --git a/README.md b/README.md index fb0ceb72..3ab6a3eb 100644 --- a/README.md +++ b/README.md @@ -714,7 +714,7 @@ 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`, `yes`, `enable`; or `false`, `off`, `0`, `no`, `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"). You cannot set positional-only arguments. 🆕 Subcommands can be triggered from configuration files if the `configurable` flag was set on the subcommand. Then the use of `[subcommand]` notation will trigger a subcommand and cause it to act as if it were on the command line. To print a configuration file from the passed -arguments, use `.config_to_str(default_also=false, prefix="", write_description=false)`, where `default_also` will also show any defaulted arguments, `prefix` will add a prefix, and `write_description` will include option descriptions. See [Config files](https://cliutils.github.io/CLI11/book/chapters/config.html) for some additional details. +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 the app and option descriptions. See [Config files](https://cliutils.github.io/CLI11/book/chapters/config.html) for some additional details. ### Inheriting defaults diff --git a/book/chapters/config.md b/book/chapters/config.md index 50a1bfcd..a9edf9aa 100644 --- a/book/chapters/config.md +++ b/book/chapters/config.md @@ -80,7 +80,27 @@ The main differences are in vector notation and comment character. Note: CLI11 ## Writing out a configure file -To print a configuration file from the passed arguments, use `.config_to_str(default_also=false, prefix="", write_description=false)`, where `default_also` will also show any defaulted arguments, `prefix` will add a prefix, and `write_description` will include option descriptions. +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<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 @@ -115,14 +135,10 @@ The default configuration file will read INI files, but will write out files in ```cpp app.config_formatter(std::make_shared()); ``` -which makes use of a predefined modification of the ConfigBase class which TOML also uses. +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, so some care must be exercised in its us with custom configurations. ## Custom formats -{% hint style='info' %} -New in CLI11 1.6 -{% endhint %} - 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 @@ -145,3 +161,11 @@ See [`examples/json.cpp`](https://github.com/CLIUtils/CLI11/blob/master/examples 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 +1. Positional name +1. First short name +1. Environment name diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 882046af..858ed595 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -1491,7 +1491,7 @@ class App { return this; } /// Produce a string that could be read in as a config of the current values of the App. Set default_also to - /// include default arguments. Prefix will add a string to the beginning of each option. + /// include default arguments. write_descriptions will print a description for the App and for each option. std::string config_to_str(bool default_also = false, bool write_description = false) const { return config_formatter_->to_config(this, default_also, write_description, ""); } @@ -2335,6 +2335,14 @@ class App { return true; } Option *op = get_option_no_throw("--" + item.name); + if(op == nullptr) { + if(item.name.size() == 1) { + op = get_option_no_throw("-" + item.name); + } + } + if(op == nullptr) { + op = get_option_no_throw(item.name); + } if(op == nullptr) { // If the option was not present if(get_allow_config_extras() == config_extras_mode::capture) diff --git a/include/CLI/Config.hpp b/include/CLI/Config.hpp index 57bb273e..8ef40552 100644 --- a/include/CLI/Config.hpp +++ b/include/CLI/Config.hpp @@ -282,14 +282,14 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description, } for(const Option *opt : app->get_options({})) { - // Only process option with a long-name and configurable - if(!opt->get_lnames().empty() && opt->get_configurable()) { + // Only process options that are configurable + if(opt->get_configurable()) { if(opt->get_group() != group) { if(!(group == "Options" && opt->get_group().empty())) { continue; } } - std::string name = prefix + opt->get_lnames()[0]; + std::string name = prefix + opt->get_single_name(); std::string value = detail::ini_join(opt->reduced_results(), arraySeparator, arrayStart, arrayEnd); if(value.empty() && default_also) { diff --git a/include/CLI/Option.hpp b/include/CLI/Option.hpp index 2e029303..64cece5a 100644 --- a/include/CLI/Option.hpp +++ b/include/CLI/Option.hpp @@ -300,7 +300,7 @@ class Option : public OptionBase