185 version_check_dev_decision{version_updates},
186 arguments{
std::move(arguments)}
195 char const *
const *
const argv,
198 parser{
std::move(app_name),
std::vector<
std::string>{argv, argv + argc}, version_updates, subcommands}
205 if (version_check_future.valid())
238 template <
typename option_type,
typename val
idator_type>
243 check_parse_not_called(
"add_option");
244 verify_option_config(
config);
246 auto operation = [
this, &value,
config]()
248 auto visit_fn = [&value, &
config](
auto & f)
250 f.add_option(value,
config);
256 operations.push_back(std::move(operation));
272 template <
typename val
idator_type>
276 check_parse_not_called(
"add_flag");
277 verify_flag_config(
config);
280 throw design_error(
"A flag's default value must be false.");
282 auto operation = [
this, &value,
config]()
284 auto visit_fn = [&value, &
config](
auto & f)
286 f.add_flag(value,
config);
292 operations.push_back(std::move(operation));
322 template <
typename option_type,
typename val
idator_type>
327 check_parse_not_called(
"add_positional_option");
328 verify_positional_option_config(
config);
330 if constexpr (detail::is_container_option<option_type>)
331 has_positional_list_option =
true;
333 auto operation = [
this, &value,
config]()
335 auto visit_fn = [&value, &
config](
auto & f)
337 f.add_positional_option(value,
config);
343 operations.push_back(std::move(operation));
416 if (parse_was_called)
417 throw design_error(
"The function parse() must only be called once!");
419 parse_was_called =
true;
422 verify_app_and_subcommand_names();
425 determine_format_and_subcommand();
428 for (
auto & operation : operations)
450 if (sub_parser ==
nullptr)
452 throw design_error(
"No subcommand was provided at the construction of the argument parser!");
488 template <
typename id_type>
493 if (!parse_was_called)
494 throw design_error{
"You can only ask which options have been set after calling the function `parse()`."};
496 detail::id_pair
const id_pair{
id};
498 if (id_pair.long_id.size() == 1u)
500 throw design_error{
"Long option identifiers must be longer than one character! If " + id_pair.long_id
501 +
"' was meant to be a short identifier, please pass it as a char ('') not a string"
505 auto const it = detail::id_pair::find(used_option_ids, id_pair);
506 if (it == used_option_ids.end())
507 throw design_error{
"You can only ask for option identifiers that you added with add_option() before."};
511 auto option_it = detail::format_parse::find_option_id(format_arguments.begin(), option_end, *it);
512 return option_it != option_end;
530 check_parse_not_called(
"add_section");
532 auto operation = [
this, title, advanced_only]()
534 auto visit_fn = [&title, advanced_only](
auto & f)
536 f.add_section(title, advanced_only);
542 operations.push_back(std::move(operation));
557 check_parse_not_called(
"add_subsection");
559 auto operation = [
this, title, advanced_only]()
561 auto visit_fn = [&title, advanced_only](
auto & f)
563 f.add_subsection(title, advanced_only);
569 operations.push_back(std::move(operation));
585 check_parse_not_called(
"add_line");
587 auto operation = [
this, text, is_paragraph, advanced_only]()
589 auto visit_fn = [&text, is_paragraph, advanced_only](
auto & f)
591 f.add_line(text, is_paragraph, advanced_only);
597 operations.push_back(std::move(operation));
622 check_parse_not_called(
"add_list_item");
624 auto operation = [
this, key, desc, advanced_only]()
626 auto visit_fn = [&key, &desc, advanced_only](
auto & f)
628 f.add_list_item(key, desc, advanced_only);
634 operations.push_back(std::move(operation));
650 auto & parser_subcommands = this->subcommands;
651 parser_subcommands.
insert(parser_subcommands.end(), subcommands.
cbegin(), subcommands.
cend());
655 parser_subcommands.erase(first, last);
713 bool parse_was_called{
false};
716 bool has_positional_list_option{
false};
725 friend struct ::sharg::detail::test_accessor;
731 std::regex app_name_regex{
"^[a-zA-Z0-9_-]+$"};
751 detail::format_short_help,
752 detail::format_version,
756 detail::format_copyright>
757 format{detail::format_short_help{}};
761 {
'\0' ,
"advanced-help"},
763 {
'\0',
"export-help"},
765 {
'\0',
"copyright"}};
809 void determine_format_and_subcommand()
811 assert(!arguments.empty());
813 auto it = arguments.begin();
816 executable_name.emplace_back(arg);
820 auto read_next_arg = [
this, &it, &arg]() ->
bool
822 assert(it != arguments.end());
824 if (++it == arguments.end())
832 auto found_subcommand = [
this, &it, &arg]() ->
bool
834 if (subcommands.empty())
845 sub_parser->executable_name.insert(sub_parser->executable_name.begin(),
846 executable_name.begin(),
847 executable_name.end());
855 if (!arg.starts_with(
'-'))
857 std::string message =
"You specified an unknown subcommand! Available subcommands are: [";
859 message += command +
", ";
860 message.
replace(message.
size() - 2, 2,
"]. Use -h/--help for more information.");
862 throw user_input_error{message};
870 for (; read_next_arg();)
876 format_arguments.emplace_back(arg);
881 format_arguments.emplace_back(arg);
891 if (found_subcommand())
894 if (arg ==
"-h" || arg ==
"--help")
896 format = detail::format_help{subcommands, version_check_dev_decision,
false};
898 else if (arg ==
"-hh" || arg ==
"--advanced-help")
900 format = detail::format_help{subcommands, version_check_dev_decision,
true};
902 else if (arg ==
"--version")
904 format = detail::format_version{};
906 else if (arg ==
"--copyright")
908 format = detail::format_copyright{};
910 else if (arg ==
"--export-help" || arg.starts_with(
"--export-help="))
917 if (!read_next_arg())
918 throw too_few_arguments{
"Option --export-help must be followed by a value."};
922 arg.remove_prefix(1u);
926 format = detail::format_html{subcommands, version_check_dev_decision};
927 else if (arg ==
"man")
928 format = detail::format_man{subcommands, version_check_dev_decision};
929 else if (arg ==
"ctd")
930 format = detail::format_tdl{detail::format_tdl::FileFormat::CTD};
931 else if (arg ==
"cwl")
932 format = detail::format_tdl{detail::format_tdl::FileFormat::CWL};
934 throw validation_error{
"Validation failed for option --export-help: "
935 "Value must be one of "
936 + detail::supported_exports +
"."};
938 else if (arg ==
"--version-check")
940 if (!read_next_arg())
941 throw too_few_arguments{
"Option --version-check must be followed by a value."};
943 if (arg ==
"1" || arg ==
"true")
944 version_check_user_decision =
true;
945 else if (arg ==
"0" || arg ==
"false")
946 version_check_user_decision =
false;
948 throw validation_error{
"Value for option --version-check must be true (1) or false (0)."};
953 format_arguments.emplace_back(arg);
963 if (!format_arguments.empty() || sub_parser)
964 format = detail::format_parse(format_arguments);
976 void verify_identifiers(
char const short_id,
std::string const & long_id)
978 auto is_valid = [](
char const c) ->
bool
980 return (c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') || (c >=
'0' && c <=
'9')
981 || c ==
'@' || c ==
'_' || c ==
'-';
984 if (short_id ==
'\0' && long_id.
empty())
985 throw design_error{
"Short and long identifiers may not both be empty."};
987 if (short_id !=
'\0')
989 if (short_id ==
'-' || !is_valid(short_id))
990 throw design_error{
"Short identifiers may only contain alphanumeric characters, '_', or '@'."};
991 if (detail::id_pair::contains(used_option_ids, short_id))
992 throw design_error{
"Short identifier '" +
std::string(1, short_id) +
"' was already used before."};
995 if (!long_id.
empty())
997 if (long_id.
size() == 1)
998 throw design_error{
"Long identifiers must be either empty or longer than one character."};
999 if (long_id[0] ==
'-')
1000 throw design_error{
"Long identifiers may not use '-' as first character."};
1002 throw design_error{
"Long identifiers may only contain alphanumeric characters, '_', '-', or '@'."};
1003 if (detail::id_pair::contains(used_option_ids, long_id))
1004 throw design_error{
"Long identifier '" + long_id +
"' was already used before."};
1007 used_option_ids.emplace(short_id, long_id);
1011 template <
typename val
idator_t>
1012 void verify_option_config(config<validator_t>
const & config)
1014 verify_identifiers(config.short_id, config.long_id);
1016 if (config.short_id !=
'\0')
1017 options.emplace(
std::string{
"-"} + config.short_id);
1018 if (!config.long_id.empty())
1019 options.emplace(
std::string{
"--"} + config.long_id);
1021 if (config.required && !config.default_message.empty())
1022 throw design_error{
"A required option cannot have a default message."};
1026 template <
typename val
idator_t>
1027 void verify_flag_config(config<validator_t>
const & config)
1029 verify_identifiers(config.short_id, config.long_id);
1031 if (!config.default_message.empty())
1032 throw design_error{
"A flag may not have a default message because the default is always `false`."};
1036 template <
typename val
idator_t>
1037 void verify_positional_option_config(config<validator_t>
const & config)
const
1039 if (config.short_id !=
'\0' || config.long_id !=
"")
1040 throw design_error{
"Positional options are identified by their position on the command line. "
1041 "Short or long ids are not permitted!"};
1043 if (config.advanced || config.hidden)
1044 throw design_error{
"Positional options are always required and therefore cannot be advanced nor hidden!"};
1046 if (!subcommands.empty())
1047 throw design_error{
"You may only specify flags and options for the top-level parser."};
1049 if (has_positional_list_option)
1050 throw design_error{
"You added a positional option with a list value before so you cannot add "
1051 "any other positional options."};
1053 if (!config.default_message.empty())
1054 throw design_error{
"A positional option may not have a default message because it is always required."};
1066 inline void check_parse_not_called(
std::string_view const function_name)
const
1068 if (parse_was_called)
1069 throw design_error{detail::to_string(function_name.
data(),
" may only be used before calling parse().")};
1079 inline void verify_app_and_subcommand_names()
const
1085 throw design_error{(
"The application name must only contain alpha-numeric characters or '_' and '-' "
1086 "(regex: \"^[a-zA-Z0-9_-]+$\").")};
1089 for (
auto & sub : this->subcommands)
1093 throw design_error{
"The subcommand name must only contain alpha-numeric characters or '_' and '-' "
1094 "(regex: \"^[a-zA-Z0-9_-]+$\")."};
1104 inline void run_version_check()
1108 if (app_version.decide_if_check_is_performed(version_check_dev_decision, version_check_user_decision))
1112 version_check_future = app_version_prom.
get_future();
1113 app_version(std::move(app_version_prom));
1127 inline void parse_format()
1129 auto format_parse_fn = [
this]<
typename format_t>(format_t & f)
1132 f.parse(info, executable_name);
1137 std::visit(std::move(format_parse_fn), format);
Parser exception that is thrown whenever there is an design error directed at the developer of the ap...
Definition exceptions.hpp:207
The Sharg command line parser.
Definition parser.hpp:154
void add_option(option_type &value, config< validator_type > const &config)
Adds an option to the sharg::parser.
Definition parser.hpp:241
void add_flag(bool &value, config< validator_type > const &config)
Adds a flag to the sharg::parser.
Definition parser.hpp:274
parser(std::string app_name, std::vector< std::string > arguments, update_notifications version_updates=update_notifications::on, std::vector< std::string > const &subcommands={})
Initializes an sharg::parser object from the command line arguments.
Definition parser.hpp:181
parser(std::string app_name, int const argc, char const *const *const argv, update_notifications version_updates=update_notifications::on, std::vector< std::string > const &subcommands={})
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition parser.hpp:193
void add_subsection(std::string const &title, bool const advanced_only=false)
Adds an help page subsection to the sharg::parser.
Definition parser.hpp:555
bool is_option_set(id_type const &id) const
Checks whether the option identifier (id) was set on the command line by the user.
Definition parser.hpp:490
void add_subcommands(std::vector< std::string > const &subcommands)
Adds subcommands to the parser.
Definition parser.hpp:648
void add_positional_option(option_type &value, config< validator_type > const &config)
Adds a positional option to the sharg::parser.
Definition parser.hpp:325
parser_meta_data info
Aggregates all parser related meta data (see sharg::parser_meta_data struct).
Definition parser.hpp:709
parser(parser &&)=default
Defaulted.
void parse()
Initiates the actual command line parsing.
Definition parser.hpp:414
parser & operator=(parser const &)=delete
Deleted.
parser(parser const &)=delete
Deleted.
void add_list_item(std::string const &key, std::string const &desc, bool const advanced_only=false)
Adds an help page list item (key-value) to the sharg::parser.
Definition parser.hpp:620
parser & operator=(parser &&)=default
Defaulted.
void add_section(std::string const &title, bool const advanced_only=false)
Adds an help page section to the sharg::parser.
Definition parser.hpp:528
~parser()
The destructor.
Definition parser.hpp:202
parser & get_sub_parser()
Returns a reference to the sub-parser instance if subcommand parsing was enabled.
Definition parser.hpp:448
void add_line(std::string const &text, bool is_paragraph=false, bool const advanced_only=false)
Adds an help page text line to the sharg::parser.
Definition parser.hpp:583
Checks whether the the type can be used in an add_(positional_)option call on the parser.
Definition concept.hpp:91
Provides sharg::config class.
update_notifications
Indicates whether application allows automatic update notifications by the sharg::parser.
Definition auxiliary.hpp:26
@ off
Automatic update notifications should be disabled.
@ on
Automatic update notifications should be enabled.
Option struct that is passed to the sharg::parser::add_option() function.
Definition config.hpp:43
Provides the version check functionality.