Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions include/argparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ namespace argparse
auto parse_args(tokens args) -> Parameters
{
parse_optional_arguments(args);
remove_pseudo_arguments(args);
consume_pseudo_arguments(args);
parse_positional_arguments(args);

ensure_no_unrecognised_arguments(args);
Expand Down Expand Up @@ -398,9 +398,12 @@ namespace argparse
}
}

static auto remove_pseudo_arguments(tokens & args) -> void
static auto consume_pseudo_arguments(tokens & args) -> void
{
std::erase(args, Token{"--"});
for (auto & arg : args | std::views::filter([](auto const & arg) { return arg.m_token == "--"; }))
{
arg.m_consumed = true;
}
}

auto ensure_no_unrecognised_arguments(tokens const & args) const -> void
Expand Down Expand Up @@ -681,7 +684,29 @@ namespace argparse

auto parse_args(tokens & args) -> void override
{
auto consumable = args | std::views::drop_while([](auto const & token) { return token.m_consumed; });
bool past_pseudo_arg = false;
auto consumable = args
| std::views::drop_while([](auto const & token)
{
if (token.m_token == "--")
{
return false;
}
return token.m_consumed;
})
| std::views::filter([&past_pseudo_arg](auto const & token)
{
if (past_pseudo_arg)
{
return true;
}
if (token.m_token == "--")
{
past_pseudo_arg = true;
return false;
}
return !token.m_token.starts_with("-");
});
if (has_nargs())
{
if (has_nargs_number())
Expand Down
56 changes: 56 additions & 0 deletions test/unittest/test_parsing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,59 @@ TEST_CASE("Arguments past the -- pseudo argument are treated as positional for p

CHECK(parsed.get_value("pos") == "-o");
}

TEST_CASE("Positional argument does not consume unrecognised optional argument")
{
auto parser = argparse::ArgumentParser().handle(argparse::Handle::none);
parser.add_argument("pos");

CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "-o"}), "unrecognised arguments: -o", argparse::parsing_error);
}

TEST_CASE("Positional argument does not consume unrecognised optional argument")
{
auto parser = argparse::ArgumentParser().handle(argparse::Handle::none);
parser.add_argument("pos");

CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "--option"}), "unrecognised arguments: --option", argparse::parsing_error);
}

TEST_CASE("Positional argument does not consume unrecognised optional argument")
{
auto parser = argparse::ArgumentParser().handle(argparse::Handle::none);
parser.add_argument("pos").nargs(1);

CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "-o"}), "unrecognised arguments: -o", argparse::parsing_error);
}

TEST_CASE("Positional argument does not consume unrecognised optional argument")
{
auto parser = argparse::ArgumentParser().handle(argparse::Handle::none);
parser.add_argument("pos").nargs(2);

CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "-o"}), "unrecognised arguments: -o", argparse::parsing_error);
}

TEST_CASE("Positional argument does not consume unrecognised optional argument")
{
auto parser = argparse::ArgumentParser().handle(argparse::Handle::none);
parser.add_argument("pos").nargs(argparse::zero_or_one);

CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "-o"}), "unrecognised arguments: -o", argparse::parsing_error);
}

TEST_CASE("Positional argument does not consume unrecognised optional argument")
{
auto parser = argparse::ArgumentParser().handle(argparse::Handle::none);
parser.add_argument("pos").nargs(argparse::zero_or_more);

CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "-o"}), "unrecognised arguments: -o", argparse::parsing_error);
}

TEST_CASE("Positional argument does not consume unrecognised optional argument")
{
auto parser = argparse::ArgumentParser().handle(argparse::Handle::none);
parser.add_argument("pos").nargs(argparse::one_or_more);

CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "-o"}), "unrecognised arguments: -o", argparse::parsing_error);
}