CLI11 2.2.0
Loading...
Searching...
No Matches
Formatter.hpp
Go to the documentation of this file.
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// [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
18namespace CLI {
19// [CLI11:formatter_hpp:verbatim]
20
21inline std::string
22Formatter::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
33inline 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
43inline 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
67inline 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
93inline 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
135inline 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
143inline 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
167inline 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
209inline std::string Formatter::make_subcommand(const App *sub) const {
210 std::stringstream out;
212 return out.str();
213}
214
215inline 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
235inline 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
242inline 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
277inline std::string Formatter::make_option_desc(const Option *opt) const { return opt->get_description(); }
278
279inline 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
Creates a command line program, with very few defaults.
Definition App.hpp:85
std::size_t get_require_option_min() const
Get the required min option value.
Definition App.hpp:1692
const Option * get_help_all_ptr() const
Get a pointer to the help all flag. (const)
Definition App.hpp:1735
Option * get_help_ptr()
Get a pointer to the help flag.
Definition App.hpp:1729
App * get_parent()
Get the parent of this subcommand (or nullptr if main app)
Definition App.hpp:1750
const std::vector< std::string > & get_aliases() const
Get the aliases of the current app.
Definition App.hpp:1759
std::vector< App * > get_subcommands() const
Definition App.hpp:1352
const std::string & get_group() const
Get the group of this subcommand.
Definition App.hpp:1680
bool get_required() const
Get the status of required.
Definition App.hpp:1704
std::size_t get_require_subcommand_max() const
Get the required max subcommand value.
Definition App.hpp:1689
std::string get_display_name(bool with_aliases=false) const
Get a display name for an app.
Definition App.hpp:1768
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:1567
std::string get_description() const
Get the app or subcommand description.
Definition App.hpp:1558
std::size_t get_require_option_max() const
Get the required max option value.
Definition App.hpp:1695
std::string get_footer() const
Generate and return the footer.
Definition App.hpp:1683
const std::string & get_name() const
Get the name of the current app.
Definition App.hpp:1756
std::vector< std::string > get_groups() const
Get the groups available directly from this option (in order)
Definition App.hpp:1814
std::size_t get_require_subcommand_min() const
Get the required min subcommand value.
Definition App.hpp:1686
std::size_t column_width_
The width of the first column.
Definition FormatterFwd.hpp:45
std::string get_label(std::string key) const
Get the current value of a name (REQUIRED, etc.)
Definition FormatterFwd.hpp:81
virtual std::string make_description(const App *app) const
This displays the description line.
Definition Formatter.hpp:67
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
virtual std::string make_usage(const App *app, std::string name) const
This displays the usage line.
Definition Formatter.hpp:93
virtual std::string make_subcommand(const App *sub) const
This prints out a subcommand.
Definition Formatter.hpp:209
std::string make_help(const App *, std::string, AppFormatMode) const override
This puts everything together.
Definition Formatter.hpp:143
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_opts(const Option *) const
This is the options part of the name, Default: combined into left column.
Definition Formatter.hpp:242
virtual std::string make_positionals(const App *app) const
This prints out just the positionals "group".
Definition Formatter.hpp:33
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
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
virtual std::string make_footer(const App *app) const
This prints out all the groups of options.
Definition Formatter.hpp:135
std::string make_groups(const App *app, AppFormatMode mode) const
This prints out all the groups of options.
Definition Formatter.hpp:43
virtual std::string make_expanded(const App *sub) const
This prints out a subcommand in help-all.
Definition Formatter.hpp:215
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_option_usage(const Option *opt) const
This is used to print the name on the USAGE line.
Definition Formatter.hpp:279
bool get_required() const
True if this is a required option.
Definition Option.hpp:125
const std::string & get_group() const
Get the group of this option.
Definition Option.hpp:122
Definition Option.hpp:238
const std::string & get_option_text() const
Definition Option.hpp:773
int get_expected_min() const
The number of times the option expects to be included.
Definition Option.hpp:735
int get_expected_max() const
The max number of times the option expects to be included.
Definition Option.hpp:737
int get_expected() const
The number of times the option expects to be included.
Definition Option.hpp:732
std::string get_default_str() const
The default value (for help printing)
Definition Option.hpp:705
const std::string & get_description() const
Get the description.
Definition Option.hpp:760
std::set< Option * > get_excludes() const
The set of options excluded.
Definition Option.hpp:702
int get_type_size() const
The number of arguments the option expects.
Definition Option.hpp:685
std::string get_type_name() const
Get the full typename for this option.
Definition Option.hpp:1184
bool nonpositional() const
True if option has at least one non-positional name.
Definition Option.hpp:754
std::string get_envname() const
The environment variable associated to this value.
Definition Option.hpp:696
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:783
bool get_positional() const
True if the argument can be given directly.
Definition Option.hpp:751
std::set< Option * > get_needs() const
The set of options needed.
Definition Option.hpp:699
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
constexpr int expected_max_vector_size
Definition StringTools.hpp:43
std::string join(const T &v, std::string delim=",")
Simple function to join a string.
Definition StringTools.hpp:63
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 to_lower(std::string str)
Return a lower case version of a string.
Definition StringTools.hpp:259
Definition App.hpp:34
AppFormatMode
Definition FormatterFwd.hpp:29
@ All
A fully expanded help.
@ Sub
Used when printed as part of expanded subcommand.