Commit c24bf7541398ffeb68e7343154b93f9a630e2147

Authored by Daniel Herrera Castro
Committed by Henry Schreiner
1 parent 003e8257

[precompile] Split Formatter.hpp

CLI11.hpp.in
... ... @@ -72,4 +72,6 @@ namespace {namespace} {{
72 72  
73 73 {formatter_hpp}
74 74  
  75 +{formatter_inl_hpp}
  76 +
75 77 }} // namespace {namespace}
... ...
include/CLI/Formatter.hpp
... ... @@ -17,276 +17,9 @@
17 17  
18 18 namespace CLI {
19 19 // [CLI11:formatter_hpp:verbatim]
20   -
21   -inline std::string
22   -Formatter::make_group(std::string group, bool is_positional, std::vector<const Option *> opts) const {
23   - std::stringstream out;
24   -
25   - out << "\n" << group << ":\n";
26   - for(const Option *opt : opts) {
27   - out << make_option(opt, is_positional);
28   - }
29   -
30   - return out.str();
31   -}
32   -
33   -inline std::string Formatter::make_positionals(const App *app) const {
34   - std::vector<const Option *> opts =
35   - app->get_options([](const Option *opt) { return !opt->get_group().empty() && opt->get_positional(); });
36   -
37   - if(opts.empty())
38   - return {};
39   -
40   - return make_group(get_label("Positionals"), true, opts);
41   -}
42   -
43   -inline std::string Formatter::make_groups(const App *app, AppFormatMode mode) const {
44   - std::stringstream out;
45   - std::vector<std::string> groups = app->get_groups();
46   -
47   - // Options
48   - for(const std::string &group : groups) {
49   - std::vector<const Option *> opts = app->get_options([app, mode, &group](const Option *opt) {
50   - return opt->get_group() == group // Must be in the right group
51   - && opt->nonpositional() // Must not be a positional
52   - && (mode != AppFormatMode::Sub // If mode is Sub, then
53   - || (app->get_help_ptr() != opt // Ignore help pointer
54   - && app->get_help_all_ptr() != opt)); // Ignore help all pointer
55   - });
56   - if(!group.empty() && !opts.empty()) {
57   - out << make_group(group, false, opts);
58   -
59   - if(group != groups.back())
60   - out << "\n";
61   - }
62   - }
63   -
64   - return out.str();
65   -}
66   -
67   -inline std::string Formatter::make_description(const App *app) const {
68   - std::string desc = app->get_description();
69   - auto min_options = app->get_require_option_min();
70   - auto max_options = app->get_require_option_max();
71   - if(app->get_required()) {
72   - desc += " REQUIRED ";
73   - }
74   - if((max_options == min_options) && (min_options > 0)) {
75   - if(min_options == 1) {
76   - desc += " \n[Exactly 1 of the following options is required]";
77   - } else {
78   - desc += " \n[Exactly " + std::to_string(min_options) + "options from the following list are required]";
79   - }
80   - } else if(max_options > 0) {
81   - if(min_options > 0) {
82   - desc += " \n[Between " + std::to_string(min_options) + " and " + std::to_string(max_options) +
83   - " of the follow options are required]";
84   - } else {
85   - desc += " \n[At most " + std::to_string(max_options) + " of the following options are allowed]";
86   - }
87   - } else if(min_options > 0) {
88   - desc += " \n[At least " + std::to_string(min_options) + " of the following options are required]";
89   - }
90   - return (!desc.empty()) ? desc + "\n" : std::string{};
91   -}
92   -
93   -inline std::string Formatter::make_usage(const App *app, std::string name) const {
94   - std::stringstream out;
95   -
96   - out << get_label("Usage") << ":" << (name.empty() ? "" : " ") << name;
97   -
98   - std::vector<std::string> groups = app->get_groups();
99   -
100   - // Print an Options badge if any options exist
101   - std::vector<const Option *> non_pos_options =
102   - app->get_options([](const Option *opt) { return opt->nonpositional(); });
103   - if(!non_pos_options.empty())
104   - out << " [" << get_label("OPTIONS") << "]";
105   -
106   - // Positionals need to be listed here
107   - std::vector<const Option *> positionals = app->get_options([](const Option *opt) { return opt->get_positional(); });
108   -
109   - // Print out positionals if any are left
110   - if(!positionals.empty()) {
111   - // Convert to help names
112   - std::vector<std::string> positional_names(positionals.size());
113   - std::transform(positionals.begin(), positionals.end(), positional_names.begin(), [this](const Option *opt) {
114   - return make_option_usage(opt);
115   - });
116   -
117   - out << " " << detail::join(positional_names, " ");
118   - }
119   -
120   - // Add a marker if subcommands are expected or optional
121   - if(!app->get_subcommands(
122   - [](const CLI::App *subc) { return ((!subc->get_disabled()) && (!subc->get_name().empty())); })
123   - .empty()) {
124   - out << " " << (app->get_require_subcommand_min() == 0 ? "[" : "")
125   - << get_label(app->get_require_subcommand_max() < 2 || app->get_require_subcommand_min() > 1 ? "SUBCOMMAND"
126   - : "SUBCOMMANDS")
127   - << (app->get_require_subcommand_min() == 0 ? "]" : "");
128   - }
129   -
130   - out << std::endl;
131   -
132   - return out.str();
133   -}
134   -
135   -inline std::string Formatter::make_footer(const App *app) const {
136   - std::string footer = app->get_footer();
137   - if(footer.empty()) {
138   - return std::string{};
139   - }
140   - return footer + "\n";
141   -}
142   -
143   -inline std::string Formatter::make_help(const App *app, std::string name, AppFormatMode mode) const {
144   -
145   - // This immediately forwards to the make_expanded method. This is done this way so that subcommands can
146   - // have overridden formatters
147   - if(mode == AppFormatMode::Sub)
148   - return make_expanded(app);
149   -
150   - std::stringstream out;
151   - if((app->get_name().empty()) && (app->get_parent() != nullptr)) {
152   - if(app->get_group() != "Subcommands") {
153   - out << app->get_group() << ':';
154   - }
155   - }
156   -
157   - out << make_description(app);
158   - out << make_usage(app, name);
159   - out << make_positionals(app);
160   - out << make_groups(app, mode);
161   - out << make_subcommands(app, mode);
162   - out << '\n' << make_footer(app);
163   -
164   - return out.str();
165   -}
166   -
167   -inline std::string Formatter::make_subcommands(const App *app, AppFormatMode mode) const {
168   - std::stringstream out;
169   -
170   - std::vector<const App *> subcommands = app->get_subcommands({});
171   -
172   - // Make a list in definition order of the groups seen
173   - std::vector<std::string> subcmd_groups_seen;
174   - for(const App *com : subcommands) {
175   - if(com->get_name().empty()) {
176   - if(!com->get_group().empty()) {
177   - out << make_expanded(com);
178   - }
179   - continue;
180   - }
181   - std::string group_key = com->get_group();
182   - if(!group_key.empty() &&
183   - std::find_if(subcmd_groups_seen.begin(), subcmd_groups_seen.end(), [&group_key](std::string a) {
184   - return detail::to_lower(a) == detail::to_lower(group_key);
185   - }) == subcmd_groups_seen.end())
186   - subcmd_groups_seen.push_back(group_key);
187   - }
188   -
189   - // For each group, filter out and print subcommands
190   - for(const std::string &group : subcmd_groups_seen) {
191   - out << "\n" << group << ":\n";
192   - std::vector<const App *> subcommands_group = app->get_subcommands(
193   - [&group](const App *sub_app) { return detail::to_lower(sub_app->get_group()) == detail::to_lower(group); });
194   - for(const App *new_com : subcommands_group) {
195   - if(new_com->get_name().empty())
196   - continue;
197   - if(mode != AppFormatMode::All) {
198   - out << make_subcommand(new_com);
199   - } else {
200   - out << new_com->help(new_com->get_name(), AppFormatMode::Sub);
201   - out << "\n";
202   - }
203   - }
204   - }
205   -
206   - return out.str();
207   -}
208   -
209   -inline std::string Formatter::make_subcommand(const App *sub) const {
210   - std::stringstream out;
211   - detail::format_help(out, sub->get_display_name(true), sub->get_description(), column_width_);
212   - return out.str();
213   -}
214   -
215   -inline std::string Formatter::make_expanded(const App *sub) const {
216   - std::stringstream out;
217   - out << sub->get_display_name(true) << "\n";
218   -
219   - out << make_description(sub);
220   - if(sub->get_name().empty() && !sub->get_aliases().empty()) {
221   - detail::format_aliases(out, sub->get_aliases(), column_width_ + 2);
222   - }
223   - out << make_positionals(sub);
224   - out << make_groups(sub, AppFormatMode::Sub);
225   - out << make_subcommands(sub, AppFormatMode::Sub);
226   -
227   - // Drop blank spaces
228   - std::string tmp = detail::find_and_replace(out.str(), "\n\n", "\n");
229   - tmp = tmp.substr(0, tmp.size() - 1); // Remove the final '\n'
230   -
231   - // Indent all but the first line (the name)
232   - return detail::find_and_replace(tmp, "\n", "\n ") + "\n";
233   -}
234   -
235   -inline std::string Formatter::make_option_name(const Option *opt, bool is_positional) const {
236   - if(is_positional)
237   - return opt->get_name(true, false);
238   -
239   - return opt->get_name(false, true);
240   -}
241   -
242   -inline std::string Formatter::make_option_opts(const Option *opt) const {
243   - std::stringstream out;
244   -
245   - if(!opt->get_option_text().empty()) {
246   - out << " " << opt->get_option_text();
247   - } else {
248   - if(opt->get_type_size() != 0) {
249   - if(!opt->get_type_name().empty())
250   - out << " " << get_label(opt->get_type_name());
251   - if(!opt->get_default_str().empty())
252   - out << " [" << opt->get_default_str() << "] ";
253   - if(opt->get_expected_max() == detail::expected_max_vector_size)
254   - out << " ...";
255   - else if(opt->get_expected_min() > 1)
256   - out << " x " << opt->get_expected();
257   -
258   - if(opt->get_required())
259   - out << " " << get_label("REQUIRED");
260   - }
261   - if(!opt->get_envname().empty())
262   - out << " (" << get_label("Env") << ":" << opt->get_envname() << ")";
263   - if(!opt->get_needs().empty()) {
264   - out << " " << get_label("Needs") << ":";
265   - for(const Option *op : opt->get_needs())
266   - out << " " << op->get_name();
267   - }
268   - if(!opt->get_excludes().empty()) {
269   - out << " " << get_label("Excludes") << ":";
270   - for(const Option *op : opt->get_excludes())
271   - out << " " << op->get_name();
272   - }
273   - }
274   - return out.str();
275   -}
276   -
277   -inline std::string Formatter::make_option_desc(const Option *opt) const { return opt->get_description(); }
278   -
279   -inline std::string Formatter::make_option_usage(const Option *opt) const {
280   - // Note that these are positionals usages
281   - std::stringstream out;
282   - out << make_option_name(opt, true);
283   - if(opt->get_expected_max() >= detail::expected_max_vector_size)
284   - out << "...";
285   - else if(opt->get_expected_max() > 1)
286   - out << "(" << opt->get_expected() << "x)";
287   -
288   - return opt->get_required() ? out.str() : "[" + out.str() + "]";
289   -}
290   -
291 20 // [CLI11:formatter_hpp:end]
292 21 } // namespace CLI
  22 +
  23 +#ifndef CLI11_COMPILE
  24 +#include "impl/Formatter_inl.hpp"
  25 +#endif
