CLI11  2.1.2
Formatter.hpp
Go to the documentation of this file.
1 // Copyright (c) 2017-2021, 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 // [CLI11:public_includes:set]
10 #include <algorithm>
11 #include <string>
12 #include <vector>
13 // [CLI11:public_includes:end]
14 
15 #include "App.hpp"
16 #include "FormatterFwd.hpp"
17 
18 namespace CLI {
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 std::string();
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;
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()) {
222  }
223  out << make_positionals(sub);
224  out << make_groups(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();
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);
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 // [CLI11:formatter_hpp:end]
292 } // namespace CLI
virtual std::string make_option_desc(const Option *) const
This is the description. Default: Right column, on new line if left column too large.
Definition: Formatter.hpp:277
std::size_t get_require_subcommand_max() const
Get the required max subcommand value.
Definition: App.hpp:1684
virtual std::string make_option(const Option *opt, bool is_positional) const
This prints out an option help line, either positional or optional form.
Definition: FormatterFwd.hpp:161
std::size_t get_require_option_min() const
Get the required min option value.
Definition: App.hpp:1687
std::size_t get_require_option_max() const
Get the required max option value.
Definition: App.hpp:1690
std::string get_footer() const
Generate and return the footer.
Definition: App.hpp:1678
int get_expected_min() const
The number of times the option expects to be included.
Definition: Option.hpp:734
virtual std::string make_subcommands(const App *app, AppFormatMode mode) const
This prints out all the subcommands.
Definition: Formatter.hpp:167
virtual std::string make_option_name(const Option *, bool) const
This is the name part of an option, Default: left column.
Definition: Formatter.hpp:235
const std::string & get_description() const
Get the description.
Definition: Option.hpp:759
Definition: App.hpp:34
int get_type_size() const
The number of arguments the option expects.
Definition: Option.hpp:684
bool get_required() const
True if this is a required option.
Definition: Option.hpp:124
virtual std::string make_subcommand(const App *sub) const
This prints out a subcommand.
Definition: Formatter.hpp:209
std::string get_description() const
Get the app or subcommand description.
Definition: App.hpp:1553
int get_expected_max() const
The max number of times the option expects to be included.
Definition: Option.hpp:736
virtual std::string make_description(const App *app) const
This displays the description line.
Definition: Formatter.hpp:67
A fully expanded help.
int get_expected() const
The number of times the option expects to be included.
Definition: Option.hpp:731
std::string get_envname() const
The environment variable associated to this value.
Definition: Option.hpp:695
Definition: Option.hpp:237
std::vector< App * > get_subcommands() const
Definition: App.hpp:1347
bool nonpositional() const
True if option has at least one non-positional name.
Definition: Option.hpp:753
virtual std::string make_option_opts(const Option *) const
This is the options part of the name, Default: combined into left column.
Definition: Formatter.hpp:242
std::string make_groups(const App *app, AppFormatMode mode) const
This prints out all the groups of options.
Definition: Formatter.hpp:43
auto to_string(T &&value) -> decltype(std::forward< T >(value))
Convert an object to a string (directly forward if this can become a string)
Definition: TypeTools.hpp:269
App * get_parent()
Get the parent of this subcommand (or nullptr if main app)
Definition: App.hpp:1743
std::string get_label(std::string key) const
Get the current value of a name (REQUIRED, etc.)
Definition: FormatterFwd.hpp:81
std::string join(const T &v, std::string delim=",")
Simple function to join a string.
Definition: StringTools.hpp:63
std::string get_name(bool positional=false, bool all_options=false) const
Gets a comma separated list of names. Will include / prefer the positional name if positional is true...
Definition: Option.hpp:782
AppFormatMode
Definition: FormatterFwd.hpp:29
std::ostream & format_help(std::ostream &out, std::string name, const std::string &description, std::size_t wid)
Print a two part "help" string.
Definition: StringTools.hpp:182
std::ostream & format_aliases(std::ostream &out, const std::vector< std::string > &aliases, std::size_t wid)
Print subcommand aliases.
Definition: StringTools.hpp:200
std::vector< const Option * > get_options(const std::function< bool(const Option *)> filter={}) const
Get the list of options (user facing function, so returns raw pointers), has optional filter function...
Definition: App.hpp:1562
virtual std::string make_group(std::string group, bool is_positional, std::vector< const Option *> opts) const
Definition: Formatter.hpp:22
virtual std::string make_usage(const App *app, std::string name) const
This displays the usage line.
Definition: Formatter.hpp:93
Option * get_help_ptr()
Get a pointer to the help flag.
Definition: App.hpp:1722
std::size_t column_width_
The width of the first column.
Definition: FormatterFwd.hpp:45
const std::string & get_name() const
Get the name of the current app.
Definition: App.hpp:1749
std::string to_lower(std::string str)
Return a lower case version of a string.
Definition: StringTools.hpp:259
const std::string & get_group() const
Get the group of this option.
Definition: Option.hpp:121
const std::vector< std::string > & get_aliases() const
Get the aliases of the current app.
Definition: App.hpp:1752
const std::string & get_group() const
Get the group of this subcommand.
Definition: App.hpp:1675
virtual std::string make_option_usage(const Option *opt) const
This is used to print the name on the USAGE line.
Definition: Formatter.hpp:279
std::string get_type_name() const
Get the full typename for this option.
Definition: Option.hpp:1183
const std::string & get_option_text() const
Definition: Option.hpp:772
std::set< Option * > get_excludes() const
The set of options excluded.
Definition: Option.hpp:701
bool get_positional() const
True if the argument can be given directly.
Definition: Option.hpp:750
Creates a command line program, with very few defaults.
Definition: App.hpp:69
bool get_required() const
Get the status of required.
Definition: App.hpp:1699
std::string find_and_replace(std::string str, std::string from, std::string to)
Find and replace a substring with another substring.
Definition: StringTools.hpp:273
std::string make_help(const App *, std::string, AppFormatMode) const override
This puts everything together.
Definition: Formatter.hpp:143
std::size_t get_require_subcommand_min() const
Get the required min subcommand value.
Definition: App.hpp:1681
Used when printed as part of expanded subcommand.
std::string get_default_str() const
The default value (for help printing)
Definition: Option.hpp:704
virtual std::string make_positionals(const App *app) const
This prints out just the positionals "group".
Definition: Formatter.hpp:33
std::set< Option * > get_needs() const
The set of options needed.
Definition: Option.hpp:698
std::string get_display_name(bool with_aliases=false) const
Get a display name for an app.
Definition: App.hpp:1761
constexpr int expected_max_vector_size
Definition: StringTools.hpp:43
std::vector< std::string > get_groups() const
Get the groups available directly from this option (in order)
Definition: App.hpp:1807
virtual std::string make_expanded(const App *sub) const
This prints out a subcommand in help-all.
Definition: Formatter.hpp:215
const Option * get_help_all_ptr() const
Get a pointer to the help all flag. (const)
Definition: App.hpp:1728
virtual std::string make_footer(const App *app) const
This prints out all the groups of options.
Definition: Formatter.hpp:135