Sharg 1.1.2-rc.1
The argument parser for bio-c++ tools.
Loading...
Searching...
No Matches
format_base.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2006-2024, Knut Reinert & Freie Universität Berlin
2// SPDX-FileCopyrightText: 2016-2024, Knut Reinert & MPI für molekulare Genetik
3// SPDX-License-Identifier: BSD-3-Clause
4
11#pragma once
12
13#include <sharg/auxiliary.hpp>
14#include <sharg/config.hpp>
17#include <sharg/validators.hpp>
18
19#if __has_include(<seqan3/version.hpp>)
20# include <seqan3/version.hpp>
21#endif
22
23namespace sharg::detail
24{
25
31{
32protected:
37 template <typename value_type>
38 static std::string get_type_name_as_string(value_type const & )
39 {
40 using type = std::decay_t<value_type>;
41
42 if constexpr (std::is_same_v<type, int8_t>)
43 return "signed 8 bit integer";
44 else if constexpr (std::is_same_v<type, uint8_t>)
45 return "unsigned 8 bit integer";
46 else if constexpr (std::is_same_v<type, int16_t>)
47 return "signed 16 bit integer";
48 else if constexpr (std::is_same_v<type, uint16_t>)
49 return "unsigned 16 bit integer";
50 else if constexpr (std::is_same_v<type, int32_t>)
51 return "signed 32 bit integer";
52 else if constexpr (std::is_same_v<type, uint32_t>)
53 return "unsigned 32 bit integer";
54 else if constexpr (std::is_same_v<type, int64_t>)
55 return "signed 64 bit integer";
56 else if constexpr (std::is_same_v<type, uint64_t>)
57 return "unsigned 64 bit integer";
58 else if constexpr (std::is_same_v<type, double>)
59 return "double";
60 else if constexpr (std::is_same_v<type, float>)
61 return "float";
62 else if constexpr (std::is_same_v<type, bool>)
63 return "bool";
64 else if constexpr (std::is_same_v<type, char>)
65 return "char";
66 else if constexpr (std::is_same_v<type, std::string>)
67 return "std::string";
69 return "std::filesystem::path";
70 else
71 return sharg::detail::type_name_as_string<value_type>;
72 }
73
78 template <detail::is_container_option container_type>
79 static std::string get_type_name_as_string(container_type const & )
80 {
81 typename container_type::value_type tmp{};
82 return get_type_name_as_string(tmp);
83 }
84
90 template <typename option_value_type>
91 static std::string option_type_and_list_info(option_value_type const & value)
92 {
93 return ("(\\fI" + get_type_name_as_string(value) + "\\fP)");
94 }
95
102 template <detail::is_container_option container_type>
103 static std::string option_type_and_list_info(container_type const & container)
104 {
105 return ("(\\fIList\\fP of \\fI" + get_type_name_as_string(container) + "\\fP)");
106 }
107
115 static std::string prep_id_for_help(char const short_id, std::string const & long_id)
116 {
117 // Build list item term.
118 std::string term;
119 if (short_id != '\0')
120 term = "\\fB-" + std::string(1, short_id) + "\\fP";
121
122 if (short_id != '\0' && !long_id.empty())
123 term.append(", ");
124
125 if (!long_id.empty())
126 term.append("\\fB--" + long_id + "\\fP");
127
128 return term;
129 }
130
138 {
139 std::string escaped;
140 escaped.reserve(original.size()); // will be at least as long
141
142 for (auto c : original)
143 {
144 if (c == '"')
145 escaped.append("&quot;");
146 else if (c == '\'')
147 escaped.append("&apos;");
148 else if (c == '&')
149 escaped.append("&amp;");
150 else if (c == '<')
151 escaped.append("&lt;");
152 else if (c == '>')
153 escaped.append("&gt;");
154 else
155 escaped.push_back(c);
156 }
157
158 return escaped;
159 }
160
167 static std::string expand_multiple_flags(std::string const & flag_cluster)
168 {
169 std::string tmp;
170 auto it{flag_cluster.begin()};
171
172 if (flag_cluster[0] == '-')
173 ++it;
174
175 for (; it != flag_cluster.end() - 1; ++it)
176 tmp.append({'-', *it, ',', ' '});
177
178 tmp.erase(tmp.find_last_of(',')); // remove last ', '
179 tmp.append({'a', 'n', 'd', ' ', '-', flag_cluster[flag_cluster.size() - 1]});
180
181 return tmp;
182 }
183
196 template <typename option_type, typename default_type>
197 static std::string get_default_message(option_type const & SHARG_DOXYGEN_ONLY(option), default_type const & value)
198 {
200
201 std::stringstream message{};
202 message << " Default: ";
203
205 {
206 // If we have a list of strings, we want to quote each string.
208 {
209 auto view = std::views::transform(value,
210 [](auto const & val)
211 {
212 return std::quoted(val);
213 });
214 message << detail::to_string(view);
215 }
216 else // Otherwise we just print the list or the default_message without quotes.
217 {
218 message << detail::to_string(value);
219 }
220 }
221 else
222 {
223 static constexpr bool option_is_string = std::same_as<option_type, std::string>;
224 static constexpr bool option_is_path = std::same_as<option_type, std::filesystem::path>;
225 static constexpr bool value_is_string = std::same_as<default_type, std::string>;
226
227 // Quote: std::string (from value + default_message), and std::filesystem::path (default_message).
228 // std::filesystem::path is quoted by the STL's operator<< in detail::to_string.
229 static constexpr bool needs_string_quote = option_is_string || (option_is_path && value_is_string);
230
231 if constexpr (needs_string_quote)
232 message << std::quoted(value);
233 else
234 message << detail::to_string(value);
235 }
236
237 return message.str();
238 }
239};
240
246template <typename derived_type>
248{
249private:
253 format_help_base() = default;
254 format_help_base(format_help_base const & pf) = default;
258 ~format_help_base() = default;
259
266 update_notifications const version_updates,
267 bool const advanced) :
268 version_check_dev_decision{version_updates},
269 command_names{names},
270 show_advanced_options{advanced}
271 {}
273
274public:
278 template <typename option_type, typename validator_t>
279 void add_option(option_type & value, config<validator_t> const & config)
280 {
283
285 info += ((config.required) ? std::string{} : get_default_message(value, value));
286 else
288
289 if (auto const & validator_message = config.validator.get_help_page_message(); !validator_message.empty())
290 info += ". " + validator_message;
291
293 [this, id, info]()
294 {
295 derived_t().print_list_item(id, info);
296 },
297 config);
298 }
299
303 template <typename validator_t>
304 void add_flag(bool & SHARG_DOXYGEN_ONLY(value), config<validator_t> const & config)
305 {
307 [this, id = prep_id_for_help(config.short_id, config.long_id), description = config.description]()
308 {
309 derived_t().print_list_item(id, description);
310 },
311 config);
312 }
313
317 template <typename option_type, typename validator_t>
318 void add_positional_option(option_type & value, config<validator_t> const & config)
319 {
320 // a list at the end may be empty and thus have a default value
321 auto positional_default_message = [&value]() -> std::string
322 {
324 {
325 return get_default_message(value, value);
326 }
327 else
328 {
329 (void)value; // Silence unused variable warning.
330 return {};
331 }
332 };
333
334 auto positional_validator_message = [&config]() -> std::string
335 {
336 if (auto const & validator_message = config.validator.get_help_page_message(); !validator_message.empty())
337 return ". " + validator_message;
338 else
339 return {};
340 };
341
343 [this,
344 &value,
345 default_message = positional_default_message(),
346 validator_message = positional_validator_message(),
347 description = config.description]()
348 {
350 derived_t().print_list_item(detail::to_string("\\fBARGUMENT-",
352 "\\fP ",
354 description + default_message + validator_message);
355 });
356 }
357
361 void parse(parser_meta_data & parser_meta)
362 {
363 meta = parser_meta;
364
365 derived_t().print_header();
366
367 if (!meta.synopsis.empty())
368 {
369 derived_t().print_section("Synopsis");
370 derived_t().print_synopsis();
371 }
372
373 if (!meta.description.empty())
374 {
375 derived_t().print_section("Description");
376 for (auto desc : meta.description)
377 print_line(desc);
378 }
379
380 if (!command_names.empty())
381 {
382 derived_t().print_section("Subcommands");
383 derived_t().print_line("This program must be invoked with one of the following subcommands:", false);
384 for (std::string const & name : command_names)
385 derived_t().print_line("- \\fB" + name + "\\fP", false);
386 derived_t().print_line("See the respective help page for further details (e.g. by calling " + meta.app_name
387 + " " + command_names[0] + " -h).",
388 true);
389 derived_t().print_line("The following options belong to the top-level parser and need to be "
390 "specified \\fBbefore\\fP the subcommand key word. Every argument after the "
391 "subcommand key word is passed on to the corresponding sub-parser.",
392 true);
393 }
394
395 // add positional options if specified
397 derived_t().print_section("Positional Arguments");
398
399 // each call will evaluate the function derived_t().print_list_item()
400 for (auto f : positional_option_calls)
401 f();
402
403 // There are always options because of the common options
404 derived_t().print_section("Options");
405
406 // each call will evaluate the function derived_t().print_list_item()
407 for (auto f : parser_set_up_calls)
408 f();
409
410 // print Common options after developer options
411 derived_t().print_subsection("Common options");
412 derived_t().print_list_item("\\fB-h\\fP, \\fB--help\\fP", "Prints the help page.");
413 derived_t().print_list_item("\\fB-hh\\fP, \\fB--advanced-help\\fP",
414 "Prints the help page including advanced options.");
415 derived_t().print_list_item("\\fB--version\\fP", "Prints the version information.");
416 derived_t().print_list_item("\\fB--copyright\\fP", "Prints the copyright/license information.");
417 derived_t().print_list_item("\\fB--export-help\\fP (std::string)",
418 "Export the help page information. Value must be one of "
419 + detail::supported_exports + ".");
421 derived_t().print_list_item("\\fB--version-check\\fP (bool)",
422 "Whether to check for the newest app version. Default: true");
423
424 if (!meta.examples.empty())
425 {
426 derived_t().print_section("Examples");
427 for (auto example : meta.examples)
428 print_line(example);
429 }
430
432
433 print_legal();
434
435 derived_t().print_footer();
436 }
437
441 void add_section(std::string const & title, bool const advanced_only)
442 {
444 [this, title]()
445 {
446 derived_t().print_section(title);
447 },
448 advanced_only,
449 false /* never hidden */);
450 }
451
455 void add_subsection(std::string const & title, bool const advanced_only)
456 {
458 [this, title]()
459 {
460 derived_t().print_subsection(title);
461 },
462 advanced_only,
463 false /* never hidden */);
464 }
465
469 void add_line(std::string const & text, bool is_paragraph, bool const advanced_only)
470 {
472 [this, text, is_paragraph]()
473 {
474 derived_t().print_line(text, is_paragraph);
475 },
476 advanced_only,
477 false /* never hidden */);
478 }
479
483 void add_list_item(std::string const & key, std::string const & desc, bool const advanced_only)
484 {
486 [this, key, desc]()
487 {
488 derived_t().print_list_item(key, desc);
489 },
490 advanced_only,
491 false /* never hidden */);
492 }
493
509
512
513protected:
516
519 {
520 return static_cast<derived_type &>(*this);
521 }
522
525 {
526 for (unsigned i = 0; i < meta.synopsis.size(); ++i)
527 {
528 std::string text = "\\fB";
529 text.append(meta.synopsis[i]);
530 text.insert(text.find_first_of(" \t"), "\\fP");
531
532 derived_t().print_line(text, false);
533 }
534 }
535
539 void print_line(std::string const & text)
540 {
541 derived_t().print_line(text, true);
542 }
543
546 {
547 std::string const version_str{sharg::sharg_version_cstring};
548
549 // Print version, date and url.
550 derived_t().print_section("Version");
551 derived_t().print_line(derived_t().in_bold("Last update: ") + meta.date, false);
552 derived_t().print_line(derived_t().in_bold(meta.app_name + " version: ") + meta.version, false);
553 derived_t().print_line(derived_t().in_bold("Sharg version: ") + version_str, false);
554
555#ifdef SEQAN3_VERSION_CSTRING
556 std::string const seqan3_version_str{seqan3::seqan3_version_cstring};
557 derived_t().print_line(derived_t().in_bold("SeqAn version: ") + seqan3_version_str, false);
558#endif
559
560 if (!empty(meta.url))
561 {
562 derived_t().print_section("Url");
563 derived_t().print_line(meta.url, false);
564 }
565 }
566
569 {
570 // Print legal stuff
571 if ((!empty(meta.short_copyright)) || (!empty(meta.long_copyright)) || (!empty(meta.citation))
572 || (!empty(meta.author)) || (!empty(meta.email)))
573 {
574 derived_t().print_section("Legal");
575
576 if (!empty(meta.short_copyright))
577 {
578 derived_t().print_line(derived_t().in_bold(meta.app_name + " Copyright: ") + meta.short_copyright,
579 false);
580 }
581
582 if (!empty(meta.author))
583 {
584 derived_t().print_line(derived_t().in_bold("Author: ") + meta.author, false);
585 }
586
587 if (!empty(meta.email))
588 {
589 derived_t().print_line(derived_t().in_bold("Contact: ") + meta.email, false);
590 }
591
592 derived_t().print_line(derived_t().in_bold("SeqAn Copyright: ")
593 + "2006-2024 Knut Reinert, FU-Berlin; released under the 3-clause BSDL.",
594 false);
595
596 if (!empty(meta.citation))
597 {
598 derived_t().print_line(derived_t().in_bold("In your academic works please cite: ") + meta.citation,
599 false);
600 }
601
602 if (!empty(meta.long_copyright))
603 {
604 derived_t().print_line("For full copyright and/or warranty information see "
605 + derived_t().in_bold("--copyright") + ".",
606 false);
607 }
608 }
609 }
610
614 std::vector<std::function<void()>> positional_option_calls; // singled out to be printed on top
621
622private:
634 void store_help_page_element(std::function<void()> printer, bool const advanced, bool const hidden)
635 {
636 if (!(hidden) && (!(advanced) || show_advanced_options))
637 parser_set_up_calls.push_back(std::move(printer));
638 }
639
650 template <typename validator_t>
652 {
654 parser_set_up_calls.push_back(std::move(printer));
655 }
656};
657
658} // namespace sharg::detail
T append(T... args)
Provides auxiliary information.
T begin(T... args)
The format that contains all helper functions needed in all formats.
Definition format_base.hpp:31
static std::string option_type_and_list_info(container_type const &container)
Formats the container and its value_type for the help page printing.
Definition format_base.hpp:103
static std::string expand_multiple_flags(std::string const &flag_cluster)
Expands multiple one character flag identifiers for pretty help output.
Definition format_base.hpp:167
static std::string get_type_name_as_string(value_type const &)
Returns the input type as a string (reflection).
Definition format_base.hpp:38
static std::string prep_id_for_help(char const short_id, std::string const &long_id)
Formats the option/flag identifier pair for the help page printing.
Definition format_base.hpp:115
static std::string get_default_message(option_type const &option, default_type const &value)
Returns the default message for the help page.
Definition format_base.hpp:197
static std::string option_type_and_list_info(option_value_type const &value)
Formats the type of a value for the help page printing.
Definition format_base.hpp:91
static std::string get_type_name_as_string(container_type const &)
Returns the value_type of the input container as a string (reflection).
Definition format_base.hpp:79
static std::string escape_special_xml_chars(std::string const &original)
Escapes certain characters for correct output.
Definition format_base.hpp:137
The format that contains all helper functions needed in all formats for printing the interface descri...
Definition format_base.hpp:248
unsigned positional_option_count
Keeps track of the number of positional options.
Definition format_base.hpp:616
bool show_advanced_options
Whether to show advanced options or not.
Definition format_base.hpp:620
update_notifications version_check_dev_decision
Set on construction and indicates whether the developer deactivated the version check calls completel...
Definition format_base.hpp:515
std::vector< std::function< void()> > parser_set_up_calls
Vector of functions that stores all calls except add_positional_option.
Definition format_base.hpp:612
format_help_base(std::vector< std::string > const &names, update_notifications const version_updates, bool const advanced)
Initializes a format_help_base object.
Definition format_base.hpp:265
format_help_base & operator=(format_help_base const &pf)=default
Defaulted.
void print_legal()
Prints the legal information.
Definition format_base.hpp:568
format_help_base & operator=(format_help_base &&)=default
Defaulted.
void add_line(std::string const &text, bool is_paragraph, bool const advanced_only)
Adds a print_line call to parser_set_up_calls.
Definition format_base.hpp:469
derived_type & derived_t()
Returns the derived type.
Definition format_base.hpp:518
format_help_base(format_help_base &&)=default
Defaulted.
format_help_base(format_help_base const &pf)=default
Defaulted.
void add_positional_option(option_type &value, config< validator_t > const &config)
Adds a sharg::print_list_item call to be evaluated later on.
Definition format_base.hpp:318
void parse(parser_meta_data &parser_meta)
Initiates the printing of the help page to std::cout.
Definition format_base.hpp:361
parser_meta_data meta
Stores all meta information about the application.
Definition format_base.hpp:508
void add_option(option_type &value, config< validator_t > const &config)
Adds a sharg::print_list_item call to be evaluated later on.
Definition format_base.hpp:279
void print_synopsis()
Prints a synopsis in any format.
Definition format_base.hpp:524
void store_help_page_element(std::function< void()> printer, config< validator_t > const &config)
Adds a function object to parser_set_up_calls if the annotation in config does not prevent it.
Definition format_base.hpp:651
std::vector< std::string > command_names
The names of subcommand programs.
Definition format_base.hpp:618
format_help_base()=default
Defaulted.
void print_line(std::string const &text)
Delegates to sharg::print_line(std::string const & text, true) of each format.
Definition format_base.hpp:539
std::vector< std::function< void()> > positional_option_calls
Vector of functions that stores add_positional_option calls.
Definition format_base.hpp:614
~format_help_base()=default
Defaulted.
friend derived_type
Befriend the derived type so it can access private functions.
Definition format_base.hpp:511
void add_list_item(std::string const &key, std::string const &desc, bool const advanced_only)
Adds a sharg::print_list_item call to parser_set_up_calls.
Definition format_base.hpp:483
void add_flag(bool &value, config< validator_t > const &config)
Adds a sharg::print_list_item call to be evaluated later on.
Definition format_base.hpp:304
void add_section(std::string const &title, bool const advanced_only)
Adds a print_section call to parser_set_up_calls.
Definition format_base.hpp:441
void print_version()
Prints the version information.
Definition format_base.hpp:545
void add_subsection(std::string const &title, bool const advanced_only)
Adds a print_subsection call to parser_set_up_calls.
Definition format_base.hpp:455
void store_help_page_element(std::function< void()> printer, bool const advanced, bool const hidden)
Adds a function object to parser_set_up_calls if the annotation in config does not prevent it.
Definition format_base.hpp:634
Whether the option type is considered to be a container.
Definition detail/concept.hpp:38
Provides sharg::config class.
Provides the concept sharg::detail::is_container_option.
T empty(T... args)
T end(T... args)
T erase(T... args)
T find_first_of(T... args)
T find_last_of(T... args)
std::string to_string(value_types &&... values)
Streams all parameters via std::ostringstream and returns a concatenated string.
Definition to_string.hpp:40
update_notifications
Indicates whether application allows automatic update notifications by the sharg::parser.
Definition auxiliary.hpp:26
@ on
Automatic update notifications should be enabled.
T insert(T... args)
T is_same_v
T push_back(T... args)
T quoted(T... args)
T reserve(T... args)
T size(T... args)
Option struct that is passed to the sharg::parser::add_option() function.
Definition config.hpp:43
std::string description
The description to be shown on any (exported) help page.
Definition config.hpp:68
std::string long_id
The long identifier for the option (e.g. "age", making the option callable via --age).
Definition config.hpp:62
bool hidden
Whether the option should be hidden.
Definition config.hpp:117
bool advanced
Whether the option should only be displayed on the advanced help page.
Definition config.hpp:105
bool required
Whether the option is required.
Definition config.hpp:129
validator_t validator
A sharg::validator that verifies the value after parsing (callable).
Definition config.hpp:135
char short_id
The short identifier for the option (e.g. 'a', making the option callable via -a).
Definition config.hpp:53
std::string default_message
The default message to be shown on any (exported) help page.
Definition config.hpp:87
Stores all parser related meta information of the sharg::parser.
Definition auxiliary.hpp:45
std::string email
The author's e-mail address for correspondence.
Definition auxiliary.hpp:63
std::vector< std::string > description
A more detailed description that is displayed on the help page in the section "DESCRIPTION"....
Definition auxiliary.hpp:97
std::vector< std::string > examples
Provide some examples on how to use your tool and what standard parameters might be appropriate in di...
Definition auxiliary.hpp:108
std::string app_name
The application name that will be displayed on the help page.
Definition auxiliary.hpp:51
std::string version
The version information MAJOR.MINOR.PATH (e.g. 3.1.3)
Definition auxiliary.hpp:54
std::vector< std::string > synopsis
Add lines of usage to the synopsis section of the help page (e.g. "./my_read_mapper [OPTIONS] FILE1 F...
Definition auxiliary.hpp:102
std::string long_copyright
Detailed copyright information that will be displayed when the user specifies "--copyright" on the co...
Definition auxiliary.hpp:79
std::string url
A link to your github/gitlab project with the newest release.
Definition auxiliary.hpp:71
std::string short_copyright
Brief copyright (and/or license) information.
Definition auxiliary.hpp:74
std::string date
The date that the application was last updated. Keep this updated, ! since it will tell your users th...
Definition auxiliary.hpp:68
std::string author
Your name ;-)
Definition auxiliary.hpp:60
std::string citation
How users shall cite your application.
Definition auxiliary.hpp:82
Provides traits to inspect some information of a type, for example its name.
Provides some standard validators for (positional) options.
constexpr char const * sharg_version_cstring
The full version as null terminated string.
Definition version.hpp:64
Hide me