1 //===-- CommandObjectHelp.cpp -----------------------------------*- C++ -*-===//
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/CommandReturnObject.h"
14 using namespace lldb_private
;
18 void CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
19 Stream
*s
, llvm::StringRef command
, llvm::StringRef prefix
,
20 llvm::StringRef subcommand
, bool include_upropos
,
21 bool include_type_lookup
) {
22 if (!s
|| command
.empty())
25 std::string command_str
= command
.str();
26 std::string prefix_str
= prefix
.str();
27 std::string subcommand_str
= subcommand
.str();
28 const std::string
&lookup_str
=
29 !subcommand_str
.empty() ? subcommand_str
: command_str
;
30 s
->Printf("'%s' is not a known command.\n", command_str
.c_str());
31 s
->Printf("Try '%shelp' to see a current list of commands.\n",
32 prefix
.str().c_str());
33 if (include_upropos
) {
34 s
->Printf("Try '%sapropos %s' for a list of related commands.\n",
35 prefix_str
.c_str(), lookup_str
.c_str());
37 if (include_type_lookup
) {
38 s
->Printf("Try '%stype lookup %s' for information on types, methods, "
39 "functions, modules, etc.",
40 prefix_str
.c_str(), lookup_str
.c_str());
44 CommandObjectHelp::CommandObjectHelp(CommandInterpreter
&interpreter
)
45 : CommandObjectParsed(interpreter
, "help",
46 "Show a list of all debugger "
47 "commands, or give details "
48 "about a specific command.",
51 CommandArgumentEntry arg
;
52 CommandArgumentData command_arg
;
54 // Define the first (and only) variant of this arg.
55 command_arg
.arg_type
= eArgTypeCommandName
;
56 command_arg
.arg_repetition
= eArgRepeatStar
;
58 // There is only one variant this argument could be; put it into the argument
60 arg
.push_back(command_arg
);
62 // Push the data for the first argument into the m_arguments vector.
63 m_arguments
.push_back(arg
);
66 CommandObjectHelp::~CommandObjectHelp() = default;
68 #define LLDB_OPTIONS_help
69 #include "CommandOptions.inc"
71 llvm::ArrayRef
<OptionDefinition
>
72 CommandObjectHelp::CommandOptions::GetDefinitions() {
73 return llvm::makeArrayRef(g_help_options
);
76 bool CommandObjectHelp::DoExecute(Args
&command
, CommandReturnObject
&result
) {
77 CommandObject::CommandMap::iterator pos
;
78 CommandObject
*cmd_obj
;
79 const size_t argc
= command
.GetArgumentCount();
81 // 'help' doesn't take any arguments, other than command names. If argc is
82 // 0, we show the user all commands (aliases and user commands if asked for).
83 // Otherwise every argument must be the name of a command or a sub-command.
85 uint32_t cmd_types
= CommandInterpreter::eCommandTypesBuiltin
;
86 if (m_options
.m_show_aliases
)
87 cmd_types
|= CommandInterpreter::eCommandTypesAliases
;
88 if (m_options
.m_show_user_defined
)
89 cmd_types
|= CommandInterpreter::eCommandTypesUserDef
;
90 if (m_options
.m_show_hidden
)
91 cmd_types
|= CommandInterpreter::eCommandTypesHidden
;
93 result
.SetStatus(eReturnStatusSuccessFinishNoResult
);
94 m_interpreter
.GetHelp(result
, cmd_types
); // General help
96 // Get command object for the first command argument. Only search built-in
97 // command dictionary.
99 auto command_name
= command
[0].ref();
100 cmd_obj
= m_interpreter
.GetCommandObject(command_name
, &matches
);
102 if (cmd_obj
!= nullptr) {
104 bool all_okay
= true;
105 CommandObject
*sub_cmd_obj
= cmd_obj
;
106 // Loop down through sub_command dictionaries until we find the command
107 // object that corresponds to the help command entered.
108 std::string sub_command
;
109 for (auto &entry
: command
.entries().drop_front()) {
110 sub_command
= entry
.ref();
112 if (sub_cmd_obj
->IsAlias())
114 ((CommandAlias
*)sub_cmd_obj
)->GetUnderlyingCommand().get();
115 if (!sub_cmd_obj
->IsMultiwordObject()) {
119 CommandObject
*found_cmd
;
121 sub_cmd_obj
->GetSubcommandObject(sub_command
.c_str(), &matches
);
122 if (found_cmd
== nullptr || matches
.GetSize() > 1) {
126 sub_cmd_obj
= found_cmd
;
130 if (!all_okay
|| (sub_cmd_obj
== nullptr)) {
131 std::string cmd_string
;
132 command
.GetCommandString(cmd_string
);
133 if (matches
.GetSize() >= 2) {
135 s
.Printf("ambiguous command %s", cmd_string
.c_str());
136 size_t num_matches
= matches
.GetSize();
137 for (size_t match_idx
= 0; match_idx
< num_matches
; match_idx
++) {
138 s
.Printf("\n\t%s", matches
.GetStringAtIndex(match_idx
));
141 result
.AppendError(s
.GetString());
142 result
.SetStatus(eReturnStatusFailed
);
144 } else if (!sub_cmd_obj
) {
145 StreamString error_msg_stream
;
146 GenerateAdditionalHelpAvenuesMessage(
147 &error_msg_stream
, cmd_string
.c_str(),
148 m_interpreter
.GetCommandPrefix(), sub_command
.c_str());
149 result
.AppendError(error_msg_stream
.GetString());
150 result
.SetStatus(eReturnStatusFailed
);
153 GenerateAdditionalHelpAvenuesMessage(
154 &result
.GetOutputStream(), cmd_string
.c_str(),
155 m_interpreter
.GetCommandPrefix(), sub_command
.c_str());
156 result
.GetOutputStream().Printf(
157 "\nThe closest match is '%s'. Help on it follows.\n\n",
158 sub_cmd_obj
->GetCommandName().str().c_str());
162 sub_cmd_obj
->GenerateHelpText(result
);
163 std::string alias_full_name
;
164 // Don't use AliasExists here, that only checks exact name matches. If
165 // the user typed a shorter unique alias name, we should still tell them
167 if (m_interpreter
.GetAliasFullName(command_name
, alias_full_name
)) {
169 m_interpreter
.GetAlias(alias_full_name
)->GetAliasExpansion(sstr
);
170 result
.GetOutputStream().Printf("\n'%s' is an abbreviation for %s\n",
171 command
[0].c_str(), sstr
.GetData());
173 } else if (matches
.GetSize() > 0) {
174 Stream
&output_strm
= result
.GetOutputStream();
175 output_strm
.Printf("Help requested with ambiguous command name, possible "
177 const size_t match_count
= matches
.GetSize();
178 for (size_t i
= 0; i
< match_count
; i
++) {
179 output_strm
.Printf("\t%s\n", matches
.GetStringAtIndex(i
));
182 // Maybe the user is asking for help about a command argument rather than
184 const CommandArgumentType arg_type
=
185 CommandObject::LookupArgumentName(command_name
);
186 if (arg_type
!= eArgTypeLastArg
) {
187 Stream
&output_strm
= result
.GetOutputStream();
188 CommandObject::GetArgumentHelp(output_strm
, arg_type
, m_interpreter
);
189 result
.SetStatus(eReturnStatusSuccessFinishNoResult
);
191 StreamString error_msg_stream
;
192 GenerateAdditionalHelpAvenuesMessage(&error_msg_stream
, command_name
,
193 m_interpreter
.GetCommandPrefix(),
195 result
.AppendError(error_msg_stream
.GetString());
196 result
.SetStatus(eReturnStatusFailed
);
201 return result
.Succeeded();
204 void CommandObjectHelp::HandleCompletion(CompletionRequest
&request
) {
205 // Return the completions of the commands in the help system:
206 if (request
.GetCursorIndex() == 0) {
207 m_interpreter
.HandleCompletionMatches(request
);
210 CommandObject
*cmd_obj
=
211 m_interpreter
.GetCommandObject(request
.GetParsedLine()[0].ref());
213 // The command that they are getting help on might be ambiguous, in which
214 // case we should complete that, otherwise complete with the command the
215 // user is getting help on...
218 request
.ShiftArguments();
219 cmd_obj
->HandleCompletion(request
);
222 m_interpreter
.HandleCompletionMatches(request
);