Commit 6f41d56f authored by Paul's avatar Paul
Browse files

Add spell checking of arguments

parent a7392ca9
......@@ -18,6 +18,7 @@
#include <migraphx/type_name.hpp>
#include <migraphx/functional.hpp>
#include <migraphx/stringutils.hpp>
#include <migraphx/algorithm.hpp>
#include <migraphx/ranges.hpp>
#include <migraphx/rank.hpp>
......@@ -388,6 +389,49 @@ struct argument_parser
actions.push_back([&](const auto& self) { x = self.exe_name; });
}
void print_usage_for(const argument& arg, const std::string& flag) const
{
std::cout << color::fg_yellow << "USAGE:" << color::reset << std::endl;
std::cout << " " << exe_name << " ";
std::cout << flag;
if(not arg.type.empty())
std::cout << " [" << arg.type << "]";
std::cout << std::endl;
}
auto spellcheck(const std::vector<std::string>& inputs)
{
struct result_t
{
const argument* arg = nullptr;
std::string correct = "";
std::string incorrect = "";
std::ptrdiff_t distance = std::numeric_limits<std::ptrdiff_t>::max();
};
result_t result;
for(const auto& input:inputs)
{
if (input.empty())
continue;
if (input[0] != '-')
continue;
for(const auto& arg:arguments)
{
for(const auto& flag:arg.flags)
{
if (flag.empty())
continue;
if (flag[0] != '-')
continue;
auto d = levenshtein_distance(flag.begin(), flag.end(), input.begin(), input.end());
if (d < result.distance)
result = result_t{&arg, flag, input, d};
}
}
}
return result;
}
bool
run_action(const argument& arg, const std::string& flag, const std::vector<std::string>& inputs)
{
......@@ -404,20 +448,30 @@ struct argument_parser
{
msg = "unknown exception";
}
auto show_usage = [&] {
std::cout << color::fg_red << color::bold << "error: " << color::reset;
auto sc = spellcheck(inputs);
std::cout << sc.distance << std::endl;
std::cout << sc.correct << std::endl;
if (sc.distance < 5)
{
std::cout << "Found argument '" << color::fg_yellow << sc.incorrect << "'";
std::cout << " which wasn't expected, or isn't valid in this context" << std::endl;
std::cout << " ";
std::cout << "Did you mean " << color::fg_green << sc.correct << color::reset << "?" << std::endl;
std::cout << std::endl;
print_usage_for(*sc.arg, sc.correct);
}
else
{
std::cout << "Invalid input to '" << color::fg_yellow;
std::cout << flag;
if(not arg.type.empty())
std::cout << " [" << arg.type << "]";
};
std::cout << color::fg_red << color::bold << "error: " << color::reset;
std::cout << "Invalid input to '" << color::fg_yellow;
show_usage();
std::cout << color::reset << "'" << std::endl;
std::cout << " " << msg << std::endl;
std::cout << std::endl;
std::cout << color::fg_yellow << "USAGE:" << color::reset << std::endl;
std::cout << " " << exe_name << " ";
show_usage();
std::cout << color::reset << "'" << std::endl;
std::cout << " " << msg << std::endl;
std::cout << std::endl;
print_usage_for(arg, flag);
}
std::cout << std::endl;
if(has_argument([](const auto& a) { return contains(a.flags, "--help"); }))
{
......
......@@ -51,6 +51,21 @@ void group_unique(Iterator start, Iterator last, Output out, Predicate pred)
}
}
template<class Iterator1, class Iterator2>
std::ptrdiff_t levenshtein_distance(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
{
if (first1 == last1)
return std::distance(first2, last2);
if (first2 == last2)
return std::distance(first1, last1);
if (*first1 == *first2)
return levenshtein_distance(std::next(first1), last1, std::next(first2), last2);
auto x1 = levenshtein_distance(std::next(first1), last1, std::next(first2), last2);
auto x2 = levenshtein_distance(first1, last1, std::next(first2), last2);
auto x3 = levenshtein_distance(std::next(first1), last1, first2, last2);
return std::ptrdiff_t{1} + std::min({x1, x2, x3});
}
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment