aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Commands/CommandObjectHelp.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-12-20 19:53:05 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-12-20 19:53:05 +0000
commit0b57cec536236d46e3dba9bd041533462f33dbb7 (patch)
tree56229dbdbbf76d18580f72f789003db17246c8d9 /contrib/llvm-project/lldb/source/Commands/CommandObjectHelp.cpp
parent718ef55ec7785aae63f98f8ca05dc07ed399c16d (diff)
Notes
Diffstat (limited to 'contrib/llvm-project/lldb/source/Commands/CommandObjectHelp.cpp')
-rw-r--r--contrib/llvm-project/lldb/source/Commands/CommandObjectHelp.cpp226
1 files changed, 226 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectHelp.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectHelp.cpp
new file mode 100644
index 000000000000..ab557919d0a0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectHelp.cpp
@@ -0,0 +1,226 @@
+//===-- CommandObjectHelp.cpp -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectHelp.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Options.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// CommandObjectHelp
+
+void CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
+ Stream *s, llvm::StringRef command, llvm::StringRef prefix,
+ llvm::StringRef subcommand, bool include_upropos,
+ bool include_type_lookup) {
+ if (!s || command.empty())
+ return;
+
+ std::string command_str = command.str();
+ std::string prefix_str = prefix.str();
+ std::string subcommand_str = subcommand.str();
+ const std::string &lookup_str = !subcommand_str.empty() ? subcommand_str : command_str;
+ s->Printf("'%s' is not a known command.\n", command_str.c_str());
+ s->Printf("Try '%shelp' to see a current list of commands.\n",
+ prefix.str().c_str());
+ if (include_upropos) {
+ s->Printf("Try '%sapropos %s' for a list of related commands.\n",
+ prefix_str.c_str(), lookup_str.c_str());
+ }
+ if (include_type_lookup) {
+ s->Printf("Try '%stype lookup %s' for information on types, methods, "
+ "functions, modules, etc.",
+ prefix_str.c_str(), lookup_str.c_str());
+ }
+}
+
+CommandObjectHelp::CommandObjectHelp(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "help", "Show a list of all debugger "
+ "commands, or give details "
+ "about a specific command.",
+ "help [<cmd-name>]"),
+ m_options() {
+ CommandArgumentEntry arg;
+ CommandArgumentData command_arg;
+
+ // Define the first (and only) variant of this arg.
+ command_arg.arg_type = eArgTypeCommandName;
+ command_arg.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument
+ // entry.
+ arg.push_back(command_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back(arg);
+}
+
+CommandObjectHelp::~CommandObjectHelp() = default;
+
+static constexpr OptionDefinition g_help_options[] = {
+#define LLDB_OPTIONS_help
+#include "CommandOptions.inc"
+};
+
+llvm::ArrayRef<OptionDefinition>
+CommandObjectHelp::CommandOptions::GetDefinitions() {
+ return llvm::makeArrayRef(g_help_options);
+}
+
+bool CommandObjectHelp::DoExecute(Args &command, CommandReturnObject &result) {
+ CommandObject::CommandMap::iterator pos;
+ CommandObject *cmd_obj;
+ const size_t argc = command.GetArgumentCount();
+
+ // 'help' doesn't take any arguments, other than command names. If argc is
+ // 0, we show the user all commands (aliases and user commands if asked for).
+ // Otherwise every argument must be the name of a command or a sub-command.
+ if (argc == 0) {
+ uint32_t cmd_types = CommandInterpreter::eCommandTypesBuiltin;
+ if (m_options.m_show_aliases)
+ cmd_types |= CommandInterpreter::eCommandTypesAliases;
+ if (m_options.m_show_user_defined)
+ cmd_types |= CommandInterpreter::eCommandTypesUserDef;
+ if (m_options.m_show_hidden)
+ cmd_types |= CommandInterpreter::eCommandTypesHidden;
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ m_interpreter.GetHelp(result, cmd_types); // General help
+ } else {
+ // Get command object for the first command argument. Only search built-in
+ // command dictionary.
+ StringList matches;
+ auto command_name = command[0].ref;
+ cmd_obj = m_interpreter.GetCommandObject(command_name, &matches);
+
+ if (cmd_obj != nullptr) {
+ StringList matches;
+ bool all_okay = true;
+ CommandObject *sub_cmd_obj = cmd_obj;
+ // Loop down through sub_command dictionaries until we find the command
+ // object that corresponds to the help command entered.
+ std::string sub_command;
+ for (auto &entry : command.entries().drop_front()) {
+ sub_command = entry.ref;
+ matches.Clear();
+ if (sub_cmd_obj->IsAlias())
+ sub_cmd_obj =
+ ((CommandAlias *)sub_cmd_obj)->GetUnderlyingCommand().get();
+ if (!sub_cmd_obj->IsMultiwordObject()) {
+ all_okay = false;
+ break;
+ } else {
+ CommandObject *found_cmd;
+ found_cmd =
+ sub_cmd_obj->GetSubcommandObject(sub_command.c_str(), &matches);
+ if (found_cmd == nullptr || matches.GetSize() > 1) {
+ all_okay = false;
+ break;
+ } else
+ sub_cmd_obj = found_cmd;
+ }
+ }
+
+ if (!all_okay || (sub_cmd_obj == nullptr)) {
+ std::string cmd_string;
+ command.GetCommandString(cmd_string);
+ if (matches.GetSize() >= 2) {
+ StreamString s;
+ s.Printf("ambiguous command %s", cmd_string.c_str());
+ size_t num_matches = matches.GetSize();
+ for (size_t match_idx = 0; match_idx < num_matches; match_idx++) {
+ s.Printf("\n\t%s", matches.GetStringAtIndex(match_idx));
+ }
+ s.Printf("\n");
+ result.AppendError(s.GetString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ } else if (!sub_cmd_obj) {
+ StreamString error_msg_stream;
+ GenerateAdditionalHelpAvenuesMessage(
+ &error_msg_stream, cmd_string.c_str(),
+ m_interpreter.GetCommandPrefix(), sub_command.c_str());
+ result.AppendError(error_msg_stream.GetString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ } else {
+ GenerateAdditionalHelpAvenuesMessage(
+ &result.GetOutputStream(), cmd_string.c_str(),
+ m_interpreter.GetCommandPrefix(), sub_command.c_str());
+ result.GetOutputStream().Printf(
+ "\nThe closest match is '%s'. Help on it follows.\n\n",
+ sub_cmd_obj->GetCommandName().str().c_str());
+ }
+ }
+
+ sub_cmd_obj->GenerateHelpText(result);
+ std::string alias_full_name;
+ // Don't use AliasExists here, that only checks exact name matches. If
+ // the user typed a shorter unique alias name, we should still tell them
+ // it was an alias.
+ if (m_interpreter.GetAliasFullName(command_name, alias_full_name)) {
+ StreamString sstr;
+ m_interpreter.GetAlias(alias_full_name)->GetAliasExpansion(sstr);
+ result.GetOutputStream().Printf("\n'%s' is an abbreviation for %s\n",
+ command[0].c_str(), sstr.GetData());
+ }
+ } else if (matches.GetSize() > 0) {
+ Stream &output_strm = result.GetOutputStream();
+ output_strm.Printf("Help requested with ambiguous command name, possible "
+ "completions:\n");
+ const size_t match_count = matches.GetSize();
+ for (size_t i = 0; i < match_count; i++) {
+ output_strm.Printf("\t%s\n", matches.GetStringAtIndex(i));
+ }
+ } else {
+ // Maybe the user is asking for help about a command argument rather than
+ // a command.
+ const CommandArgumentType arg_type =
+ CommandObject::LookupArgumentName(command_name);
+ if (arg_type != eArgTypeLastArg) {
+ Stream &output_strm = result.GetOutputStream();
+ CommandObject::GetArgumentHelp(output_strm, arg_type, m_interpreter);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ } else {
+ StreamString error_msg_stream;
+ GenerateAdditionalHelpAvenuesMessage(&error_msg_stream, command_name,
+ m_interpreter.GetCommandPrefix(),
+ "");
+ result.AppendError(error_msg_stream.GetString());
+ result.SetStatus(eReturnStatusFailed);
+ }
+ }
+ }
+
+ return result.Succeeded();
+}
+
+int CommandObjectHelp::HandleCompletion(CompletionRequest &request) {
+ // Return the completions of the commands in the help system:
+ if (request.GetCursorIndex() == 0) {
+ return m_interpreter.HandleCompletionMatches(request);
+ } else {
+ CommandObject *cmd_obj =
+ m_interpreter.GetCommandObject(request.GetParsedLine()[0].ref);
+
+ // The command that they are getting help on might be ambiguous, in which
+ // case we should complete that, otherwise complete with the command the
+ // user is getting help on...
+
+ if (cmd_obj) {
+ request.GetParsedLine().Shift();
+ request.SetCursorIndex(request.GetCursorIndex() - 1);
+ return cmd_obj->HandleCompletion(request);
+ } else {
+ return m_interpreter.HandleCompletionMatches(request);
+ }
+ }
+}