@@ -8,6 +8,7 @@ Author: Daniel Kroening, kroening@kroening.com
88
99#include " cmdline.h"
1010
11+ #include < util/edit_distance.h>
1112#include < util/exception_utils.h>
1213#include < util/invariant.h>
1314
@@ -250,6 +251,66 @@ cmdlinet::option_namest cmdlinet::option_names() const
250251 return option_namest{*this };
251252}
252253
254+ std::vector<std::string>
255+ cmdlinet::get_argument_suggestions (const std::string &unknown_argument)
256+ {
257+ struct suggestiont
258+ {
259+ std::size_t distance;
260+ std::string suggestion;
261+
262+ bool operator <(const suggestiont &other) const
263+ {
264+ return distance < other.distance ;
265+ }
266+ };
267+
268+ auto argument_suggestions = std::vector<suggestiont>{};
269+ // We allow 3 errors here. This can lead to the output being a bit chatty,
270+ // which we mitigate by reducing suggestions to those with the minimum
271+ // distance further down below
272+ const auto argument_matcher = levenshtein_automatont{unknown_argument, 3 };
273+ for (const auto &option : options)
274+ {
275+ if (option.islong )
276+ {
277+ const auto long_name = " --" + option.optstring ;
278+ if (auto distance = argument_matcher.get_edit_distance (long_name))
279+ {
280+ argument_suggestions.push_back ({distance.value (), long_name});
281+ }
282+ }
283+ if (!option.islong )
284+ {
285+ const auto short_name = std::string{" -" } + option.optchar ;
286+ if (auto distance = argument_matcher.get_edit_distance (short_name))
287+ {
288+ argument_suggestions.push_back ({distance.value (), short_name});
289+ }
290+ }
291+ }
292+
293+ auto final_suggestions = std::vector<std::string>{};
294+ if (!argument_suggestions.empty ())
295+ {
296+ // we only want to keep suggestions with the minimum distance
297+ // because otherwise they become quickly too noisy to be useful
298+ auto min = std::min_element (
299+ argument_suggestions.begin (), argument_suggestions.end ());
300+ INVARIANT (
301+ min != argument_suggestions.end (),
302+ " there is a minimum because it's not empty" );
303+ for (auto const &suggestion : argument_suggestions)
304+ {
305+ if (suggestion.distance == min->distance )
306+ {
307+ final_suggestions.push_back (suggestion.suggestion );
308+ }
309+ }
310+ }
311+ return final_suggestions;
312+ }
313+
253314cmdlinet::option_namest::option_names_iteratort::option_names_iteratort (
254315 const cmdlinet *command_line,
255316 std::size_t index)
0 commit comments