211 lines · cpp
1//===-- CommandObjectHelp.cpp ---------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "CommandObjectHelp.h"10#include "lldb/Interpreter/CommandInterpreter.h"11#include "lldb/Interpreter/CommandOptionArgumentTable.h"12#include "lldb/Interpreter/CommandReturnObject.h"13 14using namespace lldb;15using namespace lldb_private;16 17// CommandObjectHelp18 19void CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(20 Stream *s, llvm::StringRef command, llvm::StringRef prefix,21 llvm::StringRef subcommand, bool include_upropos,22 bool include_type_lookup) {23 if (!s || command.empty())24 return;25 26 std::string command_str = command.str();27 std::string prefix_str = prefix.str();28 std::string subcommand_str = subcommand.str();29 const std::string &lookup_str =30 !subcommand_str.empty() ? subcommand_str : command_str;31 s->Printf("'%s' is not a known command.\n", command_str.c_str());32 s->Printf("Try '%shelp' to see a current list of commands.\n",33 prefix.str().c_str());34 if (include_upropos) {35 s->Printf("Try '%sapropos %s' for a list of related commands.\n",36 prefix_str.c_str(), lookup_str.c_str());37 }38 if (include_type_lookup) {39 s->Printf("Try '%stype lookup %s' for information on types, methods, "40 "functions, modules, etc.",41 prefix_str.c_str(), lookup_str.c_str());42 }43}44 45CommandObjectHelp::CommandObjectHelp(CommandInterpreter &interpreter)46 : CommandObjectParsed(interpreter, "help",47 "Show a list of all debugger "48 "commands, or give details "49 "about a specific command.",50 "help [<cmd-name>]") {51 // A list of command names forming a path to the command we want help on.52 // No names is allowed - in which case we dump the top-level help.53 AddSimpleArgumentList(eArgTypeCommand, eArgRepeatStar);54}55 56CommandObjectHelp::~CommandObjectHelp() = default;57 58#define LLDB_OPTIONS_help59#include "CommandOptions.inc"60 61llvm::ArrayRef<OptionDefinition>62CommandObjectHelp::CommandOptions::GetDefinitions() {63 return llvm::ArrayRef(g_help_options);64}65 66void CommandObjectHelp::DoExecute(Args &command, CommandReturnObject &result) {67 CommandObject::CommandMap::iterator pos;68 CommandObject *cmd_obj;69 const size_t argc = command.GetArgumentCount();70 71 // 'help' doesn't take any arguments, other than command names. If argc is72 // 0, we show the user all commands (aliases and user commands if asked for).73 // Otherwise every argument must be the name of a command or a sub-command.74 if (argc == 0) {75 uint32_t cmd_types = CommandInterpreter::eCommandTypesBuiltin;76 if (m_options.m_show_aliases)77 cmd_types |= CommandInterpreter::eCommandTypesAliases;78 if (m_options.m_show_user_defined) {79 cmd_types |= CommandInterpreter::eCommandTypesUserDef;80 cmd_types |= CommandInterpreter::eCommandTypesUserMW;81 }82 if (m_options.m_show_hidden)83 cmd_types |= CommandInterpreter::eCommandTypesHidden;84 85 result.SetStatus(eReturnStatusSuccessFinishNoResult);86 m_interpreter.GetHelp(result, cmd_types); // General help87 } else {88 // Get command object for the first command argument. Only search built-in89 // command dictionary.90 StringList matches;91 auto command_name = command[0].ref();92 cmd_obj = m_interpreter.GetCommandObject(command_name, &matches);93 94 if (cmd_obj != nullptr) {95 StringList matches;96 bool all_okay = true;97 CommandObject *sub_cmd_obj = cmd_obj;98 // Loop down through sub_command dictionaries until we find the command99 // object that corresponds to the help command entered.100 std::string sub_command;101 for (auto &entry : command.entries().drop_front()) {102 sub_command = std::string(entry.ref());103 matches.Clear();104 if (sub_cmd_obj->IsAlias())105 sub_cmd_obj =106 ((CommandAlias *)sub_cmd_obj)->GetUnderlyingCommand().get();107 if (!sub_cmd_obj->IsMultiwordObject()) {108 all_okay = false;109 break;110 } else {111 CommandObject *found_cmd;112 found_cmd =113 sub_cmd_obj->GetSubcommandObject(sub_command.c_str(), &matches);114 if (found_cmd == nullptr || matches.GetSize() > 1) {115 all_okay = false;116 break;117 } else118 sub_cmd_obj = found_cmd;119 }120 }121 122 if (!all_okay || (sub_cmd_obj == nullptr)) {123 std::string cmd_string;124 command.GetCommandString(cmd_string);125 if (matches.GetSize() >= 2) {126 StreamString s;127 s.Printf("ambiguous command %s", cmd_string.c_str());128 size_t num_matches = matches.GetSize();129 for (size_t match_idx = 0; match_idx < num_matches; match_idx++) {130 s.Printf("\n\t%s", matches.GetStringAtIndex(match_idx));131 }132 s.Printf("\n");133 result.AppendError(s.GetString());134 return;135 } else if (!sub_cmd_obj) {136 StreamString error_msg_stream;137 GenerateAdditionalHelpAvenuesMessage(138 &error_msg_stream, cmd_string.c_str(),139 m_interpreter.GetCommandPrefix(), sub_command.c_str());140 result.AppendError(error_msg_stream.GetString());141 return;142 } else {143 GenerateAdditionalHelpAvenuesMessage(144 &result.GetOutputStream(), cmd_string.c_str(),145 m_interpreter.GetCommandPrefix(), sub_command.c_str());146 result.GetOutputStream().Printf(147 "\nThe closest match is '%s'. Help on it follows.\n\n",148 sub_cmd_obj->GetCommandName().str().c_str());149 }150 }151 152 sub_cmd_obj->GenerateHelpText(result);153 std::string alias_full_name;154 // Don't use AliasExists here, that only checks exact name matches. If155 // the user typed a shorter unique alias name, we should still tell them156 // it was an alias.157 if (m_interpreter.GetAliasFullName(command_name, alias_full_name)) {158 StreamString sstr;159 m_interpreter.GetAlias(alias_full_name)->GetAliasExpansion(sstr);160 result.GetOutputStream().Printf("\n'%s' is an abbreviation for %s\n",161 command[0].c_str(), sstr.GetData());162 }163 } else if (matches.GetSize() > 0) {164 Stream &output_strm = result.GetOutputStream();165 output_strm.Printf("Help requested with ambiguous command name, possible "166 "completions:\n");167 const size_t match_count = matches.GetSize();168 for (size_t i = 0; i < match_count; i++) {169 output_strm.Printf("\t%s\n", matches.GetStringAtIndex(i));170 }171 } else {172 // Maybe the user is asking for help about a command argument rather than173 // a command.174 const CommandArgumentType arg_type =175 CommandObject::LookupArgumentName(command_name);176 if (arg_type != eArgTypeLastArg) {177 Stream &output_strm = result.GetOutputStream();178 CommandObject::GetArgumentHelp(output_strm, arg_type, m_interpreter);179 result.SetStatus(eReturnStatusSuccessFinishNoResult);180 } else {181 StreamString error_msg_stream;182 GenerateAdditionalHelpAvenuesMessage(&error_msg_stream, command_name,183 m_interpreter.GetCommandPrefix(),184 "");185 result.AppendError(error_msg_stream.GetString());186 }187 }188 }189}190 191void CommandObjectHelp::HandleCompletion(CompletionRequest &request) {192 // Return the completions of the commands in the help system:193 if (request.GetCursorIndex() == 0) {194 m_interpreter.HandleCompletionMatches(request);195 return;196 }197 CommandObject *cmd_obj =198 m_interpreter.GetCommandObject(request.GetParsedLine()[0].ref());199 200 // The command that they are getting help on might be ambiguous, in which201 // case we should complete that, otherwise complete with the command the202 // user is getting help on...203 204 if (cmd_obj) {205 request.ShiftArguments();206 cmd_obj->HandleCompletion(request);207 return;208 }209 m_interpreter.HandleCompletionMatches(request);210}211