Skip to content

Commit

Permalink
[MISC] Refactor init()
Browse files Browse the repository at this point in the history
  • Loading branch information
eseiler committed Feb 15, 2024
1 parent 5855f49 commit 5bd40d2
Showing 1 changed file with 58 additions and 43 deletions.
101 changes: 58 additions & 43 deletions include/sharg/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,8 @@ class parser
// User input sanitization must happen before version check!
verify_app_and_subcommand_names();

init();
// Determine the format and subcommand.
determine_format_and_subcommand();

// If a subcommand was provided, check that it is valid.
verify_subcommand();
Expand Down Expand Up @@ -786,53 +787,66 @@ class parser
*
* If `--export-help` is specified with a value other than html, man, cwl or ctd, an sharg::parser_error is thrown.
*/
void init()
void determine_format_and_subcommand()
{
assert(!arguments.empty());
auto it = arguments.begin();

executable_name.emplace_back(arguments[0]);
executable_name.emplace_back(*it);
++it;

// Helper function for going to the next argument. This makes it more obvious that we are
// incrementing `it` (version-check, and export-help).
auto go_to_next_arg = [this](auto & it, std::string_view message) -> auto
auto go_to_next_arg = [this, &it](std::string_view message) -> auto
{
assert(it != arguments.end());

if (++it == arguments.end())
throw too_few_arguments{message.data()};
};

// start at 1 to skip binary name
for (auto it = ++arguments.begin(); it != arguments.end(); ++it)
// Helper function for finding and processing subcommands.
auto found_and_processed_subcommand = [this, &it](std::string_view arg) -> bool
{
std::string_view arg{*it};
if (subcommands.empty())
return false;

if (!subcommands.empty()) // this is a top_level parser
if (std::ranges::find(subcommands, arg) != subcommands.end())
{
if (std::ranges::find(subcommands, arg) != subcommands.end()) // identified subparser
{
sub_parser = std::make_unique<parser>(info.app_name + "-" + arg.data(),
std::vector<std::string>{it, arguments.end()},
update_notifications::off);

// Add the original calls to the front, e.g. ["raptor"],
// s.t. ["raptor", "build"] will be the list after constructing the subparser
sub_parser->executable_name.insert(sub_parser->executable_name.begin(),
executable_name.begin(),
executable_name.end());
break;
}
else
sub_parser = std::make_unique<parser>(info.app_name + "-" + arg.data(),
std::vector<std::string>{it, arguments.end()},
update_notifications::off);

// Add the original calls to the front, e.g. ["raptor"],
// s.t. ["raptor", "build"] will be the list after constructing the subparser
sub_parser->executable_name.insert(sub_parser->executable_name.begin(),
executable_name.begin(),
executable_name.end());
return true;
}
else
{
// Options and positional options are forbidden by design.
// Flags starting with '-' are allowed for the top-level parser.
// Otherwise, this is a wrongly spelled subcommand. The error will be thrown in parse().
if (!arg.empty() && arg[0] != '-')
{
// Options and positional options are forbidden by design.
// Flags starting with '-' are allowed for the top-level parser.
// Otherwise, this is a wrongly spelled subcommand. The error will be thrown in parse().
if (!arg.empty() && arg[0] != '-')
{
format_arguments.emplace_back(arg);
break;
}
format_arguments.emplace_back(arg);
return true;
}
}

return false;
};

// Process the arguments.
for (; it != arguments.end(); ++it)
{
std::string_view arg{*it};

if (found_and_processed_subcommand(arg))
break;

if (arg == "-h" || arg == "--help")
{
format = detail::format_help{subcommands, version_check_dev_decision, false};
Expand All @@ -849,28 +863,29 @@ class parser
{
format = detail::format_copyright{};
}
else if (arg.substr(0, 13) == "--export-help") // --export-help=man is also allowed
else if (std::string_view const export_cli{"--export-help"}; arg.starts_with(export_cli))
{
arg.remove_prefix(export_cli.size());

std::string_view export_format;

if (arg.size() > 13)
// --export-help man
if (arg.empty())
{
export_format = arg.substr(14);
go_to_next_arg("Option --export-help must be followed by a value.");
arg = *it;
}
else
else // --export-help=man
{
go_to_next_arg(it, "Option --export-help must be followed by a value.");
export_format = *it;
// Todo: This skips any separator, not just '='. --export-helppman would be accepted.
arg.remove_prefix(1u);
}

if (export_format == "html")
if (arg == "html")
format = detail::format_html{subcommands, version_check_dev_decision};
else if (export_format == "man")
else if (arg == "man")
format = detail::format_man{subcommands, version_check_dev_decision};
else if (export_format == "ctd")
else if (arg == "ctd")
format = detail::format_tdl{detail::format_tdl::FileFormat::CTD};
else if (export_format == "cwl")
else if (arg == "cwl")
format = detail::format_tdl{detail::format_tdl::FileFormat::CWL};
else
throw validation_error{"Validation failed for option --export-help: "
Expand All @@ -879,7 +894,7 @@ class parser
}
else if (arg == "--version-check")
{
go_to_next_arg(it, "Option --version-check must be followed by a value.");
go_to_next_arg("Option --version-check must be followed by a value.");
arg = *it;

if (arg == "1" || arg == "true")
Expand Down

0 comments on commit 5bd40d2

Please sign in to comment.