130fdc8d8SChris Lattner //===-- CommandObjectHelp.cpp -----------------------------------*- C++ -*-===// 230fdc8d8SChris Lattner // 3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 630fdc8d8SChris Lattner // 730fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 830fdc8d8SChris Lattner 926cac3afSEugene Zelenko #include "CommandObjectHelp.h" 1030fdc8d8SChris Lattner #include "lldb/Interpreter/CommandInterpreter.h" 11b9c1b51eSKate Stone #include "lldb/Interpreter/CommandObjectMultiword.h" 1230fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h" 13b9c1b51eSKate Stone #include "lldb/Interpreter/Options.h" 1430fdc8d8SChris Lattner 1530fdc8d8SChris Lattner using namespace lldb; 1630fdc8d8SChris Lattner using namespace lldb_private; 1730fdc8d8SChris Lattner 1830fdc8d8SChris Lattner //------------------------------------------------------------------------- 1930fdc8d8SChris Lattner // CommandObjectHelp 2030fdc8d8SChris Lattner //------------------------------------------------------------------------- 2130fdc8d8SChris Lattner 22b9c1b51eSKate Stone void CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage( 23a49c2019SZachary Turner Stream *s, llvm::StringRef command, llvm::StringRef prefix, llvm::StringRef subcommand, 24b9c1b51eSKate Stone bool include_apropos, bool include_type_lookup) { 25a49c2019SZachary Turner if (!s || command.empty()) 26a49c2019SZachary Turner return; 27a49c2019SZachary Turner 28a49c2019SZachary Turner std::string command_str = command.str(); 29a49c2019SZachary Turner std::string prefix_str = prefix.str(); 30a49c2019SZachary Turner std::string subcommand_str = subcommand.str(); 31a49c2019SZachary Turner const std::string &lookup_str = !subcommand_str.empty() ? subcommand_str : command_str; 32a49c2019SZachary Turner s->Printf("'%s' is not a known command.\n", command_str.c_str()); 33b9c1b51eSKate Stone s->Printf("Try '%shelp' to see a current list of commands.\n", 34a49c2019SZachary Turner prefix.str().c_str()); 35b9c1b51eSKate Stone if (include_apropos) { 3625d6072aSKate Stone s->Printf("Try '%sapropos %s' for a list of related commands.\n", 37a49c2019SZachary Turner prefix_str.c_str(), lookup_str.c_str()); 3846d4aa21SEnrico Granata } 39b9c1b51eSKate Stone if (include_type_lookup) { 40b9c1b51eSKate Stone s->Printf("Try '%stype lookup %s' for information on types, methods, " 41b9c1b51eSKate Stone "functions, modules, etc.", 42a49c2019SZachary Turner prefix_str.c_str(), lookup_str.c_str()); 4346d4aa21SEnrico Granata } 4446d4aa21SEnrico Granata } 4546d4aa21SEnrico Granata 467428a18cSKate Stone CommandObjectHelp::CommandObjectHelp(CommandInterpreter &interpreter) 47b9c1b51eSKate Stone : CommandObjectParsed(interpreter, "help", "Show a list of all debugger " 48b9c1b51eSKate Stone "commands, or give details " 49b9c1b51eSKate Stone "about a specific command.", 507428a18cSKate Stone "help [<cmd-name>]"), 51b9c1b51eSKate Stone m_options() { 52405fe67fSCaroline Tice CommandArgumentEntry arg; 53405fe67fSCaroline Tice CommandArgumentData command_arg; 54405fe67fSCaroline Tice 55405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 56405fe67fSCaroline Tice command_arg.arg_type = eArgTypeCommandName; 57405fe67fSCaroline Tice command_arg.arg_repetition = eArgRepeatStar; 58405fe67fSCaroline Tice 59b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the argument 60b9c1b51eSKate Stone // entry. 61405fe67fSCaroline Tice arg.push_back(command_arg); 62405fe67fSCaroline Tice 63405fe67fSCaroline Tice // Push the data for the first argument into the m_arguments vector. 64405fe67fSCaroline Tice m_arguments.push_back(arg); 6530fdc8d8SChris Lattner } 6630fdc8d8SChris Lattner 6726cac3afSEugene Zelenko CommandObjectHelp::~CommandObjectHelp() = default; 6830fdc8d8SChris Lattner 698fe53c49STatyana Krasnukha static constexpr OptionDefinition g_help_options[] = { 70ac9c3a62SKate Stone // clang-format off 718fe53c49STatyana Krasnukha {LLDB_OPT_SET_ALL, false, "hide-aliases", 'a', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Hide aliases in the command list."}, 728fe53c49STatyana Krasnukha {LLDB_OPT_SET_ALL, false, "hide-user-commands", 'u', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Hide user-defined commands from the list."}, 738fe53c49STatyana Krasnukha {LLDB_OPT_SET_ALL, false, "show-hidden-commands", 'h', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Include commands prefixed with an underscore."}, 74ac9c3a62SKate Stone // clang-format on 7508633eeaSEnrico Granata }; 7608633eeaSEnrico Granata 771f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> 781f0f5b5bSZachary Turner CommandObjectHelp::CommandOptions::GetDefinitions() { 7970602439SZachary Turner return llvm::makeArrayRef(g_help_options); 801f0f5b5bSZachary Turner } 811f0f5b5bSZachary Turner 82b9c1b51eSKate Stone bool CommandObjectHelp::DoExecute(Args &command, CommandReturnObject &result) { 8330fdc8d8SChris Lattner CommandObject::CommandMap::iterator pos; 8430fdc8d8SChris Lattner CommandObject *cmd_obj; 85c7bece56SGreg Clayton const size_t argc = command.GetArgumentCount(); 8630fdc8d8SChris Lattner 8705097246SAdrian Prantl // 'help' doesn't take any arguments, other than command names. If argc is 8805097246SAdrian Prantl // 0, we show the user all commands (aliases and user commands if asked for). 8905097246SAdrian Prantl // Otherwise every argument must be the name of a command or a sub-command. 90b9c1b51eSKate Stone if (argc == 0) { 9108633eeaSEnrico Granata uint32_t cmd_types = CommandInterpreter::eCommandTypesBuiltin; 9208633eeaSEnrico Granata if (m_options.m_show_aliases) 9308633eeaSEnrico Granata cmd_types |= CommandInterpreter::eCommandTypesAliases; 9408633eeaSEnrico Granata if (m_options.m_show_user_defined) 9508633eeaSEnrico Granata cmd_types |= CommandInterpreter::eCommandTypesUserDef; 96a487aa4cSKate Stone if (m_options.m_show_hidden) 97a487aa4cSKate Stone cmd_types |= CommandInterpreter::eCommandTypesHidden; 9808633eeaSEnrico Granata 9930fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishNoResult); 10008633eeaSEnrico Granata m_interpreter.GetHelp(result, cmd_types); // General help 101b9c1b51eSKate Stone } else { 102b9c1b51eSKate Stone // Get command object for the first command argument. Only search built-in 103b9c1b51eSKate Stone // command dictionary. 104279a6c26SJim Ingham StringList matches; 10514f6b2c0SZachary Turner auto command_name = command[0].ref; 10614f6b2c0SZachary Turner cmd_obj = m_interpreter.GetCommandObject(command_name, &matches); 10730fdc8d8SChris Lattner 108b9c1b51eSKate Stone if (cmd_obj != nullptr) { 109271ad29aSJim Ingham StringList matches; 11030fdc8d8SChris Lattner bool all_okay = true; 11130fdc8d8SChris Lattner CommandObject *sub_cmd_obj = cmd_obj; 112b9c1b51eSKate Stone // Loop down through sub_command dictionaries until we find the command 11397d2c401SZachary Turner // object that corresponds to the help command entered. 11446d4aa21SEnrico Granata std::string sub_command; 11597d2c401SZachary Turner for (auto &entry : command.entries().drop_front()) { 11697d2c401SZachary Turner sub_command = entry.ref; 117271ad29aSJim Ingham matches.Clear(); 118bef55ac8SEnrico Granata if (sub_cmd_obj->IsAlias()) 119b9c1b51eSKate Stone sub_cmd_obj = 120b9c1b51eSKate Stone ((CommandAlias *)sub_cmd_obj)->GetUnderlyingCommand().get(); 121b9c1b51eSKate Stone if (!sub_cmd_obj->IsMultiwordObject()) { 12230fdc8d8SChris Lattner all_okay = false; 12397d2c401SZachary Turner break; 124b9c1b51eSKate Stone } else { 125271ad29aSJim Ingham CommandObject *found_cmd; 126b9c1b51eSKate Stone found_cmd = 127b9c1b51eSKate Stone sub_cmd_obj->GetSubcommandObject(sub_command.c_str(), &matches); 12897d2c401SZachary Turner if (found_cmd == nullptr || matches.GetSize() > 1) { 12930fdc8d8SChris Lattner all_okay = false; 13097d2c401SZachary Turner break; 13197d2c401SZachary Turner } else 132271ad29aSJim Ingham sub_cmd_obj = found_cmd; 13330fdc8d8SChris Lattner } 13430fdc8d8SChris Lattner } 13530fdc8d8SChris Lattner 136b9c1b51eSKate Stone if (!all_okay || (sub_cmd_obj == nullptr)) { 13730fdc8d8SChris Lattner std::string cmd_string; 13830fdc8d8SChris Lattner command.GetCommandString(cmd_string); 139b9c1b51eSKate Stone if (matches.GetSize() >= 2) { 140271ad29aSJim Ingham StreamString s; 141271ad29aSJim Ingham s.Printf("ambiguous command %s", cmd_string.c_str()); 142271ad29aSJim Ingham size_t num_matches = matches.GetSize(); 143b9c1b51eSKate Stone for (size_t match_idx = 0; match_idx < num_matches; match_idx++) { 144271ad29aSJim Ingham s.Printf("\n\t%s", matches.GetStringAtIndex(match_idx)); 145271ad29aSJim Ingham } 146271ad29aSJim Ingham s.Printf("\n"); 147c156427dSZachary Turner result.AppendError(s.GetString()); 14830fdc8d8SChris Lattner result.SetStatus(eReturnStatusFailed); 1499b62d1d5SEnrico Granata return false; 150b9c1b51eSKate Stone } else if (!sub_cmd_obj) { 15146d4aa21SEnrico Granata StreamString error_msg_stream; 152b9c1b51eSKate Stone GenerateAdditionalHelpAvenuesMessage( 153b9c1b51eSKate Stone &error_msg_stream, cmd_string.c_str(), 154b9c1b51eSKate Stone m_interpreter.GetCommandPrefix(), sub_command.c_str()); 155c156427dSZachary Turner result.AppendError(error_msg_stream.GetString()); 1569b62d1d5SEnrico Granata result.SetStatus(eReturnStatusFailed); 1579b62d1d5SEnrico Granata return false; 158b9c1b51eSKate Stone } else { 159b9c1b51eSKate Stone GenerateAdditionalHelpAvenuesMessage( 160b9c1b51eSKate Stone &result.GetOutputStream(), cmd_string.c_str(), 161b9c1b51eSKate Stone m_interpreter.GetCommandPrefix(), sub_command.c_str()); 162b9c1b51eSKate Stone result.GetOutputStream().Printf( 163b9c1b51eSKate Stone "\nThe closest match is '%s'. Help on it follows.\n\n", 164a449698cSZachary Turner sub_cmd_obj->GetCommandName().str().c_str()); 165e139cf23SCaroline Tice } 166c007e846SJim Ingham } 167c007e846SJim Ingham 168998255bfSGreg Clayton sub_cmd_obj->GenerateHelpText(result); 16979d8105fSJim Ingham std::string alias_full_name; 17079d8105fSJim Ingham // Don't use AliasExists here, that only checks exact name matches. If 17179d8105fSJim Ingham // the user typed a shorter unique alias name, we should still tell them 17279d8105fSJim Ingham // it was an alias. 17379d8105fSJim Ingham if (m_interpreter.GetAliasFullName(command_name, alias_full_name)) { 174e7941795SCaroline Tice StreamString sstr; 17579d8105fSJim Ingham m_interpreter.GetAlias(alias_full_name)->GetAliasExpansion(sstr); 176b9c1b51eSKate Stone result.GetOutputStream().Printf("\n'%s' is an abbreviation for %s\n", 17714f6b2c0SZachary Turner command[0].c_str(), sstr.GetData()); 178e7941795SCaroline Tice } 179b9c1b51eSKate Stone } else if (matches.GetSize() > 0) { 180279a6c26SJim Ingham Stream &output_strm = result.GetOutputStream(); 181b9c1b51eSKate Stone output_strm.Printf("Help requested with ambiguous command name, possible " 182b9c1b51eSKate Stone "completions:\n"); 183c7bece56SGreg Clayton const size_t match_count = matches.GetSize(); 184b9c1b51eSKate Stone for (size_t i = 0; i < match_count; i++) { 185279a6c26SJim Ingham output_strm.Printf("\t%s\n", matches.GetStringAtIndex(i)); 186279a6c26SJim Ingham } 187b9c1b51eSKate Stone } else { 188b9c1b51eSKate Stone // Maybe the user is asking for help about a command argument rather than 189b9c1b51eSKate Stone // a command. 190b9c1b51eSKate Stone const CommandArgumentType arg_type = 19114f6b2c0SZachary Turner CommandObject::LookupArgumentName(command_name); 192b9c1b51eSKate Stone if (arg_type != eArgTypeLastArg) { 193e139cf23SCaroline Tice Stream &output_strm = result.GetOutputStream(); 194e139cf23SCaroline Tice CommandObject::GetArgumentHelp(output_strm, arg_type, m_interpreter); 195e139cf23SCaroline Tice result.SetStatus(eReturnStatusSuccessFinishNoResult); 196b9c1b51eSKate Stone } else { 19746d4aa21SEnrico Granata StreamString error_msg_stream; 19814f6b2c0SZachary Turner GenerateAdditionalHelpAvenuesMessage(&error_msg_stream, command_name, 19914f6b2c0SZachary Turner m_interpreter.GetCommandPrefix(), 20014f6b2c0SZachary Turner ""); 201c156427dSZachary Turner result.AppendError(error_msg_stream.GetString()); 20230fdc8d8SChris Lattner result.SetStatus(eReturnStatusFailed); 20330fdc8d8SChris Lattner } 20430fdc8d8SChris Lattner } 205e139cf23SCaroline Tice } 20630fdc8d8SChris Lattner 20730fdc8d8SChris Lattner return result.Succeeded(); 20830fdc8d8SChris Lattner } 20930fdc8d8SChris Lattner 2102443bbd4SRaphael Isemann int CommandObjectHelp::HandleCompletion(CompletionRequest &request) { 21130fdc8d8SChris Lattner // Return the completions of the commands in the help system: 2122443bbd4SRaphael Isemann if (request.GetCursorIndex() == 0) { 2132443bbd4SRaphael Isemann return m_interpreter.HandleCompletionMatches(request); 214b9c1b51eSKate Stone } else { 2152443bbd4SRaphael Isemann CommandObject *cmd_obj = 2162443bbd4SRaphael Isemann m_interpreter.GetCommandObject(request.GetParsedLine()[0].ref); 2171d18ebf6SJim Ingham 218b9c1b51eSKate Stone // The command that they are getting help on might be ambiguous, in which 21905097246SAdrian Prantl // case we should complete that, otherwise complete with the command the 22005097246SAdrian Prantl // user is getting help on... 2211d18ebf6SJim Ingham 222b9c1b51eSKate Stone if (cmd_obj) { 2232443bbd4SRaphael Isemann request.GetParsedLine().Shift(); 2242443bbd4SRaphael Isemann request.SetCursorIndex(request.GetCursorIndex() - 1); 2252443bbd4SRaphael Isemann return cmd_obj->HandleCompletion(request); 226b9c1b51eSKate Stone } else { 2272443bbd4SRaphael Isemann return m_interpreter.HandleCompletionMatches(request); 2281d18ebf6SJim Ingham } 2291d18ebf6SJim Ingham } 23030fdc8d8SChris Lattner } 231