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 result.AppendError(error_msg);
208}
209
211 if (m_subcommand_dict.empty())
212 return "";
213 const size_t maxCount = 5;
214 size_t i = 0;
215 std::string buffer = " Valid subcommand";
216 buffer.append(m_subcommand_dict.size() > 1 ? "s are:" : " is");
217 CommandMap::iterator pos;
218 for (pos = m_subcommand_dict.begin();
219 pos != m_subcommand_dict.end() && i < maxCount; ++pos, ++i) {
220 buffer.append(" ");
221 buffer.append(pos->first);
222 buffer.append(",");
223 }
224 if (i < m_subcommand_dict.size())
225 buffer.append(" and others");
226 else
227 buffer.pop_back();
228
229 buffer.append(".");
230 return buffer;
231}
232
234 // First time through here, generate the help text for the object and push it
235 // to the return result object as well
236
237 CommandObject::GenerateHelpText(output_stream);
238 output_stream.PutCString("\nThe following subcommands are supported:\n\n");
239
240 CommandMap::iterator pos;
241 uint32_t max_len = FindLongestCommandWord(m_subcommand_dict);
242
243 if (max_len)
244 max_len += 4; // Indent the output by 4 spaces.
245
246 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) {
247 std::string indented_command(" ");
248 indented_command.append(pos->first);
249 if (pos->second->WantsRawCommandString()) {
250 std::string help_text(std::string(pos->second->GetHelp()));
251 help_text.append(" Expects 'raw' input (see 'help raw-input'.)");
252 m_interpreter.OutputFormattedHelpText(output_stream, indented_command,
253 "--", help_text, max_len);
254 } else
255 m_interpreter.OutputFormattedHelpText(output_stream, indented_command,
256 "--", pos->second->GetHelp(),
257 max_len);
258 }
259
260 output_stream.PutCString("\nFor more help on any particular subcommand, type "
261 "'help <command> <subcommand>'.\n");
262}
263
265 auto arg0 = request.GetParsedLine()[0].ref();
266 if (request.GetCursorIndex() == 0) {
267 StringList new_matches, descriptions;
269 &descriptions);
270 request.AddCompletions(new_matches, descriptions);
271
272 if (new_matches.GetSize() == 1 &&
273 new_matches.GetStringAtIndex(0) != nullptr &&
274 (arg0 == new_matches.GetStringAtIndex(0))) {
275 StringList temp_matches;
276 CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches);
277 if (cmd_obj != nullptr) {
278 if (request.GetParsedLine().GetArgumentCount() != 1) {
279 request.GetParsedLine().Shift();
280 request.AppendEmptyArgument();
281 cmd_obj->HandleCompletion(request);
282 }
283 }
284 }
285 return;
286 }
287
288 StringList new_matches;
289 CommandObject *sub_command_object = GetSubcommandObject(arg0, &new_matches);
290
291 // The subcommand is ambiguous. The completion isn't meaningful.
292 if (!sub_command_object)
293 return;
294
295 // Remove the one match that we got from calling GetSubcommandObject.
296 new_matches.DeleteStringAtIndex(0);
297 request.AddCompletions(new_matches);
298 request.ShiftArguments();
299 sub_command_object->HandleCompletion(request);
300}
301
302std::optional<std::string>
304 uint32_t index) {
305 index++;
306 if (current_command_args.GetArgumentCount() <= index)
307 return std::nullopt;
308 CommandObject *sub_command_object =
309 GetSubcommandObject(current_command_args[index].ref());
310 if (sub_command_object == nullptr)
311 return std::nullopt;
312 return sub_command_object->GetRepeatCommand(current_command_args, index);
313}
314
316 const char *name, const char *help,
317 const char *syntax, uint32_t flags)
318 : CommandObject(interpreter, name, help, syntax, flags) {}
319
321
323 CommandObject *proxy_command = GetProxyCommandObject();
324 if (proxy_command)
325 return proxy_command->GetOptions();
327}
328
330 CommandObject *proxy_command = GetProxyCommandObject();
331 if (proxy_command)
332 return proxy_command->GetHelp();
333 return CommandObject::GetHelp();
334}
335
337 CommandObject *proxy_command = GetProxyCommandObject();
338 if (proxy_command)
339 return proxy_command->GetSyntax();
341}
342
344 CommandObject *proxy_command = GetProxyCommandObject();
345 if (proxy_command)
346 return proxy_command->GetHelpLong();
348}
349
351 const CommandObject *proxy_command =
352 const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
353 if (proxy_command)
354 return proxy_command->IsRemovable();
355 return false;
356}
357
359 CommandObject *proxy_command = GetProxyCommandObject();
360 if (proxy_command)
361 return proxy_command->IsMultiwordObject();
362 return false;
363}
364
366 CommandObject *proxy_command = GetProxyCommandObject();
367 if (proxy_command)
368 return proxy_command->GetAsMultiwordCommand();
369 return nullptr;
370}
371
373 CommandObject *proxy_command = GetProxyCommandObject();
374 if (proxy_command)
375 proxy_command->GenerateHelpText(result);
376 else
378}
379
382 StringList *matches) {
383 CommandObject *proxy_command = GetProxyCommandObject();
384 if (proxy_command)
385 return proxy_command->GetSubcommandSP(sub_cmd, matches);
386 return lldb::CommandObjectSP();
387}
388
390 StringList *matches) {
391 CommandObject *proxy_command = GetProxyCommandObject();
392 if (proxy_command)
393 return proxy_command->GetSubcommandObject(sub_cmd, matches);
394 return nullptr;
395}
396
398 llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) {
399 CommandObject *proxy_command = GetProxyCommandObject();
400 if (proxy_command)
401 return proxy_command->LoadSubCommand(cmd_name, command_sp);
402 return false;
403}
404
406 CommandObject *proxy_command = GetProxyCommandObject();
407 if (proxy_command)
408 return proxy_command->WantsRawCommandString();
409 return false;
410}
411
413 CommandObject *proxy_command = GetProxyCommandObject();
414 if (proxy_command)
415 return proxy_command->WantsCompletion();
416 return false;
417}
418
420 CommandObject *proxy_command = GetProxyCommandObject();
421 if (proxy_command)
422 proxy_command->HandleCompletion(request);
423}
424
426 CompletionRequest &request, OptionElementVector &opt_element_vector) {
427 CommandObject *proxy_command = GetProxyCommandObject();
428 if (proxy_command)
429 proxy_command->HandleArgumentCompletion(request, opt_element_vector);
430}
431
432std::optional<std::string>
434 uint32_t index) {
435 CommandObject *proxy_command = GetProxyCommandObject();
436 if (proxy_command)
437 return proxy_command->GetRepeatCommand(current_command_args, index);
438 return std::nullopt;
439}
440
442 return "command is not implemented";
443}
444
445void CommandObjectProxy::Execute(const char *args_string,
446 CommandReturnObject &result) {
447 if (CommandObject *proxy_command = GetProxyCommandObject())
448 proxy_command->Execute(args_string, result);
449 else
451}
#define lldbassert(x)
Definition LLDBAssert.h:16
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 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
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
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
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()
CommandObject(CommandInterpreter &interpreter, llvm::StringRef name, llvm::StringRef help="", llvm::StringRef syntax="", uint32_t flags=0)
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 AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
"lldb/Utility/ArgCompletionRequest.h"
void AddCompletions(const StringList &completions)
Adds multiple possible completion strings.
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)
const char * GetStringAtIndex(size_t idx) const
void DeleteStringAtIndex(size_t id)
A class that represents a running process on the host machine.
size_t FindLongestCommandWord(std::map< std::string, ValueType, std::less<> > &dict)
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)
std::shared_ptr< lldb_private::CommandObject > CommandObjectSP