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(std::string(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(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
162void 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;
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;
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;
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;
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}
218
220 // First time through here, generate the help text for the object and push it
221 // to the return result object as well
222
223 CommandObject::GenerateHelpText(output_stream);
224 output_stream.PutCString("\nThe following subcommands are supported:\n\n");
225
226 CommandMap::iterator pos;
227 uint32_t max_len = FindLongestCommandWord(m_subcommand_dict);
228
229 if (max_len)
230 max_len += 4; // Indent the output by 4 spaces.
231
232 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) {
233 std::string indented_command(" ");
234 indented_command.append(pos->first);
235 if (pos->second->WantsRawCommandString()) {
236 std::string help_text(std::string(pos->second->GetHelp()));
237 help_text.append(" Expects 'raw' input (see 'help raw-input'.)");
238 m_interpreter.OutputFormattedHelpText(output_stream, indented_command,
239 "--", help_text, max_len);
240 } else
241 m_interpreter.OutputFormattedHelpText(output_stream, indented_command,
242 "--", pos->second->GetHelp(),
243 max_len);
244 }
245
246 output_stream.PutCString("\nFor more help on any particular subcommand, type "
247 "'help <command> <subcommand>'.\n");
248}
249
251 auto arg0 = request.GetParsedLine()[0].ref();
252 if (request.GetCursorIndex() == 0) {
253 StringList new_matches, descriptions;
255 &descriptions);
256 request.AddCompletions(new_matches, descriptions);
257
258 if (new_matches.GetSize() == 1 &&
259 new_matches.GetStringAtIndex(0) != nullptr &&
260 (arg0 == new_matches.GetStringAtIndex(0))) {
261 StringList temp_matches;
262 CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches);
263 if (cmd_obj != nullptr) {
264 if (request.GetParsedLine().GetArgumentCount() != 1) {
265 request.GetParsedLine().Shift();
266 request.AppendEmptyArgument();
267 cmd_obj->HandleCompletion(request);
268 }
269 }
270 }
271 return;
272 }
273
274 StringList new_matches;
275 CommandObject *sub_command_object = GetSubcommandObject(arg0, &new_matches);
276
277 // The subcommand is ambiguous. The completion isn't meaningful.
278 if (!sub_command_object)
279 return;
280
281 // Remove the one match that we got from calling GetSubcommandObject.
282 new_matches.DeleteStringAtIndex(0);
283 request.AddCompletions(new_matches);
284 request.ShiftArguments();
285 sub_command_object->HandleCompletion(request);
286}
287
288std::optional<std::string>
290 uint32_t index) {
291 index++;
292 if (current_command_args.GetArgumentCount() <= index)
293 return std::nullopt;
294 CommandObject *sub_command_object =
295 GetSubcommandObject(current_command_args[index].ref());
296 if (sub_command_object == nullptr)
297 return std::nullopt;
298 return sub_command_object->GetRepeatCommand(current_command_args, index);
299}
300
302 const char *name, const char *help,
303 const char *syntax, uint32_t flags)
304 : CommandObject(interpreter, name, help, syntax, flags) {}
305
307
309 CommandObject *proxy_command = GetProxyCommandObject();
310 if (proxy_command)
311 return proxy_command->GetOptions();
313}
314
316 CommandObject *proxy_command = GetProxyCommandObject();
317 if (proxy_command)
318 return proxy_command->GetHelp();
319 return CommandObject::GetHelp();
320}
321
323 CommandObject *proxy_command = GetProxyCommandObject();
324 if (proxy_command)
325 return proxy_command->GetSyntax();
327}
328
330 CommandObject *proxy_command = GetProxyCommandObject();
331 if (proxy_command)
332 return proxy_command->GetHelpLong();
334}
335
337 const CommandObject *proxy_command =
338 const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
339 if (proxy_command)
340 return proxy_command->IsRemovable();
341 return false;
342}
343
345 CommandObject *proxy_command = GetProxyCommandObject();
346 if (proxy_command)
347 return proxy_command->IsMultiwordObject();
348 return false;
349}
350
352 CommandObject *proxy_command = GetProxyCommandObject();
353 if (proxy_command)
354 return proxy_command->GetAsMultiwordCommand();
355 return nullptr;
356}
357
359 CommandObject *proxy_command = GetProxyCommandObject();
360 if (proxy_command)
361 proxy_command->GenerateHelpText(result);
362 else
364}
365
368 StringList *matches) {
369 CommandObject *proxy_command = GetProxyCommandObject();
370 if (proxy_command)
371 return proxy_command->GetSubcommandSP(sub_cmd, matches);
372 return lldb::CommandObjectSP();
373}
374
376 StringList *matches) {
377 CommandObject *proxy_command = GetProxyCommandObject();
378 if (proxy_command)
379 return proxy_command->GetSubcommandObject(sub_cmd, matches);
380 return nullptr;
381}
382
384 llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) {
385 CommandObject *proxy_command = GetProxyCommandObject();
386 if (proxy_command)
387 return proxy_command->LoadSubCommand(cmd_name, command_sp);
388 return false;
389}
390
392 CommandObject *proxy_command = GetProxyCommandObject();
393 if (proxy_command)
394 return proxy_command->WantsRawCommandString();
395 return false;
396}
397
399 CommandObject *proxy_command = GetProxyCommandObject();
400 if (proxy_command)
401 return proxy_command->WantsCompletion();
402 return false;
403}
404
406 CommandObject *proxy_command = GetProxyCommandObject();
407 if (proxy_command)
408 proxy_command->HandleCompletion(request);
409}
410
412 CompletionRequest &request, OptionElementVector &opt_element_vector) {
413 CommandObject *proxy_command = GetProxyCommandObject();
414 if (proxy_command)
415 proxy_command->HandleArgumentCompletion(request, opt_element_vector);
416}
417
418std::optional<std::string>
420 uint32_t index) {
421 CommandObject *proxy_command = GetProxyCommandObject();
422 if (proxy_command)
423 return proxy_command->GetRepeatCommand(current_command_args, index);
424 return std::nullopt;
425}
426
428 return "command is not implemented";
429}
430
431void CommandObjectProxy::Execute(const char *args_string,
432 CommandReturnObject &result) {
433 if (CommandObject *proxy_command = GetProxyCommandObject())
434 proxy_command->Execute(args_string, result);
435 else
437}
#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: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)
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: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: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.
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
std::shared_ptr< lldb_private::CommandObject > CommandObjectSP
Definition: lldb-forward.h:331