LLDB mainline
CommandObjectMultiword.cpp
Go to the documentation of this file.
1//===-- CommandObjectMultiword.cpp ----------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
13#include <optional>
14
15using namespace lldb;
16using namespace lldb_private;
17
18// CommandObjectMultiword
19
21 const char *name,
22 const char *help,
23 const char *syntax,
24 uint32_t flags)
25 : CommandObject(interpreter, name, help, syntax, flags),
26 m_can_be_removed(false) {}
27
29
30CommandObjectSP
32 if (m_subcommand_dict.empty())
33 return {};
34
35 auto pos = m_subcommand_dict.find(std::string(sub_cmd));
36 if (pos == m_subcommand_dict.end())
37 return {};
38
39 return pos->second;
40}
41
42CommandObjectSP CommandObjectMultiword::GetSubcommandSP(llvm::StringRef sub_cmd,
43 StringList *matches) {
44 if (m_subcommand_dict.empty())
45 return {};
46
47 CommandObjectSP return_cmd_sp = GetSubcommandSPExact(sub_cmd);
48 if (return_cmd_sp) {
49 if (matches)
50 matches->AppendString(sub_cmd);
51 return return_cmd_sp;
52 }
53
54 CommandObject::CommandMap::iterator pos;
55
56 StringList local_matches;
57 if (matches == nullptr)
58 matches = &local_matches;
59 int num_matches =
61
62 if (num_matches == 1) {
63 // Cleaner, but slightly less efficient would be to call back into this
64 // function, since I now know I have an exact match...
65
66 sub_cmd = matches->GetStringAtIndex(0);
67 pos = m_subcommand_dict.find(std::string(sub_cmd));
68 if (pos != m_subcommand_dict.end())
69 return_cmd_sp = pos->second;
70 }
71
72 return return_cmd_sp;
73}
74
77 StringList *matches) {
78 return GetSubcommandSP(sub_cmd, matches).get();
79}
80
82 const CommandObjectSP &cmd_obj_sp) {
83 if (cmd_obj_sp)
84 lldbassert((&GetCommandInterpreter() == &cmd_obj_sp->GetCommandInterpreter()) &&
85 "tried to add a CommandObject from a different interpreter");
86
87 CommandMap::iterator pos;
88 bool success = true;
89
90 pos = m_subcommand_dict.find(std::string(name));
91 if (pos == m_subcommand_dict.end()) {
92 m_subcommand_dict[std::string(name)] = cmd_obj_sp;
93 } else
94 success = false;
95
96 return success;
97}
98
100 llvm::StringRef name, const CommandObjectSP &cmd_obj_sp, bool can_replace) {
101 Status result;
102 if (cmd_obj_sp)
103 lldbassert((&GetCommandInterpreter() == &cmd_obj_sp->GetCommandInterpreter()) &&
104 "tried to add a CommandObject from a different interpreter");
105 if (!IsUserCommand()) {
106 return llvm::createStringError(llvm::inconvertibleErrorCode(),
107 "can't add a user subcommand to a builtin container command.");
108 }
109 // Make sure this a user command if it isn't already:
110 cmd_obj_sp->SetIsUserCommand(true);
111
112 std::string str_name(name);
113
114 auto pos = m_subcommand_dict.find(str_name);
115 if (pos == m_subcommand_dict.end()) {
116 m_subcommand_dict[str_name] = cmd_obj_sp;
117 return llvm::Error::success();
118 }
119
120 const char *error_str = nullptr;
121 if (!can_replace)
122 error_str = "sub-command already exists";
123 if (!(*pos).second->IsUserCommand())
124 error_str = "can't replace a builtin subcommand";
125
126 if (error_str) {
127 return llvm::createStringError(llvm::inconvertibleErrorCode(), error_str);
128 }
129 m_subcommand_dict[str_name] = cmd_obj_sp;
130 return llvm::Error::success();
131}
132
133llvm::Error CommandObjectMultiword::RemoveUserSubcommand(llvm::StringRef cmd_name,
134 bool must_be_multiword) {
135 CommandMap::iterator pos;
136 std::string str_name(cmd_name);
137
138 pos = m_subcommand_dict.find(str_name);
139 if (pos == m_subcommand_dict.end()) {
140 return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' not found.",
141 str_name.c_str());
142 }
143 if (!(*pos).second->IsUserCommand()) {
144 return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' not a user command.",
145 str_name.c_str());
146 }
147
148 if (must_be_multiword && !(*pos).second->IsMultiwordObject()) {
149 return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' is not a container command",
150 str_name.c_str());
151 }
152 if (!must_be_multiword && (*pos).second->IsMultiwordObject()) {
153 return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' is not a user command",
154 str_name.c_str());
155 }
156
157 m_subcommand_dict.erase(pos);
158
159 return llvm::Error::success();
160}
161
162bool CommandObjectMultiword::Execute(const char *args_string,
163 CommandReturnObject &result) {
164 Args args(args_string);
165 const size_t argc = args.GetArgumentCount();
166 if (argc == 0) {
168 return result.Succeeded();
169 }
170
171 auto sub_command = args[0].ref();
172 if (sub_command.empty()) {
173 result.AppendError("Need to specify a non-empty subcommand.");
174 return result.Succeeded();
175 }
176
177 if (m_subcommand_dict.empty()) {
178 result.AppendErrorWithFormat("'%s' does not have any subcommands.\n",
179 GetCommandName().str().c_str());
180 return false;
181 }
182
183 StringList matches;
184 CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches);
185 if (sub_cmd_obj != nullptr) {
186 // Now call CommandObject::Execute to process options in `rest_of_line`.
187 // From there the command-specific version of Execute will be called, with
188 // the processed arguments.
189
190 args.Shift();
191 sub_cmd_obj->Execute(args_string, result);
192 return result.Succeeded();
193 }
194
195 std::string error_msg;
196 const size_t num_subcmd_matches = matches.GetSize();
197 if (num_subcmd_matches > 0)
198 error_msg.assign("ambiguous command ");
199 else
200 error_msg.assign("invalid command ");
201
202 error_msg.append("'");
203 error_msg.append(std::string(GetCommandName()));
204 error_msg.append(" ");
205 error_msg.append(std::string(sub_command));
206 error_msg.append("'.");
207
208 if (num_subcmd_matches > 0) {
209 error_msg.append(" Possible completions:");
210 for (const std::string &match : matches) {
211 error_msg.append("\n\t");
212 error_msg.append(match);
213 }
214 }
215 error_msg.append("\n");
216 result.AppendRawError(error_msg.c_str());
217 return false;
218}
219
221 // First time through here, generate the help text for the object and push it
222 // to the return result object as well
223
224 CommandObject::GenerateHelpText(output_stream);
225 output_stream.PutCString("\nThe following subcommands are supported:\n\n");
226
227 CommandMap::iterator pos;
229
230 if (max_len)
231 max_len += 4; // Indent the output by 4 spaces.
232
233 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) {
234 std::string indented_command(" ");
235 indented_command.append(pos->first);
236 if (pos->second->WantsRawCommandString()) {
237 std::string help_text(std::string(pos->second->GetHelp()));
238 help_text.append(" Expects 'raw' input (see 'help raw-input'.)");
239 m_interpreter.OutputFormattedHelpText(output_stream, indented_command,
240 "--", help_text, max_len);
241 } else
242 m_interpreter.OutputFormattedHelpText(output_stream, indented_command,
243 "--", pos->second->GetHelp(),
244 max_len);
245 }
246
247 output_stream.PutCString("\nFor more help on any particular subcommand, type "
248 "'help <command> <subcommand>'.\n");
249}
250
252 auto arg0 = request.GetParsedLine()[0].ref();
253 if (request.GetCursorIndex() == 0) {
254 StringList new_matches, descriptions;
256 &descriptions);
257 request.AddCompletions(new_matches, descriptions);
258
259 if (new_matches.GetSize() == 1 &&
260 new_matches.GetStringAtIndex(0) != nullptr &&
261 (arg0 == new_matches.GetStringAtIndex(0))) {
262 StringList temp_matches;
263 CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches);
264 if (cmd_obj != nullptr) {
265 if (request.GetParsedLine().GetArgumentCount() != 1) {
266 request.GetParsedLine().Shift();
267 request.AppendEmptyArgument();
268 cmd_obj->HandleCompletion(request);
269 }
270 }
271 }
272 return;
273 }
274
275 StringList new_matches;
276 CommandObject *sub_command_object = GetSubcommandObject(arg0, &new_matches);
277 if (sub_command_object == nullptr) {
278 request.AddCompletions(new_matches);
279 return;
280 }
281
282 // Remove the one match that we got from calling GetSubcommandObject.
283 new_matches.DeleteStringAtIndex(0);
284 request.AddCompletions(new_matches);
285 request.ShiftArguments();
286 sub_command_object->HandleCompletion(request);
287}
288
289std::optional<std::string>
291 uint32_t index) {
292 index++;
293 if (current_command_args.GetArgumentCount() <= index)
294 return std::nullopt;
295 CommandObject *sub_command_object =
296 GetSubcommandObject(current_command_args[index].ref());
297 if (sub_command_object == nullptr)
298 return std::nullopt;
299 return sub_command_object->GetRepeatCommand(current_command_args, index);
300}
301
303 const char *name, const char *help,
304 const char *syntax, uint32_t flags)
305 : CommandObject(interpreter, name, help, syntax, flags) {}
306
308
310 CommandObject *proxy_command = GetProxyCommandObject();
311 if (proxy_command)
312 return proxy_command->GetOptions();
314}
315
317 CommandObject *proxy_command = GetProxyCommandObject();
318 if (proxy_command)
319 return proxy_command->GetHelp();
320 return CommandObject::GetHelp();
321}
322
324 CommandObject *proxy_command = GetProxyCommandObject();
325 if (proxy_command)
326 return proxy_command->GetSyntax();
328}
329
331 CommandObject *proxy_command = GetProxyCommandObject();
332 if (proxy_command)
333 return proxy_command->GetHelpLong();
335}
336
338 const CommandObject *proxy_command =
339 const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
340 if (proxy_command)
341 return proxy_command->IsRemovable();
342 return false;
343}
344
346 CommandObject *proxy_command = GetProxyCommandObject();
347 if (proxy_command)
348 return proxy_command->IsMultiwordObject();
349 return false;
350}
351
353 CommandObject *proxy_command = GetProxyCommandObject();
354 if (proxy_command)
355 return proxy_command->GetAsMultiwordCommand();
356 return nullptr;
357}
358
360 CommandObject *proxy_command = GetProxyCommandObject();
361 if (proxy_command)
362 proxy_command->GenerateHelpText(result);
363 else
365}
366
367lldb::CommandObjectSP
369 StringList *matches) {
370 CommandObject *proxy_command = GetProxyCommandObject();
371 if (proxy_command)
372 return proxy_command->GetSubcommandSP(sub_cmd, matches);
373 return lldb::CommandObjectSP();
374}
375
377 StringList *matches) {
378 CommandObject *proxy_command = GetProxyCommandObject();
379 if (proxy_command)
380 return proxy_command->GetSubcommandObject(sub_cmd, matches);
381 return nullptr;
382}
383
385 llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) {
386 CommandObject *proxy_command = GetProxyCommandObject();
387 if (proxy_command)
388 return proxy_command->LoadSubCommand(cmd_name, command_sp);
389 return false;
390}
391
393 CommandObject *proxy_command = GetProxyCommandObject();
394 if (proxy_command)
395 return proxy_command->WantsRawCommandString();
396 return false;
397}
398
400 CommandObject *proxy_command = GetProxyCommandObject();
401 if (proxy_command)
402 return proxy_command->WantsCompletion();
403 return false;
404}
405
407 CommandObject *proxy_command = GetProxyCommandObject();
408 if (proxy_command)
409 proxy_command->HandleCompletion(request);
410}
411
413 CompletionRequest &request, OptionElementVector &opt_element_vector) {
414 CommandObject *proxy_command = GetProxyCommandObject();
415 if (proxy_command)
416 proxy_command->HandleArgumentCompletion(request, opt_element_vector);
417}
418
419std::optional<std::string>
421 uint32_t index) {
422 CommandObject *proxy_command = GetProxyCommandObject();
423 if (proxy_command)
424 return proxy_command->GetRepeatCommand(current_command_args, index);
425 return std::nullopt;
426}
427
429 return "command is not implemented";
430}
431
432bool CommandObjectProxy::Execute(const char *args_string,
433 CommandReturnObject &result) {
434 CommandObject *proxy_command = GetProxyCommandObject();
435 if (proxy_command)
436 return proxy_command->Execute(args_string, result);
438 return false;
439}
#define lldbassert(x)
Definition: LLDBAssert.h:13
A command line argument class.
Definition: Args.h:33
void Shift()
Shifts the first argument C string value of the array off the argument array.
Definition: Args.cpp:285
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition: Args.h:116
void OutputFormattedHelpText(Stream &strm, llvm::StringRef prefix, llvm::StringRef help_text)
llvm::Error LoadUserSubcommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj, bool can_replace) override
bool Execute(const char *args_string, CommandReturnObject &result) override
void GenerateHelpText(Stream &output_stream) override
CommandObject::CommandMap m_subcommand_dict
void HandleCompletion(CompletionRequest &request) override
This default version handles calling option argument completions and then calls HandleArgumentComplet...
std::optional< std::string > GetRepeatCommand(Args &current_command_args, uint32_t index) override
Get the command that appropriate for a "repeat" of the current command.
bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj) override
CommandObject * GetSubcommandObject(llvm::StringRef sub_cmd, StringList *matches=nullptr) override
llvm::Error RemoveUserSubcommand(llvm::StringRef cmd_name, bool multiword_okay)
CommandObjectMultiword(CommandInterpreter &interpreter, const char *name, const char *help=nullptr, const char *syntax=nullptr, uint32_t flags=0)
lldb::CommandObjectSP GetSubcommandSPExact(llvm::StringRef sub_cmd) override
lldb::CommandObjectSP GetSubcommandSP(llvm::StringRef sub_cmd, StringList *matches=nullptr) override
void GenerateHelpText(Stream &result) override
virtual CommandObject * GetProxyCommandObject()=0
llvm::StringRef GetHelpLong() override
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The input array contains a parsed version of the line.
lldb::CommandObjectSP GetSubcommandSP(llvm::StringRef sub_cmd, StringList *matches=nullptr) override
bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj) override
bool Execute(const char *args_string, CommandReturnObject &result) override
CommandObjectMultiword * GetAsMultiwordCommand() override
CommandObject * GetSubcommandObject(llvm::StringRef sub_cmd, StringList *matches=nullptr) override
CommandObjectProxy(CommandInterpreter &interpreter, const char *name, const char *help=nullptr, const char *syntax=nullptr, uint32_t flags=0)
virtual llvm::StringRef GetUnsupportedError()
void HandleCompletion(CompletionRequest &request) override
This default version handles calling option argument completions and then calls HandleArgumentComplet...
std::optional< std::string > GetRepeatCommand(Args &current_command_args, uint32_t index) override
Get the command that appropriate for a "repeat" of the current command.
virtual bool WantsRawCommandString()=0
void GenerateHelpText(CommandReturnObject &result)
virtual llvm::StringRef GetHelpLong()
llvm::StringRef GetCommandName() const
virtual bool IsMultiwordObject()
virtual void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector)
The input array contains a parsed version of the line.
virtual bool WantsCompletion()
CommandInterpreter & GetCommandInterpreter()
CommandInterpreter & m_interpreter
virtual bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj)
virtual std::optional< std::string > GetRepeatCommand(Args &current_command_args, uint32_t index)
Get the command that appropriate for a "repeat" of the current command.
virtual CommandObject * GetSubcommandObject(llvm::StringRef sub_cmd, StringList *matches=nullptr)
virtual bool Execute(const char *args_string, CommandReturnObject &result)=0
virtual CommandObjectMultiword * GetAsMultiwordCommand()
virtual Options * GetOptions()
virtual llvm::StringRef GetSyntax()
virtual bool IsRemovable() const
virtual void HandleCompletion(CompletionRequest &request)
This default version handles calling option argument completions and then calls HandleArgumentComplet...
virtual llvm::StringRef GetHelp()
virtual lldb::CommandObjectSP GetSubcommandSP(llvm::StringRef sub_cmd, StringList *matches=nullptr)
void void AppendError(llvm::StringRef in_string)
void AppendRawError(llvm::StringRef in_string)
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
"lldb/Utility/ArgCompletionRequest.h"
void AddCompletions(const StringList &completions)
Adds multiple possible completion strings.
const Args & GetParsedLine() const
void ShiftArguments()
Drops the first argument from the argument list.
void AppendEmptyArgument()
Adds an empty argument at the end of the argument list and moves the cursor to this new argument.
A command line option parsing protocol class.
Definition: Options.h:58
An error handling class.
Definition: Status.h:44
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:63
void AppendString(const std::string &s)
Definition: StringList.cpp:43
const char * GetStringAtIndex(size_t idx) const
Definition: StringList.cpp:86
size_t GetSize() const
Definition: StringList.cpp:74
void DeleteStringAtIndex(size_t id)
Definition: StringList.cpp:147
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
int AddNamesMatchingPartialString(const std::map< std::string, ValueType > &in_map, llvm::StringRef cmd_str, StringList &matches, StringList *descriptions=nullptr)
Definition: CommandObject.h:37
std::vector< OptionArgElement > OptionElementVector
Definition: Options.h:43
size_t FindLongestCommandWord(std::map< std::string, ValueType > &dict)
Definition: CommandObject.h:57
Definition: SBAddress.h:15