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
32 if (m_subcommand_dict.empty())
33 return {};
34
35 auto pos = m_subcommand_dict.find(sub_cmd);
36 if (pos == m_subcommand_dict.end())
37 return {};
38
39 return pos->second;
40}
41
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(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 return m_subcommand_dict.try_emplace(std::string(name), cmd_obj_sp).second;
88}
89
91 llvm::StringRef name, const CommandObjectSP &cmd_obj_sp, bool can_replace) {
92 Status result;
93 if (cmd_obj_sp)
94 lldbassert((&GetCommandInterpreter() == &cmd_obj_sp->GetCommandInterpreter()) &&
95 "tried to add a CommandObject from a different interpreter");
96 if (!IsUserCommand()) {
97 return llvm::createStringError(llvm::inconvertibleErrorCode(),
98 "can't add a user subcommand to a builtin container command.");
99 }
100 // Make sure this a user command if it isn't already:
101 cmd_obj_sp->SetIsUserCommand(true);
102
103 std::string str_name(name);
104
105 auto [pos, inserted] = m_subcommand_dict.try_emplace(str_name, cmd_obj_sp);
106 if (inserted)
107 return llvm::Error::success();
108
109 const char *error_str = nullptr;
110 if (!can_replace)
111 error_str = "sub-command already exists";
112 if (!(*pos).second->IsUserCommand())
113 error_str = "can't replace a builtin subcommand";
114
115 if (error_str) {
116 return llvm::createStringError(llvm::inconvertibleErrorCode(), error_str);
117 }
118 pos->second = cmd_obj_sp;
119 return llvm::Error::success();
120}
121
122llvm::Error CommandObjectMultiword::RemoveUserSubcommand(llvm::StringRef cmd_name,
123 bool must_be_multiword) {
124 CommandMap::iterator pos;
125 std::string str_name(cmd_name);
126
127 pos = m_subcommand_dict.find(str_name);
128 if (pos == m_subcommand_dict.end()) {
129 return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' not found.",
130 str_name.c_str());
131 }
132 if (!(*pos).second->IsUserCommand()) {
133 return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' not a user command.",
134 str_name.c_str());
135 }
136
137 if (must_be_multiword && !(*pos).second->IsMultiwordObject()) {
138 return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' is not a container command",
139 str_name.c_str());
140 }
141 if (!must_be_multiword && (*pos).second->IsMultiwordObject()) {
142 return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' is not a user command",
143 str_name.c_str());
144 }
145
146 m_subcommand_dict.erase(pos);
147
148 return llvm::Error::success();
149}
150
151void CommandObjectMultiword::Execute(const char *args_string,
152 CommandReturnObject &result) {
153 Args args(args_string);
154 const size_t argc = args.GetArgumentCount();
155 if (argc == 0) {
157 return;
158 }
159
160 auto sub_command = args[0].ref();
161 if (sub_command.empty()) {
162 result.AppendError("Need to specify a non-empty subcommand.");
163 return;
164 }
165
166 if (m_subcommand_dict.empty()) {
167 result.AppendErrorWithFormat("'%s' does not have any subcommands.\n",
168 GetCommandName().str().c_str());
169 return;
170 }
171
172 StringList matches;
173 CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches);
174 if (sub_cmd_obj != nullptr) {
175 // Now call CommandObject::Execute to process options in `rest_of_line`.
176 // From there the command-specific version of Execute will be called, with
177 // the processed arguments.
178
179 args.Shift();
180 sub_cmd_obj->Execute(args_string, result);
181 return;
182 }
183
184 std::string error_msg;
185 const size_t num_subcmd_matches = matches.GetSize();
186 if (num_subcmd_matches > 0) {
187 error_msg.assign("ambiguous command ");
188 error_msg.append("'");
189 error_msg.append(std::string(GetCommandName()));
190 error_msg.append(" ");
191 error_msg.append(std::string(sub_command));
192 error_msg.append("'.");
193
194 error_msg.append(" Possible completions:");
195 for (const std::string &match : matches) {
196 error_msg.append("\n\t");
197 error_msg.append(match);
198 }
199 } else {
200 // Try to offer some alternatives to help correct the command.
201 error_msg.assign(
202 llvm::Twine("\"" + sub_command + "\" is not a valid subcommand of \"" +
204 " Use \"help " + GetCommandName() + "\" to find out more.")
205 .str());
206 }
207 error_msg.append("\n");
208 result.AppendRawError(error_msg.c_str());
209}
210
212 if (m_subcommand_dict.empty())
213 return "";
214 const size_t maxCount = 5;
215 size_t i = 0;
216 std::string buffer = " Valid subcommand";
217 buffer.append(m_subcommand_dict.size() > 1 ? "s are:" : " is");
218 CommandMap::iterator pos;
219 for (pos = m_subcommand_dict.begin();
220 pos != m_subcommand_dict.end() && i < maxCount; ++pos, ++i) {
221 buffer.append(" ");
222 buffer.append(pos->first);
223 buffer.append(",");
224 }
225 if (i < m_subcommand_dict.size())
226 buffer.append(" and others");
227 else
228 buffer.pop_back();
229
230 buffer.append(".");
231 return buffer;
232}
233
235 // First time through here, generate the help text for the object and push it
236 // to the return result object as well
237
238 CommandObject::GenerateHelpText(output_stream);
239 output_stream.PutCString("\nThe following subcommands are supported:\n\n");
240
241 CommandMap::iterator pos;
242 uint32_t max_len = FindLongestCommandWord(m_subcommand_dict);
243
244 if (max_len)
245 max_len += 4; // Indent the output by 4 spaces.
246
247 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) {
248 std::string indented_command(" ");
249 indented_command.append(pos->first);
250 if (pos->second->WantsRawCommandString()) {
251 std::string help_text(std::string(pos->second->GetHelp()));
252 help_text.append(" Expects 'raw' input (see 'help raw-input'.)");
253 m_interpreter.OutputFormattedHelpText(output_stream, indented_command,
254 "--", help_text, max_len);
255 } else
256 m_interpreter.OutputFormattedHelpText(output_stream, indented_command,
257 "--", pos->second->GetHelp(),
258 max_len);
259 }
260
261 output_stream.PutCString("\nFor more help on any particular subcommand, type "
262 "'help <command> <subcommand>'.\n");
263}
264
266 auto arg0 = request.GetParsedLine()[0].ref();
267 if (request.GetCursorIndex() == 0) {
268 StringList new_matches, descriptions;
270 &descriptions);
271 request.AddCompletions(new_matches, descriptions);
272
273 if (new_matches.GetSize() == 1 &&
274 new_matches.GetStringAtIndex(0) != nullptr &&
275 (arg0 == new_matches.GetStringAtIndex(0))) {
276 StringList temp_matches;
277 CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches);
278 if (cmd_obj != nullptr) {
279 if (request.GetParsedLine().GetArgumentCount() != 1) {
280 request.GetParsedLine().Shift();
281 request.AppendEmptyArgument();
282 cmd_obj->HandleCompletion(request);
283 }
284 }
285 }
286 return;
287 }
288
289 StringList new_matches;
290 CommandObject *sub_command_object = GetSubcommandObject(arg0, &new_matches);
291
292 // The subcommand is ambiguous. The completion isn't meaningful.
293 if (!sub_command_object)
294 return;
295
296 // Remove the one match that we got from calling GetSubcommandObject.
297 new_matches.DeleteStringAtIndex(0);
298 request.AddCompletions(new_matches);
299 request.ShiftArguments();
300 sub_command_object->HandleCompletion(request);
301}
302
303std::optional<std::string>
305 uint32_t index) {
306 index++;
307 if (current_command_args.GetArgumentCount() <= index)
308 return std::nullopt;
309 CommandObject *sub_command_object =
310 GetSubcommandObject(current_command_args[index].ref());
311 if (sub_command_object == nullptr)
312 return std::nullopt;
313 return sub_command_object->GetRepeatCommand(current_command_args, index);
314}
315
317 const char *name, const char *help,
318 const char *syntax, uint32_t flags)
319 : CommandObject(interpreter, name, help, syntax, flags) {}
320
322
324 CommandObject *proxy_command = GetProxyCommandObject();
325 if (proxy_command)
326 return proxy_command->GetOptions();
328}
329
331 CommandObject *proxy_command = GetProxyCommandObject();
332 if (proxy_command)
333 return proxy_command->GetHelp();
334 return CommandObject::GetHelp();
335}
336
338 CommandObject *proxy_command = GetProxyCommandObject();
339 if (proxy_command)
340 return proxy_command->GetSyntax();
342}
343
345 CommandObject *proxy_command = GetProxyCommandObject();
346 if (proxy_command)
347 return proxy_command->GetHelpLong();
349}
350
352 const CommandObject *proxy_command =
353 const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
354 if (proxy_command)
355 return proxy_command->IsRemovable();
356 return false;
357}
358
360 CommandObject *proxy_command = GetProxyCommandObject();
361 if (proxy_command)
362 return proxy_command->IsMultiwordObject();
363 return false;
364}
365
367 CommandObject *proxy_command = GetProxyCommandObject();
368 if (proxy_command)
369 return proxy_command->GetAsMultiwordCommand();
370 return nullptr;
371}
372
374 CommandObject *proxy_command = GetProxyCommandObject();
375 if (proxy_command)
376 proxy_command->GenerateHelpText(result);
377 else
379}
380
383 StringList *matches) {
384 CommandObject *proxy_command = GetProxyCommandObject();
385 if (proxy_command)
386 return proxy_command->GetSubcommandSP(sub_cmd, matches);
387 return lldb::CommandObjectSP();
388}
389
391 StringList *matches) {
392 CommandObject *proxy_command = GetProxyCommandObject();
393 if (proxy_command)
394 return proxy_command->GetSubcommandObject(sub_cmd, matches);
395 return nullptr;
396}
397
399 llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) {
400 CommandObject *proxy_command = GetProxyCommandObject();
401 if (proxy_command)
402 return proxy_command->LoadSubCommand(cmd_name, command_sp);
403 return false;
404}
405
407 CommandObject *proxy_command = GetProxyCommandObject();
408 if (proxy_command)
409 return proxy_command->WantsRawCommandString();
410 return false;
411}
412
414 CommandObject *proxy_command = GetProxyCommandObject();
415 if (proxy_command)
416 return proxy_command->WantsCompletion();
417 return false;
418}
419
421 CommandObject *proxy_command = GetProxyCommandObject();
422 if (proxy_command)
423 proxy_command->HandleCompletion(request);
424}
425
427 CompletionRequest &request, OptionElementVector &opt_element_vector) {
428 CommandObject *proxy_command = GetProxyCommandObject();
429 if (proxy_command)
430 proxy_command->HandleArgumentCompletion(request, opt_element_vector);
431}
432
433std::optional<std::string>
435 uint32_t index) {
436 CommandObject *proxy_command = GetProxyCommandObject();
437 if (proxy_command)
438 return proxy_command->GetRepeatCommand(current_command_args, index);
439 return std::nullopt;
440}
441
443 return "command is not implemented";
444}
445
446void CommandObjectProxy::Execute(const char *args_string,
447 CommandReturnObject &result) {
448 if (CommandObject *proxy_command = GetProxyCommandObject())
449 proxy_command->Execute(args_string, result);
450 else
452}
#define lldbassert(x)
Definition: LLDBAssert.h:15
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:295
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition: Args.h:120
void OutputFormattedHelpText(Stream &strm, llvm::StringRef prefix, llvm::StringRef help_text)
void Execute(const char *args_string, CommandReturnObject &result) override
llvm::Error LoadUserSubcommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj, bool can_replace) 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 default version handles argument definitions that have only one argument type,...
lldb::CommandObjectSP GetSubcommandSP(llvm::StringRef sub_cmd, StringList *matches=nullptr) override
bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj) override
CommandObjectMultiword * GetAsMultiwordCommand() override
CommandObject * GetSubcommandObject(llvm::StringRef sub_cmd, StringList *matches=nullptr) override
void Execute(const char *args_string, CommandReturnObject &result) 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 bool WantsCompletion()
CommandInterpreter & GetCommandInterpreter()
virtual void Execute(const char *args_string, CommandReturnObject &result)=0
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 CommandObjectMultiword * GetAsMultiwordCommand()
virtual Options * GetOptions()
virtual void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector)
The default version handles argument definitions that have only one argument type,...
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:118
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:65
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.
size_t FindLongestCommandWord(std::map< std::string, ValueType, std::less<> > &dict)
Definition: CommandObject.h:59
std::vector< OptionArgElement > OptionElementVector
Definition: Options.h:43
int AddNamesMatchingPartialString(const std::map< std::string, ValueType, std::less<> > &in_map, llvm::StringRef cmd_str, StringList &matches, StringList *descriptions=nullptr)
Definition: CommandObject.h:37
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::CommandObject > CommandObjectSP
Definition: lldb-forward.h:333