Commit f4ba69223a8aef627132dd3e98a47c1d604b38a0

Authored by Henry Fredrick Schreiner
1 parent b774c57d

Adding example for group and documentation

CHANGELOG.md
1 1 ## Version 0.3 (in progress)
2 2  
  3 +* More tests for Help strings, improvements in formatting
  4 +* Support type and set syntax in positionals help strings
  5 +* Added help groups, with `->group("name")` syntax
  6 +* Added initial support for ini file reading with `add_config` option.
3 7 * Supports GCC 4.7 again
4   -* Support type and set syntax in positionals
5 8 * Changes `setup` for an explicit help bool in constructor/`add_subcommand`
6 9  
7 10  
... ...
README.md
... ... @@ -81,12 +81,19 @@ app.add_set(option_name,
81 81 help_string="",
82 82 default=false)
83 83  
  84 +app.add_config(option_name,
  85 + default_file_name="",
  86 + help_string="Read an ini file",
  87 + required=false)
  88 +
84 89 App* subcom = app.add_subcommand(name, discription);
85 90  
86 91 ```
87 92  
88 93 An option name must start with a alphabetic character or underscore. For long options, anything but an equals sign or a comma is valid after that. Names are given as a comma separated string, with the dash or dashes. An option or flag 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 help line for its positional form.
89 94  
  95 +Adding a configuration option is special. If it is present, it will be read along with the normal command line arguments. The file will be read if it exists, and does not throw an error unless required is `true`.
  96 +
90 97 > ### Example
91 98 >
92 99 > * `"one,-o,--one"`: Valid as long as not a flag, would create an option that can be specified positionally, or with `-o` or `--option`
... ... @@ -98,11 +105,12 @@ The add commands return a pointer to an internally stored `Option`. If you set t
98 105  
99 106 * `->required()`: The program will quit if this option is not present
100 107 * `->expected(N)`: Take `N` values instead of as many as possible, only for vector args
  108 +* `->group(name)`: The help group to put the option in. No effect for positional options. Defaults to `"Options"`.
101 109 * `->check(CLI::ExistingFile)`: Requires that the file exists if given
102 110 * `->check(CLI::ExistingDirectory)`: Requires that the directory exists
103 111 * `->check(CLI::NonexistentPath)`: Requires that the path does not exist
104 112  
105   -These options return the `Option` pointer, so you can chain them together, and even skip storing the pointer entirely. Check takes any function that has the signature `bool(std::string)`.
  113 +These options return the `Option` pointer, so you can chain them together, and even skip storing the pointer entirely. Check takes any function that has the signature `bool(std::string)`. If you want to change the default help option, it is available through `get_help_ptr`.
106 114  
107 115  
108 116 On the command line, options can be given as:
... ...
examples/CMakeLists.txt
1 1 add_executable(try try.cpp)
2 2 target_link_libraries(try PUBLIC CLI)
  3 +
3 4 add_executable(try1 try1.cpp)
4 5 target_link_libraries(try1 PUBLIC CLI)
  6 +
  7 +add_executable(try2 try2.cpp)
  8 +target_link_libraries(try2 PUBLIC CLI)
... ...
examples/try2.cpp 0 → 100644
  1 +#include "CLI/CLI.hpp"
  2 +
  3 +
  4 +int main (int argc, char** argv) {
  5 +
  6 + CLI::App app("K3Pi goofit fitter");
  7 +
  8 + std::string file;
  9 + CLI::Option* opt = app.add_option("-f,--file,file", file, "File name")
  10 + ->required()->group("Important");
  11 +
  12 + int count;
  13 + CLI::Option* copt = app.add_flag("-c,--count", count, "Counter")
  14 + ->required()->group("Important");
  15 +
  16 + double value;// = 3.14;
  17 + app.add_option("-d,--double", value, "Some Value")
  18 + ->group("Other");
  19 +
  20 + try {
  21 + app.run(argc, argv);
  22 + } catch (const CLI::Error &e) {
  23 + return app.exit(e);
  24 + }
  25 +
  26 + std::cout << "Working on file: " << file
  27 + << ", direct count: " << app.count("--file")
  28 + << ", opt count: " << opt->count()
  29 + << std::endl;
  30 + std::cout << "Working on count: " << count
  31 + << ", direct count: " << app.count("--count")
  32 + << ", opt count: " << copt->count()
  33 + << std::endl;
  34 + std::cout << "Some value: " << value << std::endl;
  35 +
  36 + return 0;
  37 +}
... ...
include/CLI/App.hpp
... ... @@ -84,6 +84,17 @@ public:
84 84 app->reset();
85 85 }
86 86 }
  87 +
  88 + /// Get a pointer to the help flag.
  89 + Option* get_help_ptr() {
  90 + return help_flag;
  91 + }
  92 +
  93 + /// Get a pointer to the config option.
  94 + Option* get_config_ptr() {
  95 + return ini_setting;
  96 + }
  97 +
87 98  
88 99 /// Create a new program. Pass in the same arguments as main(), along with a help string.
89 100 App(std::string prog_description="", bool help=true)
... ... @@ -290,22 +301,29 @@ public:
290 301  
291 302  
292 303 /// Add a configuration ini file option
293   - void add_config(std::string name="--config",
  304 + Option* add_config(std::string name="--config",
294 305 std::string default_filename="",
295 306 std::string help="Read an ini file",
296 307 bool required=false) {
297 308  
298 309 // Remove existing config if present
299   - if(ini_setting != nullptr) {
300   - auto iterator = std::find_if(std::begin(options), std::end(options),
301   - [this](const Option_p &v){return v.get() == ini_setting;});
302   - if (iterator != std::end(options)) {
303   - options.erase(iterator);
304   - }
305   - }
  310 + if(ini_setting != nullptr)
  311 + remove_option(ini_setting);
306 312 ini_file = default_filename;
307 313 ini_required = required;
308 314 ini_setting = add_option(name, ini_file, help, default_filename!="");
  315 + return ini_setting;
  316 + }
  317 +
  318 + /// Removes an option from the App. Takes an option pointer. Returns true if found and removed.
  319 + bool remove_option(Option* opt) {
  320 + auto iterator = std::find_if(std::begin(options), std::end(options),
  321 + [opt](const Option_p &v){return v.get() == opt;});
  322 + if (iterator != std::end(options)) {
  323 + options.erase(iterator);
  324 + return true;
  325 + }
  326 + return false;
309 327 }
310 328  
311 329 /// This allows subclasses to inject code before callbacks but after parse
... ...