2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
44#ifndef DOXYGEN_SHOULD_SKIP_THIS
60 CLI11_INLINE std::string
62 std::stringstream out;
63 std::string commentLead;
64 commentLead.push_back(commentChar);
65 commentLead.push_back(
' ');
67 std::vector<std::string> groups = app->get_groups();
68 bool defaultUsed =
false;
69 groups.insert(groups.begin(), std::string(
"Options"));
70 for (
const auto& group : groups) {
71 if (group ==
"Options" || group.empty()) {
77 if (write_description && group !=
"Options" && !group.empty() &&
78 !app->get_options([group](
const Option* opt) ->
bool {
79 return opt->get_group() == group && opt->get_configurable();
82 out <<
'\n' << commentChar << commentLead << group <<
"\n";
84 for (
const Option* opt : app->get_options({})) {
86 if (opt->get_configurable()) {
87 if (opt->get_group() != group) {
88 if (!(group ==
"Options" && opt->get_group().empty())) {
92 const std::string name = prefix + opt->get_single_name();
94 detail::ini_join(opt->reduced_results(), arraySeparator, arrayStart, arrayEnd, stringQuote, literalQuote);
96 std::string defaultValue{};
98 static_assert(std::string::npos +
static_cast<std::string::size_type>(1) == 0,
99 "std::string::npos + static_cast<std::string::size_type>(1) != 0");
100 if (!value.empty() && detail::convert_arg_for_ini(opt->get_default_str(), stringQuote, literalQuote) == value) {
103 if (!opt->get_default_str().empty()) {
104 defaultValue = detail::convert_arg_for_ini(opt->get_default_str(), stringQuote, literalQuote);
105 if (defaultValue ==
"'\"\"'") {
108 }
else if (opt->get_run_callback_for_default()) {
109 defaultValue =
"\"\"";
110 }
else if (opt->get_required()) {
111 defaultValue =
"\"<REQUIRED>\"";
112 }
else if (opt->get_expected_min() == 0) {
113 defaultValue =
"false";
115 defaultValue =
"\"\"";
118 if (write_description && opt->has_description() && (default_also || !value.empty())) {
119 out << commentLead << detail::fix_newlines(commentLead, opt->get_description()) <<
'\n';
121 if (default_also && !defaultValue.empty()) {
122 out << commentChar << name << valueDelimiter << defaultValue <<
"\n";
124 if (!value.empty()) {
125 if (!opt->get_fnames().empty()) {
126 value = opt->get_flag_value(name, value);
128 if (value ==
"\"default\"") {
131 out << name << valueDelimiter << value <<
"\n\n";
138 auto subcommands = app->get_subcommands({});
139 for (
const App* subcom : subcommands) {
140 if (subcom->get_name().empty()) {
141 if (write_description && !subcom->get_group().empty()) {
142 out <<
'\n' << commentLead << subcom->get_group() <<
" Options\n";
144 out <<
to_config(subcom
, default_also
, write_description
, prefix
);
148 for (
const App* subcom : subcommands) {
149 if (!subcom->get_name().empty()) {
150 if (subcom->get_configurable() && app->got_subcommand(subcom)) {
151 if (!prefix.empty() || app->get_parent() ==
nullptr) {
152 out <<
'[' << prefix << subcom->get_name() <<
"]\n";
154 std::string subname = app->get_name() + parentSeparatorChar + subcom->get_name();
155 const auto* p = app->get_parent();
156 while (p->get_parent() !=
nullptr) {
157 subname = p->get_name() + parentSeparatorChar + subname;
160 out <<
'[' << subname <<
"]\n";
164 out <<
to_config(subcom
, default_also
, write_description
, prefix + subcom->get_name() + parentSeparatorChar
);
169 std::string outString;
170 if (write_description && !out.str().empty()) {
172 commentChar + std::string(
"#") + commentLead + detail::fix_newlines(commentChar + commentLead, app->get_description());
175 return outString + out.str();
181 CLI11_INLINE std::string
HelpFormatter::
make_group(std::string group,
bool is_positional, std::vector<
const Option*> opts)
const {
182 std::stringstream out;
185 out <<
"\n" << group <<
":\n";
186 for (
const Option* opt : opts) {
187 out << make_option(opt, is_positional);
194 std::string desc = app->get_description();
195 auto min_options = app->get_require_option_min();
196 auto max_options = app->get_require_option_max();
198 if ((max_options == min_options) && (min_options > 0)) {
199 if (min_options == 1) {
200 desc +=
" \n[Exactly 1 of the following options is required]";
202 desc +=
" \n[Exactly " + std::to_string(min_options) +
" options from the following list are required]";
204 }
else if (max_options > 0) {
205 if (min_options > 0) {
206 desc +=
" \n[Between " + std::to_string(min_options) +
" and " + std::to_string(max_options) +
207 " of the follow options are required]";
209 desc +=
" \n[At most " + std::to_string(max_options) +
" of the following options are allowed]";
211 }
else if (min_options > 0) {
212 desc +=
" \n[At least " + std::to_string(min_options) +
" of the following options are required]";
214 return (!desc.empty()) ? desc +
"\n" : std::string{};
218 const std::string usage = app->get_usage();
219 if (!usage.empty()) {
223 std::stringstream out;
225 out << get_label(
"Usage") <<
":" << (name.empty() ?
"" :
" ") << name;
228 const std::vector<
const Option*> non_pos_options = app->get_options([](
const Option* opt) {
229 return opt->nonpositional();
231 if (!non_pos_options.empty()) {
232 out <<
" [" << get_label(
"OPTIONS") <<
"]";
236 std::vector<
const Option*> positionals = app->get_options([](
const Option* opt) {
237 return opt->get_positional();
241 if (!positionals.empty()) {
243 std::vector<std::string> positional_names(positionals.size());
244 std::transform(positionals.begin(), positionals.end(), positional_names.begin(), [
this](
const Option* opt) {
245 return make_option_usage(opt);
248 out <<
" " << detail::join(positional_names,
" ");
252 if (!app->get_subcommands([](
const App* subc) {
253 return !subc->get_disabled() && !subc->get_name().empty();
258 << get_label(app->get_subcommands([](
const CLI::App* subc) {
259 return ((!subc->get_disabled()) && (!subc->get_name().empty()) );
267 const Option* disabledOpt = app->get_option_no_throw(
"--disabled");
268 if (disabledOpt !=
nullptr ? disabledOpt->as<
bool>() :
false) {
269 out <<
" " << get_label(
"DISABLED");
270 }
else if (app->get_required()) {
271 out <<
" " << get_label(
"REQUIRED");
274 out << std::endl << std::endl;
280 std::stringstream out;
282 const std::vector<
const App*> subcommands = app->get_subcommands([](
const App* subc) {
283 if (subc->get_group() ==
"Instances") {
284 if (subc->get_option(
"--disabled")->as<
bool>()) {
285 const_cast<
CLI::App*>(subc)->group(subc->get_group() +
" (disabled)");
288 return !subc->get_disabled() && !subc->get_name().empty();
292 std::set<std::string> subcmd_groups_seen;
293 for (
const App* com : subcommands) {
294 if (com->get_name().empty()) {
295 if (!com->get_group().empty()) {
300 std::string group_key = com->get_group();
301 if (!group_key.empty() &&
302 std::find_if(subcmd_groups_seen.begin(), subcmd_groups_seen.end(), [&group_key](
const std::string& a) {
303 return detail::to_lower(a) == detail::to_lower(group_key);
304 }) == subcmd_groups_seen.end()) {
305 subcmd_groups_seen.insert(group_key);
310 const Option* disabledOpt = app->get_option_no_throw(
"--disabled");
311 bool disabled =
false;
312 if (disabledOpt !=
nullptr) {
313 disabled = disabledOpt->as<
bool>();
317 for (
const std::string& group : subcmd_groups_seen) {
318 out <<
"\n" << group <<
":\n";
319 const std::vector<
const App*> subcommands_group = app->get_subcommands([&group](
const App* sub_app) {
320 return detail::to_lower(sub_app->get_group()) == detail::to_lower(group) && !sub_app->get_disabled() &&
321 !sub_app->get_name().empty();
323 for (
const App* new_com : subcommands_group) {
324 if (new_com->get_name().empty()) {
327 if (mode != AppFormatMode::All) {
330 out << new_com->help(disabledOpt !=
nullptr && (app->get_help_ptr()->as<std::string>() ==
"exact" ||
331 app->get_help_ptr()->as<std::string>() ==
"expanded")
344 std::string tmp = out.str();
345 if (mode == AppFormatMode::All && !tmp.empty()) {
356 std::stringstream out;
357 std::string name =
" " + sub->get_display_name(
true) + (sub->get_required() ?
" " + get_label(
"REQUIRED") :
"");
359 out << std::setw(
static_cast<
int>(column_width_)) << std::left << name;
360 std::string desc = sub->get_description();
362 bool skipFirstLinePrefix =
true;
363 if (out.str().length() >= column_width_) {
365 skipFirstLinePrefix =
false;
367 detail::streamOutAsParagraph(out, desc, right_column_width_, std::string(column_width_,
' '), skipFirstLinePrefix);
376 std::stringstream out;
378 const Option* disabledOpt = sub->get_option_no_throw(
"--disabled");
379 out << sub->get_display_name(
true) +
" [OPTIONS]" + (!sub->get_subcommands({}).empty() ?
" [SECTIONS]" :
"") +
380 ((disabledOpt !=
nullptr ? disabledOpt->as<
bool>() :
false) ?
" " + get_label(
"DISABLED")
381 : (sub->get_required() ?
" " + get_label(
"REQUIRED") :
""))
384 detail::streamOutAsParagraph(out,
make_description(sub
), description_paragraph_width_,
"");
386 if (sub->get_name().empty() && !sub->get_aliases().empty()) {
387 detail::format_aliases(out, sub->get_aliases(), column_width_ + 2);
389 out << make_positionals(sub);
390 out << make_groups(sub, mode);
394 std::string tmp = out.str();
398 return detail::find_and_replace(tmp,
"\n",
"\n ") +
"\n";
402 std::stringstream out;
404 if (!opt->get_option_text().empty()) {
405 out <<
" " << opt->get_option_text();
407 if (opt->get_type_size() != 0) {
408 if (!opt->get_type_name().empty()) {
410 out << ((opt->get_items_expected_max() == 0) ?
"=" :
" ") << get_label(opt->get_type_name());
412 if (!opt->get_default_str().empty()) {
413 out <<
" [" << opt->get_default_str() <<
"]";
415 if (opt->count() > 0 && opt->get_default_str() != opt->as<std::string>()) {
416 out <<
" {" << opt->as<std::string>() <<
"}";
418 if (opt->get_expected_max() == detail::expected_max_vector_size) {
420 }
else if (opt->get_expected_min() > 1) {
421 out <<
" x " << opt->get_expected();
423 if (opt->get_required() && !get_label(
"REQUIRED").empty()) {
424 out <<
" " << get_label(
"REQUIRED");
426 if (opt->get_configurable() && !get_label(
"PERSISTENT").empty()) {
427 out <<
" " << get_label(
"PERSISTENT");
430 if (!opt->get_envname().empty()) {
431 out <<
" (" << get_label(
"Env") <<
":" << opt->get_envname() <<
") ";
433 if (!opt->get_needs().empty()) {
434 out <<
" " << get_label(
"Needs") <<
":";
435 for (
const Option* op : opt->get_needs()) {
436 out <<
" " << op->get_name();
439 if (!opt->get_excludes().empty()) {
440 out <<
" " << get_label(
"Excludes") <<
":";
441 for (
const Option* op : opt->get_excludes()) {
442 out <<
" " << op->get_name();