mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
cmake: Add CLI argument spell checking
Use Levenshtein distance to track when the user may have made a typo in an argument to `cmake`, `cmake --build`, `cmake --install`, or `cmake --workflow`.
This commit is contained in:
@@ -291,3 +291,18 @@ private:
|
||||
!(arg.size() >= 2 && cmsysString_isdigit(arg[1]));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename FunctionSignature>
|
||||
std::string cmFindClosestCommandLineArgument(
|
||||
std::string const& arg,
|
||||
std::vector<cmCommandLineArgument<FunctionSignature>> const& arguments)
|
||||
{
|
||||
std::vector<std::string> candidates;
|
||||
candidates.reserve(arguments.size());
|
||||
for (auto const& option : arguments) {
|
||||
if (!option.Name.empty()) {
|
||||
candidates.push_back(option.Name);
|
||||
}
|
||||
}
|
||||
return cmFindClosestString(arg, candidates);
|
||||
}
|
||||
|
||||
+13
-1
@@ -200,6 +200,12 @@ std::string normalizeCliWarningName(cm::string_view cliName)
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string findClosestOption(std::string const& arg,
|
||||
std::vector<CommandArgument> const& arguments)
|
||||
{
|
||||
return cmFindClosestCommandLineArgument(arg, arguments);
|
||||
}
|
||||
|
||||
bool cmakeCheckStampFile(std::string const& stampName)
|
||||
{
|
||||
// The stamp file does not exist. Use the stamp dependencies to
|
||||
@@ -1548,7 +1554,13 @@ void cmake::SetArgs(std::vector<std::string> const& args)
|
||||
}
|
||||
if (!possibleUnknownArg.empty() &&
|
||||
this->State->GetRole() != cmState::Role::Script) {
|
||||
cmSystemTools::Error(cmStrCat("Unknown argument ", possibleUnknownArg));
|
||||
std::string error = cmStrCat("Unknown argument ", possibleUnknownArg);
|
||||
std::string const suggestion =
|
||||
findClosestOption(possibleUnknownArg, arguments);
|
||||
if (!suggestion.empty()) {
|
||||
error = cmStrCat(error, ". Did you mean: ", suggestion, '?');
|
||||
}
|
||||
cmSystemTools::Error(error);
|
||||
cmSystemTools::Error("Run 'cmake --help' for all supported options.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
+21
-3
@@ -635,7 +635,13 @@ int do_build(int ac, char const* const* av)
|
||||
if (!(matched && parsed)) {
|
||||
buildArgs.binaryDir.clear();
|
||||
if (!matched) {
|
||||
std::cerr << "Unknown argument " << arg << std::endl;
|
||||
std::string error = cmStrCat("Unknown argument ", arg);
|
||||
std::string const suggestion =
|
||||
cmFindClosestCommandLineArgument(arg, arguments);
|
||||
if (!suggestion.empty()) {
|
||||
error = cmStrCat(error, ". Did you mean: ", suggestion, '?');
|
||||
}
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -933,7 +939,13 @@ int do_install(int ac, char const* const* av)
|
||||
if (!(matched && parsed)) {
|
||||
dir.clear();
|
||||
if (!matched) {
|
||||
std::cerr << "Unknown argument " << arg << std::endl;
|
||||
std::string error = cmStrCat("Unknown argument ", arg);
|
||||
std::string const suggestion =
|
||||
cmFindClosestCommandLineArgument(arg, arguments);
|
||||
if (!suggestion.empty()) {
|
||||
error = cmStrCat(error, ". Did you mean: ", suggestion, '?');
|
||||
}
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1136,7 +1148,13 @@ int do_workflow(int ac, char const* const* av)
|
||||
if (!(matched && parsed)) {
|
||||
if (!matched) {
|
||||
presetsArgs.Clear();
|
||||
std::cerr << "Unknown argument " << arg << std::endl;
|
||||
std::string error = cmStrCat("Unknown argument ", arg);
|
||||
std::string const suggestion =
|
||||
cmFindClosestCommandLineArgument(arg, arguments);
|
||||
if (!suggestion.empty()) {
|
||||
error = cmStrCat(error, ". Did you mean: ", suggestion, '?');
|
||||
}
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -235,6 +235,7 @@ run_cmake_command(PresetsNoArgEq-workflow ${CMAKE_COMMAND} "--workflow" "--prese
|
||||
run_cmake_command(PresetsFileNoArg-workflow ${CMAKE_COMMAND} "--workflow" "--presets-file")
|
||||
run_cmake_workflow_presets(InvalidOption -DINVALID_OPTION)
|
||||
run_cmake_workflow_presets(ListPresetsInvalidValue --list-presets=invalid)
|
||||
run_cmake_command(UnknownOptionDidYouMean ${CMAKE_COMMAND} "--workflow" "--fresh" "--presett")
|
||||
|
||||
set(RunCMake_TEST_NO_CLEAN TRUE)
|
||||
file(REMOVE_RECURSE "${RunCMake_BINARY_DIR}/Fresh")
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,3 @@
|
||||
^Unknown argument --presett\. Did you mean: --preset\?
|
||||
Usage: cmake --workflow <options>
|
||||
Options:
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,2 @@
|
||||
^CMake Error: Unknown argument --toolchan\. Did you mean: --toolchain\?
|
||||
CMake Error: Run 'cmake --help' for all supported options\.$
|
||||
@@ -42,6 +42,7 @@ run_cmake_command(versionVJsonNoArg ${CMAKE_COMMAND} /V=json-v1)
|
||||
run_cmake_command(NoArgs ${CMAKE_COMMAND})
|
||||
run_cmake_command(InvalidArg1 ${CMAKE_COMMAND} -invalid)
|
||||
run_cmake_command(InvalidArg2 ${CMAKE_COMMAND} --invalid)
|
||||
run_cmake_command(InvalidArg3 ${CMAKE_COMMAND} --toolchan)
|
||||
run_cmake_command(Wizard ${CMAKE_COMMAND} -i)
|
||||
run_cmake_command(C-no-arg ${CMAKE_COMMAND} -B DummyBuildDir -C)
|
||||
run_cmake_command(C-no-arg2 ${CMAKE_COMMAND} -B DummyBuildDir -C -T)
|
||||
@@ -145,6 +146,8 @@ run_cmake_command(build-unknown-command-long
|
||||
${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR} --invalid-command)
|
||||
run_cmake_command(build-unknown-command-partial-match
|
||||
${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR} --targetinvalid)
|
||||
run_cmake_command(build-unknown-command-did-you-mean
|
||||
${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR} --targe)
|
||||
run_cmake_command(build-invalid-target-syntax
|
||||
${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR} --target=invalid)
|
||||
run_cmake_command(build-no-generator
|
||||
@@ -164,6 +167,8 @@ run_cmake_command(install-unknown-command-short
|
||||
${CMAKE_COMMAND} --install ${RunCMake_SOURCE_DIR} -invalid-command)
|
||||
run_cmake_command(install-unknown-command-long
|
||||
${CMAKE_COMMAND} --install ${RunCMake_SOURCE_DIR} --invalid-command)
|
||||
run_cmake_command(install-unknown-command-did-you-mean
|
||||
${CMAKE_COMMAND} --install ${RunCMake_SOURCE_DIR} --compnent)
|
||||
run_cmake_command(install-options-to-vars
|
||||
${CMAKE_COMMAND} --install ${RunCMake_SOURCE_DIR}/dir-install-options-to-vars
|
||||
--strip --prefix /var/test --config sample --component pack)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,2 @@
|
||||
^Unknown argument --targe\. Did you mean: --target\?
|
||||
Usage: cmake --build <dir> +\[options\] \[-- \[native-options\]\]
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,2 @@
|
||||
^Unknown argument --compnent\. Did you mean: --component\?
|
||||
Usage: cmake --install <dir> \[options\]
|
||||
Reference in New Issue
Block a user