mirror of
https://github.com/KeqingMoe/argparse.git
synced 2025-07-03 22:54:39 +00:00
Closes #285
This commit is contained in:
parent
7657a22001
commit
62052fefcb
@ -452,6 +452,46 @@ template <typename T> struct IsChoiceTypeSupported {
|
|||||||
std::is_same<CleanType, const char *>::value;
|
std::is_same<CleanType, const char *>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename StringType>
|
||||||
|
int get_levenshtein_distance(const StringType &s1, const StringType &s2) {
|
||||||
|
std::vector<std::vector<int>> dp(s1.size() + 1,
|
||||||
|
std::vector<int>(s2.size() + 1, 0));
|
||||||
|
|
||||||
|
for (int i = 0; i <= s1.size(); ++i) {
|
||||||
|
for (int j = 0; j <= s2.size(); ++j) {
|
||||||
|
if (i == 0) {
|
||||||
|
dp[i][j] = j;
|
||||||
|
} else if (j == 0) {
|
||||||
|
dp[i][j] = i;
|
||||||
|
} else if (s1[i - 1] == s2[j - 1]) {
|
||||||
|
dp[i][j] = dp[i - 1][j - 1];
|
||||||
|
} else {
|
||||||
|
dp[i][j] = 1 + std::min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dp[s1.size()][s2.size()];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ValueType>
|
||||||
|
std::string_view
|
||||||
|
get_most_similar_string(const std::map<std::string_view, ValueType> &map,
|
||||||
|
const std::string_view input) {
|
||||||
|
std::string_view most_similar{};
|
||||||
|
int min_distance = std::numeric_limits<int>::max();
|
||||||
|
|
||||||
|
for (const auto &entry : map) {
|
||||||
|
int distance = get_levenshtein_distance(entry.first, input);
|
||||||
|
if (distance < min_distance) {
|
||||||
|
min_distance = distance;
|
||||||
|
most_similar = entry.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return most_similar;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
|
||||||
enum class nargs_pattern { optional, any, at_least_one };
|
enum class nargs_pattern { optional, any, at_least_one };
|
||||||
@ -1804,6 +1844,15 @@ private:
|
|||||||
|
|
||||||
if (m_positional_arguments.empty()) {
|
if (m_positional_arguments.empty()) {
|
||||||
|
|
||||||
|
/// Check sub-parsers first
|
||||||
|
if (!m_subparser_map.empty()) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Failed to parse '" + current_argument + "', did you mean '" +
|
||||||
|
std::string{details::get_most_similar_string(
|
||||||
|
m_subparser_map, current_argument)} +
|
||||||
|
"'");
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_optional_arguments.empty()) {
|
if (!m_optional_arguments.empty()) {
|
||||||
bool not_help_or_version{true};
|
bool not_help_or_version{true};
|
||||||
for (const auto &opt : m_optional_arguments) {
|
for (const auto &opt : m_optional_arguments) {
|
||||||
|
@ -66,4 +66,32 @@ TEST_CASE("Missing optional argument name with other positional arguments" *
|
|||||||
"Maximum number of positional arguments exceeded, failed to parse '3'",
|
"Maximum number of positional arguments exceeded, failed to parse '3'",
|
||||||
std::runtime_error);
|
std::runtime_error);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Detect unknown subcommand" * test_suite("error_reporting")) {
|
||||||
|
argparse::ArgumentParser program("git");
|
||||||
|
argparse::ArgumentParser log_command("log");
|
||||||
|
argparse::ArgumentParser notes_command("notes");
|
||||||
|
argparse::ArgumentParser add_command("add");
|
||||||
|
program.add_subparser(log_command);
|
||||||
|
program.add_subparser(notes_command);
|
||||||
|
program.add_subparser(add_command);
|
||||||
|
|
||||||
|
SUBCASE("Typo for 'notes'") {
|
||||||
|
REQUIRE_THROWS_WITH_AS(program.parse_args({"git", "tote"}),
|
||||||
|
"Failed to parse 'tote', did you mean 'notes'",
|
||||||
|
std::runtime_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("Typo for 'add'") {
|
||||||
|
REQUIRE_THROWS_WITH_AS(program.parse_args({"git", "bad"}),
|
||||||
|
"Failed to parse 'bad', did you mean 'add'",
|
||||||
|
std::runtime_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("Typo for 'log'") {
|
||||||
|
REQUIRE_THROWS_WITH_AS(program.parse_args({"git", "logic"}),
|
||||||
|
"Failed to parse 'logic', did you mean 'log'",
|
||||||
|
std::runtime_error);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user