Commit 101d847c295fd710d98975bfdd3602d2e6f201b2

Authored by Henry Fredrick Schreiner
Committed by Henry Schreiner
1 parent 3ff6fcae

Use filter fn to simplify, sort includes

CHANGELOG.md
... ... @@ -33,6 +33,8 @@ Other changes:
33 33 * Testing (only) now uses submodules. [#111]
34 34 * Removed `requires` in favor of `needs` (deprecated in last version) [#112]
35 35 * Better CMake policy handling [#110]
  36 +* Includes are properly sorted [#120]
  37 +* `lname` and `sname` have getters, added `const get_parent` [#120]
36 38  
37 39 [#109]: https://github.com/CLIUtils/CLI11/pull/109
38 40 [#110]: https://github.com/CLIUtils/CLI11/pull/110
... ... @@ -42,6 +44,7 @@ Other changes:
42 44 [#116]: https://github.com/CLIUtils/CLI11/pull/116
43 45 [#118]: https://github.com/CLIUtils/CLI11/pull/118
44 46 [#118]: https://github.com/CLIUtils/CLI11/pull/119
  47 +[#120]: https://github.com/CLIUtils/CLI11/pull/120
45 48  
46 49 ### Version 1.5.3: Compiler compatibility
47 50 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.
... ...
examples/enum.cpp
1   -#include <sstream>
2 1 #include <CLI/CLI.hpp>
  2 +#include <sstream>
3 3  
4 4 enum class Level : int { High, Medium, Low };
5 5  
... ...
examples/inter_argument_order.cpp
1 1 #include <CLI/CLI.hpp>
  2 +#include <algorithm>
2 3 #include <iostream>
3   -#include <vector>
4 4 #include <tuple>
5   -#include <algorithm>
  5 +#include <vector>
6 6  
7 7 int main(int argc, char **argv) {
8 8 CLI::App app{"An app to practice mixing unlimited arguments, but still recover the original order."};
... ...
include/CLI/App.hpp
... ... @@ -1013,8 +1013,8 @@ class App {
1013 1013 for(const Option_p &opt : options_) {
1014 1014  
1015 1015 // Only process option with a long-name and configurable
1016   - if(!opt->lnames_.empty() && opt->get_configurable()) {
1017   - std::string name = prefix + opt->lnames_[0];
  1016 + if(!opt->get_lnames().empty() && opt->get_configurable()) {
  1017 + std::string name = prefix + opt->get_lnames()[0];
1018 1018 std::string value;
1019 1019  
1020 1020 // Non-flags
... ... @@ -1025,8 +1025,8 @@ class App {
1025 1025 value = detail::inijoin(opt->results());
1026 1026  
1027 1027 // If the option has a default and is requested by optional argument
1028   - else if(default_also && !opt->defaultval_.empty())
1029   - value = opt->defaultval_;
  1028 + else if(default_also && !opt->get_defaultval().empty())
  1029 + value = opt->get_defaultval();
1030 1030 // Flag, one passed
1031 1031 } else if(opt->count() == 1) {
1032 1032 value = "true";
... ... @@ -1148,6 +1148,9 @@ class App {
1148 1148 /// Get the parent of this subcommand (or nullptr if master app)
1149 1149 App *get_parent() { return parent_; }
1150 1150  
  1151 + /// Get the parent of this subcommand (or nullptr if master app) (const version)
  1152 + const App *get_parent() const { return parent_; }
  1153 +
1151 1154 /// Get a pointer to the config option. (const)
1152 1155 const Option *get_config_ptr() const { return config_ptr_; }
1153 1156  
... ...
include/CLI/Formatter.hpp
... ... @@ -10,42 +10,44 @@
10 10  
11 11 namespace CLI {
12 12  
13   -inline std::string
14   -Formatter::make_group(std::string group, std::vector<const Option *> opts, bool is_positional) const {
  13 +inline std::string Formatter::make_group(const App *app,
  14 + std::string group,
  15 + bool is_positional,
  16 + std::function<bool(const Option *)> filter) const {
15 17 std::stringstream out;
16   - out << "\n" << group << ":\n";
17   - for(const Option *opt : opts) {
18   - out << make_option(opt, is_positional);
  18 + std::vector<const Option *> opts = app->get_options(filter);
  19 +
  20 + if(!opts.empty()) {
  21 + out << "\n" << group << ":\n";
  22 + for(const Option *opt : opts) {
  23 + out << make_option(opt, is_positional);
  24 + }
19 25 }
20 26  
21 27 return out.str();
22 28 }
23 29  
  30 +inline std::string Formatter::make_positionals(const App *app) const {
  31 + return make_group(app, get_label("Positionals"), true, [](const Option *opt) {
  32 + return !opt->get_group().empty() && opt->get_positional();
  33 + });
  34 +}
  35 +
24 36 inline std::string Formatter::make_groups(const App *app, AppFormatMode mode) const {
25 37 std::stringstream out;
26 38 std::vector<std::string> groups = app->get_groups();
27   - std::vector<const Option *> positionals =
28   - app->get_options([](const Option *opt) { return !opt->get_group().empty() && opt->get_positional(); });
29   -
30   - if(!positionals.empty())
31   - out << make_group(get_label("Positionals"), positionals, true);
32 39  
33 40 // Options
34 41 for(const std::string &group : groups) {
35   - std::vector<const Option *> grouped_items =
36   - app->get_options([&group](const Option *opt) { return opt->nonpositional() && opt->get_group() == group; });
37   -
38   - if(mode == AppFormatMode::Sub) {
39   - grouped_items.erase(std::remove_if(grouped_items.begin(),
40   - grouped_items.end(),
41   - [app](const Option *opt) {
42   - return app->get_help_ptr() == opt || app->get_help_all_ptr() == opt;
43   - }),
44   - grouped_items.end());
45   - }
  42 + if(!group.empty()) {
  43 + out << make_group(app, group, false, [app, mode, &group](const Option *opt) {
  44 + return opt->get_group() == group // Must be in the right group
  45 + && opt->nonpositional() // Must not be a positional
  46 + && (mode != AppFormatMode::Sub // If mode is Sub, then
  47 + || (app->get_help_ptr() != opt // Ignore help pointer
  48 + && app->get_help_all_ptr() != opt)); // Ignore help all pointer
  49 + });
46 50  
47   - if(!group.empty() && !grouped_items.empty()) {
48   - out << make_group(group, grouped_items, false);
49 51 if(group != groups.back())
50 52 out << "\n";
51 53 }
... ... @@ -113,21 +115,19 @@ inline std::string Formatter::make_footer(const App *app) const {
113 115  
114 116 inline std::string Formatter::operator()(const App *app, std::string name, AppFormatMode mode) const {
115 117  
  118 + // This immediatly forwards to the make_expanded method. This is done this way so that subcommands can
  119 + // have overridden formatters
  120 + if(mode == AppFormatMode::Sub)
  121 + return make_expanded(app);
  122 +
116 123 std::stringstream out;
117   - if(mode == AppFormatMode::Normal) {
118   - out << make_description(app);
119   - out << make_usage(app, name);
120   - out << make_groups(app, mode);
121   - out << make_subcommands(app, mode);
122   - out << make_footer(app);
123   - } else if(mode == AppFormatMode::Sub) {
124   - out << make_expanded(app);
125   - } else if(mode == AppFormatMode::All) {
126   - out << make_description(app);
127   - out << make_usage(app, name);
128   - out << make_groups(app, mode);
129   - out << make_subcommands(app, mode);
130   - }
  124 +
  125 + out << make_description(app);
  126 + out << make_usage(app, name);
  127 + out << make_positionals(app);
  128 + out << make_groups(app, mode);
  129 + out << make_subcommands(app, mode);
  130 + out << make_footer(app);
131 131  
132 132 return out.str();
133 133 }
... ... @@ -151,8 +151,6 @@ inline std::string Formatter::make_subcommands(const App *app, AppFormatMode mod
151 151 // For each group, filter out and print subcommands
152 152 for(const std::string &group : subcmd_groups_seen) {
153 153 out << "\n" << group << ":\n";
154   - if(mode == AppFormatMode::All)
155   - out << "\n";
156 154 std::vector<const App *> subcommands_group = app->get_subcommands(
157 155 [&group](const App *app) { return detail::to_lower(app->get_group()) == detail::to_lower(group); });
158 156 for(const App *new_com : subcommands_group) {
... ... @@ -177,7 +175,10 @@ inline std::string Formatter::make_subcommand(const App *sub) const {
177 175  
178 176 inline std::string Formatter::make_expanded(const App *sub) const {
179 177 std::stringstream out;
180   - out << sub->get_name() << "\n " << sub->get_description();
  178 + if(sub->get_description().empty())
  179 + out << sub->get_name();
  180 + else
  181 + out << sub->get_name() << " -> " << sub->get_description();
181 182 out << make_groups(sub, AppFormatMode::Sub);
182 183 return out.str();
183 184 }
... ...
include/CLI/FormatterFwd.hpp
... ... @@ -3,8 +3,8 @@
3 3 // Distributed under the 3-Clause BSD License. See accompanying
4 4 // file LICENSE or https://github.com/CLIUtils/CLI11 for details.
5 5  
6   -#include <string>
7 6 #include <map>
  7 +#include <string>
8 8  
9 9 #include "CLI/StringTools.hpp"
10 10  
... ... @@ -72,10 +72,16 @@ class Formatter {
72 72 ///@{
73 73  
74 74 /// This prints out a group of options
75   - virtual std::string make_group(std::string group, std::vector<const Option *> opts, bool is_positional) const;
  75 + ///
  76 + /// Use the filter to pick out the items you want in your group
  77 + virtual std::string
  78 + make_group(const App *app, std::string group, bool is_positional, std::function<bool(const Option *)> filter) const;
  79 +
  80 + /// This prints out just the positionals "group"
  81 + virtual std::string make_positionals(const App *app) const;
76 82  
77 83 /// This prints out all the groups of options
78   - virtual std::string make_groups(const App *app, AppFormatMode mode) const;
  84 + std::string make_groups(const App *app, AppFormatMode mode) const;
79 85  
80 86 /// This prints out all the subcommands
81 87 virtual std::string make_subcommands(const App *app, AppFormatMode mode) const;
... ... @@ -102,6 +108,7 @@ class Formatter {
102 108 /// @name Options
103 109 ///@{
104 110  
  111 + /// This prints out an option help line, either positional or optional form
105 112 virtual std::string make_option(const Option *opt, bool is_positional) const {
106 113 std::stringstream out;
107 114 detail::format_help(
... ...
include/CLI/Option.hpp
... ... @@ -402,6 +402,12 @@ class Option : public OptionBase&lt;Option&gt; {
402 402 /// The default value (for help printing)
403 403 std::string get_defaultval() const { return defaultval_; }
404 404  
  405 + /// Get the long names
  406 + const std::vector<std::string> get_lnames() const { return lnames_; }
  407 +
  408 + /// Get the short names
  409 + const std::vector<std::string> get_snames() const { return snames_; }
  410 +
405 411 /// The number of times the option expects to be included
406 412 int get_expected() const { return expected_; }
407 413  
... ...
include/CLI/StringTools.hpp
... ... @@ -8,8 +8,8 @@
8 8 #include <locale>
9 9 #include <sstream>
10 10 #include <string>
11   -#include <vector>
12 11 #include <type_traits>
  12 +#include <vector>
13 13  
14 14 namespace CLI {
15 15 namespace detail {
... ...
include/CLI/Validators.hpp
... ... @@ -28,7 +28,7 @@ namespace CLI {
28 28  
29 29 ///
30 30 struct Validator {
31   - /// This is the type name, if emtpy the type name will not be changed
  31 + /// This is the type name, if empty the type name will not be changed
32 32 std::string tname;
33 33 std::function<std::string(const std::string &filename)> func;
34 34  
... ... @@ -77,7 +77,7 @@ struct Validator {
77 77 }
78 78 };
79 79  
80   -// The implemntation of the built in validators is using the Validator class;
  80 +// The implementation of the built in validators is using the Validator class;
81 81 // the user is only expected to use the const (static) versions (since there's no setup).
82 82 // Therefore, this is in detail.
83 83 namespace detail {
... ...
scripts/check_style.sh
... ... @@ -3,7 +3,7 @@ set -evx
3 3  
4 4 clang-format --version
5 5  
6   -git ls-files -- '*.cpp' '*.hpp' | xargs clang-format -i -style=file
  6 +git ls-files -- '*.cpp' '*.hpp' | xargs clang-format -sort-includes -i -style=file
7 7  
8 8 git diff --exit-code --color
9 9  
... ...
tests/AppTest.cpp
1 1 #include "app_helper.hpp"
2   -#include <cstdlib>
3 2 #include <complex>
  3 +#include <cstdlib>
4 4  
5 5 TEST_F(TApp, OneFlagShort) {
6 6 app.add_flag("-c,--count");
... ...
tests/CreationTest.cpp
... ... @@ -2,7 +2,10 @@
2 2 #include <cstdlib>
3 3  
4 4 TEST_F(TApp, AddingExistingShort) {
5   - app.add_flag("-c,--count");
  5 + CLI::Option *opt = app.add_flag("-c,--count");
  6 + EXPECT_EQ(opt->get_lnames(), std::vector<std::string>({"count"}));
  7 + EXPECT_EQ(opt->get_snames(), std::vector<std::string>({"c"}));
  8 +
6 9 EXPECT_THROW(app.add_flag("--cat,-c"), CLI::OptionAlreadyAdded);
7 10 }
8 11  
... ...
tests/FormatterTest.cpp
... ... @@ -4,8 +4,8 @@
4 4 #include "CLI/CLI.hpp"
5 5 #endif
6 6  
7   -#include "gtest/gtest.h"
8 7 #include "gmock/gmock.h"
  8 +#include "gtest/gtest.h"
9 9 #include <fstream>
10 10  
11 11 using ::testing::HasSubstr;
... ...
tests/HelpTest.cpp
... ... @@ -4,8 +4,8 @@
4 4 #include "CLI/CLI.hpp"
5 5 #endif
6 6  
7   -#include "gtest/gtest.h"
8 7 #include "gmock/gmock.h"
  8 +#include "gtest/gtest.h"
9 9 #include <fstream>
10 10  
11 11 using ::testing::HasSubstr;
... ... @@ -492,7 +492,8 @@ TEST_F(CapturedHelp, CallForAllHelp) {
492 492 EXPECT_EQ(err.str(), "");
493 493 }
494 494 TEST_F(CapturedHelp, CallForAllHelpOutput) {
495   - app.add_subcommand("one");
  495 + app.set_help_all_flag("--help-all", "Help all");
  496 + app.add_subcommand("one", "One description");
496 497 CLI::App *sub = app.add_subcommand("two");
497 498 sub->add_flag("--three");
498 499  
... ... @@ -502,6 +503,20 @@ TEST_F(CapturedHelp, CallForAllHelpOutput) {
502 503 EXPECT_THAT(out.str(), HasSubstr("one"));
503 504 EXPECT_THAT(out.str(), HasSubstr("two"));
504 505 EXPECT_THAT(out.str(), HasSubstr("--three"));
  506 +
  507 + EXPECT_EQ(out.str(),
  508 + "My Test Program\n"
  509 + "Usage: [OPTIONS] [SUBCOMMAND]\n"
  510 + "\n"
  511 + "Options:\n"
  512 + " -h,--help Print this help message and exit\n"
  513 + " --help-all Help all\n"
  514 + "\n"
  515 + "Subcommands:\n"
  516 + "one -> One description\n"
  517 + "two\n"
  518 + "Options:\n"
  519 + " --three \n");
505 520 }
506 521 TEST_F(CapturedHelp, NewFormattedHelp) {
507 522 app.formatter([](const CLI::App *, std::string, CLI::AppFormatMode) { return "New Help"; });
... ...
tests/HelpersTest.cpp
1 1 #include "app_helper.hpp"
2 2  
  3 +#include <complex>
  4 +#include <cstdint>
3 5 #include <cstdio>
4 6 #include <fstream>
5   -#include <cstdint>
6 7 #include <string>
7   -#include <complex>
8 8  
9 9 TEST(Split, SimpleByToken) {
10 10 auto out = CLI::detail::split("one.two.three", '.');
... ...
tests/IniTest.cpp
1 1 #include "app_helper.hpp"
2 2  
  3 +#include "gmock/gmock.h"
3 4 #include <cstdio>
4 5 #include <sstream>
5   -#include "gmock/gmock.h"
6 6  
7 7 using ::testing::HasSubstr;
8 8 using ::testing::Not;
... ...
tests/SubcommandTest.cpp
1 1 #include "app_helper.hpp"
2 2  
3   -#include "gtest/gtest.h"
4 3 #include "gmock/gmock.h"
  4 +#include "gtest/gtest.h"
5 5  
6 6 using ::testing::HasSubstr;
7 7 using ::testing::Not;
... ...
tests/TimerTest.cpp
1   -#include "gtest/gtest.h"
2   -#include "gmock/gmock.h"
3 1 #include "CLI/Timer.hpp"
4   -#include <string>
  2 +#include "gmock/gmock.h"
  3 +#include "gtest/gtest.h"
5 4 #include <chrono>
6   -#include <thread>
7 5 #include <sstream>
  6 +#include <string>
  7 +#include <thread>
8 8  
9 9 using ::testing::HasSubstr;
10 10  
... ...