blob: b39323e0acb06e08590cca93dce85e99b7987f6e [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- CommandObjectHelp.cpp -----------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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-exception
Chris Lattner30fdc8d2010-06-08 16:52:24 +00006//
7//===----------------------------------------------------------------------===//
8
Eugene Zelenko26cac3a2016-02-20 00:58:29 +00009#include "CommandObjectHelp.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000010#include "lldb/Interpreter/CommandInterpreter.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000011#include "lldb/Interpreter/CommandObjectMultiword.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000012#include "lldb/Interpreter/CommandReturnObject.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000013#include "lldb/Interpreter/Options.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000014
15using namespace lldb;
16using namespace lldb_private;
17
18//-------------------------------------------------------------------------
19// CommandObjectHelp
20//-------------------------------------------------------------------------
21
Kate Stoneb9c1b512016-09-06 20:57:50 +000022void CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
Zachary Turnera49c2012016-11-16 21:34:22 +000023 Stream *s, llvm::StringRef command, llvm::StringRef prefix, llvm::StringRef subcommand,
Kate Stoneb9c1b512016-09-06 20:57:50 +000024 bool include_apropos, bool include_type_lookup) {
Zachary Turnera49c2012016-11-16 21:34:22 +000025 if (!s || command.empty())
26 return;
27
28 std::string command_str = command.str();
29 std::string prefix_str = prefix.str();
30 std::string subcommand_str = subcommand.str();
31 const std::string &lookup_str = !subcommand_str.empty() ? subcommand_str : command_str;
32 s->Printf("'%s' is not a known command.\n", command_str.c_str());
33 s->Printf("Try '%shelp' to see a current list of commands.\n",
34 prefix.str().c_str());
35 if (include_apropos) {
36 s->Printf("Try '%sapropos %s' for a list of related commands.\n",
37 prefix_str.c_str(), lookup_str.c_str());
38 }
39 if (include_type_lookup) {
40 s->Printf("Try '%stype lookup %s' for information on types, methods, "
41 "functions, modules, etc.",
42 prefix_str.c_str(), lookup_str.c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +000043 }
Enrico Granata46d4aa22016-02-29 23:22:53 +000044}
45
Kate Stone7428a182016-07-14 22:03:10 +000046CommandObjectHelp::CommandObjectHelp(CommandInterpreter &interpreter)
Kate Stoneb9c1b512016-09-06 20:57:50 +000047 : CommandObjectParsed(interpreter, "help", "Show a list of all debugger "
48 "commands, or give details "
49 "about a specific command.",
Kate Stone7428a182016-07-14 22:03:10 +000050 "help [<cmd-name>]"),
Kate Stoneb9c1b512016-09-06 20:57:50 +000051 m_options() {
52 CommandArgumentEntry arg;
53 CommandArgumentData command_arg;
Caroline Tice405fe672010-10-04 22:28:36 +000054
Kate Stoneb9c1b512016-09-06 20:57:50 +000055 // Define the first (and only) variant of this arg.
56 command_arg.arg_type = eArgTypeCommandName;
57 command_arg.arg_repetition = eArgRepeatStar;
Caroline Tice405fe672010-10-04 22:28:36 +000058
Kate Stoneb9c1b512016-09-06 20:57:50 +000059 // There is only one variant this argument could be; put it into the argument
60 // entry.
61 arg.push_back(command_arg);
Caroline Tice405fe672010-10-04 22:28:36 +000062
Kate Stoneb9c1b512016-09-06 20:57:50 +000063 // Push the data for the first argument into the m_arguments vector.
64 m_arguments.push_back(arg);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000065}
66
Eugene Zelenko26cac3a2016-02-20 00:58:29 +000067CommandObjectHelp::~CommandObjectHelp() = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000068
Tatyana Krasnukha8fe53c492018-09-26 18:50:19 +000069static constexpr OptionDefinition g_help_options[] = {
Kate Stoneb9c1b512016-09-06 20:57:50 +000070 // clang-format off
Tatyana Krasnukha8fe53c492018-09-26 18:50:19 +000071 {LLDB_OPT_SET_ALL, false, "hide-aliases", 'a', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Hide aliases in the command list."},
72 {LLDB_OPT_SET_ALL, false, "hide-user-commands", 'u', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Hide user-defined commands from the list."},
73 {LLDB_OPT_SET_ALL, false, "show-hidden-commands", 'h', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Include commands prefixed with an underscore."},
Kate Stoneb9c1b512016-09-06 20:57:50 +000074 // clang-format on
Enrico Granata08633ee2011-09-09 17:49:36 +000075};
76
Zachary Turner1f0f5b52016-09-22 20:22:55 +000077llvm::ArrayRef<OptionDefinition>
78CommandObjectHelp::CommandOptions::GetDefinitions() {
Zachary Turner70602432016-09-22 21:06:13 +000079 return llvm::makeArrayRef(g_help_options);
Zachary Turner1f0f5b52016-09-22 20:22:55 +000080}
81
Kate Stoneb9c1b512016-09-06 20:57:50 +000082bool CommandObjectHelp::DoExecute(Args &command, CommandReturnObject &result) {
83 CommandObject::CommandMap::iterator pos;
84 CommandObject *cmd_obj;
85 const size_t argc = command.GetArgumentCount();
Enrico Granata08633ee2011-09-09 17:49:36 +000086
Adrian Prantl05097242018-04-30 16:49:04 +000087 // 'help' doesn't take any arguments, other than command names. If argc is
88 // 0, we show the user all commands (aliases and user commands if asked for).
89 // Otherwise every argument must be the name of a command or a sub-command.
Kate Stoneb9c1b512016-09-06 20:57:50 +000090 if (argc == 0) {
91 uint32_t cmd_types = CommandInterpreter::eCommandTypesBuiltin;
92 if (m_options.m_show_aliases)
93 cmd_types |= CommandInterpreter::eCommandTypesAliases;
94 if (m_options.m_show_user_defined)
95 cmd_types |= CommandInterpreter::eCommandTypesUserDef;
96 if (m_options.m_show_hidden)
97 cmd_types |= CommandInterpreter::eCommandTypesHidden;
98
99 result.SetStatus(eReturnStatusSuccessFinishNoResult);
100 m_interpreter.GetHelp(result, cmd_types); // General help
101 } else {
102 // Get command object for the first command argument. Only search built-in
103 // command dictionary.
104 StringList matches;
Zachary Turner14f6b2c2016-12-09 01:08:29 +0000105 auto command_name = command[0].ref;
106 cmd_obj = m_interpreter.GetCommandObject(command_name, &matches);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000107
108 if (cmd_obj != nullptr) {
109 StringList matches;
110 bool all_okay = true;
111 CommandObject *sub_cmd_obj = cmd_obj;
112 // Loop down through sub_command dictionaries until we find the command
Zachary Turner97d2c402016-10-05 23:40:23 +0000113 // object that corresponds to the help command entered.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000114 std::string sub_command;
Zachary Turner97d2c402016-10-05 23:40:23 +0000115 for (auto &entry : command.entries().drop_front()) {
116 sub_command = entry.ref;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000117 matches.Clear();
118 if (sub_cmd_obj->IsAlias())
119 sub_cmd_obj =
120 ((CommandAlias *)sub_cmd_obj)->GetUnderlyingCommand().get();
121 if (!sub_cmd_obj->IsMultiwordObject()) {
122 all_okay = false;
Zachary Turner97d2c402016-10-05 23:40:23 +0000123 break;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000124 } else {
125 CommandObject *found_cmd;
126 found_cmd =
127 sub_cmd_obj->GetSubcommandObject(sub_command.c_str(), &matches);
Zachary Turner97d2c402016-10-05 23:40:23 +0000128 if (found_cmd == nullptr || matches.GetSize() > 1) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000129 all_okay = false;
Zachary Turner97d2c402016-10-05 23:40:23 +0000130 break;
131 } else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000132 sub_cmd_obj = found_cmd;
133 }
134 }
135
136 if (!all_okay || (sub_cmd_obj == nullptr)) {
137 std::string cmd_string;
138 command.GetCommandString(cmd_string);
139 if (matches.GetSize() >= 2) {
140 StreamString s;
141 s.Printf("ambiguous command %s", cmd_string.c_str());
142 size_t num_matches = matches.GetSize();
143 for (size_t match_idx = 0; match_idx < num_matches; match_idx++) {
144 s.Printf("\n\t%s", matches.GetStringAtIndex(match_idx));
145 }
146 s.Printf("\n");
Zachary Turnerc1564272016-11-16 21:15:24 +0000147 result.AppendError(s.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000148 result.SetStatus(eReturnStatusFailed);
149 return false;
150 } else if (!sub_cmd_obj) {
151 StreamString error_msg_stream;
152 GenerateAdditionalHelpAvenuesMessage(
153 &error_msg_stream, cmd_string.c_str(),
154 m_interpreter.GetCommandPrefix(), sub_command.c_str());
Zachary Turnerc1564272016-11-16 21:15:24 +0000155 result.AppendError(error_msg_stream.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000156 result.SetStatus(eReturnStatusFailed);
157 return false;
158 } else {
159 GenerateAdditionalHelpAvenuesMessage(
160 &result.GetOutputStream(), cmd_string.c_str(),
161 m_interpreter.GetCommandPrefix(), sub_command.c_str());
162 result.GetOutputStream().Printf(
163 "\nThe closest match is '%s'. Help on it follows.\n\n",
Zachary Turnera4496982016-10-05 21:14:38 +0000164 sub_cmd_obj->GetCommandName().str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000165 }
166 }
167
168 sub_cmd_obj->GenerateHelpText(result);
Jim Ingham79d81052018-12-21 01:45:28 +0000169 std::string alias_full_name;
170 // Don't use AliasExists here, that only checks exact name matches. If
171 // the user typed a shorter unique alias name, we should still tell them
172 // it was an alias.
173 if (m_interpreter.GetAliasFullName(command_name, alias_full_name)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000174 StreamString sstr;
Jim Ingham79d81052018-12-21 01:45:28 +0000175 m_interpreter.GetAlias(alias_full_name)->GetAliasExpansion(sstr);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000176 result.GetOutputStream().Printf("\n'%s' is an abbreviation for %s\n",
Zachary Turner14f6b2c2016-12-09 01:08:29 +0000177 command[0].c_str(), sstr.GetData());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000178 }
179 } else if (matches.GetSize() > 0) {
180 Stream &output_strm = result.GetOutputStream();
181 output_strm.Printf("Help requested with ambiguous command name, possible "
182 "completions:\n");
183 const size_t match_count = matches.GetSize();
184 for (size_t i = 0; i < match_count; i++) {
185 output_strm.Printf("\t%s\n", matches.GetStringAtIndex(i));
186 }
187 } else {
188 // Maybe the user is asking for help about a command argument rather than
189 // a command.
190 const CommandArgumentType arg_type =
Zachary Turner14f6b2c2016-12-09 01:08:29 +0000191 CommandObject::LookupArgumentName(command_name);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000192 if (arg_type != eArgTypeLastArg) {
193 Stream &output_strm = result.GetOutputStream();
194 CommandObject::GetArgumentHelp(output_strm, arg_type, m_interpreter);
195 result.SetStatus(eReturnStatusSuccessFinishNoResult);
196 } else {
197 StreamString error_msg_stream;
Zachary Turner14f6b2c2016-12-09 01:08:29 +0000198 GenerateAdditionalHelpAvenuesMessage(&error_msg_stream, command_name,
199 m_interpreter.GetCommandPrefix(),
200 "");
Zachary Turnerc1564272016-11-16 21:15:24 +0000201 result.AppendError(error_msg_stream.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000202 result.SetStatus(eReturnStatusFailed);
203 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000204 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000205 }
206
207 return result.Succeeded();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000208}
209
Raphael Isemann2443bbd2018-07-02 21:29:56 +0000210int CommandObjectHelp::HandleCompletion(CompletionRequest &request) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000211 // Return the completions of the commands in the help system:
Raphael Isemann2443bbd2018-07-02 21:29:56 +0000212 if (request.GetCursorIndex() == 0) {
213 return m_interpreter.HandleCompletionMatches(request);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000214 } else {
Raphael Isemann2443bbd2018-07-02 21:29:56 +0000215 CommandObject *cmd_obj =
216 m_interpreter.GetCommandObject(request.GetParsedLine()[0].ref);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000217
218 // The command that they are getting help on might be ambiguous, in which
Adrian Prantl05097242018-04-30 16:49:04 +0000219 // case we should complete that, otherwise complete with the command the
220 // user is getting help on...
Kate Stoneb9c1b512016-09-06 20:57:50 +0000221
222 if (cmd_obj) {
Raphael Isemann2443bbd2018-07-02 21:29:56 +0000223 request.GetParsedLine().Shift();
224 request.SetCursorIndex(request.GetCursorIndex() - 1);
225 return cmd_obj->HandleCompletion(request);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000226 } else {
Raphael Isemann2443bbd2018-07-02 21:29:56 +0000227 return m_interpreter.HandleCompletionMatches(request);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000228 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000229 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000230}