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