cmake -E: Add CLI argument spell checking Use Levenshtein distance to track when the user may have made a typo in an argument to `cmake -E` (i.e., an invalid mode; mode sub-arguments are not tracked).
diff --git a/.codespellrc b/.codespellrc index 85614e5..94fa8e8 100644 --- a/.codespellrc +++ b/.codespellrc
@@ -16,6 +16,7 @@ Source/CursesDialog/form/*, Source/kwsys/*, Tests/RunCMake/CPack/tests/DMG_SLA/German.*, + Tests/RunCMake/CommandLine/RunCMakeTest.cmake, Tests/RunCMake/ParseImplicitData/*.input, Tests/RunCMake/cmake_language/call_typo_function.cmake, Tests/StringFileTest/test.utf8,
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 2ef3526..77b5771 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx
@@ -2518,6 +2518,26 @@ } return 1; } + + std::vector<std::string> availableCommands = + CommandLineHelpEntryNames(AvailableCommands); +#if defined(_WIN32) && !defined(__CYGWIN__) + cm::append(availableCommands, + CommandLineHelpEntryNames(AvailableWindowsCommands)); +#endif + // Some commands above only fall through to here when they were + // matched by name but had the wrong number/form of arguments; only + // offer a suggestion when the name itself is not recognized. + if (std::find(availableCommands.begin(), availableCommands.end(), + args[1]) == availableCommands.end()) { + std::string error = cmStrCat("Unknown command \"", args[1], "\"."); + std::string const suggestion = + cmFindClosestString(args[1], availableCommands); + if (!suggestion.empty()) { + error = cmStrCat(error, " Did you mean \"", suggestion, "\"?"); + } + cmSystemTools::Error(error); + } } CMakeCommandUsage(args[0]);
diff --git a/Tests/RunCMake/CommandLine/E_unknown-command-did-you-mean-result.txt b/Tests/RunCMake/CommandLine/E_unknown-command-did-you-mean-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_unknown-command-did-you-mean-result.txt
@@ -0,0 +1 @@ +1
diff --git a/Tests/RunCMake/CommandLine/E_unknown-command-did-you-mean-stderr.txt b/Tests/RunCMake/CommandLine/E_unknown-command-did-you-mean-stderr.txt new file mode 100644 index 0000000..221fd85 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_unknown-command-did-you-mean-stderr.txt
@@ -0,0 +1,4 @@ +^CMake Error: Unknown command "enviroment"\. Did you mean "environment"\? +CMake Error: cmake version .* +Usage: .* -E <command> \[arguments\.\.\.\] +Available commands:
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index efacda3..ad4678c 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -61,6 +61,7 @@ run_cmake_command(U-no-src ${CMAKE_COMMAND} -B DummyBuildDir -U VAR) run_cmake_command(Uno-src ${CMAKE_COMMAND} -B DummyBuildDir -UVAR) run_cmake_command(E-no-arg ${CMAKE_COMMAND} -E) +run_cmake_command(E_unknown-command-did-you-mean ${CMAKE_COMMAND} -E enviroment) run_cmake_command(E_capabilities ${CMAKE_COMMAND} -E capabilities) run_cmake_command(E_capabilities-arg ${CMAKE_COMMAND} -E capabilities --extra-arg) run_cmake_command(E_compare_files-different-eol ${CMAKE_COMMAND} -E compare_files ${RunCMake_SOURCE_DIR}/compare_files/lf ${RunCMake_SOURCE_DIR}/compare_files/crlf)