LLDB  mainline
CommandObjectMultiword.cpp
Go to the documentation of this file.
1 //===-- CommandObjectMultiword.cpp ------------------------------*- C++ -*-===//
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 
10 #include "lldb/Core/Debugger.h"
14 
15 using namespace lldb;
16 using namespace lldb_private;
17 
18 // CommandObjectMultiword
19 
20 CommandObjectMultiword::CommandObjectMultiword(CommandInterpreter &interpreter,
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 
30 CommandObjectSP CommandObjectMultiword::GetSubcommandSP(llvm::StringRef sub_cmd,
31  StringList *matches) {
32  CommandObjectSP return_cmd_sp;
33  CommandObject::CommandMap::iterator pos;
34 
35  if (!m_subcommand_dict.empty()) {
36  pos = m_subcommand_dict.find(sub_cmd);
37  if (pos != m_subcommand_dict.end()) {
38  // An exact match; append the sub_cmd to the 'matches' string list.
39  if (matches)
40  matches->AppendString(sub_cmd);
41  return_cmd_sp = pos->second;
42  } else {
43  StringList local_matches;
44  if (matches == nullptr)
45  matches = &local_matches;
46  int num_matches =
48 
49  if (num_matches == 1) {
50  // Cleaner, but slightly less efficient would be to call back into this
51  // function, since I now know I have an exact match...
52 
53  sub_cmd = matches->GetStringAtIndex(0);
54  pos = m_subcommand_dict.find(sub_cmd);
55  if (pos != m_subcommand_dict.end())
56  return_cmd_sp = pos->second;
57  }
58  }
59  }
60  return return_cmd_sp;
61 }
62 
65  StringList *matches) {
66  return GetSubcommandSP(sub_cmd, matches).get();
67 }
68 
69 bool CommandObjectMultiword::LoadSubCommand(llvm::StringRef name,
70  const CommandObjectSP &cmd_obj) {
71  if (cmd_obj)
72  assert((&GetCommandInterpreter() == &cmd_obj->GetCommandInterpreter()) &&
73  "tried to add a CommandObject from a different interpreter");
74 
75  CommandMap::iterator pos;
76  bool success = true;
77 
78  pos = m_subcommand_dict.find(name);
79  if (pos == m_subcommand_dict.end()) {
80  m_subcommand_dict[name] = cmd_obj;
81  } else
82  success = false;
83 
84  return success;
85 }
86 
87 bool CommandObjectMultiword::Execute(const char *args_string,
88  CommandReturnObject &result) {
89  Args args(args_string);
90  const size_t argc = args.GetArgumentCount();
91  if (argc == 0) {
92  this->CommandObject::GenerateHelpText(result);
93  return result.Succeeded();
94  }
95 
96  auto sub_command = args[0].ref;
97  if (sub_command.empty())
98  return result.Succeeded();
99 
100  if (sub_command.equals_lower("help")) {
101  this->CommandObject::GenerateHelpText(result);
102  return result.Succeeded();
103  }
104 
105  if (m_subcommand_dict.empty()) {
106  result.AppendErrorWithFormat("'%s' does not have any subcommands.\n",
107  GetCommandName().str().c_str());
109  return false;
110  }
111 
112  StringList matches;
113  CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches);
114  if (sub_cmd_obj != nullptr) {
115  // Now call CommandObject::Execute to process options in `rest_of_line`.
116  // From there the command-specific version of Execute will be called, with
117  // the processed arguments.
118 
119  args.Shift();
120  sub_cmd_obj->Execute(args_string, result);
121  return result.Succeeded();
122  }
123 
124  std::string error_msg;
125  const size_t num_subcmd_matches = matches.GetSize();
126  if (num_subcmd_matches > 0)
127  error_msg.assign("ambiguous command ");
128  else
129  error_msg.assign("invalid command ");
130 
131  error_msg.append("'");
132  error_msg.append(GetCommandName());
133  error_msg.append(" ");
134  error_msg.append(sub_command);
135  error_msg.append("'.");
136 
137  if (num_subcmd_matches > 0) {
138  error_msg.append(" Possible completions:");
139  for (size_t i = 0; i < matches.GetSize(); i++) {
140  error_msg.append("\n\t");
141  error_msg.append(matches.GetStringAtIndex(i));
142  }
143  }
144  error_msg.append("\n");
145  result.AppendRawError(error_msg.c_str());
147  return false;
148 }
149 
151  // First time through here, generate the help text for the object and push it
152  // to the return result object as well
153 
154  CommandObject::GenerateHelpText(output_stream);
155  output_stream.PutCString("\nThe following subcommands are supported:\n\n");
156 
157  CommandMap::iterator pos;
159 
160  if (max_len)
161  max_len += 4; // Indent the output by 4 spaces.
162 
163  for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) {
164  std::string indented_command(" ");
165  indented_command.append(pos->first);
166  if (pos->second->WantsRawCommandString()) {
167  std::string help_text(pos->second->GetHelp());
168  help_text.append(" Expects 'raw' input (see 'help raw-input'.)");
170  indented_command.c_str(), "--",
171  help_text.c_str(), max_len);
172  } else
174  indented_command.c_str(), "--",
175  pos->second->GetHelp(), max_len);
176  }
177 
178  output_stream.PutCString("\nFor more help on any particular subcommand, type "
179  "'help <command> <subcommand>'.\n");
180 }
181 
183  // Any of the command matches will provide a complete word, otherwise the
184  // individual completers will override this.
185  request.SetWordComplete(true);
186 
187  auto arg0 = request.GetParsedLine()[0].ref;
188  if (request.GetCursorIndex() == 0) {
189  StringList new_matches, descriptions;
191  &descriptions);
192  request.AddCompletions(new_matches, descriptions);
193 
194  if (new_matches.GetSize() == 1 &&
195  new_matches.GetStringAtIndex(0) != nullptr &&
196  (arg0 == new_matches.GetStringAtIndex(0))) {
197  StringList temp_matches;
198  CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches);
199  if (cmd_obj != nullptr) {
200  if (request.GetParsedLine().GetArgumentCount() == 1) {
201  request.SetWordComplete(true);
202  } else {
203  request.GetParsedLine().Shift();
204  request.SetCursorCharPosition(0);
205  request.GetParsedLine().AppendArgument(llvm::StringRef());
206  return cmd_obj->HandleCompletion(request);
207  }
208  }
209  }
210  return new_matches.GetSize();
211  } else {
212  StringList new_matches;
213  CommandObject *sub_command_object = GetSubcommandObject(arg0, &new_matches);
214  if (sub_command_object == nullptr) {
215  request.AddCompletions(new_matches);
216  return request.GetNumberOfMatches();
217  } else {
218  // Remove the one match that we got from calling GetSubcommandObject.
219  new_matches.DeleteStringAtIndex(0);
220  request.AddCompletions(new_matches);
221  request.GetParsedLine().Shift();
222  request.SetCursorIndex(request.GetCursorIndex() - 1);
223  return sub_command_object->HandleCompletion(request);
224  }
225  }
226 }
227 
228 const char *CommandObjectMultiword::GetRepeatCommand(Args &current_command_args,
229  uint32_t index) {
230  index++;
231  if (current_command_args.GetArgumentCount() <= index)
232  return nullptr;
233  CommandObject *sub_command_object =
234  GetSubcommandObject(current_command_args[index].ref);
235  if (sub_command_object == nullptr)
236  return nullptr;
237  return sub_command_object->GetRepeatCommand(current_command_args, index);
238 }
239 
241  llvm::StringRef search_word,
242  StringList &commands_found,
243  StringList &commands_help) {
244  CommandObject::CommandMap::const_iterator pos;
245 
246  for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) {
247  const char *command_name = pos->first.c_str();
248  CommandObject *sub_cmd_obj = pos->second.get();
249  StreamString complete_command_name;
250 
251  complete_command_name << prefix << " " << command_name;
252 
253  if (sub_cmd_obj->HelpTextContainsWord(search_word)) {
254  commands_found.AppendString(complete_command_name.GetString());
255  commands_help.AppendString(sub_cmd_obj->GetHelp());
256  }
257 
258  if (sub_cmd_obj->IsMultiwordObject())
259  sub_cmd_obj->AproposAllSubCommands(complete_command_name.GetString(),
260  search_word, commands_found,
261  commands_help);
262  }
263 }
264 
266  const char *name, const char *help,
267  const char *syntax, uint32_t flags)
268  : CommandObject(interpreter, name, help, syntax, flags) {}
269 
271 
273  CommandObject *proxy_command = GetProxyCommandObject();
274  if (proxy_command)
275  return proxy_command->GetHelpLong();
276  return llvm::StringRef();
277 }
278 
280  const CommandObject *proxy_command =
281  const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
282  if (proxy_command)
283  return proxy_command->IsRemovable();
284  return false;
285 }
286 
288  CommandObject *proxy_command = GetProxyCommandObject();
289  if (proxy_command)
290  return proxy_command->IsMultiwordObject();
291  return false;
292 }
293 
295  CommandObject *proxy_command = GetProxyCommandObject();
296  if (proxy_command)
297  return proxy_command->GetAsMultiwordCommand();
298  return nullptr;
299 }
300 
302  CommandObject *proxy_command = GetProxyCommandObject();
303  if (proxy_command)
304  return proxy_command->GenerateHelpText(result);
305 }
306 
307 lldb::CommandObjectSP
308 CommandObjectProxy::GetSubcommandSP(llvm::StringRef sub_cmd,
309  StringList *matches) {
310  CommandObject *proxy_command = GetProxyCommandObject();
311  if (proxy_command)
312  return proxy_command->GetSubcommandSP(sub_cmd, matches);
313  return lldb::CommandObjectSP();
314 }
315 
317  StringList *matches) {
318  CommandObject *proxy_command = GetProxyCommandObject();
319  if (proxy_command)
320  return proxy_command->GetSubcommandObject(sub_cmd, matches);
321  return nullptr;
322 }
323 
324 void CommandObjectProxy::AproposAllSubCommands(llvm::StringRef prefix,
325  llvm::StringRef search_word,
326  StringList &commands_found,
327  StringList &commands_help) {
328  CommandObject *proxy_command = GetProxyCommandObject();
329  if (proxy_command)
330  return proxy_command->AproposAllSubCommands(prefix, search_word,
331  commands_found, commands_help);
332 }
333 
335  llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) {
336  CommandObject *proxy_command = GetProxyCommandObject();
337  if (proxy_command)
338  return proxy_command->LoadSubCommand(cmd_name, command_sp);
339  return false;
340 }
341 
343  CommandObject *proxy_command = GetProxyCommandObject();
344  if (proxy_command)
345  return proxy_command->WantsRawCommandString();
346  return false;
347 }
348 
350  CommandObject *proxy_command = GetProxyCommandObject();
351  if (proxy_command)
352  return proxy_command->WantsCompletion();
353  return false;
354 }
355 
357  CommandObject *proxy_command = GetProxyCommandObject();
358  if (proxy_command)
359  return proxy_command->GetOptions();
360  return nullptr;
361 }
362 
364  CommandObject *proxy_command = GetProxyCommandObject();
365  if (proxy_command)
366  return proxy_command->HandleCompletion(request);
367  return 0;
368 }
369 
371  CompletionRequest &request, OptionElementVector &opt_element_vector) {
372  CommandObject *proxy_command = GetProxyCommandObject();
373  if (proxy_command)
374  return proxy_command->HandleArgumentCompletion(request, opt_element_vector);
375  return 0;
376 }
377 
378 const char *CommandObjectProxy::GetRepeatCommand(Args &current_command_args,
379  uint32_t index) {
380  CommandObject *proxy_command = GetProxyCommandObject();
381  if (proxy_command)
382  return proxy_command->GetRepeatCommand(current_command_args, index);
383  return nullptr;
384 }
385 
386 bool CommandObjectProxy::Execute(const char *args_string,
387  CommandReturnObject &result) {
388  CommandObject *proxy_command = GetProxyCommandObject();
389  if (proxy_command)
390  return proxy_command->Execute(args_string, result);
391  result.AppendError("command is not implemented");
393  return false;
394 }
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:61
bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj) override
A command line argument class.
Definition: Args.h:32
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
void Shift()
Shifts the first argument C string value of the array off the argument array.
Definition: Args.cpp:284
CommandInterpreter & m_interpreter
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
void AproposAllSubCommands(llvm::StringRef prefix, llvm::StringRef search_word, StringList &commands_found, StringList &commands_help) override
virtual llvm::StringRef GetHelpLong()
bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj) override
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition: Args.cpp:254
virtual bool WantsCompletion()
virtual const char * GetRepeatCommand(Args &current_command_args, uint32_t index)
Get the command that appropriate for a "repeat" of the current command.
void AddCompletions(const StringList &completions)
Adds multiple possible completion strings.
std::size_t GetNumberOfMatches() const
lldb::CommandObjectSP GetSubcommandSP(llvm::StringRef sub_cmd, StringList *matches=nullptr) override
void AppendRawError(llvm::StringRef in_string)
const char * GetRepeatCommand(Args &current_command_args, uint32_t index) override
Get the command that appropriate for a "repeat" of the current command.
virtual int HandleCompletion(CompletionRequest &request)
This default version handles calling option argument completions and then calls HandleArgumentComplet...
"lldb/Utility/ArgCompletionRequest.h"
std::vector< OptionArgElement > OptionElementVector
Definition: Options.h:41
virtual bool IsRemovable() const
CommandObjectProxy(CommandInterpreter &interpreter, const char *name, const char *help=nullptr, const char *syntax=nullptr, uint32_t flags=0)
int HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The input array contains a parsed version of the line.
int HandleCompletion(CompletionRequest &request) override
This default version handles calling option argument completions and then calls HandleArgumentComplet...
virtual lldb::CommandObjectSP GetSubcommandSP(llvm::StringRef sub_cmd, StringList *matches=nullptr)
virtual bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj)
virtual CommandObjectMultiword * GetAsMultiwordCommand()
virtual bool Execute(const char *args_string, CommandReturnObject &result)=0
const char * GetStringAtIndex(size_t idx) const
Definition: StringList.cpp:82
int HandleCompletion(CompletionRequest &request) override
This default version handles calling option argument completions and then calls HandleArgumentComplet...
bool Execute(const char *args_string, CommandReturnObject &result) override
virtual bool IsMultiwordObject()
virtual bool WantsRawCommandString()=0
llvm::StringRef GetString() const
lldb::CommandObjectSP GetSubcommandSP(llvm::StringRef sub_cmd, StringList *matches=nullptr) override
void GenerateHelpText(Stream &output_stream) override
void OutputFormattedHelpText(Stream &strm, llvm::StringRef prefix, llvm::StringRef help_text)
virtual Options * GetOptions()
void DeleteStringAtIndex(size_t id)
Definition: StringList.cpp:144
size_t GetSize() const
Definition: StringList.cpp:70
void GenerateHelpText(Stream &result) override
CommandObject * GetSubcommandObject(llvm::StringRef sub_cmd, StringList *matches=nullptr) override
CommandObject::CommandMap m_subcommand_dict
A command line option parsing protocol class.
Definition: Options.h:62
CommandInterpreter & GetCommandInterpreter()
llvm::StringRef GetHelpLong() override
int AddNamesMatchingPartialString(const std::map< std::string, ValueType > &in_map, llvm::StringRef cmd_str, StringList &matches, StringList *descriptions=nullptr)
Definition: CommandObject.h:35
void void AppendError(llvm::StringRef in_string)
virtual void AproposAllSubCommands(llvm::StringRef prefix, llvm::StringRef search_word, StringList &commands_found, StringList &commands_help)
Definition: SBAddress.h:15
void AppendArgument(llvm::StringRef arg_str, char quote_char='\0')
Appends a new argument to the end of the list argument list.
Definition: Args.cpp:321
virtual int HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector)
The input array contains a parsed version of the line.
CommandObject * GetSubcommandObject(llvm::StringRef sub_cmd, StringList *matches=nullptr) override
virtual CommandObject * GetProxyCommandObject()=0
bool HelpTextContainsWord(llvm::StringRef search_word, bool search_short_help=true, bool search_long_help=true, bool search_syntax=true, bool search_options=true)
const Args & GetParsedLine() const
size_t FindLongestCommandWord(std::map< std::string, ValueType > &dict)
Definition: CommandObject.h:55
virtual CommandObject * GetSubcommandObject(llvm::StringRef sub_cmd, StringList *matches=nullptr)
const char * GetRepeatCommand(Args &current_command_args, uint32_t index) override
Get the command that appropriate for a "repeat" of the current command.
CommandObjectMultiword * GetAsMultiwordCommand() override
void AproposAllSubCommands(llvm::StringRef prefix, llvm::StringRef search_word, StringList &commands_found, StringList &commands_help) override
void AppendString(const std::string &s)
Definition: StringList.cpp:43
virtual llvm::StringRef GetHelp()
llvm::StringRef GetCommandName() const
void SetStatus(lldb::ReturnStatus status)
bool Execute(const char *args_string, CommandReturnObject &result) override
void GenerateHelpText(CommandReturnObject &result)