... ...
include/CLI/impl/Formatter_inl.hpp 0 → 100644
  1 +// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
  2 +// under NSF AWARD 1414736 and by the respective contributors.
  3 +// All rights reserved.
  4 +//
  5 +// SPDX-License-Identifier: BSD-3-Clause
  6 +
  7 +#pragma once
  8 +
  9 +// This include is only needed for IDEs to discover symbols
  10 +#include <CLI/Formatter.hpp>
  11 +
  12 +// [CLI11:public_includes:set]
  13 +#include <algorithm>
  14 +#include <string>
  15 +#include <utility>
  16 +#include <vector>
  17 +// [CLI11:public_includes:end]
  18 +
  19 +namespace CLI {
  20 +// [CLI11:formatter_inl_hpp:verbatim]
  21 +CLI11_INLINE std::string
  22 +Formatter::make_group(std::string group, bool is_positional, std::vector<const Option *> opts) const {
  23 + std::stringstream out;
  24 +
  25 + out << "\n" << group << ":\n";
  26 + for(const Option *opt : opts) {
  27 + out << make_option(opt, is_positional);
  28 + }
  29 +
  30 + return out.str();
  31 +}
  32 +
  33 +CLI11_INLINE std::string Formatter::make_positionals(const App *app) const {
  34 + std::vector<const Option *> opts =
  35 + app->get_options([](const Option *opt) { return !opt->get_group().empty() && opt->get_positional(); });
  36 +
  37 + if(opts.empty())
  38 + return {};
  39 +
  40 + return make_group(get_label("Positionals"), true, opts);
  41 +}
  42 +
  43 +CLI11_INLINE std::string Formatter::make_groups(const App *app, AppFormatMode mode) const {
  44 + std::stringstream out;
  45 + std::vector<std::string> groups = app->get_groups();
  46 +
  47 + // Options
  48 + for(const std::string &group : groups) {
  49 + std::vector<const Option *> opts = app->get_options([app, mode, &group](const Option *opt) {
  50 + return opt->get_group() == group // Must be in the right group
  51 + && opt->nonpositional() // Must not be a positional
  52 + && (mode != AppFormatMode::Sub // If mode is Sub, then
  53 + || (app->get_help_ptr() != opt // Ignore help pointer
  54 + && app->get_help_all_ptr() != opt)); // Ignore help all pointer
  55 + });
  56 + if(!group.empty() && !opts.empty()) {
  57 + out << make_group(group, false, opts);
  58 +
  59 + if(group != groups.back())
  60 + out << "\n";
  61 + }
  62 + }
  63 +
  64 + return out.str();
  65 +}
  66 +
  67 +CLI11_INLINE std::string Formatter::make_description(const App *app) const {
  68 + std::string desc = app->get_description();
  69 + auto min_options = app->get_require_option_min();
  70 + auto max_options = app->get_require_option_max();
  71 + if(app->get_required()) {
  72 + desc += " REQUIRED ";
  73 + }
  74 + if((max_options == min_options) && (min_options > 0)) {
  75 + if(min_options == 1) {
  76 + desc += " \n[Exactly 1 of the following options is required]";
  77 + } else {
  78 + desc += " \n[Exactly " + std::to_string(min_options) + "options from the following list are required]";
  79 + }
  80 + } else if(max_options > 0) {
  81 + if(min_options > 0) {
  82 + desc += " \n[Between " + std::to_string(min_options) + " and " + std::to_string(max_options) +
  83 + " of the follow options are required]";
  84 + } else {
  85 + desc += " \n[At most " + std::to_string(max_options) + " of the following options are allowed]";
  86 + }
  87 + } else if(min_options > 0) {
  88 + desc += " \n[At least " + std::to_string(min_options) + " of the following options are required]";
  89 + }
  90 + return (!desc.empty()) ? desc + "\n" : std::string{};
  91 +}
  92 +
  93 +CLI11_INLINE std::string Formatter::make_usage(const App *app, std::string name) const {
  94 + std::stringstream out;
  95 +
  96 + out << get_label("Usage") << ":" << (name.empty() ? "" : " ") << name;
  97 +
  98 + std::vector<std::string> groups = app->get_groups();
  99 +
  100 + // Print an Options badge if any options exist
  101 + std::vector<const Option *> non_pos_options =
  102 + app->get_options([](const Option *opt) { return opt->nonpositional(); });
  103 + if(!non_pos_options.empty())
  104 + out << " [" << get_label("OPTIONS") << "]";
  105 +
  106 + // Positionals need to be listed here
  107 + std::vector<const Option *> positionals = app->get_options([](const Option *opt) { return opt->get_positional(); });
  108 +
  109 + // Print out positionals if any are left
  110 + if(!positionals.empty()) {
  111 + // Convert to help names
  112 + std::vector<std::string> positional_names(positionals.size());
  113 + std::transform(positionals.begin(), positionals.end(), positional_names.begin(), [this](const Option *opt) {
  114 + return make_option_usage(opt);
  115 + });
  116 +
  117 + out << " " << detail::join(positional_names, " ");
  118 + }
  119 +
  120 + // Add a marker if subcommands are expected or optional
  121 + if(!app->get_subcommands(
  122 + [](const CLI::App *subc) { return ((!subc->get_disabled()) && (!subc->get_name().empty())); })
  123 + .empty()) {
  124 + out << " " << (app->get_require_subcommand_min() == 0 ? "[" : "")
  125 + << get_label(app->get_require_subcommand_max() < 2 || app->get_require_subcommand_min() > 1 ? "SUBCOMMAND"
  126 + : "SUBCOMMANDS")
  127 + << (app->get_require_subcommand_min() == 0 ? "]" : "");
  128 + }
  129 +
  130 + out << std::endl;
  131 +
  132 + return out.str();
  133 +}
  134 +
  135 +CLI11_INLINE std::string Formatter::make_footer(const App *app) const {
  136 + std::string footer = app->get_footer();
  137 + if(footer.empty()) {
  138 + return std::string{};
  139 + }
  140 + return footer + "\n";
  141 +}
  142 +
  143 +CLI11_INLINE std::string Formatter::make_help(const App *app, std::string name, AppFormatMode mode) const {
  144 +
  145 + // This immediately forwards to the make_expanded method. This is done this way so that subcommands can
  146 + // have overridden formatters
  147 + if(mode == AppFormatMode::Sub)
  148 + return make_expanded(app);
  149 +
  150 + std::stringstream out;
  151 + if((app->get_name().empty()) && (app->get_parent() != nullptr)) {
  152 + if(app->get_group() != "Subcommands") {
  153 + out << app->get_group() << ':';
  154 + }
  155 + }
  156 +
  157 + out << make_description(app);
  158 + out << make_usage(app, name);
  159 + out << make_positionals(app);
  160 + out << make_groups(app, mode);
  161 + out << make_subcommands(app, mode);
  162 + out << '\n' << make_footer(app);
  163 +
  164 + return out.str();
  165 +}
  166 +
  167 +CLI11_INLINE std::string Formatter::make_subcommands(const App *app, AppFormatMode mode) const {
  168 + std::stringstream out;
  169 +
  170 + std::vector<const App *> subcommands = app->get_subcommands({});
  171 +
  172 + // Make a list in definition order of the groups seen
  173 + std::vector<std::string> subcmd_groups_seen;
  174 + for(const App *com : subcommands) {
  175 + if(com->get_name().empty()) {
  176 + if(!com->get_group().empty()) {
  177 + out << make_expanded(com);
  178 + }
  179 + continue;
  180 + }
  181 + std::string group_key = com->get_group();
  182 + if(!group_key.empty() &&
  183 + std::find_if(subcmd_groups_seen.begin(), subcmd_groups_seen.end(), [&group_key](std::string a) {
  184 + return detail::to_lower(a) == detail::to_lower(group_key);
  185 + }) == subcmd_groups_seen.end())
  186 + subcmd_groups_seen.push_back(group_key);
  187 + }
  188 +
  189 + // For each group, filter out and print subcommands
  190 + for(const std::string &group : subcmd_groups_seen) {
  191 + out << "\n" << group << ":\n";
  192 + std::vector<const App *> subcommands_group = app->get_subcommands(
  193 + [&group](const App *sub_app) { return detail::to_lower(sub_app->get_group()) == detail::to_lower(group); });
  194 + for(const App *new_com : subcommands_group) {
  195 + if(new_com->get_name().empty())
  196 + continue;
  197 + if(mode != AppFormatMode::All) {
  198 + out << make_subcommand(new_com);
  199 + } else {
  200 + out << new_com->help(new_com->get_name(), AppFormatMode::Sub);
  201 + out << "\n";
  202 + }
  203 + }
  204 + }
  205 +
  206 + return out.str();
  207 +}
  208 +
  209 +CLI11_INLINE std::string Formatter::make_subcommand(const App *sub) const {
  210 + std::stringstream out;
  211 + detail::format_help(out, sub->get_display_name(true), sub->get_description(), column_width_);
  212 + return out.str();
  213 +}
  214 +
  215 +CLI11_INLINE std::string Formatter::make_expanded(const App *sub) const {
  216 + std::stringstream out;
  217 + out << sub->get_display_name(true) << "\n";
  218 +
  219 + out << make_description(sub);
  220 + if(sub->get_name().empty() && !sub->get_aliases().empty()) {
  221 + detail::format_aliases(out, sub->get_aliases(), column_width_ + 2);
  222 + }
  223 + out << make_positionals(sub);
  224 + out << make_groups(sub, AppFormatMode::Sub);
  225 + out << make_subcommands(sub, AppFormatMode::Sub);
  226 +
  227 + // Drop blank spaces
  228 + std::string tmp = detail::find_and_replace(out.str(), "\n\n", "\n");
  229 + tmp = tmp.substr(0, tmp.size() - 1); // Remove the final '\n'
  230 +
  231 + // Indent all but the first line (the name)
  232 + return detail::find_and_replace(tmp, "\n", "\n ") + "\n";
  233 +}
  234 +
  235 +CLI11_INLINE std::string Formatter::make_option_name(const Option *opt, bool is_positional) const {
  236 + if(is_positional)
  237 + return opt->get_name(true, false);
  238 +
  239 + return opt->get_name(false, true);
  240 +}
  241 +
  242 +CLI11_INLINE std::string Formatter::make_option_opts(const Option *opt) const {
  243 + std::stringstream out;
  244 +
  245 + if(!opt->get_option_text().empty()) {
  246 + out << " " << opt->get_option_text();
  247 + } else {
  248 + if(opt->get_type_size() != 0) {
  249 + if(!opt->get_type_name().empty())
  250 + out << " " << get_label(opt->get_type_name());
  251 + if(!opt->get_default_str().empty())
  252 + out << " [" << opt->get_default_str() << "] ";
  253 + if(opt->get_expected_max() == detail::expected_max_vector_size)
  254 + out << " ...";
  255 + else if(opt->get_expected_min() > 1)
  256 + out << " x " << opt->get_expected();
  257 +
  258 + if(opt->get_required())
  259 + out << " " << get_label("REQUIRED");
  260 + }
  261 + if(!opt->get_envname().empty())
  262 + out << " (" << get_label("Env") << ":" << opt->get_envname() << ")";
  263 + if(!opt->get_needs().empty()) {
  264 + out << " " << get_label("Needs") << ":";
  265 + for(const Option *op : opt->get_needs())
  266 + out << " " << op->get_name();
  267 + }
  268 + if(!opt->get_excludes().empty()) {
  269 + out << " " << get_label("Excludes") << ":";
  270 + for(const Option *op : opt->get_excludes())
  271 + out << " " << op->get_name();
  272 + }
  273 + }
  274 + return out.str();
  275 +}
  276 +
  277 +CLI11_INLINE std::string Formatter::make_option_desc(const Option *opt) const { return opt->get_description(); }
  278 +
  279 +CLI11_INLINE std::string Formatter::make_option_usage(const Option *opt) const {
  280 + // Note that these are positionals usages
  281 + std::stringstream out;
  282 + out << make_option_name(opt, true);
  283 + if(opt->get_expected_max() >= detail::expected_max_vector_size)
  284 + out << "...";
  285 + else if(opt->get_expected_max() > 1)
  286 + out << "(" << opt->get_expected() << "x)";
  287 +
  288 + return opt->get_required() ? out.str() : "[" + out.str() + "]";
  289 +}
  290 +// [CLI11:formatter_inl_hpp:end]
  291 +} // namespace CLI
... ...
src/Formatter.cpp 0 → 100644
  1 +// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
  2 +// under NSF AWARD 1414736 and by the respective contributors.
  3 +// All rights reserved.
  4 +//
  5 +// SPDX-License-Identifier: BSD-3-Clause
  6 +
  7 +#include <CLI/impl/Formatter_inl.hpp>
... ...