|
15 | 15 | *
|
16 | 16 | */
|
17 | 17 |
|
18 |
| -#ifndef IGNITION_UTILS_CLI_IGNITION_FORMATTER_HPP_ |
19 |
| -#define IGNITION_UTILS_CLI_IGNITION_FORMATTER_HPP_ |
20 |
| - |
21 |
| -#include <algorithm> |
22 |
| -#include <string> |
23 |
| -#include <sstream> |
24 |
| -#include <vector> |
25 |
| -#include <unordered_map> |
26 |
| - |
27 |
| -#include "ignition/utils/cli/App.hpp" |
28 |
| -#include "ignition/utils/cli/FormatterFwd.hpp" |
29 |
| - |
30 |
| -////////////////////////////////////////////////// |
31 |
| -/// \brief CLI Formatter class that implements custom Ignition-specific |
32 |
| -/// formatting. |
33 |
| -/// |
34 |
| -/// More information on custom formatters: |
35 |
| -/// https://cliutils.github.io/CLI11/book/chapters/formatting.html |
36 |
| -class IgnitionFormatter: public CLI::Formatter { |
37 |
| - |
38 |
| -////////////////////////////////////////////////// |
39 |
| -public: explicit IgnitionFormatter(const CLI::App *_app) |
40 |
| -{ |
41 |
| - // find needs/needed_by for root options |
42 |
| - for (const CLI::Option *appOpt: _app->get_options()) |
43 |
| - { |
44 |
| - for(const CLI::Option *needsOpt : appOpt->get_needs()) |
45 |
| - { |
46 |
| - this->needed_by.insert({needsOpt->get_name(), appOpt->get_name()}); |
47 |
| - this->needs.insert({appOpt->get_name(), needsOpt->get_name()}); |
48 |
| - } |
49 |
| - } |
50 |
| - |
51 |
| - // find needs/needed_by for subcommand (or command group) options |
52 |
| - auto subcommands = _app->get_subcommands([](const CLI::App*){return true;}); |
53 |
| - for (const CLI::App *sub : subcommands) |
54 |
| - { |
55 |
| - // find needs/needed_by for root options |
56 |
| - for (const CLI::Option *subOpt: sub->get_options()) |
57 |
| - { |
58 |
| - for(const CLI::Option *needsOpt : subOpt->get_needs()) |
59 |
| - { |
60 |
| - this->needed_by.insert({needsOpt->get_name(), subOpt->get_name()}); |
61 |
| - this->needs.insert({subOpt->get_name(), needsOpt->get_name()}); |
62 |
| - } |
63 |
| - } |
64 |
| - } |
65 |
| -} |
66 |
| - |
67 |
| -////////////////////////////////////////////////// |
68 |
| -public: std::string make_option_name( |
69 |
| - const CLI::Option *opt, bool is_positional) const override { |
70 |
| - if (is_positional) |
71 |
| - return opt->get_name(true, false); |
72 |
| - |
73 |
| - std::stringstream out; |
74 |
| - |
75 |
| - auto snames = opt->get_snames(); |
76 |
| - auto lnames = opt->get_lnames(); |
77 |
| - |
78 |
| - std::vector<std::string> sname_list; |
79 |
| - std::transform(snames.begin(), snames.end(), std::back_inserter(sname_list), |
80 |
| - [](const std::string &sname) { return "-" + sname; }); |
81 |
| - |
82 |
| - std::vector<std::string> lname_list; |
83 |
| - std::transform(lnames.begin(), lnames.end(), std::back_inserter(lname_list), |
84 |
| - [](const std::string &lname) { return "--" + lname; }); |
85 |
| - |
86 |
| - // If no short options, just use long |
87 |
| - if (sname_list.empty()) |
88 |
| - { |
89 |
| - out << CLI::detail::join(lname_list); |
90 |
| - } |
91 |
| - else |
92 |
| - { |
93 |
| - out << CLI::detail::join(sname_list); |
94 |
| - // Put lnames in brackets to look like ruby formatting |
95 |
| - if (!lnames.empty()) |
96 |
| - { |
97 |
| - out << " [" << CLI::detail::join(lname_list) << "]"; |
98 |
| - } |
99 |
| - } |
100 |
| - |
101 |
| - return out.str(); |
102 |
| -} |
103 |
| - |
104 |
| - |
105 |
| -////////////////////////////////////////////////// |
106 |
| -public: std::string make_option_opts(const CLI::Option *opt) const override { |
107 |
| - std::stringstream out; |
108 |
| - |
109 |
| - if(opt->get_type_size() != 0) { |
110 |
| - if(!opt->get_type_name().empty()) |
111 |
| - out << " " << get_label(opt->get_type_name()); |
112 |
| - if(!opt->get_default_str().empty()) |
113 |
| - out << "=" << opt->get_default_str(); |
114 |
| - if(opt->get_expected_max() == CLI::detail::expected_max_vector_size) |
115 |
| - out << " ..."; |
116 |
| - else if(opt->get_expected_min() > 1) |
117 |
| - out << " x " << opt->get_expected(); |
118 |
| - } |
119 |
| - if(!opt->get_envname().empty()) |
120 |
| - out << " (" << get_label("Env") << ":" << opt->get_envname() << ")"; |
121 |
| - return out.str(); |
122 |
| -} |
123 |
| - |
124 |
| - |
125 |
| -////////////////////////////////////////////////// |
126 |
| -std::string make_option_desc(const CLI::Option *opt) const override { |
127 |
| - std::stringstream out; |
128 |
| - |
129 |
| - out << opt->get_description(); |
130 |
| - |
131 |
| - if (opt->get_required()) |
132 |
| - { |
133 |
| - out << "\nREQUIRED"; |
134 |
| - } |
135 |
| - |
136 |
| - auto range = this->needs.equal_range(opt->get_name()); |
137 |
| - std::for_each( |
138 |
| - range.first, |
139 |
| - range.second, |
140 |
| - [&out](const auto &opt_name) |
141 |
| - { |
142 |
| - out << "\nRequires: " << opt_name.second; |
143 |
| - }); |
144 |
| - |
145 |
| - range = this->needed_by.equal_range(opt->get_name()); |
146 |
| - std::for_each( |
147 |
| - range.first, |
148 |
| - range.second, |
149 |
| - [&out](const auto &opt_name) |
150 |
| - { |
151 |
| - out << "\nRequired by: " << opt_name.second; |
152 |
| - }); |
153 |
| - |
154 |
| - if (!opt->get_excludes().empty()) { |
155 |
| - out << "\n" << get_label("Excludes") << ":"; |
156 |
| - for(const CLI::Option *op : opt->get_excludes()) |
157 |
| - out << " " << op->get_name(); |
158 |
| - } |
159 |
| - |
160 |
| - return out.str() + '\n'; |
161 |
| -} |
162 |
| - |
163 |
| -/// \brief Track dependent options |
164 |
| -private: std::unordered_multimap<std::string, std::string> needs; |
165 |
| - |
166 |
| -/// \brief Track dependent options (inverse) |
167 |
| -private: std::unordered_multimap<std::string, std::string> needed_by; |
168 |
| -}; |
169 |
| - |
170 |
| -#endif // IGNITION_UTILS_CLI_IGNITION_FORMATTER_HPP_ |
| 18 | +#include <gz/utils/cli/GzFormatter.hpp> |
0 commit comments