mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-29 20:23:55 +00:00
feat: added usage message replacement feature (#786)
* fix: show newline before footer only if footer is set and not empty * feat: added usage message replacement feature * fix: tests corrected for new help message formatting
This commit is contained in:
parent
291c58789c
commit
d3505540e7
@ -1062,6 +1062,10 @@ option_groups. These are:
|
|||||||
- `.prefix_command()`: Like `allow_extras`, but stop immediately on the first
|
- `.prefix_command()`: Like `allow_extras`, but stop immediately on the first
|
||||||
unrecognized item. It is ideal for allowing your app or subcommand to be a
|
unrecognized item. It is ideal for allowing your app or subcommand to be a
|
||||||
"prefix" to calling another app.
|
"prefix" to calling another app.
|
||||||
|
- `.usage(message)`: Replace text to appear at the start of the help string
|
||||||
|
after description.
|
||||||
|
- `.usage(std::string())`: Set a callback to generate a string that will appear
|
||||||
|
at the start of the help string after description.
|
||||||
- `.footer(message)`: Set text to appear at the bottom of the help string.
|
- `.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
|
- `.footer(std::string())`: Set a callback to generate a string that will appear
|
||||||
at the end of the help string.
|
at the end of the help string.
|
||||||
@ -1356,8 +1360,9 @@ multiple calls or using `|` operations with the transform.
|
|||||||
Many of the defaults for subcommands and even options are inherited from their
|
Many of the defaults for subcommands and even options are inherited from their
|
||||||
creators. The inherited default values for subcommands are `allow_extras`,
|
creators. The inherited default values for subcommands are `allow_extras`,
|
||||||
`prefix_command`, `ignore_case`, `ignore_underscore`, `fallthrough`, `group`,
|
`prefix_command`, `ignore_case`, `ignore_underscore`, `fallthrough`, `group`,
|
||||||
`footer`,`immediate_callback` and maximum number of required subcommands. The
|
`usage`, `footer`, `immediate_callback` and maximum number of required
|
||||||
help flag existence, name, and description are inherited, as well.
|
subcommands. The help flag existence, name, and description are inherited, as
|
||||||
|
well.
|
||||||
|
|
||||||
Options have defaults for `group`, `required`, `multi_option_policy`,
|
Options have defaults for `group`, `required`, `multi_option_policy`,
|
||||||
`ignore_case`, `ignore_underscore`, `delimiter`, and `disable_flag_override`. To
|
`ignore_case`, `ignore_underscore`, `delimiter`, and `disable_flag_override`. To
|
||||||
|
@ -150,6 +150,12 @@ class App {
|
|||||||
/// @name Help
|
/// @name Help
|
||||||
///@{
|
///@{
|
||||||
|
|
||||||
|
/// Usage to put after program/subcommand description in the help output INHERITABLE
|
||||||
|
std::string usage_{};
|
||||||
|
|
||||||
|
/// This is a function that generates a usage to put after program/subcommand description in help output
|
||||||
|
std::function<std::string()> usage_callback_{};
|
||||||
|
|
||||||
/// Footer to put after all options in the help output INHERITABLE
|
/// Footer to put after all options in the help output INHERITABLE
|
||||||
std::string footer_{};
|
std::string footer_{};
|
||||||
|
|
||||||
@ -947,6 +953,16 @@ class App {
|
|||||||
/// @name Help
|
/// @name Help
|
||||||
///@{
|
///@{
|
||||||
|
|
||||||
|
/// Set usage.
|
||||||
|
App *usage(std::string usage_string) {
|
||||||
|
usage_ = std::move(usage_string);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/// Set usage.
|
||||||
|
App *usage(std::function<std::string()> usage_function) {
|
||||||
|
usage_callback_ = std::move(usage_function);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
/// Set footer.
|
/// Set footer.
|
||||||
App *footer(std::string footer_string) {
|
App *footer(std::string footer_string) {
|
||||||
footer_ = std::move(footer_string);
|
footer_ = std::move(footer_string);
|
||||||
@ -1055,6 +1071,11 @@ class App {
|
|||||||
/// Get the group of this subcommand
|
/// Get the group of this subcommand
|
||||||
CLI11_NODISCARD const std::string &get_group() const { return group_; }
|
CLI11_NODISCARD const std::string &get_group() const { return group_; }
|
||||||
|
|
||||||
|
/// Generate and return the usage.
|
||||||
|
CLI11_NODISCARD std::string get_usage() const {
|
||||||
|
return (usage_callback_) ? usage_callback_() + '\n' + usage_ : usage_;
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate and return the footer.
|
/// Generate and return the footer.
|
||||||
CLI11_NODISCARD std::string get_footer() const {
|
CLI11_NODISCARD std::string get_footer() const {
|
||||||
return (footer_callback_) ? footer_callback_() + '\n' + footer_ : footer_;
|
return (footer_callback_) ? footer_callback_() + '\n' + footer_ : footer_;
|
||||||
|
@ -46,6 +46,7 @@ CLI11_INLINE App::App(std::string app_description, std::string app_name, App *pa
|
|||||||
configurable_ = parent_->configurable_;
|
configurable_ = parent_->configurable_;
|
||||||
allow_windows_style_options_ = parent_->allow_windows_style_options_;
|
allow_windows_style_options_ = parent_->allow_windows_style_options_;
|
||||||
group_ = parent_->group_;
|
group_ = parent_->group_;
|
||||||
|
usage_ = parent_->usage_;
|
||||||
footer_ = parent_->footer_;
|
footer_ = parent_->footer_;
|
||||||
formatter_ = parent_->formatter_;
|
formatter_ = parent_->formatter_;
|
||||||
config_formatter_ = parent_->config_formatter_;
|
config_formatter_ = parent_->config_formatter_;
|
||||||
|
@ -91,6 +91,11 @@ CLI11_INLINE std::string Formatter::make_description(const App *app) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CLI11_INLINE std::string Formatter::make_usage(const App *app, std::string name) const {
|
CLI11_INLINE std::string Formatter::make_usage(const App *app, std::string name) const {
|
||||||
|
std::string usage = app->get_usage();
|
||||||
|
if(!usage.empty()) {
|
||||||
|
return usage + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
std::stringstream out;
|
std::stringstream out;
|
||||||
|
|
||||||
out << get_label("Usage") << ":" << (name.empty() ? "" : " ") << name;
|
out << get_label("Usage") << ":" << (name.empty() ? "" : " ") << name;
|
||||||
|
@ -455,6 +455,7 @@ TEST_CASE_METHOD(TApp, "SubcommandDefaults", "[creation]") {
|
|||||||
CHECK(!app.get_configurable());
|
CHECK(!app.get_configurable());
|
||||||
CHECK(!app.get_validate_positionals());
|
CHECK(!app.get_validate_positionals());
|
||||||
|
|
||||||
|
CHECK(app.get_usage().empty());
|
||||||
CHECK(app.get_footer().empty());
|
CHECK(app.get_footer().empty());
|
||||||
CHECK("Subcommands" == app.get_group());
|
CHECK("Subcommands" == app.get_group());
|
||||||
CHECK(0u == app.get_require_subcommand_min());
|
CHECK(0u == app.get_require_subcommand_min());
|
||||||
@ -474,6 +475,7 @@ TEST_CASE_METHOD(TApp, "SubcommandDefaults", "[creation]") {
|
|||||||
|
|
||||||
app.fallthrough();
|
app.fallthrough();
|
||||||
app.validate_positionals();
|
app.validate_positionals();
|
||||||
|
app.usage("ussy");
|
||||||
app.footer("footy");
|
app.footer("footy");
|
||||||
app.group("Stuff");
|
app.group("Stuff");
|
||||||
app.require_subcommand(2, 3);
|
app.require_subcommand(2, 3);
|
||||||
@ -494,6 +496,7 @@ TEST_CASE_METHOD(TApp, "SubcommandDefaults", "[creation]") {
|
|||||||
CHECK(app2->get_fallthrough());
|
CHECK(app2->get_fallthrough());
|
||||||
CHECK(app2->get_validate_positionals());
|
CHECK(app2->get_validate_positionals());
|
||||||
CHECK(app2->get_configurable());
|
CHECK(app2->get_configurable());
|
||||||
|
CHECK("ussy" == app2->get_usage());
|
||||||
CHECK("footy" == app2->get_footer());
|
CHECK("footy" == app2->get_footer());
|
||||||
CHECK("Stuff" == app2->get_group());
|
CHECK("Stuff" == app2->get_group());
|
||||||
CHECK(0u == app2->get_require_subcommand_min());
|
CHECK(0u == app2->get_require_subcommand_min());
|
||||||
|
@ -26,6 +26,43 @@ TEST_CASE("THelp: Basic", "[help]") {
|
|||||||
CHECK_THAT(help, Contains("Usage:"));
|
CHECK_THAT(help, Contains("Usage:"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("THelp: Usage", "[help]") {
|
||||||
|
CLI::App app{"My prog"};
|
||||||
|
app.usage("use: just use it");
|
||||||
|
|
||||||
|
std::string help = app.help();
|
||||||
|
|
||||||
|
CHECK_THAT(help, Contains("My prog"));
|
||||||
|
CHECK_THAT(help, Contains("-h,--help"));
|
||||||
|
CHECK_THAT(help, Contains("Options:"));
|
||||||
|
CHECK_THAT(help, Contains("use: just use it"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("THelp: UsageCallback", "[help]") {
|
||||||
|
CLI::App app{"My prog"};
|
||||||
|
app.usage([]() { return "use: just use it"; });
|
||||||
|
|
||||||
|
std::string help = app.help();
|
||||||
|
|
||||||
|
CHECK_THAT(help, Contains("My prog"));
|
||||||
|
CHECK_THAT(help, Contains("-h,--help"));
|
||||||
|
CHECK_THAT(help, Contains("Options:"));
|
||||||
|
CHECK_THAT(help, Contains("use: just use it"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("THelp: UsageCallbackBoth", "[help]") {
|
||||||
|
CLI::App app{"My prog"};
|
||||||
|
app.usage([]() { return "use: just use it"; });
|
||||||
|
app.usage("like 1, 2, and 3");
|
||||||
|
std::string help = app.help();
|
||||||
|
|
||||||
|
CHECK_THAT(help, Contains("My prog"));
|
||||||
|
CHECK_THAT(help, Contains("-h,--help"));
|
||||||
|
CHECK_THAT(help, Contains("Options:"));
|
||||||
|
CHECK_THAT(help, Contains("use: just use it"));
|
||||||
|
CHECK_THAT(help, Contains("like 1, 2, and 3"));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("THelp: Footer", "[help]") {
|
TEST_CASE("THelp: Footer", "[help]") {
|
||||||
CLI::App app{"My prog"};
|
CLI::App app{"My prog"};
|
||||||
app.footer("Report bugs to bugs@example.com");
|
app.footer("Report bugs to bugs@example.com");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user