1 //===-- CommandObjectMultiword.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 "lldb/Interpreter/CommandObjectMultiword.h"
10 #include "lldb/Interpreter/CommandInterpreter.h"
11 #include "lldb/Interpreter/CommandReturnObject.h"
12 #include "lldb/Interpreter/Options.h"
15 using namespace lldb_private
;
17 // CommandObjectMultiword
19 CommandObjectMultiword::CommandObjectMultiword(CommandInterpreter
&interpreter
,
24 : CommandObject(interpreter
, name
, help
, syntax
, flags
),
25 m_can_be_removed(false) {}
27 CommandObjectMultiword::~CommandObjectMultiword() = default;
29 CommandObjectSP
CommandObjectMultiword::GetSubcommandSP(llvm::StringRef sub_cmd
,
30 StringList
*matches
) {
31 CommandObjectSP return_cmd_sp
;
32 CommandObject::CommandMap::iterator pos
;
34 if (!m_subcommand_dict
.empty()) {
35 pos
= m_subcommand_dict
.find(sub_cmd
);
36 if (pos
!= m_subcommand_dict
.end()) {
37 // An exact match; append the sub_cmd to the 'matches' string list.
39 matches
->AppendString(sub_cmd
);
40 return_cmd_sp
= pos
->second
;
42 StringList local_matches
;
43 if (matches
== nullptr)
44 matches
= &local_matches
;
46 AddNamesMatchingPartialString(m_subcommand_dict
, sub_cmd
, *matches
);
48 if (num_matches
== 1) {
49 // Cleaner, but slightly less efficient would be to call back into this
50 // function, since I now know I have an exact match...
52 sub_cmd
= matches
->GetStringAtIndex(0);
53 pos
= m_subcommand_dict
.find(sub_cmd
);
54 if (pos
!= m_subcommand_dict
.end())
55 return_cmd_sp
= pos
->second
;
63 CommandObjectMultiword::GetSubcommandObject(llvm::StringRef sub_cmd
,
64 StringList
*matches
) {
65 return GetSubcommandSP(sub_cmd
, matches
).get();
68 bool CommandObjectMultiword::LoadSubCommand(llvm::StringRef name
,
69 const CommandObjectSP
&cmd_obj
) {
71 assert((&GetCommandInterpreter() == &cmd_obj
->GetCommandInterpreter()) &&
72 "tried to add a CommandObject from a different interpreter");
74 CommandMap::iterator pos
;
77 pos
= m_subcommand_dict
.find(name
);
78 if (pos
== m_subcommand_dict
.end()) {
79 m_subcommand_dict
[name
] = cmd_obj
;
86 bool CommandObjectMultiword::Execute(const char *args_string
,
87 CommandReturnObject
&result
) {
88 Args
args(args_string
);
89 const size_t argc
= args
.GetArgumentCount();
91 this->CommandObject::GenerateHelpText(result
);
92 return result
.Succeeded();
95 auto sub_command
= args
[0].ref();
96 if (sub_command
.empty()) {
97 result
.AppendError("Need to specify a non-empty subcommand.");
98 return result
.Succeeded();
101 if (sub_command
.equals_lower("help")) {
102 this->CommandObject::GenerateHelpText(result
);
103 return result
.Succeeded();
106 if (m_subcommand_dict
.empty()) {
107 result
.AppendErrorWithFormat("'%s' does not have any subcommands.\n",
108 GetCommandName().str().c_str());
109 result
.SetStatus(eReturnStatusFailed
);
114 CommandObject
*sub_cmd_obj
= GetSubcommandObject(sub_command
, &matches
);
115 if (sub_cmd_obj
!= nullptr) {
116 // Now call CommandObject::Execute to process options in `rest_of_line`.
117 // From there the command-specific version of Execute will be called, with
118 // the processed arguments.
121 sub_cmd_obj
->Execute(args_string
, result
);
122 return result
.Succeeded();
125 std::string error_msg
;
126 const size_t num_subcmd_matches
= matches
.GetSize();
127 if (num_subcmd_matches
> 0)
128 error_msg
.assign("ambiguous command ");
130 error_msg
.assign("invalid command ");
132 error_msg
.append("'");
133 error_msg
.append(GetCommandName());
134 error_msg
.append(" ");
135 error_msg
.append(sub_command
);
136 error_msg
.append("'.");
138 if (num_subcmd_matches
> 0) {
139 error_msg
.append(" Possible completions:");
140 for (const std::string
&match
: matches
) {
141 error_msg
.append("\n\t");
142 error_msg
.append(match
);
145 error_msg
.append("\n");
146 result
.AppendRawError(error_msg
.c_str());
147 result
.SetStatus(eReturnStatusFailed
);
151 void CommandObjectMultiword::GenerateHelpText(Stream
&output_stream
) {
152 // First time through here, generate the help text for the object and push it
153 // to the return result object as well
155 CommandObject::GenerateHelpText(output_stream
);
156 output_stream
.PutCString("\nThe following subcommands are supported:\n\n");
158 CommandMap::iterator pos
;
159 uint32_t max_len
= FindLongestCommandWord(m_subcommand_dict
);
162 max_len
+= 4; // Indent the output by 4 spaces.
164 for (pos
= m_subcommand_dict
.begin(); pos
!= m_subcommand_dict
.end(); ++pos
) {
165 std::string
indented_command(" ");
166 indented_command
.append(pos
->first
);
167 if (pos
->second
->WantsRawCommandString()) {
168 std::string
help_text(pos
->second
->GetHelp());
169 help_text
.append(" Expects 'raw' input (see 'help raw-input'.)");
170 m_interpreter
.OutputFormattedHelpText(output_stream
,
171 indented_command
.c_str(), "--",
172 help_text
.c_str(), max_len
);
174 m_interpreter
.OutputFormattedHelpText(output_stream
,
175 indented_command
.c_str(), "--",
176 pos
->second
->GetHelp(), max_len
);
179 output_stream
.PutCString("\nFor more help on any particular subcommand, type "
180 "'help <command> <subcommand>'.\n");
183 void CommandObjectMultiword::HandleCompletion(CompletionRequest
&request
) {
184 auto arg0
= request
.GetParsedLine()[0].ref();
185 if (request
.GetCursorIndex() == 0) {
186 StringList new_matches
, descriptions
;
187 AddNamesMatchingPartialString(m_subcommand_dict
, arg0
, new_matches
,
189 request
.AddCompletions(new_matches
, descriptions
);
191 if (new_matches
.GetSize() == 1 &&
192 new_matches
.GetStringAtIndex(0) != nullptr &&
193 (arg0
== new_matches
.GetStringAtIndex(0))) {
194 StringList temp_matches
;
195 CommandObject
*cmd_obj
= GetSubcommandObject(arg0
, &temp_matches
);
196 if (cmd_obj
!= nullptr) {
197 if (request
.GetParsedLine().GetArgumentCount() != 1) {
198 request
.GetParsedLine().Shift();
199 request
.AppendEmptyArgument();
200 cmd_obj
->HandleCompletion(request
);
207 StringList new_matches
;
208 CommandObject
*sub_command_object
= GetSubcommandObject(arg0
, &new_matches
);
209 if (sub_command_object
== nullptr) {
210 request
.AddCompletions(new_matches
);
214 // Remove the one match that we got from calling GetSubcommandObject.
215 new_matches
.DeleteStringAtIndex(0);
216 request
.AddCompletions(new_matches
);
217 request
.ShiftArguments();
218 sub_command_object
->HandleCompletion(request
);
221 const char *CommandObjectMultiword::GetRepeatCommand(Args
¤t_command_args
,
224 if (current_command_args
.GetArgumentCount() <= index
)
226 CommandObject
*sub_command_object
=
227 GetSubcommandObject(current_command_args
[index
].ref());
228 if (sub_command_object
== nullptr)
230 return sub_command_object
->GetRepeatCommand(current_command_args
, index
);
233 void CommandObjectMultiword::AproposAllSubCommands(llvm::StringRef prefix
,
234 llvm::StringRef search_word
,
235 StringList
&commands_found
,
236 StringList
&commands_help
) {
237 CommandObject::CommandMap::const_iterator pos
;
239 for (pos
= m_subcommand_dict
.begin(); pos
!= m_subcommand_dict
.end(); ++pos
) {
240 const char *command_name
= pos
->first
.c_str();
241 CommandObject
*sub_cmd_obj
= pos
->second
.get();
242 StreamString complete_command_name
;
244 complete_command_name
<< prefix
<< " " << command_name
;
246 if (sub_cmd_obj
->HelpTextContainsWord(search_word
)) {
247 commands_found
.AppendString(complete_command_name
.GetString());
248 commands_help
.AppendString(sub_cmd_obj
->GetHelp());
251 if (sub_cmd_obj
->IsMultiwordObject())
252 sub_cmd_obj
->AproposAllSubCommands(complete_command_name
.GetString(),
253 search_word
, commands_found
,
258 CommandObjectProxy::CommandObjectProxy(CommandInterpreter
&interpreter
,
259 const char *name
, const char *help
,
260 const char *syntax
, uint32_t flags
)
261 : CommandObject(interpreter
, name
, help
, syntax
, flags
) {}
263 CommandObjectProxy::~CommandObjectProxy() = default;
265 llvm::StringRef
CommandObjectProxy::GetHelpLong() {
266 CommandObject
*proxy_command
= GetProxyCommandObject();
268 return proxy_command
->GetHelpLong();
269 return llvm::StringRef();
272 bool CommandObjectProxy::IsRemovable() const {
273 const CommandObject
*proxy_command
=
274 const_cast<CommandObjectProxy
*>(this)->GetProxyCommandObject();
276 return proxy_command
->IsRemovable();
280 bool CommandObjectProxy::IsMultiwordObject() {
281 CommandObject
*proxy_command
= GetProxyCommandObject();
283 return proxy_command
->IsMultiwordObject();
287 CommandObjectMultiword
*CommandObjectProxy::GetAsMultiwordCommand() {
288 CommandObject
*proxy_command
= GetProxyCommandObject();
290 return proxy_command
->GetAsMultiwordCommand();
294 void CommandObjectProxy::GenerateHelpText(Stream
&result
) {
295 CommandObject
*proxy_command
= GetProxyCommandObject();
297 return proxy_command
->GenerateHelpText(result
);
300 lldb::CommandObjectSP
301 CommandObjectProxy::GetSubcommandSP(llvm::StringRef sub_cmd
,
302 StringList
*matches
) {
303 CommandObject
*proxy_command
= GetProxyCommandObject();
305 return proxy_command
->GetSubcommandSP(sub_cmd
, matches
);
306 return lldb::CommandObjectSP();
309 CommandObject
*CommandObjectProxy::GetSubcommandObject(llvm::StringRef sub_cmd
,
310 StringList
*matches
) {
311 CommandObject
*proxy_command
= GetProxyCommandObject();
313 return proxy_command
->GetSubcommandObject(sub_cmd
, matches
);
317 void CommandObjectProxy::AproposAllSubCommands(llvm::StringRef prefix
,
318 llvm::StringRef search_word
,
319 StringList
&commands_found
,
320 StringList
&commands_help
) {
321 CommandObject
*proxy_command
= GetProxyCommandObject();
323 return proxy_command
->AproposAllSubCommands(prefix
, search_word
,
324 commands_found
, commands_help
);
327 bool CommandObjectProxy::LoadSubCommand(
328 llvm::StringRef cmd_name
, const lldb::CommandObjectSP
&command_sp
) {
329 CommandObject
*proxy_command
= GetProxyCommandObject();
331 return proxy_command
->LoadSubCommand(cmd_name
, command_sp
);
335 bool CommandObjectProxy::WantsRawCommandString() {
336 CommandObject
*proxy_command
= GetProxyCommandObject();
338 return proxy_command
->WantsRawCommandString();
342 bool CommandObjectProxy::WantsCompletion() {
343 CommandObject
*proxy_command
= GetProxyCommandObject();
345 return proxy_command
->WantsCompletion();
349 Options
*CommandObjectProxy::GetOptions() {
350 CommandObject
*proxy_command
= GetProxyCommandObject();
352 return proxy_command
->GetOptions();
356 void CommandObjectProxy::HandleCompletion(CompletionRequest
&request
) {
357 CommandObject
*proxy_command
= GetProxyCommandObject();
359 proxy_command
->HandleCompletion(request
);
362 void CommandObjectProxy::HandleArgumentCompletion(
363 CompletionRequest
&request
, OptionElementVector
&opt_element_vector
) {
364 CommandObject
*proxy_command
= GetProxyCommandObject();
366 proxy_command
->HandleArgumentCompletion(request
, opt_element_vector
);
369 const char *CommandObjectProxy::GetRepeatCommand(Args
¤t_command_args
,
371 CommandObject
*proxy_command
= GetProxyCommandObject();
373 return proxy_command
->GetRepeatCommand(current_command_args
, index
);
377 bool CommandObjectProxy::Execute(const char *args_string
,
378 CommandReturnObject
&result
) {
379 CommandObject
*proxy_command
= GetProxyCommandObject();
381 return proxy_command
->Execute(args_string
, result
);
382 result
.AppendError("command is not implemented");
383 result
.SetStatus(eReturnStatusFailed
);