1 //===-- CommandObjectMultiword.cpp ------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
12 // Other libraries and framework includes
14 #include "lldb/Interpreter/CommandObjectMultiword.h"
15 #include "lldb/Core/Debugger.h"
16 #include "lldb/Interpreter/CommandInterpreter.h"
17 #include "lldb/Interpreter/CommandReturnObject.h"
18 #include "lldb/Interpreter/Options.h"
21 using namespace lldb_private;
23 //-------------------------------------------------------------------------
24 // CommandObjectMultiword
25 //-------------------------------------------------------------------------
27 CommandObjectMultiword::CommandObjectMultiword(CommandInterpreter &interpreter,
32 : CommandObject(interpreter, name, help, syntax, flags),
33 m_can_be_removed(false) {}
35 CommandObjectMultiword::~CommandObjectMultiword() = default;
37 CommandObjectSP CommandObjectMultiword::GetSubcommandSP(llvm::StringRef sub_cmd,
38 StringList *matches) {
39 CommandObjectSP return_cmd_sp;
40 CommandObject::CommandMap::iterator pos;
42 if (!m_subcommand_dict.empty()) {
43 pos = m_subcommand_dict.find(sub_cmd);
44 if (pos != m_subcommand_dict.end()) {
45 // An exact match; append the sub_cmd to the 'matches' string list.
47 matches->AppendString(sub_cmd);
48 return_cmd_sp = pos->second;
50 StringList local_matches;
51 if (matches == nullptr)
52 matches = &local_matches;
54 AddNamesMatchingPartialString(m_subcommand_dict, sub_cmd, *matches);
56 if (num_matches == 1) {
57 // Cleaner, but slightly less efficient would be to call back into this
58 // function, since I now know I have an exact match...
60 sub_cmd = matches->GetStringAtIndex(0);
61 pos = m_subcommand_dict.find(sub_cmd);
62 if (pos != m_subcommand_dict.end())
63 return_cmd_sp = pos->second;
71 CommandObjectMultiword::GetSubcommandObject(llvm::StringRef sub_cmd,
72 StringList *matches) {
73 return GetSubcommandSP(sub_cmd, matches).get();
76 bool CommandObjectMultiword::LoadSubCommand(llvm::StringRef name,
77 const CommandObjectSP &cmd_obj) {
79 assert((&GetCommandInterpreter() == &cmd_obj->GetCommandInterpreter()) &&
80 "tried to add a CommandObject from a different interpreter");
82 CommandMap::iterator pos;
85 pos = m_subcommand_dict.find(name);
86 if (pos == m_subcommand_dict.end()) {
87 m_subcommand_dict[name] = cmd_obj;
94 bool CommandObjectMultiword::Execute(const char *args_string,
95 CommandReturnObject &result) {
96 Args args(args_string);
97 const size_t argc = args.GetArgumentCount();
99 this->CommandObject::GenerateHelpText(result);
100 return result.Succeeded();
103 auto sub_command = args[0].ref;
104 if (sub_command.empty())
105 return result.Succeeded();
107 if (sub_command.equals_lower("help")) {
108 this->CommandObject::GenerateHelpText(result);
109 return result.Succeeded();
112 if (m_subcommand_dict.empty()) {
113 result.AppendErrorWithFormat("'%s' does not have any subcommands.\n",
114 GetCommandName().str().c_str());
115 result.SetStatus(eReturnStatusFailed);
120 CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches);
121 if (sub_cmd_obj != nullptr) {
122 // Now call CommandObject::Execute to process options in `rest_of_line`.
123 // From there the command-specific version of Execute will be called, with
124 // the processed arguments.
127 sub_cmd_obj->Execute(args_string, result);
128 return result.Succeeded();
131 std::string error_msg;
132 const size_t num_subcmd_matches = matches.GetSize();
133 if (num_subcmd_matches > 0)
134 error_msg.assign("ambiguous command ");
136 error_msg.assign("invalid command ");
138 error_msg.append("'");
139 error_msg.append(GetCommandName());
140 error_msg.append(" ");
141 error_msg.append(sub_command);
142 error_msg.append("'.");
144 if (num_subcmd_matches > 0) {
145 error_msg.append(" Possible completions:");
146 for (size_t i = 0; i < matches.GetSize(); i++) {
147 error_msg.append("\n\t");
148 error_msg.append(matches.GetStringAtIndex(i));
151 error_msg.append("\n");
152 result.AppendRawError(error_msg.c_str());
153 result.SetStatus(eReturnStatusFailed);
157 void CommandObjectMultiword::GenerateHelpText(Stream &output_stream) {
158 // First time through here, generate the help text for the object and push it
159 // to the return result object as well
161 CommandObject::GenerateHelpText(output_stream);
162 output_stream.PutCString("\nThe following subcommands are supported:\n\n");
164 CommandMap::iterator pos;
165 uint32_t max_len = FindLongestCommandWord(m_subcommand_dict);
168 max_len += 4; // Indent the output by 4 spaces.
170 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) {
171 std::string indented_command(" ");
172 indented_command.append(pos->first);
173 if (pos->second->WantsRawCommandString()) {
174 std::string help_text(pos->second->GetHelp());
175 help_text.append(" Expects 'raw' input (see 'help raw-input'.)");
176 m_interpreter.OutputFormattedHelpText(output_stream,
177 indented_command.c_str(), "--",
178 help_text.c_str(), max_len);
180 m_interpreter.OutputFormattedHelpText(output_stream,
181 indented_command.c_str(), "--",
182 pos->second->GetHelp(), max_len);
185 output_stream.PutCString("\nFor more help on any particular subcommand, type "
186 "'help <command> <subcommand>'.\n");
189 int CommandObjectMultiword::HandleCompletion(CompletionRequest &request) {
190 // Any of the command matches will provide a complete word, otherwise the
191 // individual completers will override this.
192 request.SetWordComplete(true);
194 auto arg0 = request.GetParsedLine()[0].ref;
195 if (request.GetCursorIndex() == 0) {
196 StringList new_matches;
197 AddNamesMatchingPartialString(m_subcommand_dict, arg0, new_matches);
198 request.AddCompletions(new_matches);
200 if (new_matches.GetSize() == 1 &&
201 new_matches.GetStringAtIndex(0) != nullptr &&
202 (arg0 == new_matches.GetStringAtIndex(0))) {
203 StringList temp_matches;
204 CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches);
205 if (cmd_obj != nullptr) {
206 if (request.GetParsedLine().GetArgumentCount() == 1) {
207 request.SetWordComplete(true);
209 request.GetParsedLine().Shift();
210 request.SetCursorCharPosition(0);
211 request.GetParsedLine().AppendArgument(llvm::StringRef());
212 return cmd_obj->HandleCompletion(request);
216 return new_matches.GetSize();
218 StringList new_matches;
219 CommandObject *sub_command_object = GetSubcommandObject(arg0, &new_matches);
220 if (sub_command_object == nullptr) {
221 request.AddCompletions(new_matches);
222 return request.GetNumberOfMatches();
224 // Remove the one match that we got from calling GetSubcommandObject.
225 new_matches.DeleteStringAtIndex(0);
226 request.AddCompletions(new_matches);
227 request.GetParsedLine().Shift();
228 request.SetCursorIndex(request.GetCursorIndex() - 1);
229 return sub_command_object->HandleCompletion(request);
234 const char *CommandObjectMultiword::GetRepeatCommand(Args ¤t_command_args,
237 if (current_command_args.GetArgumentCount() <= index)
239 CommandObject *sub_command_object =
240 GetSubcommandObject(current_command_args[index].ref);
241 if (sub_command_object == nullptr)
243 return sub_command_object->GetRepeatCommand(current_command_args, index);
246 void CommandObjectMultiword::AproposAllSubCommands(llvm::StringRef prefix,
247 llvm::StringRef search_word,
248 StringList &commands_found,
249 StringList &commands_help) {
250 CommandObject::CommandMap::const_iterator pos;
252 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) {
253 const char *command_name = pos->first.c_str();
254 CommandObject *sub_cmd_obj = pos->second.get();
255 StreamString complete_command_name;
257 complete_command_name << prefix << " " << command_name;
259 if (sub_cmd_obj->HelpTextContainsWord(search_word)) {
260 commands_found.AppendString(complete_command_name.GetString());
261 commands_help.AppendString(sub_cmd_obj->GetHelp());
264 if (sub_cmd_obj->IsMultiwordObject())
265 sub_cmd_obj->AproposAllSubCommands(complete_command_name.GetString(),
266 search_word, commands_found,
271 CommandObjectProxy::CommandObjectProxy(CommandInterpreter &interpreter,
272 const char *name, const char *help,
273 const char *syntax, uint32_t flags)
274 : CommandObject(interpreter, name, help, syntax, flags) {}
276 CommandObjectProxy::~CommandObjectProxy() = default;
278 llvm::StringRef CommandObjectProxy::GetHelpLong() {
279 CommandObject *proxy_command = GetProxyCommandObject();
281 return proxy_command->GetHelpLong();
282 return llvm::StringRef();
285 bool CommandObjectProxy::IsRemovable() const {
286 const CommandObject *proxy_command =
287 const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
289 return proxy_command->IsRemovable();
293 bool CommandObjectProxy::IsMultiwordObject() {
294 CommandObject *proxy_command = GetProxyCommandObject();
296 return proxy_command->IsMultiwordObject();
300 CommandObjectMultiword *CommandObjectProxy::GetAsMultiwordCommand() {
301 CommandObject *proxy_command = GetProxyCommandObject();
303 return proxy_command->GetAsMultiwordCommand();
307 void CommandObjectProxy::GenerateHelpText(Stream &result) {
308 CommandObject *proxy_command = GetProxyCommandObject();
310 return proxy_command->GenerateHelpText(result);
313 lldb::CommandObjectSP
314 CommandObjectProxy::GetSubcommandSP(llvm::StringRef sub_cmd,
315 StringList *matches) {
316 CommandObject *proxy_command = GetProxyCommandObject();
318 return proxy_command->GetSubcommandSP(sub_cmd, matches);
319 return lldb::CommandObjectSP();
322 CommandObject *CommandObjectProxy::GetSubcommandObject(llvm::StringRef sub_cmd,
323 StringList *matches) {
324 CommandObject *proxy_command = GetProxyCommandObject();
326 return proxy_command->GetSubcommandObject(sub_cmd, matches);
330 void CommandObjectProxy::AproposAllSubCommands(llvm::StringRef prefix,
331 llvm::StringRef search_word,
332 StringList &commands_found,
333 StringList &commands_help) {
334 CommandObject *proxy_command = GetProxyCommandObject();
336 return proxy_command->AproposAllSubCommands(prefix, search_word,
337 commands_found, commands_help);
340 bool CommandObjectProxy::LoadSubCommand(
341 llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) {
342 CommandObject *proxy_command = GetProxyCommandObject();
344 return proxy_command->LoadSubCommand(cmd_name, command_sp);
348 bool CommandObjectProxy::WantsRawCommandString() {
349 CommandObject *proxy_command = GetProxyCommandObject();
351 return proxy_command->WantsRawCommandString();
355 bool CommandObjectProxy::WantsCompletion() {
356 CommandObject *proxy_command = GetProxyCommandObject();
358 return proxy_command->WantsCompletion();
362 Options *CommandObjectProxy::GetOptions() {
363 CommandObject *proxy_command = GetProxyCommandObject();
365 return proxy_command->GetOptions();
369 int CommandObjectProxy::HandleCompletion(CompletionRequest &request) {
370 CommandObject *proxy_command = GetProxyCommandObject();
372 return proxy_command->HandleCompletion(request);
376 int CommandObjectProxy::HandleArgumentCompletion(
377 CompletionRequest &request, OptionElementVector &opt_element_vector) {
378 CommandObject *proxy_command = GetProxyCommandObject();
380 return proxy_command->HandleArgumentCompletion(request, opt_element_vector);
384 const char *CommandObjectProxy::GetRepeatCommand(Args ¤t_command_args,
386 CommandObject *proxy_command = GetProxyCommandObject();
388 return proxy_command->GetRepeatCommand(current_command_args, index);
392 bool CommandObjectProxy::Execute(const char *args_string,
393 CommandReturnObject &result) {
394 CommandObject *proxy_command = GetProxyCommandObject();
396 return proxy_command->Execute(args_string, result);
397 result.AppendError("command is not implemented");
398 result.SetStatus(eReturnStatusFailed);