Default --help to print help and exit

The change also fixes a rare bug introduced in 9007958:
when there are duplicated keys, insert_or_update overrides
previously inserted ones, emplace doesn't.

fixes: p-ranav/argparse#59
This commit is contained in:
Zhihao Yuan 2019-11-22 16:12:44 -06:00
parent 4cc2c75dec
commit 77f3bd9b8d
No known key found for this signature in database
GPG Key ID: 0BC0BC626A0C5A8E
2 changed files with 40 additions and 14 deletions

View File

@ -30,6 +30,7 @@ SOFTWARE.
#pragma once #pragma once
#include <algorithm> #include <algorithm>
#include <any> #include <any>
#include <cstdlib>
#include <functional> #include <functional>
#include <iostream> #include <iostream>
#include <iterator> #include <iterator>
@ -372,20 +373,15 @@ private:
bool mIsOptional : 1; bool mIsOptional : 1;
bool mIsRequired : 1; bool mIsRequired : 1;
bool mIsUsed : 1; // True if the optional argument is used by user bool mIsUsed : 1; // True if the optional argument is used by user
static constexpr auto mHelpOption = "-h";
static constexpr auto mHelpOptionLong = "--help";
}; };
class ArgumentParser { class ArgumentParser {
public: public:
explicit ArgumentParser(std::string aProgramName = {}) explicit ArgumentParser(std::string aProgramName = {})
: mProgramName(std::move(aProgramName)) { : mProgramName(std::move(aProgramName)) {
add_argument(Argument::mHelpOption, Argument::mHelpOptionLong) add_argument("-h", "--help")
.help("show this help message and exit") .help("show this help message and exit")
.nargs(0) .nargs(0);
.default_value(false)
.implicit_value(true);
} }
ArgumentParser(ArgumentParser &&) noexcept = default; ArgumentParser(ArgumentParser &&) noexcept = default;
@ -542,10 +538,6 @@ private:
auto positionalArgumentIt = std::begin(mPositionalArguments); auto positionalArgumentIt = std::begin(mPositionalArguments);
for (auto it = std::next(std::begin(aArguments)); it != end;) { for (auto it = std::next(std::begin(aArguments)); it != end;) {
const auto &tCurrentArgument = *it; const auto &tCurrentArgument = *it;
if (tCurrentArgument == Argument::mHelpOption ||
tCurrentArgument == Argument::mHelpOptionLong) {
throw std::runtime_error("help called");
}
if (Argument::is_positional(tCurrentArgument)) { if (Argument::is_positional(tCurrentArgument)) {
if (positionalArgumentIt == std::end(mPositionalArguments)) { if (positionalArgumentIt == std::end(mPositionalArguments)) {
throw std::runtime_error( throw std::runtime_error(
@ -553,9 +545,19 @@ private:
} }
auto tArgument = positionalArgumentIt++; auto tArgument = positionalArgumentIt++;
it = tArgument->consume(it, end); it = tArgument->consume(it, end);
} else if (auto tIterator = mArgumentMap.find(tCurrentArgument); continue;
tIterator != mArgumentMap.end()) { }
auto tIterator = mArgumentMap.find(tCurrentArgument);
if (tIterator != mArgumentMap.end()) {
auto tArgument = tIterator->second; auto tArgument = tIterator->second;
// the first optional argument is --help
if (tArgument == mOptionalArguments.begin()) {
std::cout << *this;
std::exit(0);
}
it = tArgument->consume(std::next(it), end, tCurrentArgument); it = tArgument->consume(std::next(it), end, tCurrentArgument);
} else if (const auto &tCompoundArgument = tCurrentArgument; } else if (const auto &tCompoundArgument = tCurrentArgument;
tCompoundArgument.size() > 1 && tCompoundArgument[0] == '-' && tCompoundArgument.size() > 1 && tCompoundArgument[0] == '-' &&
@ -607,7 +609,7 @@ private:
void index_argument(list_iterator argIt) { void index_argument(list_iterator argIt) {
for (auto &mName : std::as_const(argIt->mNames)) for (auto &mName : std::as_const(argIt->mNames))
mArgumentMap.emplace(mName, argIt); mArgumentMap.insert_or_assign(mName, argIt);
} }
std::string mProgramName; std::string mProgramName;

View File

@ -17,3 +17,27 @@ TEST_CASE("Users can format help message" * test_suite("help")) {
auto msg = program.help().str(); auto msg = program.help().str();
REQUIRE(msg == s.str()); REQUIRE(msg == s.str());
} }
TEST_CASE("Users can override the help options" * test_suite("help")) {
GIVEN("a program that meant to take -h as a normal option") {
argparse::ArgumentParser program("test");
program.add_argument("input");
program.add_argument("-h").implicit_value('h').default_value('x');
WHEN("provided -h without fulfilling other requirements") {
THEN("validation fails") {
REQUIRE_THROWS_AS(program.parse_args({"test", "-h"}),
std::runtime_error);
}
}
WHEN("provided arguments to all parameters") {
program.parse_args({"test", "-h", "some input"});
THEN("these parameters get their values") {
REQUIRE(program["-h"] == 'h');
REQUIRE(program.get("input") == "some input");
}
}
}
}