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 // 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
);
56 CommandObjectHelp::~CommandObjectHelp() = default;
58 #define LLDB_OPTIONS_help
59 #include "CommandOptions.inc"
61 llvm::ArrayRef
<OptionDefinition
>
62 CommandObjectHelp::CommandOptions::GetDefinitions() {
63 return llvm::ArrayRef(g_help_options
);
66 void CommandObjectHelp::DoExecute(Args
&command
, CommandReturnObject
&result
) {
67 CommandObject::CommandMap::iterator pos
;
68 CommandObject
*cmd_obj
;
69 const size_t argc
= command
.GetArgumentCount();
71 // 'help' doesn't take any arguments, other than command names. If argc is
72 // 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.
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
;
82 if (m_options
.m_show_hidden
)
83 cmd_types
|= CommandInterpreter::eCommandTypesHidden
;
85 result
.SetStatus(eReturnStatusSuccessFinishNoResult
);
86 m_interpreter
.GetHelp(result
, cmd_types
); // General help
88 // Get command object for the first command argument. Only search built-in
89 // command dictionary.
91 auto command_name
= command
[0].ref();
92 cmd_obj
= m_interpreter
.GetCommandObject(command_name
, &matches
);
94 if (cmd_obj
!= nullptr) {
97 CommandObject
*sub_cmd_obj
= cmd_obj
;
98 // Loop down through sub_command dictionaries until we find the command
99 // 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());
104 if (sub_cmd_obj
->IsAlias())
106 ((CommandAlias
*)sub_cmd_obj
)->GetUnderlyingCommand().get();
107 if (!sub_cmd_obj
->IsMultiwordObject()) {
111 CommandObject
*found_cmd
;
113 sub_cmd_obj
->GetSubcommandObject(sub_command
.c_str(), &matches
);
114 if (found_cmd
== nullptr || matches
.GetSize() > 1) {
118 sub_cmd_obj
= found_cmd
;
122 if (!all_okay
|| (sub_cmd_obj
== nullptr)) {
123 std::string cmd_string
;
124 command
.GetCommandString(cmd_string
);
125 if (matches
.GetSize() >= 2) {
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
));
133 result
.AppendError(s
.GetString());
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());
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());
152 sub_cmd_obj
->GenerateHelpText(result
);
153 std::string alias_full_name
;
154 // Don't use AliasExists here, that only checks exact name matches. If
155 // the user typed a shorter unique alias name, we should still tell them
157 if (m_interpreter
.GetAliasFullName(command_name
, alias_full_name
)) {
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());
163 } else if (matches
.GetSize() > 0) {
164 Stream
&output_strm
= result
.GetOutputStream();
165 output_strm
.Printf("Help requested with ambiguous command name, possible "
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
));
172 // Maybe the user is asking for help about a command argument rather than
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
);
181 StreamString error_msg_stream
;
182 GenerateAdditionalHelpAvenuesMessage(&error_msg_stream
, command_name
,
183 m_interpreter
.GetCommandPrefix(),
185 result
.AppendError(error_msg_stream
.GetString());
191 void 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
);
197 CommandObject
*cmd_obj
=
198 m_interpreter
.GetCommandObject(request
.GetParsedLine()[0].ref());
200 // The command that they are getting help on might be ambiguous, in which
201 // case we should complete that, otherwise complete with the command the
202 // user is getting help on...
205 request
.ShiftArguments();
206 cmd_obj
->HandleCompletion(request
);
209 m_interpreter
.HandleCompletionMatches(request
);