summaryrefslogtreecommitdiff
path: root/lib/Option/OptTable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Option/OptTable.cpp')
-rw-r--r--lib/Option/OptTable.cpp81
1 files changed, 70 insertions, 11 deletions
diff --git a/lib/Option/OptTable.cpp b/lib/Option/OptTable.cpp
index c1bb05e817f0..022b9d5d933e 100644
--- a/lib/Option/OptTable.cpp
+++ b/lib/Option/OptTable.cpp
@@ -219,7 +219,7 @@ OptTable::suggestValueCompletions(StringRef Option, StringRef Arg) const {
std::vector<std::string> Result;
for (StringRef Val : Candidates)
- if (Val.startswith(Arg))
+ if (Val.startswith(Arg) && Arg.compare(Val))
Result.push_back(Val);
return Result;
}
@@ -240,13 +240,76 @@ OptTable::findByPrefix(StringRef Cur, unsigned short DisableFlags) const {
std::string S = std::string(In.Prefixes[I]) + std::string(In.Name) + "\t";
if (In.HelpText)
S += In.HelpText;
- if (StringRef(S).startswith(Cur))
+ if (StringRef(S).startswith(Cur) && S.compare(std::string(Cur) + "\t"))
Ret.push_back(S);
}
}
return Ret;
}
+unsigned OptTable::findNearest(StringRef Option, std::string &NearestString,
+ unsigned FlagsToInclude, unsigned FlagsToExclude,
+ unsigned MinimumLength) const {
+ assert(!Option.empty());
+
+ // Consider each option 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.
+ if (CandidateName.empty() || CandidateName.size() < MinimumLength)
+ continue;
+
+ // If FlagsToInclude were specified, ignore options that don't include
+ // those flags.
+ if (FlagsToInclude && !(CandidateInfo.Flags & FlagsToInclude))
+ continue;
+ // Ignore options that contain the FlagsToExclude.
+ if (CandidateInfo.Flags & FlagsToExclude)
+ continue;
+
+ // 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
+ // 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 = "";
+ char Last = CandidateName.back();
+ if (Last == '=' || Last == ':')
+ Delimiter = std::string(1, Last);
+
+ StringRef LHS, RHS;
+ if (Delimiter.empty())
+ LHS = Option;
+ 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();
+ }
+ }
+ return BestDistance;
+}
+
bool OptTable::addValues(const char *Option, const char *Values) {
for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E; I++) {
Info &In = OptionInfos[I];
@@ -474,12 +537,9 @@ void OptTable::PrintHelp(raw_ostream &OS, const char *Name, const char *Title,
// Render help text into a map of group-name to a list of (option, help)
// pairs.
- using helpmap_ty = std::map<std::string, std::vector<OptionInfo>>;
- helpmap_ty GroupedOptionHelp;
-
- for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
- unsigned Id = i + 1;
+ std::map<std::string, std::vector<OptionInfo>> GroupedOptionHelp;
+ for (unsigned Id = 1, e = getNumOptions() + 1; Id != e; ++Id) {
// FIXME: Split out option groups.
if (getOptionKind(Id) == Option::GroupClass)
continue;
@@ -506,11 +566,10 @@ void OptTable::PrintHelp(raw_ostream &OS, const char *Name, const char *Title,
}
}
- for (helpmap_ty::iterator it = GroupedOptionHelp .begin(),
- ie = GroupedOptionHelp.end(); it != ie; ++it) {
- if (it != GroupedOptionHelp .begin())
+ for (auto& OptionGroup : GroupedOptionHelp) {
+ if (OptionGroup.first != GroupedOptionHelp.begin()->first)
OS << "\n";
- PrintHelpOptionList(OS, it->first, it->second);
+ PrintHelpOptionList(OS, OptionGroup.first, OptionGroup.second);
}
OS.flush();