diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b9b35789..232714587 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ Other changes: * Testing (only) now uses submodules. [#111] * Removed `requires` in favor of `needs` (deprecated in last version) [#112] * Better CMake policy handling [#110] +* Includes are properly sorted [#120] +* `lname` and `sname` have getters, added `const get_parent` [#120] [#109]: https://github.com/CLIUtils/CLI11/pull/109 [#110]: https://github.com/CLIUtils/CLI11/pull/110 @@ -42,6 +44,7 @@ Other changes: [#116]: https://github.com/CLIUtils/CLI11/pull/116 [#118]: https://github.com/CLIUtils/CLI11/pull/118 [#118]: https://github.com/CLIUtils/CLI11/pull/119 +[#120]: https://github.com/CLIUtils/CLI11/pull/120 ### Version 1.5.3: Compiler compatibility This version fixes older AppleClang compilers by removing the optimization for casting. The minimum version of Boost Optional supported has been clarified to be 1.58. CUDA 7.0 NVCC is now supported. 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