From a00d849fc0284bea743608535b977c5d72f8f51e Mon Sep 17 00:00:00 2001 From: Henry Fredrick Schreiner Date: Sun, 6 May 2018 16:43:25 +0200 Subject: [PATCH] Use filter fn to simplify, sort includes --- examples/enum.cpp | 2 +- examples/inter_argument_order.cpp | 4 +- include/CLI/App.hpp | 11 +++-- include/CLI/Formatter.hpp | 81 ++++++++++++++++--------------- include/CLI/FormatterFwd.hpp | 13 +++-- include/CLI/Option.hpp | 6 +++ include/CLI/StringTools.hpp | 2 +- include/CLI/Validators.hpp | 4 +- scripts/check_style.sh | 2 +- tests/AppTest.cpp | 2 +- tests/CreationTest.cpp | 5 +- tests/FormatterTest.cpp | 2 +- tests/HelpTest.cpp | 19 +++++++- tests/HelpersTest.cpp | 4 +- tests/IniTest.cpp | 2 +- tests/SubcommandTest.cpp | 2 +- tests/TimerTest.cpp | 8 +-- 17 files changed, 102 insertions(+), 67 deletions(-) diff --git a/examples/enum.cpp b/examples/enum.cpp index 7018681fa..3e841da6a 100644 --- a/examples/enum.cpp +++ b/examples/enum.cpp @@ -1,5 +1,5 @@ -#include #include +#include enum class Level : int { High, Medium, Low }; diff --git a/examples/inter_argument_order.cpp b/examples/inter_argument_order.cpp index 9e3c246b9..23f8fec36 100644 --- a/examples/inter_argument_order.cpp +++ b/examples/inter_argument_order.cpp @@ -1,8 +1,8 @@ #include +#include #include -#include #include -#include +#include int main(int argc, char **argv) { CLI::App app{"An app to practice mixing unlimited arguments, but still recover the original order."}; diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 2ecc52633..7b6edb1dc 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -1013,8 +1013,8 @@ class App { for(const Option_p &opt : options_) { // Only process option with a long-name and configurable - if(!opt->lnames_.empty() && opt->get_configurable()) { - std::string name = prefix + opt->lnames_[0]; + if(!opt->get_lnames().empty() && opt->get_configurable()) { + std::string name = prefix + opt->get_lnames()[0]; std::string value; // Non-flags @@ -1025,8 +1025,8 @@ class App { value = detail::inijoin(opt->results()); // If the option has a default and is requested by optional argument - else if(default_also && !opt->defaultval_.empty()) - value = opt->defaultval_; + else if(default_also && !opt->get_defaultval().empty()) + value = opt->get_defaultval(); // Flag, one passed } else if(opt->count() == 1) { value = "true"; @@ -1148,6 +1148,9 @@ class App { /// Get the parent of this subcommand (or nullptr if master app) App *get_parent() { return parent_; } + /// Get the parent of this subcommand (or nullptr if master app) (const version) + const App *get_parent() const { return parent_; } + /// Get a pointer to the config option. (const) const Option *get_config_ptr() const { return config_ptr_; } diff --git a/include/CLI/Formatter.hpp b/include/CLI/Formatter.hpp index 0ba4ac9fa..5486fff3b 100644 --- a/include/CLI/Formatter.hpp +++ b/include/CLI/Formatter.hpp @@ -10,42 +10,44 @@ namespace CLI { -inline std::string -Formatter::make_group(std::string group, std::vector opts, bool is_positional) const { +inline std::string Formatter::make_group(const App *app, + std::string group, + bool is_positional, + std::function filter) const { std::stringstream out; - out << "\n" << group << ":\n"; - for(const Option *opt : opts) { - out << make_option(opt, is_positional); + std::vector opts = app->get_options(filter); + + if(!opts.empty()) { + out << "\n" << group << ":\n"; + for(const Option *opt : opts) { + out << make_option(opt, is_positional); + } } return out.str(); } +inline std::string Formatter::make_positionals(const App *app) const { + return make_group(app, get_label("Positionals"), true, [](const Option *opt) { + return !opt->get_group().empty() && opt->get_positional(); + }); +} + inline std::string Formatter::make_groups(const App *app, AppFormatMode mode) const { std::stringstream out; std::vector groups = app->get_groups(); - std::vector positionals = - app->get_options([](const Option *opt) { return !opt->get_group().empty() && opt->get_positional(); }); - - if(!positionals.empty()) - out << make_group(get_label("Positionals"), positionals, true); // Options for(const std::string &group : groups) { - std::vector grouped_items = - app->get_options([&group](const Option *opt) { return opt->nonpositional() && opt->get_group() == group; }); - - if(mode == AppFormatMode::Sub) { - grouped_items.erase(std::remove_if(grouped_items.begin(), - grouped_items.end(), - [app](const Option *opt) { - return app->get_help_ptr() == opt || app->get_help_all_ptr() == opt; - }), - grouped_items.end()); - } + if(!group.empty()) { + out << make_group(app, group, false, [app, mode, &group](const Option *opt) { + return opt->get_group() == group // Must be in the right group + && opt->nonpositional() // Must not be a positional + && (mode != AppFormatMode::Sub // If mode is Sub, then + || (app->get_help_ptr() != opt // Ignore help pointer + && app->get_help_all_ptr() != opt)); // Ignore help all pointer + }); - if(!group.empty() && !grouped_items.empty()) { - out << make_group(group, grouped_items, false); if(group != groups.back()) out << "\n"; } @@ -113,21 +115,19 @@ inline std::string Formatter::make_footer(const App *app) const { inline std::string Formatter::operator()(const App *app, std::string name, AppFormatMode mode) const { + // This immediatly forwards to the make_expanded method. This is done this way so that subcommands can + // have overridden formatters + if(mode == AppFormatMode::Sub) + return make_expanded(app); + std::stringstream out; - if(mode == AppFormatMode::Normal) { - out << make_description(app); - out << make_usage(app, name); - out << make_groups(app, mode); - out << make_subcommands(app, mode); - out << make_footer(app); - } else if(mode == AppFormatMode::Sub) { - out << make_expanded(app); - } else if(mode == AppFormatMode::All) { - out << make_description(app); - out << make_usage(app, name); - out << make_groups(app, mode); - out << make_subcommands(app, mode); - } + + out << make_description(app); + out << make_usage(app, name); + out << make_positionals(app); + out << make_groups(app, mode); + out << make_subcommands(app, mode); + out << make_footer(app); return out.str(); } @@ -151,8 +151,6 @@ inline std::string Formatter::make_subcommands(const App *app, AppFormatMode mod // For each group, filter out and print subcommands for(const std::string &group : subcmd_groups_seen) { out << "\n" << group << ":\n"; - if(mode == AppFormatMode::All) - out << "\n"; std::vector subcommands_group = app->get_subcommands( [&group](const App *app) { return detail::to_lower(app->get_group()) == detail::to_lower(group); }); for(const App *new_com : subcommands_group) { @@ -177,7 +175,10 @@ inline std::string Formatter::make_subcommand(const App *sub) const { inline std::string Formatter::make_expanded(const App *sub) const { std::stringstream out; - out << sub->get_name() << "\n " << sub->get_description(); + if(sub->get_description().empty()) + out << sub->get_name(); + else + out << sub->get_name() << " -> " << sub->get_description(); out << make_groups(sub, AppFormatMode::Sub); return out.str(); } diff --git a/include/CLI/FormatterFwd.hpp b/include/CLI/FormatterFwd.hpp index 462539aeb..f4535e186 100644 --- a/include/CLI/FormatterFwd.hpp +++ b/include/CLI/FormatterFwd.hpp @@ -3,8 +3,8 @@ // Distributed under the 3-Clause BSD License. See accompanying // file LICENSE or https://github.com/CLIUtils/CLI11 for details. -#include #include +#include #include "CLI/StringTools.hpp" @@ -72,10 +72,16 @@ class Formatter { ///@{ /// This prints out a group of options - virtual std::string make_group(std::string group, std::vector opts, bool is_positional) const; + /// + /// Use the filter to pick out the items you want in your group + virtual std::string + make_group(const App *app, std::string group, bool is_positional, std::function filter) const; + + /// This prints out just the positionals "group" + virtual std::string make_positionals(const App *app) const; /// This prints out all the groups of options - virtual std::string make_groups(const App *app, AppFormatMode mode) const; + std::string make_groups(const App *app, AppFormatMode mode) const; /// This prints out all the subcommands virtual std::string make_subcommands(const App *app, AppFormatMode mode) const; @@ -102,6 +108,7 @@ class Formatter { /// @name Options ///@{ + /// This prints out an option help line, either positional or optional form virtual std::string make_option(const Option *opt, bool is_positional) const { std::stringstream out; detail::format_help( diff --git a/include/CLI/Option.hpp b/include/CLI/Option.hpp index 4b64d9a80..a2bb80041 100644 --- a/include/CLI/Option.hpp +++ b/include/CLI/Option.hpp @@ -402,6 +402,12 @@ class Option : public OptionBase