188 char const *
const *
const argv,
191 version_check_dev_decision{version_updates},
192 subcommands{std::move(subcommands)}
194 if (!std::regex_match(app_name, app_name_regex))
196 throw design_error{(
"The application name must only contain alpha-numeric characters or '_' and '-' "
197 "(regex: \"^[a-zA-Z0-9_-]+$\").")};
200 for (
auto & sub : this->subcommands)
202 if (!std::regex_match(sub, app_name_regex))
204 throw design_error{
"The subcommand name must only contain alpha-numeric characters or '_' and '-' "
205 "(regex: \"^[a-zA-Z0-9_-]+$\")."};
218 if (version_check_future.
valid())
248 template <
typename option_type,
typename val
idator_type>
250 && std::invocable<validator_type, option_type>
253 verify_option_config(
config);
258 [&value, &
config](
auto & f)
260 f.add_option(value,
config);
275 template <
typename val
idator_type>
276 requires std::invocable<validator_type, bool>
279 verify_flag_config(
config);
282 throw design_error(
"A flag's default value must be false.");
287 [&value, &
config](
auto & f)
289 f.add_flag(value,
config);
316 template <
typename option_type,
typename val
idator_type>
318 && std::invocable<validator_type, option_type>
321 verify_positional_option_config(
config);
323 if constexpr (detail::is_container_option<option_type>)
324 has_positional_list_option =
true;
329 [&value, &
config](
auto & f)
331 f.add_positional_option(value,
config);
406 if (parse_was_called)
407 throw design_error(
"The function parse() must only be called once!");
411 if (std::holds_alternative<detail::format_parse>(format) && !subcommands.empty() && sub_parser ==
nullptr)
413 assert(!subcommands.empty());
416 subcommands_str += command +
", ";
417 subcommands_str.
replace(subcommands_str.size() - 2, 2,
"]");
419 throw too_few_arguments{
"You either forgot or misspelled the subcommand! Please specify which sub-program "
420 "you want to use: one of "
422 +
". Use -h/--help for more "
426 if (app_version.decide_if_check_is_performed(version_check_dev_decision, version_check_user_decision))
430 version_check_future = app_version_prom.
get_future();
431 app_version(std::move(app_version_prom));
440 parse_was_called =
true;
451 if (sub_parser ==
nullptr)
453 throw design_error(
"No subcommand was provided at the construction of the argument parser!");
489 template <
typename id_type>
490 requires std::same_as<id_type, char> || std::constructible_from<std::string, id_type>
494 if (!parse_was_called)
495 throw design_error{
"You can only ask which options have been set after calling the function `parse()`."};
499 char_or_string_t short_or_long_id = {
id};
501 if constexpr (!std::same_as<id_type, char>)
503 if (short_or_long_id.size() == 1)
505 throw design_error{
"Long option identifiers must be longer than one character! If " + short_or_long_id
506 +
"' was meant to be a short identifier, please pass it as a char ('') not a string"
512 throw design_error{
"You can only ask for option identifiers that you added with add_option() before."};
515 auto end_of_options = std::find(cmd_arguments.
begin(), cmd_arguments.
end(), end_of_options_indentifier);
516 auto option_it = detail::format_parse::find_option_id(cmd_arguments.
begin(), end_of_options, short_or_long_id);
517 return option_it != end_of_options;
535 [&title, advanced_only](
auto & f)
537 f.add_section(title, advanced_only);
554 [&title, advanced_only](
auto & f)
556 f.add_subsection(title, advanced_only);
574 [&text, is_paragraph, advanced_only](
auto & f)
576 f.add_line(text, is_paragraph, advanced_only);
603 [&key, &desc, advanced_only](
auto & f)
605 f.add_list_item(key, desc, advanced_only);
665 bool parse_was_called{
false};
668 bool has_positional_list_option{
false};
677 friend struct ::sharg::detail::test_accessor;
683 std::regex app_name_regex{
"^[a-zA-Z0-9_-]+$"};
703 detail::format_short_help,
704 detail::format_version,
707 detail::format_copyright
708> format{detail::format_help{{},
false}};
711 std::set<std::string> used_option_ids{
"h",
"hh",
"help",
"advanced-help",
"export-help",
"version",
"copyright"};
748 void init(
int argc,
char const *
const *
const argv)
750 bool special_format_was_set{
false};
752 for (
int i = 1, argv_len = argc; i < argv_len; ++i)
756 if (std::find(subcommands.begin(), subcommands.end(), arg) != subcommands.end())
763 if (arg ==
"-h" || arg ==
"--help")
765 format = detail::format_help{subcommands,
false};
766 init_standard_options();
767 special_format_was_set =
true;
769 else if (arg ==
"-hh" || arg ==
"--advanced-help")
771 format = detail::format_help{subcommands,
true};
772 init_standard_options();
773 special_format_was_set =
true;
775 else if (arg ==
"--version")
777 format = detail::format_version{};
778 special_format_was_set =
true;
780 else if (arg.substr(0, 13) ==
"--export-help")
786 export_format = arg.
substr(14);
790 if (argv_len <= i + 1)
791 throw too_few_arguments{
"Option --export-help must be followed by a value."};
792 export_format = {argv[i + 1]};
795 if (export_format ==
"html")
796 format = detail::format_html{subcommands};
797 else if (export_format ==
"man")
798 format = detail::format_man{subcommands};
803 throw validation_error{
"Validation failed for option --export-help: "
804 "Value must be one of [html, man]"};
805 init_standard_options();
806 special_format_was_set =
true;
808 else if (arg ==
"--copyright")
810 format = detail::format_copyright{};
811 special_format_was_set =
true;
813 else if (arg ==
"--version-check")
816 throw too_few_arguments{
"Option --version-check must be followed by a value."};
820 if (arg ==
"1" || arg ==
"true")
821 version_check_user_decision =
true;
822 else if (arg ==
"0" || arg ==
"false")
823 version_check_user_decision =
false;
825 throw validation_error{
"Value for option --version-check must be true (1) or false (0)."};
840 format = detail::format_short_help{};
844 if (!special_format_was_set)
845 format = detail::format_parse(argc, cmd_arguments);
849 void init_standard_options()
852 add_list_item(
"\\fB-h\\fP, \\fB--help\\fP",
"Prints the help page.");
853 add_list_item(
"\\fB-hh\\fP, \\fB--advanced-help\\fP",
"Prints the help page including advanced options.");
854 add_list_item(
"\\fB--version\\fP",
"Prints the version information.");
855 add_list_item(
"\\fB--copyright\\fP",
"Prints the copyright/license information.");
857 "Export the help page information. Value must be one of [html, man].");
860 "Whether to check for the newest app version. Default: true.");
868 template <
typename id_type>
869 bool id_exists(id_type
const &
id)
871 if (detail::format_parse::is_empty_id(
id))
885 void verify_identifiers(
char const short_id,
std::string const & long_id)
887 constexpr std::string_view valid_chars{
"@_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
888 auto is_valid = [&valid_chars](
char const c)
890 return valid_chars.
find(c) != std::string::npos;
893 if (id_exists(short_id))
894 throw design_error(
"Option Identifier '" +
std::string(1, short_id) +
"' was already used before.");
895 if (id_exists(long_id))
896 throw design_error(
"Option Identifier '" + long_id +
"' was already used before.");
897 if (long_id.
length() == 1)
898 throw design_error(
"Long IDs must be either empty, or longer than one character.");
899 if ((short_id !=
'\0') && !is_valid(short_id))
900 throw design_error(
"Option identifiers may only contain alphanumeric characters, '_', or '@'.");
901 if (long_id.
size() > 0 && (long_id[0] ==
'-'))
902 throw design_error(
"First character of long ID cannot be '-'.");
908 if (!((c ==
'-') || is_valid(c)))
910 "Long identifiers may only contain alphanumeric characters, '_', '-', or '@'.");
912 if (detail::format_parse::is_empty_id(short_id) && detail::format_parse::is_empty_id(long_id))
913 throw design_error(
"Option Identifiers cannot both be empty.");
917 void verify_option_config(config<auto>
const & config)
919 if (sub_parser !=
nullptr)
920 throw design_error{
"You may only specify flags for the top-level parser."};
922 verify_identifiers(config.short_id, config.long_id);
924 if (config.required && !config.default_message.empty())
925 throw design_error{
"A required option cannot have a default message."};
929 void verify_flag_config(config<auto>
const & config)
931 verify_identifiers(config.short_id, config.long_id);
933 if (!config.default_message.empty())
934 throw design_error{
"A flag may not have a default message because the default is always `false`."};
938 void verify_positional_option_config(config<auto>
const & config)
const
940 if (config.short_id !=
'\0' || config.long_id !=
"")
941 throw design_error{
"Positional options are identified by their position on the command line. "
942 "Short or long ids are not permitted!"};
944 if (config.advanced || config.hidden)
945 throw design_error{
"Positional options are always required and therefore cannot be advanced nor hidden!"};
947 if (sub_parser !=
nullptr)
948 throw design_error{
"You may only specify flags for the top-level parser."};
950 if (has_positional_list_option)
951 throw design_error{
"You added a positional option with a list value before so you cannot add "
952 "any other positional options."};
954 if (!config.default_message.empty())
955 throw design_error{
"A positional option may not have a default message because it is always required."};
Parser exception that is thrown whenever there is an design error directed at the developer of the ap...
Definition: exceptions.hpp:210
The Sharg command line parser.
Definition: parser.hpp:156
void add_option(option_type &value, config< validator_type > const &config)
Adds an option to the sharg::parser.
Definition: parser.hpp:251
void add_flag(bool &value, config< validator_type > const &config)
Adds a flag to the sharg::parser.
Definition: parser.hpp:277
void add_subsection(std::string const &title, bool const advanced_only=false)
Adds an help page subsection to the sharg::parser.
Definition: parser.hpp:551
parser & operator=(parser const &)=default
Defaulted.
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:491
void add_positional_option(option_type &value, config< validator_type > const &config)
Adds a positional option to the sharg::parser.
Definition: parser.hpp:319
parser_meta_data info
Aggregates all parser related meta data (see sharg::parser_meta_data struct).
Definition: parser.hpp:661
parser(std::string const &app_name, int const argc, char const *const *const argv, update_notifications version_updates=update_notifications::on, std::vector< std::string > subcommands={})
Initializes an sharg::parser object from the command line arguments.
Definition: parser.hpp:186
parser(parser &&)=default
Defaulted.
void parse()
Initiates the actual command line parsing.
Definition: parser.hpp:404
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:600
parser & operator=(parser &&)=default
Defaulted.
parser(parser const &)=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:532
~parser()
The destructor.
Definition: parser.hpp:215
parser & get_sub_parser()
Returns a reference to the sub-parser instance if subcommand parsing was enabled.
Definition: parser.hpp:449
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:571
Parser exception thrown when too few arguments are provided.
Definition: exceptions.hpp:103
Checks whether the the type can be used in an add_(positional_)option call on the parser.
Definition: concept.hpp:94
Provides sharg::config class.
update_notifications
Indicates whether application allows automatic update notifications by the sharg::parser.
Definition: auxiliary.hpp:29
@ 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:46
Provides the version check functionality.