1 //===-- CommandObjectHelp.cpp ---------------------------------------------===//
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-exception
7 //===----------------------------------------------------------------------===//
9 #include "CommandObjectHelp.h"
10 #include "lldb/Interpreter/CommandInterpreter.h"
11 #include "lldb/Interpreter/CommandOptionArgumentTable.h"
12 #include "lldb/Interpreter/CommandReturnObject.h"
15 using namespace lldb_private
;
19 void 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())
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());
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());
45 CommandObjectHelp::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 CommandArgumentEntry arg
;
52 CommandArgumentData command_arg
;
54 // A list of command names forming a path to the command we want help on.
55 // No names is allowed - in which case we dump the top-level help.
56 command_arg
.arg_type
= eArgTypeCommand
;
57 command_arg
.arg_repetition
= eArgRepeatStar
;
59 // There is only one variant this argument could be; put it into the argument
61 arg
.push_back(command_arg
);
63 // Push the data for the first argument into the m_arguments vector.
64 m_arguments
.push_back(arg
);
67 CommandObjectHelp::~CommandObjectHelp() = default;
69 #define LLDB_OPTIONS_help
70 #include "CommandOptions.inc"
72 llvm::ArrayRef
<OptionDefinition
>
73 CommandObjectHelp::CommandOptions::GetDefinitions() {
74 return llvm::ArrayRef(g_help_options
);
77 void CommandObjectHelp::DoExecute(Args
&command
, CommandReturnObject
&result
) {
78 CommandObject::CommandMap::iterator pos
;
79 CommandObject
*cmd_obj
;
80 const size_t argc
= command
.GetArgumentCount();
82 // 'help' doesn't take any arguments, other than command names. If argc is
83 // 0, we show the user all commands (aliases and user commands if asked for).
84 // Otherwise every argument must be the name of a command or a sub-command.
86 uint32_t cmd_types
= CommandInterpreter::eCommandTypesBuiltin
;
87 if (m_options
.m_show_aliases
)
88 cmd_types
|= CommandInterpreter::eCommandTypesAliases
;
89 if (m_options
.m_show_user_defined
) {
90 cmd_types
|= CommandInterpreter::eCommandTypesUserDef
;
91 cmd_types
|= CommandInterpreter::eCommandTypesUserMW
;
93 if (m_options
.m_show_hidden
)
94 cmd_types
|= CommandInterpreter::eCommandTypesHidden
;
96 result
.SetStatus(eReturnStatusSuccessFinishNoResult
);
97 m_interpreter
.GetHelp(result
, cmd_types
); // General help
99 // Get command object for the first command argument. Only search built-in
100 // command dictionary.
102 auto command_name
= command
[0].ref();
103 cmd_obj
= m_interpreter
.GetCommandObject(command_name
, &matches
);
105 if (cmd_obj
!= nullptr) {
107 bool all_okay
= true;
108 CommandObject
*sub_cmd_obj
= cmd_obj
;
109 // Loop down through sub_command dictionaries until we find the command
110 // object that corresponds to the help command entered.
111 std::string sub_command
;
112 for (auto &entry
: command
.entries().drop_front()) {
113 sub_command
= std::string(entry
.ref());
115 if (sub_cmd_obj
->IsAlias())
117 ((CommandAlias
*)sub_cmd_obj
)->GetUnderlyingCommand().get();
118 if (!sub_cmd_obj
->IsMultiwordObject()) {
122 CommandObject
*found_cmd
;
124 sub_cmd_obj
->GetSubcommandObject(sub_command
.c_str(), &matches
);
125 if (found_cmd
== nullptr || matches
.GetSize() > 1) {
129 sub_cmd_obj
= found_cmd
;
133 if (!all_okay
|| (sub_cmd_obj
== nullptr)) {
134 std::string cmd_string
;
135 command
.GetCommandString(cmd_string
);
136 if (matches
.GetSize() >= 2) {
138 s
.Printf("ambiguous command %s", cmd_string
.c_str());
139 size_t num_matches
= matches
.GetSize();
140 for (size_t match_idx
= 0; match_idx
< num_matches
; match_idx
++) {
141 s
.Printf("\n\t%s", matches
.GetStringAtIndex(match_idx
));
144 result
.AppendError(s
.GetString());
146 } else if (!sub_cmd_obj
) {
147 StreamString error_msg_stream
;
148 GenerateAdditionalHelpAvenuesMessage(
149 &error_msg_stream
, cmd_string
.c_str(),
150 m_interpreter
.GetCommandPrefix(), sub_command
.c_str());
151 result
.AppendError(error_msg_stream
.GetString());
154 GenerateAdditionalHelpAvenuesMessage(
155 &result
.GetOutputStream(), cmd_string
.c_str(),
156 m_interpreter
.GetCommandPrefix(), sub_command
.c_str());
157 result
.GetOutputStream().Printf(
158 "\nThe closest match is '%s'. Help on it follows.\n\n",
159 sub_cmd_obj
->GetCommandName().str().c_str());
163 sub_cmd_obj
->GenerateHelpText(result
);
164 std::string alias_full_name
;
165 // Don't use AliasExists here, that only checks exact name matches. If
166 // the user typed a shorter unique alias name, we should still tell them
168 if (m_interpreter
.GetAliasFullName(command_name
, alias_full_name
)) {
170 m_interpreter
.GetAlias(alias_full_name
)->GetAliasExpansion(sstr
);
171 result
.GetOutputStream().Printf("\n'%s' is an abbreviation for %s\n",
172 command
[0].c_str(), sstr
.GetData());
174 } else if (matches
.GetSize() > 0) {
175 Stream
&output_strm
= result
.GetOutputStream();
176 output_strm
.Printf("Help requested with ambiguous command name, possible "
178 const size_t match_count
= matches
.GetSize();
179 for (size_t i
= 0; i
< match_count
; i
++) {
180 output_strm
.Printf("\t%s\n", matches
.GetStringAtIndex(i
));
183 // Maybe the user is asking for help about a command argument rather than
185 const CommandArgumentType arg_type
=
186 CommandObject::LookupArgumentName(command_name
);
187 if (arg_type
!= eArgTypeLastArg
) {
188 Stream
&output_strm
= result
.GetOutputStream();
189 CommandObject::GetArgumentHelp(output_strm
, arg_type
, m_interpreter
);
190 result
.SetStatus(eReturnStatusSuccessFinishNoResult
);
192 StreamString error_msg_stream
;
193 GenerateAdditionalHelpAvenuesMessage(&error_msg_stream
, command_name
,
194 m_interpreter
.GetCommandPrefix(),
196 result
.AppendError(error_msg_stream
.GetString());
202 void CommandObjectHelp::HandleCompletion(CompletionRequest
&request
) {
203 // Return the completions of the commands in the help system:
204 if (request
.GetCursorIndex() == 0) {
205 m_interpreter
.HandleCompletionMatches(request
);
208 CommandObject
*cmd_obj
=
209 m_interpreter
.GetCommandObject(request
.GetParsedLine()[0].ref());
211 // The command that they are getting help on might be ambiguous, in which
212 // case we should complete that, otherwise complete with the command the
213 // user is getting help on...
216 request
.ShiftArguments();
217 cmd_obj
->HandleCompletion(request
);
220 m_interpreter
.HandleCompletionMatches(request
);