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]));
|
!(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;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string findClosestOption(std::string const& arg,
|
||||||
|
std::vector<CommandArgument> const& arguments)
|
||||||
|
{
|
||||||
|
return cmFindClosestCommandLineArgument(arg, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
bool cmakeCheckStampFile(std::string const& stampName)
|
bool cmakeCheckStampFile(std::string const& stampName)
|
||||||
{
|
{
|
||||||
// The stamp file does not exist. Use the stamp dependencies to
|
// 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() &&
|
if (!possibleUnknownArg.empty() &&
|
||||||
this->State->GetRole() != cmState::Role::Script) {
|
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.");
|
cmSystemTools::Error("Run 'cmake --help' for all supported options.");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-3
@@ -635,7 +635,13 @@ int do_build(int ac, char const* const* av)
|
|||||||
if (!(matched && parsed)) {
|
if (!(matched && parsed)) {
|
||||||
buildArgs.binaryDir.clear();
|
buildArgs.binaryDir.clear();
|
||||||
if (!matched) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
@@ -933,7 +939,13 @@ int do_install(int ac, char const* const* av)
|
|||||||
if (!(matched && parsed)) {
|
if (!(matched && parsed)) {
|
||||||
dir.clear();
|
dir.clear();
|
||||||
if (!matched) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1136,7 +1148,13 @@ int do_workflow(int ac, char const* const* av)
|
|||||||
if (!(matched && parsed)) {
|
if (!(matched && parsed)) {
|
||||||
if (!matched) {
|
if (!matched) {
|
||||||
presetsArgs.Clear();
|
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;
|
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_command(PresetsFileNoArg-workflow ${CMAKE_COMMAND} "--workflow" "--presets-file")
|
||||||
run_cmake_workflow_presets(InvalidOption -DINVALID_OPTION)
|
run_cmake_workflow_presets(InvalidOption -DINVALID_OPTION)
|
||||||
run_cmake_workflow_presets(ListPresetsInvalidValue --list-presets=invalid)
|
run_cmake_workflow_presets(ListPresetsInvalidValue --list-presets=invalid)
|
||||||
|
run_cmake_command(UnknownOptionDidYouMean ${CMAKE_COMMAND} "--workflow" "--fresh" "--presett")
|
||||||
|
|
||||||
set(RunCMake_TEST_NO_CLEAN TRUE)
|
set(RunCMake_TEST_NO_CLEAN TRUE)
|
||||||
file(REMOVE_RECURSE "${RunCMake_BINARY_DIR}/Fresh")
|
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(NoArgs ${CMAKE_COMMAND})
|
||||||
run_cmake_command(InvalidArg1 ${CMAKE_COMMAND} -invalid)
|
run_cmake_command(InvalidArg1 ${CMAKE_COMMAND} -invalid)
|
||||||
run_cmake_command(InvalidArg2 ${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(Wizard ${CMAKE_COMMAND} -i)
|
||||||
run_cmake_command(C-no-arg ${CMAKE_COMMAND} -B DummyBuildDir -C)
|
run_cmake_command(C-no-arg ${CMAKE_COMMAND} -B DummyBuildDir -C)
|
||||||
run_cmake_command(C-no-arg2 ${CMAKE_COMMAND} -B DummyBuildDir -C -T)
|
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)
|
${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR} --invalid-command)
|
||||||
run_cmake_command(build-unknown-command-partial-match
|
run_cmake_command(build-unknown-command-partial-match
|
||||||
${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR} --targetinvalid)
|
${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
|
run_cmake_command(build-invalid-target-syntax
|
||||||
${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR} --target=invalid)
|
${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR} --target=invalid)
|
||||||
run_cmake_command(build-no-generator
|
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)
|
${CMAKE_COMMAND} --install ${RunCMake_SOURCE_DIR} -invalid-command)
|
||||||
run_cmake_command(install-unknown-command-long
|
run_cmake_command(install-unknown-command-long
|
||||||
${CMAKE_COMMAND} --install ${RunCMake_SOURCE_DIR} --invalid-command)
|
${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
|
run_cmake_command(install-options-to-vars
|
||||||
${CMAKE_COMMAND} --install ${RunCMake_SOURCE_DIR}/dir-install-options-to-vars
|
${CMAKE_COMMAND} --install ${RunCMake_SOURCE_DIR}/dir-install-options-to-vars
|
||||||
--strip --prefix /var/test --config sample --component pack)
|
--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