20#if __has_include(<seqan3/version.hpp>)
21# include <seqan3/version.hpp>
24namespace sharg::detail
39 template <
typename value_type,
bool verbose = true>
45 return verbose ?
"signed 8 bit integer" :
"int8";
47 return verbose ?
"unsigned 8 bit integer" :
"uint8";
49 return verbose ?
"signed 16 bit integer" :
"int16";
51 return verbose ?
"unsigned 16 bit integer" :
"uint16";
53 return verbose ?
"signed 32 bit integer" :
"int32";
55 return verbose ?
"unsigned 32 bit integer" :
"uint32";
57 return verbose ?
"signed 64 bit integer" :
"int64";
59 return verbose ?
"unsigned 64 bit integer" :
"uint64";
61 return verbose ?
"double" :
"double";
63 return verbose ?
"float" :
"float";
65 return verbose ?
"bool" :
"bool";
67 return verbose ?
"char" :
"char";
69 return verbose ?
"std::string" :
"string";
71 return verbose ?
"std::filesystem::path" :
"path";
75 return sharg::detail::type_name_as_string<value_type>;
83 template <detail::is_container_option container_type,
bool verbose = true>
86 return get_type_name_as_string<std::ranges::range_value_t<container_type>, verbose>();
93 template <
typename option_value_type>
94 static std::string option_type_and_list_info(option_value_type
const &)
96 return (
"(\\fI" + get_type_name_as_string<option_value_type>() +
"\\fP)");
104 template <detail::is_container_option container_type>
105 static std::string option_type_and_list_info(container_type
const &)
107 return (
"(\\fIList\\fP of \\fI" + get_type_name_as_string<container_type>() +
"\\fP)");
119 static std::string prep_id_for_help(detail::id_pair
const &
id,
bool const is_synopsis =
false)
124 if (!
id.empty_short_id())
125 term =
"\\fB-" +
std::string(1,
id.short_id) +
"\\fP";
127 if (
id.has_both_ids())
130 if (!
id.empty_long_id())
131 term.
append(
"\\fB--" +
id.long_id +
"\\fP");
147 for (
auto c : original)
175 auto it{flag_cluster.
begin()};
177 if (flag_cluster[0] ==
'-')
180 for (; it != flag_cluster.
end() - 1; ++it)
181 tmp.
append({
'-', *it,
',',
' '});
184 tmp.
append({
'a',
'n',
'd',
' ',
'-', flag_cluster[flag_cluster.
size() - 1]});
201 template <
typename option_type,
typename default_type>
202 static std::string get_default_message(option_type
const & SHARG_DOXYGEN_ONLY(option), default_type
const & value)
207 message <<
" Default: ";
209 if constexpr (detail::is_container_option<option_type>)
214 auto view = std::views::transform(value,
219 message << detail::to_string(view);
223 message << detail::to_string(value);
234 static constexpr bool needs_string_quote = option_is_string || (option_is_path && value_is_string);
236 if constexpr (needs_string_quote)
239 message << detail::to_string(value);
242 return message.str();
287 static void print_as_lowercase(
std::string const & str)
293 return std::tolower(c);
301 static void print_as_uppercase(
std::string const & str)
307 return std::toupper(c);
317template <
typename derived_type>
318class format_help_base :
public format_base
324 format_help_base() =
default;
325 format_help_base(format_help_base
const & pf) =
default;
326 format_help_base & operator=(format_help_base
const & pf) =
default;
327 format_help_base(format_help_base &&) =
default;
328 format_help_base & operator=(format_help_base &&) =
default;
329 ~format_help_base() =
default;
338 bool const advanced) :
339 version_check_dev_decision{version_updates},
340 command_names{names},
341 show_advanced_options{advanced}
349 template <
typename option_type,
typename val
idator_t>
350 void add_option(option_type & value, config<validator_t>
const & config)
352 detail::id_pair
const id_pair{config.short_id, config.long_id};
353 std::string id = prep_id_for_help(id_pair) +
" " + option_type_and_list_info(value);
356 if (config.default_message.empty())
357 info += ((config.required) ?
std::string{} : get_default_message(value, value));
359 info += get_default_message(value, config.default_message);
361 if (
auto const & validator_message = config.validator.get_help_page_message(); !validator_message.empty())
362 info +=
". " + validator_message;
364 store_help_page_element(
367 derived_t().print_list_item(
id, info);
371 if (!(config.hidden) && (!(config.advanced) || show_advanced_options))
372 store_synopsis_option(id_pair,
373 get_type_name_as_string<option_type, false>(),
375 detail::is_container_option<option_type>);
381 template <
typename val
idator_t>
382 void add_flag(
bool & SHARG_DOXYGEN_ONLY(value), config<validator_t>
const & config)
384 detail::id_pair
const id_pair{config.short_id, config.long_id};
385 store_help_page_element(
386 [
this,
id = prep_id_for_help(id_pair), description = config.description]()
388 derived_t().print_list_item(id, description);
393 if (!(config.hidden) && (!(config.advanced) || show_advanced_options))
394 store_synopsis_flag(id_pair);
400 template <
typename option_type,
typename val
idator_t>
401 void add_positional_option(option_type & value, config<validator_t>
const & config)
404 auto positional_default_message = [&value]() ->
std::string
406 if constexpr (detail::is_container_option<option_type>)
408 return get_default_message(value, value);
417 auto positional_validator_message = [&config]() ->
std::string
419 if (
auto const & validator_message = config.validator.get_help_page_message(); !validator_message.empty())
420 return ". " + validator_message;
428 default_message = positional_default_message(),
429 validator_message = positional_validator_message(),
430 description = config.description]()
432 ++positional_option_count;
433 derived_t().print_list_item(detail::to_string(
"\\fBARGUMENT-",
434 positional_option_count,
436 option_type_and_list_info(value)),
437 description + default_message + validator_message);
441 store_synopsis_positional(get_type_name_as_string<option_type, false>(),
442 detail::is_container_option<option_type>);
454 derived_t().print_header();
456 if (meta.synopsis.empty())
457 generate_default_synopsis(executable_name);
460 if (!meta.synopsis.empty() && !meta.synopsis.front().empty())
462 derived_t().print_section(
"Synopsis");
463 derived_t().print_synopsis();
466 if (!meta.description.empty())
468 derived_t().print_section(
"Description");
469 for (
auto && desc : meta.description)
473 if (!command_names.empty())
475 derived_t().print_section(
"Subcommands");
476 derived_t().print_line(
"This program must be invoked with one of the following subcommands:",
false);
478 derived_t().print_line(
"- \\fB" + name +
"\\fP", false);
479 derived_t().print_line(
"See the respective help page for further details (e.g. by calling " + meta.app_name
480 +
" " + command_names[0] +
" -h).",
482 derived_t().print_line(
"The following options belong to the top-level parser and need to be "
483 "specified \\fBbefore\\fP the subcommand key word. Every argument after the "
484 "subcommand key word is passed on to the corresponding sub-parser.",
489 if (!positional_option_calls.empty())
490 derived_t().print_section(
"Positional Arguments");
493 for (
auto && f : positional_option_calls)
497 derived_t().print_section(
"Options");
500 for (
auto && f : parser_set_up_calls)
504 derived_t().print_subsection(
"Common options");
505 derived_t().print_list_item(
"\\fB-h\\fP, \\fB--help\\fP",
"Prints the help page.");
506 derived_t().print_list_item(
"\\fB-hh\\fP, \\fB--advanced-help\\fP",
507 "Prints the help page including advanced options.");
508 derived_t().print_list_item(
"\\fB--version\\fP",
"Prints the version information.");
509 derived_t().print_list_item(
"\\fB--copyright\\fP",
"Prints the copyright/license information.");
510 derived_t().print_list_item(
"\\fB--export-help\\fP (std::string)",
511 "Export the help page information. Value must be one of "
512 + detail::supported_exports +
".");
514 derived_t().print_list_item(
"\\fB--version-check\\fP (bool)",
515 "Whether to check for the newest app version. Default: true");
517 if (!meta.examples.empty())
519 derived_t().print_section(
"Examples");
520 for (
auto && example : meta.examples)
528 derived_t().print_footer();
534 void add_section(
std::string const & title,
bool const advanced_only)
536 store_help_page_element(
539 derived_t().print_section(title);
548 void add_subsection(
std::string const & title,
bool const advanced_only)
550 store_help_page_element(
553 derived_t().print_subsection(title);
562 void add_line(
std::string const & text,
bool is_paragraph,
bool const advanced_only)
564 store_help_page_element(
565 [
this, text, is_paragraph]()
567 derived_t().print_line(text, is_paragraph);
578 store_help_page_element(
581 derived_t().print_list_item(key, desc);
601 parser_meta_data meta;
611 derived_type & derived_t()
613 return static_cast<derived_type &
>(*this);
617 void print_synopsis()
620 for (
unsigned i = 0; i < meta.synopsis.size(); ++i)
623 text.
append(meta.synopsis[i]);
627 derived_t().print_line(text,
false);
636 derived_t().print_line(text,
true);
645 derived_t().print_section(
"Version");
646 derived_t().print_line(derived_t().in_bold(
"Last update: ") + meta.date,
false);
647 derived_t().print_line(derived_t().in_bold(meta.app_name +
" version: ") + meta.version,
false);
648 derived_t().print_line(derived_t().in_bold(
"Sharg version: ") + version_str,
false);
650#ifdef SEQAN3_VERSION_CSTRING
651 std::string const seqan3_version_str{seqan3::seqan3_version_cstring};
652 derived_t().print_line(derived_t().in_bold(
"SeqAn version: ") + seqan3_version_str,
false);
655 if (!
empty(meta.url))
657 derived_t().print_section(
"Url");
658 derived_t().print_line(meta.url,
false);
666 if ((!
empty(meta.short_copyright)) || (!
empty(meta.long_copyright)) || (!
empty(meta.citation))
667 || (!
empty(meta.author)) || (!
empty(meta.email)))
669 derived_t().print_section(
"Legal");
671 if (!
empty(meta.short_copyright))
673 derived_t().print_line(derived_t().in_bold(meta.app_name +
" Copyright: ") + meta.short_copyright,
677 if (!
empty(meta.author))
679 derived_t().print_line(derived_t().in_bold(
"Author: ") + meta.author,
false);
682 if (!
empty(meta.email))
684 derived_t().print_line(derived_t().in_bold(
"Contact: ") + meta.email,
false);
687 derived_t().print_line(derived_t().in_bold(
"SeqAn Copyright: ")
688 +
"2006-2026 Knut Reinert, FU-Berlin; released under the 3-clause BSDL.",
691 if (!
empty(meta.citation))
693 derived_t().print_line(derived_t().in_bold(
"In your academic works please cite: "),
false);
694 for (
size_t i = 0; i < meta.citation.size(); ++i)
702 derived_t().print_list_item(
"\\fB[" +
std::to_string(i + 1u) +
"]\\fP", meta.citation[i]);
706 if (!
empty(meta.long_copyright))
708 derived_t().print_line(
"For full copyright and/or warranty information see "
709 + derived_t().in_bold(
"--copyright") +
".",
718 if (synopsis_elements.empty())
724#ifdef __cpp_lib_ranges_join_with
725 auto view = std::views::join_with(executable_name,
' ');
729 for (
size_t i = 0; i < executable_name.
size(); ++i)
732 synopsis_line +=
' ';
733 synopsis_line += executable_name[i];
739 synopsis_element::option_type::positional,
741 &synopsis_element::type);
743 for (
auto it = synopsis_elements.begin(); it != pivot; ++it)
745 synopsis_line +=
" " + it->option_str;
747 if (pivot != synopsis_elements.end())
749 synopsis_line +=
" [\\fB--\\fP]";
750 for (
auto it = pivot; it != synopsis_elements.end(); ++it)
752 synopsis_line +=
" " + it->option_str;
756 meta.synopsis.emplace_back(std::move(synopsis_line));
764 unsigned positional_option_count{0};
768 bool show_advanced_options{
true};
770 struct synopsis_element
773 enum class option_type : uint8_t
798 void store_help_page_element(
std::function<
void()> printer,
bool const advanced,
bool const hidden)
800 if (!(hidden) && (!(advanced) || show_advanced_options))
801 parser_set_up_calls.
push_back(std::move(printer));
811 void store_synopsis_option(detail::id_pair
const &
id,
818 opt_str +=
" \\fI" + type_str +
"\\fP";
822 opt_str =
"[" + opt_str +
"]";
829 opt_str = opt_str +
" [" + opt_str +
"]...";
832 synopsis_elements.
push_back({std::move(opt_str), synopsis_element::option_type::option});
839 void store_synopsis_flag(detail::id_pair
const &
id)
841 std::string flag_str =
"[" + prep_id_for_help(
id,
true) +
"]";
842 synopsis_elements.
push_back({std::move(flag_str), synopsis_element::option_type::flag});
850 void store_synopsis_positional(
std::string const & type_str,
bool const is_list)
857 synopsis_elements.
push_back({std::move(pos_str), synopsis_element::option_type::positional});
870 template <
typename val
idator_t>
871 void store_help_page_element(
std::function<
void()> printer, config<validator_t>
const & config)
873 if (!(config.hidden) && (!(config.advanced) || show_advanced_options))
874 parser_set_up_calls.push_back(std::move(printer));
Provides auxiliary information.
Provides sharg::config class.
Provides the concept sharg::detail::is_container_option.
T find_first_of(T... args)
T find_last_of(T... args)
update_notifications
Indicates whether application allows automatic update notifications by the sharg::parser.
Definition auxiliary.hpp:27
@ on
Automatic update notifications should be enabled.
Provides sharg::detail::id_pair.
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