1
0
mirror of https://github.com/CLIUtils/CLI11.git synced 2025-01-15 06:38:02 +00:00

Compare commits

...

3 Commits

Author SHA1 Message Date
Philip Top
25cca2dcb9
docs: add custom parse example (#603) 2021-06-17 17:44:19 -04:00
Philip Top
a8ef5b8d2f
fix: avoid printing description for non configurable subcommand (#604) 2021-06-17 17:42:53 -04:00
Philip Top
2fa8cae9e8
feat: add changeable help message string to version (#601)
add an optional help message string to the version_add flag if desired to override
2021-06-17 12:04:55 -04:00
7 changed files with 92 additions and 11 deletions

View File

@ -599,6 +599,7 @@ There are several options that are supported on the main app and subcommands and
- `.footer(message)`: Set text to appear at the bottom of the help string.
- `.footer(std::string())`: 🆕 Set a callback to generate a string that will appear at the end of the help string.
- `.set_help_flag(name, message)`: Set the help flag name and message, returns a pointer to the created option.
- `.set_version_flag(name, versionString or callback, help_message)`: 🆕 Set the version flag name and version string or callback and optional help message, returns a pointer to the created option.
- `.set_help_all_flag(name, message)`: Set the help all flag name and message, returns a pointer to the created option. Expands subcommands.
- `.failure_message(func)`: Set the failure message function. Two provided: `CLI::FailureMessage::help` and `CLI::FailureMessage::simple` (the default).
- `.group(name)`: Set a group name, defaults to `"Subcommands"`. Setting `""` will be hide the subcommand.
@ -798,7 +799,7 @@ Every `add_` option you have seen so far depends on one method that takes a lamb
Other values can be added as long as they support `operator>>` (and defaults can be printed if they support `operator<<`). To add a new type, for example, provide a custom `operator>>` with an `istream` (inside the CLI namespace is fine if you don't want to interfere with an existing `operator>>`).
If you wanted to extend this to support a completely new type, use a lambda or add a specialization of the `lexical_cast` function template in the namespace `CLI::detail` with the type you need to convert to. Some examples of some new parsers for `complex<double>` that support all of the features of a standard `add_options` call are in [one of the tests](./tests/NewParseTest.cpp). A simpler example is shown below:
If you wanted to extend this to support a completely new type, use a lambda or add a specialization of the `lexical_cast` function template in the namespace of the type you need to convert to. Some examples of some new parsers for `complex<double>` that support all of the features of a standard `add_options` call are in [one of the tests](./tests/NewParseTest.cpp). A simpler example is shown below:
#### Example
@ -870,6 +871,7 @@ The API is [documented here][api-docs]. Also see the [CLI11 tutorial GitBook][gi
Several short examples of different features are included in the repository. A brief description of each is included here
- [callback_passthrough](https://github.com/CLIUtils/CLI11/blob/master/examples/callback_passthrough.cpp): Example of directly passing remaining arguments through to a callback function which generates a CLI11 application based on existing arguments.
- [custom_parse](https://github.com/CLIUtils/CLI11/blob/master/examples/custom_parse.cpp): Based on [Issue #566](https://github.com/CLIUtils/CLI11/issues/566), example of custom parser
- [digit_args](https://github.com/CLIUtils/CLI11/blob/master/examples/digit_args.cpp): Based on [Issue #123](https://github.com/CLIUtils/CLI11/issues/123), uses digit flags to pass a value
- [enum](https://github.com/CLIUtils/CLI11/blob/master/examples/enum.cpp): Using enumerations in an option, and the use of [CheckedTransformer](#transforming-validators)
- [enum_ostream](https://github.com/CLIUtils/CLI11/blob/master/examples/enum_ostream.cpp): In addition to the contents of example enum.cpp, this example shows how a custom ostream operator overrides CLI11's enum streaming.

View File

@ -242,3 +242,8 @@ set_property(TEST retired_retired_test2 PROPERTY PASS_REGULAR_EXPRESSION "WARNIN
set_property(TEST retired_retired_test3 PROPERTY PASS_REGULAR_EXPRESSION "WARNING.*retired")
set_property(TEST retired_deprecated PROPERTY PASS_REGULAR_EXPRESSION "deprecated.*not_deprecated")
#--------------------------------------------
add_cli_exe(custom_parse custom_parse.cpp)
add_test(NAME cp_test COMMAND custom_parse --dv 1.7)
set_property(TEST cp_test PROPERTY PASS_REGULAR_EXPRESSION "called correct")

39
examples/custom_parse.cpp Normal file
View File

@ -0,0 +1,39 @@
// Copyright (c) 2017-2020, University of Cincinnati, developed by Henry Schreiner
// under NSF AWARD 1414736 and by the respective contributors.
// All rights reserved.
//
// SPDX-License-Identifier: BSD-3-Clause
// from Issue #566 on github https://github.com/CLIUtils/CLI11/issues/566
#include <CLI/CLI.hpp>
#include <iostream>
#include <sstream>
// example file to demonstrate a custom lexical cast function
template <class T = int> struct Values {
T a;
T b;
T c;
};
// in C++20 this is constructible from a double due to the new aggregate initialization in C++20.
using DoubleValues = Values<double>;
// the lexical cast operator should be in the same namespace as the type for ADL to work properly
bool lexical_cast(const std::string &input, Values<double> &v) {
std::cout << "called correct lexical_cast function ! val: " << input << std::endl;
return true;
}
DoubleValues doubles;
void argparse(CLI::Option_group *group) { group->add_option("--dv", doubles)->default_str("0"); }
int main(int argc, char **argv) {
CLI::App app;
argparse(app.add_option_group("param"));
CLI11_PARSE(app, argc, argv);
return 0;
}

View File

@ -732,7 +732,9 @@ class App {
}
/// Set a version flag and version display string, replace the existing one if present
Option *set_version_flag(std::string flag_name = "", const std::string &versionString = "") {
Option *set_version_flag(std::string flag_name = "",
const std::string &versionString = "",
const std::string &version_help = "Display program version information and exit") {
// take flag_description by const reference otherwise add_flag tries to assign to version_description
if(version_ptr_ != nullptr) {
remove_option(version_ptr_);
@ -742,17 +744,16 @@ class App {
// Empty name will simply remove the version flag
if(!flag_name.empty()) {
version_ptr_ = add_flag_callback(
flag_name,
[versionString]() { throw(CLI::CallForVersion(versionString, 0)); },
"Display program version information and exit");
flag_name, [versionString]() { throw(CLI::CallForVersion(versionString, 0)); }, version_help);
version_ptr_->configurable(false);
}
return version_ptr_;
}
/// Generate the version string through a callback function
Option *set_version_flag(std::string flag_name, std::function<std::string()> vfunc) {
// take flag_description by const reference otherwise add_flag tries to assign to version_description
Option *set_version_flag(std::string flag_name,
std::function<std::string()> vfunc,
const std::string &version_help = "Display program version information and exit") {
if(version_ptr_ != nullptr) {
remove_option(version_ptr_);
version_ptr_ = nullptr;
@ -761,9 +762,7 @@ class App {
// Empty name will simply remove the version flag
if(!flag_name.empty()) {
version_ptr_ = add_flag_callback(
flag_name,
[vfunc]() { throw(CLI::CallForVersion(vfunc(), 0)); },
"Display program version information and exit");
flag_name, [vfunc]() { throw(CLI::CallForVersion(vfunc(), 0)); }, version_help);
version_ptr_->configurable(false);
}

View File

@ -277,7 +277,7 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description,
std::vector<std::string> groups = app->get_groups();
bool defaultUsed = false;
groups.insert(groups.begin(), std::string("Options"));
if(write_description) {
if(write_description && (app->get_configurable() || app->get_parent() == nullptr || app->get_name().empty())) {
out << commentLead << app->get_description() << '\n';
}
for(auto &group : groups) {

View File

@ -1888,6 +1888,27 @@ TEST_CASE_METHOD(TApp, "TomlOutputSubsubcomConfigurable", "[config]") {
CHECK(std::string::npos == str.find("sub2.newest=true"));
}
TEST_CASE_METHOD(TApp, "TomlOutputSubcomNonConfigurable", "[config]") {
app.add_flag("--simple");
auto subcom = app.add_subcommand("other", "other_descriptor")->configurable();
subcom->add_flag("--newer");
auto subcom2 = app.add_subcommand("sub2", "descriptor2");
subcom2->add_flag("--newest")->configurable(false);
args = {"--simple", "other", "--newer", "sub2", "--newest"};
run();
std::string str = app.config_to_str(true, true);
CHECK_THAT(str, Contains("other_descriptor"));
CHECK_THAT(str, Contains("simple=true"));
CHECK_THAT(str, Contains("[other]"));
CHECK_THAT(str, Contains("newer=true"));
CHECK_THAT(str, !Contains("newest"));
CHECK_THAT(str, !Contains("descriptor2"));
}
TEST_CASE_METHOD(TApp, "TomlOutputSubsubcomConfigurableDeep", "[config]") {
app.add_flag("--simple");

View File

@ -1220,6 +1220,21 @@ TEST_CASE("TVersion: callback_flag", "[help]") {
CHECK_THAT(vers, Contains("VERSION"));
}
TEST_CASE("TVersion: help", "[help]") {
CLI::App app;
app.set_version_flag("-v,--version", "version_string", "help_for_version");
auto hvers = app.help();
CHECK_THAT(hvers, Contains("help_for_version"));
app.set_version_flag(
"-v", []() { return std::string("VERSION2 " CLI11_VERSION); }, "help_for_version2");
hvers = app.help();
CHECK_THAT(hvers, Contains("help_for_version2"));
}
TEST_CASE("TVersion: parse_throw", "[help]") {
CLI::App app;