|
@@ -252,38 +252,33 @@ unsigned OptTable::findNearest(StringRef Option, std::string &NearestString,
|
|
|
unsigned MinimumLength) const {
|
|
|
assert(!Option.empty());
|
|
|
|
|
|
- // Consider each option as a candidate, finding the closest match.
|
|
|
+ // Consider each [option prefix + option name] pair as a candidate, finding
|
|
|
+ // the closest match.
|
|
|
unsigned BestDistance = UINT_MAX;
|
|
|
for (const Info &CandidateInfo :
|
|
|
ArrayRef<Info>(OptionInfos).drop_front(FirstSearchableIndex)) {
|
|
|
StringRef CandidateName = CandidateInfo.Name;
|
|
|
|
|
|
- // Ignore option candidates with empty names, such as "--", or names
|
|
|
- // that do not meet the minimum length.
|
|
|
+ // We can eliminate some option prefix/name pairs as candidates right away:
|
|
|
+ // * Ignore option candidates with empty names, such as "--", or names
|
|
|
+ // that do not meet the minimum length.
|
|
|
if (CandidateName.empty() || CandidateName.size() < MinimumLength)
|
|
|
continue;
|
|
|
|
|
|
- // If FlagsToInclude were specified, ignore options that don't include
|
|
|
- // those flags.
|
|
|
+ // * If FlagsToInclude were specified, ignore options that don't include
|
|
|
+ // those flags.
|
|
|
if (FlagsToInclude && !(CandidateInfo.Flags & FlagsToInclude))
|
|
|
continue;
|
|
|
- // Ignore options that contain the FlagsToExclude.
|
|
|
+ // * Ignore options that contain the FlagsToExclude.
|
|
|
if (CandidateInfo.Flags & FlagsToExclude)
|
|
|
continue;
|
|
|
|
|
|
- // Ignore positional argument option candidates (which do not
|
|
|
- // have prefixes).
|
|
|
+ // * Ignore positional argument option candidates (which do not
|
|
|
+ // have prefixes).
|
|
|
if (!CandidateInfo.Prefixes)
|
|
|
continue;
|
|
|
- // Find the most appropriate prefix. For example, if a user asks for
|
|
|
- // "--helm", suggest "--help" over "-help".
|
|
|
- StringRef Prefix = CandidateInfo.Prefixes[0];
|
|
|
- for (int P = 1; CandidateInfo.Prefixes[P]; P++) {
|
|
|
- if (Option.startswith(CandidateInfo.Prefixes[P]))
|
|
|
- Prefix = CandidateInfo.Prefixes[P];
|
|
|
- }
|
|
|
|
|
|
- // Check if the candidate ends with a character commonly used when
|
|
|
+ // Now check if the candidate ends with a character commonly used when
|
|
|
// delimiting an option from its value, such as '=' or ':'. If it does,
|
|
|
// attempt to split the given option based on that delimiter.
|
|
|
std::string Delimiter = "";
|
|
@@ -297,14 +292,19 @@ unsigned OptTable::findNearest(StringRef Option, std::string &NearestString,
|
|
|
else
|
|
|
std::tie(LHS, RHS) = Option.split(Last);
|
|
|
|
|
|
- std::string NormalizedName =
|
|
|
- (LHS.drop_front(Prefix.size()) + Delimiter).str();
|
|
|
- unsigned Distance =
|
|
|
- CandidateName.edit_distance(NormalizedName, /*AllowReplacements=*/true,
|
|
|
- /*MaxEditDistance=*/BestDistance);
|
|
|
- if (Distance < BestDistance) {
|
|
|
- BestDistance = Distance;
|
|
|
- NearestString = (Prefix + CandidateName + RHS).str();
|
|
|
+ // Consider each possible prefix for each candidate to find the most
|
|
|
+ // appropriate one. For example, if a user asks for "--helm", suggest
|
|
|
+ // "--help" over "-help".
|
|
|
+ for (int P = 0; const char *const CandidatePrefix = CandidateInfo.Prefixes[P]; P++) {
|
|
|
+ std::string NormalizedName = (LHS + Delimiter).str();
|
|
|
+ StringRef Candidate = (CandidatePrefix + CandidateName).str();
|
|
|
+ unsigned Distance =
|
|
|
+ Candidate.edit_distance(NormalizedName, /*AllowReplacements=*/true,
|
|
|
+ /*MaxEditDistance=*/BestDistance);
|
|
|
+ if (Distance < BestDistance) {
|
|
|
+ BestDistance = Distance;
|
|
|
+ NearestString = (Candidate + RHS).str();
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
return BestDistance;
|