SeqAn3 3.4.0-rc.1
The Modern C++ library for sequence analysis.
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 <filesystem>
14#include <iostream>
15#include <limits>
16#include <sstream>
17#include <string>
18
24#include <seqan3/version.hpp>
25
26namespace seqan3::detail
27{
28
34{
35protected:
40 template <typename value_type>
41 static std::string get_type_name_as_string(value_type const & )
42 {
43 using type = std::decay_t<value_type>;
44 using types = type_list<int8_t,
45 uint8_t,
46 int16_t,
47 uint16_t,
48 int32_t,
49 uint32_t,
50 int64_t,
51 uint64_t,
52 double,
53 float,
54 bool,
55 char,
58 std::vector<std::string> names{"signed 8 bit integer",
59 "unsigned 8 bit integer",
60 "signed 16 bit integer",
61 "unsigned 16 bit integer",
62 "signed 32 bit integer",
63 "unsigned 32 bit integer",
64 "signed 64 bit integer",
65 "unsigned 64 bit integer",
66 "double",
67 "float",
68 "bool",
69 "char",
70 "std::string",
71 "std::filesystem::path"};
72
73 if constexpr (list_traits::contains<type, types>)
74 return names[list_traits::find<type, types>];
75 else
76 return detail::type_name_as_string<value_type>;
77 }
78
83 template <detail::is_container_option container_type>
84 static std::string get_type_name_as_string(container_type const & )
85 {
86 typename container_type::value_type tmp{};
87 return get_type_name_as_string(tmp);
88 }
89
95 template <typename option_value_type>
96 static std::string option_type_and_list_info(option_value_type const & value)
97 {
98 return ("(\\fI" + get_type_name_as_string(value) + "\\fP)");
99 }
100
107 template <detail::is_container_option container_type>
108 static std::string option_type_and_list_info(container_type const & container)
109 {
110 return ("(\\fIList\\fP of \\fI" + get_type_name_as_string(container) + "\\fP)");
111 }
112
120 static std::string prep_id_for_help(char const short_id, std::string const & long_id)
121 {
122 // Build list item term.
123 std::string term;
124 if (short_id != '\0')
125 term = "\\fB-" + std::string(1, short_id) + "\\fP";
126
127 if (short_id != '\0' && !long_id.empty())
128 term.append(", ");
129
130 if (!long_id.empty())
131 term.append("\\fB--" + long_id + "\\fP");
132
133 return term;
134 }
135
143 {
144 std::string escaped;
145 escaped.reserve(original.size()); // will be at least as long
146
147 for (auto c : original)
148 {
149 if (c == '"')
150 escaped.append("&quot;");
151 else if (c == '\'')
152 escaped.append("&apos;");
153 else if (c == '&')
154 escaped.append("&amp;");
155 else if (c == '<')
156 escaped.append("&lt;");
157 else if (c == '>')
158 escaped.append("&gt;");
159 else
160 escaped.push_back(c);
161 }
162
163 return escaped;
164 }
165
172 static std::string expand_multiple_flags(std::string const & flag_cluster)
173 {
174 std::string tmp;
175 auto it{flag_cluster.begin()};
176
177 if (flag_cluster[0] == '-')
178 ++it;
179
180 for (; it != flag_cluster.end() - 1; ++it)
181 tmp.append({'-', *it, ',', ' '});
182
183 tmp.erase(tmp.find_last_of(',')); // remove last ', '
184 tmp.append({'a', 'n', 'd', ' ', '-', flag_cluster[flag_cluster.size() - 1]});
185
186 return tmp;
187 }
188};
189
195template <typename derived_type>
197{
198private:
202 format_help_base() = default;
203 format_help_base(format_help_base const & pf) = default;
207 ~format_help_base() = default;
208
218
219public:
223 template <typename option_type, typename validator_type>
224 void add_option(option_type & value,
225 char const short_id,
226 std::string const & long_id,
227 std::string const & desc,
228 option_spec const spec,
229 validator_type && option_validator)
230 {
231 std::string id = prep_id_for_help(short_id, long_id) + " " + option_type_and_list_info(value);
232 std::string info{desc};
233 info += ((spec & option_spec::required) ? std::string{" "} : detail::to_string(" Default: ", value, ". "));
234 info += option_validator.get_help_page_message();
236 [this, id, info]()
237 {
238 derived_t().print_list_item(id, info);
239 },
240 spec);
241 }
242
246 void add_flag(bool & SEQAN3_DOXYGEN_ONLY(value),
247 char const short_id,
248 std::string const & long_id,
249 std::string const & desc,
250 option_spec const spec)
251 {
252 std::string id = prep_id_for_help(short_id, long_id);
254 [this, id, desc]()
255 {
256 derived_t().print_list_item(id, desc);
257 },
258 spec);
259 }
260
264 template <typename option_type, typename validator_type>
265 void add_positional_option(option_type & value, std::string const & desc, validator_type & option_validator)
266 {
267 std::string msg = option_validator.get_help_page_message();
268
270 [this, &value, desc, msg]()
271 {
273 derived_t().print_list_item(detail::to_string("\\fBARGUMENT-",
275 "\\fP ",
277 desc +
278 // a list at the end may be empty and thus have a default value
279 ((detail::is_container_option<option_type>)
280 ? detail::to_string(" Default: ", value, ". ")
281 : std::string{" "})
282 + msg);
283 });
284 }
285
290 {
291 meta = parser_meta;
292
293 derived_t().print_header();
294
295 if (!meta.synopsis.empty())
296 {
297 derived_t().print_section("Synopsis");
298 derived_t().print_synopsis();
299 }
300
301 if (!meta.description.empty())
302 {
303 derived_t().print_section("Description");
304 for (auto desc : meta.description)
305 print_line(desc);
306 }
307
308 if (!command_names.empty())
309 {
310 derived_t().print_section("Subcommands");
311 derived_t().print_line("This program must be invoked with one of the following subcommands:", false);
312 for (std::string const & name : command_names)
313 derived_t().print_line("- \\fB" + name + "\\fP", false);
314 derived_t().print_line("See the respective help page for further details (e.g. by calling " + meta.app_name
315 + " " + command_names[0] + " -h).",
316 true);
317 derived_t().print_line("The following options below belong to the top-level parser and need to be "
318 "specified \\fBbefore\\fP the subcommand key word. Every argument after the "
319 "subcommand key word is passed on to the corresponding sub-parser.",
320 true);
321 }
322
323 // add positional options if specified
325 derived_t().print_section("Positional Arguments");
326
327 // each call will evaluate the function derived_t().print_list_item()
328 for (auto f : positional_option_calls)
329 f();
330
331 // add options and flags if specified
333 derived_t().print_section("Options");
334
335 // each call will evaluate the function derived_t().print_list_item()
336 for (auto f : parser_set_up_calls)
337 f();
338
339 if (!meta.examples.empty())
340 {
341 derived_t().print_section("Examples");
342 for (auto example : meta.examples)
343 print_line(example);
344 }
345
347
348 print_legal();
349
350 derived_t().print_footer();
351
352 std::exit(EXIT_SUCCESS); // program should not continue from here
353 }
354
358 void add_section(std::string const & title, option_spec const spec)
359 {
361 [this, title]()
362 {
363 derived_t().print_section(title);
364 },
365 spec);
366 }
367
371 void add_subsection(std::string const & title, option_spec const spec)
372 {
374 [this, title]()
375 {
376 derived_t().print_subsection(title);
377 },
378 spec);
379 }
380
384 void add_line(std::string const & text, bool is_paragraph, option_spec const spec)
385 {
387 [this, text, is_paragraph]()
388 {
389 derived_t().print_line(text, is_paragraph);
390 },
391 spec);
392 }
393
397 void add_list_item(std::string const & key, std::string const & desc, option_spec const spec)
398 {
400 [this, key, desc]()
401 {
402 derived_t().print_list_item(key, desc);
403 },
404 spec);
405 }
406
422
425
426protected:
429 {
430 return static_cast<derived_type &>(*this);
431 }
432
435 {
436 for (unsigned i = 0; i < meta.synopsis.size(); ++i)
437 {
438 std::string text = "\\fB";
439 text.append(meta.synopsis[i]);
440 text.insert(text.find_first_of(" \t"), "\\fP");
441
442 derived_t().print_line(text, false);
443 }
444 }
445
449 void print_line(std::string const & text)
450 {
451 derived_t().print_line(text, true);
452 }
453
456 {
457 std::string const version_str{seqan3_version_cstring};
458
459 // Print version, date and url.
460 derived_t().print_section("Version");
461 derived_t().print_line(derived_t().in_bold("Last update: ") + meta.date, false);
462 derived_t().print_line(derived_t().in_bold(meta.app_name + " version: ") + meta.version, false);
463 derived_t().print_line(derived_t().in_bold("SeqAn version: ") + version_str, false);
464
465 if (!empty(meta.url))
466 {
467 derived_t().print_section("Url");
468 derived_t().print_line(meta.url, false);
469 }
470 }
471
474 {
475 // Print legal stuff
476 if ((!empty(meta.short_copyright)) || (!empty(meta.long_copyright)) || (!empty(meta.citation))
477 || (!empty(meta.author)) || (!empty(meta.email)))
478 {
479 derived_t().print_section("Legal");
480
481 if (!empty(meta.short_copyright))
482 {
483 derived_t().print_line(derived_t().in_bold(meta.app_name + " Copyright: ") + meta.short_copyright,
484 false);
485 }
486
487 if (!empty(meta.author))
488 {
489 derived_t().print_line(derived_t().in_bold("Author: ") + meta.author, false);
490 }
491
492 if (!empty(meta.email))
493 {
494 derived_t().print_line(derived_t().in_bold("Contact: ") + meta.email, false);
495 }
496
497 derived_t().print_line(derived_t().in_bold("SeqAn Copyright: ")
498 + "2006-2023 Knut Reinert, FU-Berlin; released under the 3-clause BSDL.",
499 false);
500
501 if (!empty(meta.citation))
502 {
503 derived_t().print_line(derived_t().in_bold("In your academic works please cite: ") + meta.citation,
504 false);
505 }
506
507 if (!empty(meta.long_copyright))
508 {
509 derived_t().print_line("For full copyright and/or warranty information see "
510 + derived_t().in_bold("--copyright") + ".",
511 false);
512 }
513 }
514 }
515
519 std::vector<std::function<void()>> positional_option_calls; // singled out to be printed on top
526
527private:
538 void store_help_page_element(std::function<void()> printer, option_spec const spec)
539 {
541 parser_set_up_calls.push_back(std::move(printer));
542 }
543};
544
545} // namespace seqan3::detail
T append(T... args)
Provides the concept seqan3::detail::is_container_option.
Provides auxiliary information.
T begin(T... args)
The format that contains all helper functions needed in all formats.
Definition format_base.hpp:34
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:96
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:120
static std::string get_type_name_as_string(value_type const &)
Returns the input type as a string (reflection).
Definition format_base.hpp:41
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:84
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:172
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:108
std::string escape_special_xml_chars(std::string const &original)
Escapes certain characters for correct output.
Definition format_base.hpp:142
The format that contains all helper functions needed in all formats for printing the interface descri...
Definition format_base.hpp:197
void add_subsection(std::string const &title, option_spec const spec)
Adds a print_subsection call to parser_set_up_calls.
Definition format_base.hpp:371
friend derived_type
Befriend the derived type so it can access private functions.
Definition format_base.hpp:424
format_help_base()=default
Defaulted.
std::vector< std::string > command_names
The names of subcommand programs.
Definition format_base.hpp:523
argument_parser_meta_data meta
Stores all meta information about the application.
Definition format_base.hpp:421
void print_version()
Prints the version information.
Definition format_base.hpp:455
std::vector< std::function< void()> > parser_set_up_calls
Vector of functions that stores all calls except add_positional_option.
Definition format_base.hpp:517
void add_list_item(std::string const &key, std::string const &desc, option_spec const spec)
Adds a seqan3::print_list_item call to parser_set_up_calls.
Definition format_base.hpp:397
~format_help_base()=default
Defaulted.
void print_legal()
Prints the legal information.
Definition format_base.hpp:473
bool show_advanced_options
Whether to show advanced options or not.
Definition format_base.hpp:525
void add_section(std::string const &title, option_spec const spec)
Adds a print_section call to parser_set_up_calls.
Definition format_base.hpp:358
derived_type & derived_t()
Returns the derived type.
Definition format_base.hpp:428
format_help_base & operator=(format_help_base &&)=default
Defaulted.
format_help_base(format_help_base const &pf)=default
Defaulted.
void store_help_page_element(std::function< void()> printer, option_spec const spec)
Adds a function object to parser_set_up_calls if the annotation in spec does not prevent it.
Definition format_base.hpp:538
format_help_base(std::vector< std::string > const &names, bool const advanced)
Initializes a format_help_base object.
Definition format_base.hpp:213
void add_option(option_type &value, char const short_id, std::string const &long_id, std::string const &desc, option_spec const spec, validator_type &&option_validator)
Adds a seqan3::print_list_item call to be evaluated later on.
Definition format_base.hpp:224
format_help_base & operator=(format_help_base const &pf)=default
Defaulted.
void parse(argument_parser_meta_data &parser_meta)
Initiates the printing of the help page to std::cout.
Definition format_base.hpp:289
format_help_base(format_help_base &&)=default
Defaulted.
void print_line(std::string const &text)
Delegates to seqan3::print_line(std::string const & text, true) of each format.
Definition format_base.hpp:449
std::vector< std::function< void()> > positional_option_calls
Vector of functions that stores add_positional_option calls.
Definition format_base.hpp:519
unsigned positional_option_count
Keeps track of the number of positional options.
Definition format_base.hpp:521
void add_line(std::string const &text, bool is_paragraph, option_spec const spec)
Adds a print_line call to parser_set_up_calls.
Definition format_base.hpp:384
void add_flag(bool &value, char const short_id, std::string const &long_id, std::string const &desc, option_spec const spec)
Adds a seqan3::print_list_item call to be evaluated later on.
Definition format_base.hpp:246
void print_synopsis()
Prints a synopsis in any format.
Definition format_base.hpp:434
void add_positional_option(option_type &value, std::string const &desc, validator_type &option_validator)
Adds a seqan3::print_list_item call to be evaluated later on.
Definition format_base.hpp:265
T empty(T... args)
T end(T... args)
T erase(T... args)
Provides parser related exceptions.
T exit(T... args)
T find_first_of(T... args)
T find_last_of(T... args)
option_spec
Used to further specify argument_parser options/flags.
Definition auxiliary.hpp:245
@ advanced
Definition auxiliary.hpp:252
@ hidden
Definition auxiliary.hpp:256
@ required
Definition auxiliary.hpp:247
T insert(T... args)
The (most general) container concept as defined by the standard library.
The internal SeqAn3 namespace.
Definition aligned_sequence_concept.hpp:26
std::string to_string(value_type &&... values)
Streams all parameters via the seqan3::debug_stream and returns a concatenated string.
Definition to_string.hpp:26
constexpr char const * seqan3_version_cstring
The full version as null terminated string.
Definition version.hpp:64
T push_back(T... args)
T reserve(T... args)
T size(T... args)
Stores all parser related meta information of the seqan3::argument_parser.
Definition auxiliary.hpp:283
std::string long_copyright
Detailed copyright information that will be displayed when the user specifies "--copyright" on the co...
Definition auxiliary.hpp:309
std::string email
The author's e-mail address for correspondence.
Definition auxiliary.hpp:297
std::string short_copyright
Brief copyright (and/or license) information.
Definition auxiliary.hpp:305
std::string date
The date that the application was last updated. Keep this updated, ! since it will tell your users th...
Definition auxiliary.hpp:301
std::string author
Your name ;-)
Definition auxiliary.hpp:295
std::string version
The version information MAJOR.MINOR.PATH (e.g. 3.1.3)
Definition auxiliary.hpp:291
std::string app_name
The application name that will be displayed on the help page.
Definition auxiliary.hpp:289
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:327
std::string url
A link to your github/gitlab project with the newest release.
Definition auxiliary.hpp:303
std::string citation
How users shall cite your application.
Definition auxiliary.hpp:311
std::vector< std::string > description
A more detailed description that is displayed on the help page in the section "DESCRIPTION"....
Definition auxiliary.hpp:323
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:332
Type that contains multiple types.
Definition type_list.hpp:26
Provides traits to inspect some information of a type, for example its name.
Provides some standard validators for (positional) options.
Provides SeqAn version macros and global variables.
Hide me