From 53cdd9c4fce31e0bdebabefd095da4ff23f4c542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= Date: Wed, 13 Nov 2024 11:13:52 +0100 Subject: [PATCH] Hint when an unknown option is available on different commands Closes: https://github.com/rpm-software-management/dnf5/issues/1830 --- dnf5/main.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/dnf5/main.cpp b/dnf5/main.cpp index eaae11e69..dcf0bb526 100644 --- a/dnf5/main.cpp +++ b/dnf5/main.cpp @@ -1261,13 +1261,59 @@ int main(int argc, char * argv[]) try { context.print_error(libdnf5::utils::sformat( _("{}. Add \"--help\" for more information about the arguments."), ex.what())); } - // If the error is an unknown top-level command, suggest - // installing a package that provides the command + if (auto * unknown_arg_ex = dynamic_cast(&ex)) { if (unknown_arg_ex->get_command() == "dnf5" && unknown_arg_ex->get_argument()[0] != '-') { + // If the error is an unknown top-level command, suggest + // installing a package that provides the command + context.print_error(libdnf5::utils::sformat( _("It could be a command provided by a plugin, try: dnf5 install 'dnf5-command({})'"), unknown_arg_ex->get_argument())); + + } else if (unknown_arg_ex->get_argument()[0] == '-') { + // If the error is an unknown option check if it is used by some other command and provide a hint + + std::unordered_set commands_with_option; + // Remove any values passed with the option + std::string tmp = + unknown_arg_ex->get_argument().substr(0, unknown_arg_ex->get_argument().find("=")); + // Both short and long options start with a '-', remove it + tmp.erase(0, 1); + std::function + comparator; + if (tmp[0] == '-') { + // Long option, erase the second '-' + tmp.erase(0, 1); + comparator = [](libdnf5::cli::ArgumentParser::NamedArg * arg, + const std::string & tmp) -> bool { return (arg->get_long_name() == tmp); }; + } else { + // Short option + comparator = [](libdnf5::cli::ArgumentParser::NamedArg * arg, + const std::string & tmp) -> bool { + return (arg->get_short_name() == tmp[0]); + }; + } + + for (const auto & cmd : arg_parser.get_commands()) { + for (const auto & arg : cmd->get_named_args()) { + if (comparator(arg, tmp)) { + if (!dynamic_cast(cmd.get())) { + auto invoc = cmd->get_invocation(); + // Erase first element which is the root command (dnf) + invoc.erase(invoc.begin()); + commands_with_option.insert(libdnf5::utils::string::join(invoc, " ")); + } + } + } + } + + if (!commands_with_option.empty()) { + context.print_error(libdnf5::utils::sformat( + _("The argument is available for commands: {}. (It has to be placed after the " + "command.)"), + libdnf5::utils::string::join(commands_with_option, _(", ")))); + } } } return static_cast(libdnf5::cli::ExitCode::ARGPARSER_ERROR);