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
59 // know I have an exact match...
61 sub_cmd = matches->GetStringAtIndex(0);
62 pos = m_subcommand_dict.find(sub_cmd);
63 if (pos != m_subcommand_dict.end())
64 return_cmd_sp = pos->second;
72 CommandObjectMultiword::GetSubcommandObject(llvm::StringRef sub_cmd,
73 StringList *matches) {
74 return GetSubcommandSP(sub_cmd, matches).get();
77 bool CommandObjectMultiword::LoadSubCommand(llvm::StringRef name,
78 const CommandObjectSP &cmd_obj) {
80 assert((&GetCommandInterpreter() == &cmd_obj->GetCommandInterpreter()) &&
81 "tried to add a CommandObject from a different interpreter");
83 CommandMap::iterator pos;
86 pos = m_subcommand_dict.find(name);
87 if (pos == m_subcommand_dict.end()) {
88 m_subcommand_dict[name] = cmd_obj;
95 bool CommandObjectMultiword::Execute(const char *args_string,
96 CommandReturnObject &result) {
97 Args args(args_string);
98 const size_t argc = args.GetArgumentCount();
100 this->CommandObject::GenerateHelpText(result);
101 return result.Succeeded();
104 auto sub_command = args[0].ref;
105 if (sub_command.empty())
106 return result.Succeeded();
108 if (sub_command.equals_lower("help")) {
109 this->CommandObject::GenerateHelpText(result);
110 return result.Succeeded();
113 if (m_subcommand_dict.empty()) {
114 result.AppendErrorWithFormat("'%s' does not have any subcommands.\n",
115 GetCommandName().str().c_str());
116 result.SetStatus(eReturnStatusFailed);
121 CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches);
122 if (sub_cmd_obj != nullptr) {
123 // Now call CommandObject::Execute to process options in `rest_of_line`.
124 // From there the command-specific version of Execute will be called,
125 // with the processed arguments.
128 sub_cmd_obj->Execute(args_string, result);
129 return result.Succeeded();
132 std::string error_msg;
133 const size_t num_subcmd_matches = matches.GetSize();
134 if (num_subcmd_matches > 0)
135 error_msg.assign("ambiguous command ");
137 error_msg.assign("invalid command ");
139 error_msg.append("'");
140 error_msg.append(GetCommandName());
141 error_msg.append(" ");
142 error_msg.append(sub_command);
143 error_msg.append("'.");
145 if (num_subcmd_matches > 0) {
146 error_msg.append(" Possible completions:");
147 for (size_t i = 0; i < num_subcmd_matches; i++) {
148 error_msg.append("\n\t");
149 error_msg.append(matches.GetStringAtIndex(i));
152 error_msg.append("\n");
153 result.AppendRawError(error_msg.c_str());
154 result.SetStatus(eReturnStatusFailed);
158 void CommandObjectMultiword::GenerateHelpText(Stream &output_stream) {
159 // First time through here, generate the help text for the object and
160 // push it to the return result object as well
162 CommandObject::GenerateHelpText(output_stream);
163 output_stream.PutCString("\nThe following subcommands are supported:\n\n");
165 CommandMap::iterator pos;
166 uint32_t max_len = FindLongestCommandWord(m_subcommand_dict);
169 max_len += 4; // Indent the output by 4 spaces.
171 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) {
172 std::string indented_command(" ");
173 indented_command.append(pos->first);
174 if (pos->second->WantsRawCommandString()) {
175 std::string help_text(pos->second->GetHelp());
176 help_text.append(" Expects 'raw' input (see 'help raw-input'.)");
177 m_interpreter.OutputFormattedHelpText(output_stream,
178 indented_command.c_str(), "--",
179 help_text.c_str(), max_len);
181 m_interpreter.OutputFormattedHelpText(output_stream,
182 indented_command.c_str(), "--",
183 pos->second->GetHelp(), max_len);
186 output_stream.PutCString("\nFor more help on any particular subcommand, type "
187 "'help <command> <subcommand>'.\n");
190 int CommandObjectMultiword::HandleCompletion(Args &input, int &cursor_index,
191 int &cursor_char_position,
192 int match_start_point,
193 int max_return_elements,
195 StringList &matches) {
196 // Any of the command matches will provide a complete word, otherwise the
197 // individual completers will override this.
198 word_complete = true;
200 auto arg0 = input[0].ref;
201 if (cursor_index == 0) {
202 AddNamesMatchingPartialString(m_subcommand_dict, arg0, matches);
204 if (matches.GetSize() == 1 && matches.GetStringAtIndex(0) != nullptr &&
205 (arg0 == matches.GetStringAtIndex(0))) {
206 StringList temp_matches;
207 CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches);
208 if (cmd_obj != nullptr) {
209 if (input.GetArgumentCount() == 1) {
210 word_complete = true;
212 matches.DeleteStringAtIndex(0);
214 cursor_char_position = 0;
215 input.AppendArgument(llvm::StringRef());
216 return cmd_obj->HandleCompletion(
217 input, cursor_index, cursor_char_position, match_start_point,
218 max_return_elements, word_complete, matches);
222 return matches.GetSize();
224 CommandObject *sub_command_object = GetSubcommandObject(arg0, &matches);
225 if (sub_command_object == nullptr) {
226 return matches.GetSize();
228 // Remove the one match that we got from calling GetSubcommandObject.
229 matches.DeleteStringAtIndex(0);
232 return sub_command_object->HandleCompletion(
233 input, cursor_index, cursor_char_position, match_start_point,
234 max_return_elements, word_complete, matches);
239 const char *CommandObjectMultiword::GetRepeatCommand(Args ¤t_command_args,
242 if (current_command_args.GetArgumentCount() <= index)
244 CommandObject *sub_command_object =
245 GetSubcommandObject(current_command_args[index].ref);
246 if (sub_command_object == nullptr)
248 return sub_command_object->GetRepeatCommand(current_command_args, index);
251 void CommandObjectMultiword::AproposAllSubCommands(llvm::StringRef prefix,
252 llvm::StringRef search_word,
253 StringList &commands_found,
254 StringList &commands_help) {
255 CommandObject::CommandMap::const_iterator pos;
257 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) {
258 const char *command_name = pos->first.c_str();
259 CommandObject *sub_cmd_obj = pos->second.get();
260 StreamString complete_command_name;
262 complete_command_name << prefix << " " << command_name;
264 if (sub_cmd_obj->HelpTextContainsWord(search_word)) {
265 commands_found.AppendString(complete_command_name.GetString());
266 commands_help.AppendString(sub_cmd_obj->GetHelp());
269 if (sub_cmd_obj->IsMultiwordObject())
270 sub_cmd_obj->AproposAllSubCommands(complete_command_name.GetString(),
271 search_word, commands_found,
276 CommandObjectProxy::CommandObjectProxy(CommandInterpreter &interpreter,
277 const char *name, const char *help,
278 const char *syntax, uint32_t flags)
279 : CommandObject(interpreter, name, help, syntax, flags) {}
281 CommandObjectProxy::~CommandObjectProxy() = default;
283 llvm::StringRef CommandObjectProxy::GetHelpLong() {
284 CommandObject *proxy_command = GetProxyCommandObject();
286 return proxy_command->GetHelpLong();
287 return llvm::StringRef();
290 bool CommandObjectProxy::IsRemovable() const {
291 const CommandObject *proxy_command =
292 const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
294 return proxy_command->IsRemovable();
298 bool CommandObjectProxy::IsMultiwordObject() {
299 CommandObject *proxy_command = GetProxyCommandObject();
301 return proxy_command->IsMultiwordObject();
305 CommandObjectMultiword *CommandObjectProxy::GetAsMultiwordCommand() {
306 CommandObject *proxy_command = GetProxyCommandObject();
308 return proxy_command->GetAsMultiwordCommand();
312 void CommandObjectProxy::GenerateHelpText(Stream &result) {
313 CommandObject *proxy_command = GetProxyCommandObject();
315 return proxy_command->GenerateHelpText(result);
318 lldb::CommandObjectSP
319 CommandObjectProxy::GetSubcommandSP(llvm::StringRef sub_cmd,
320 StringList *matches) {
321 CommandObject *proxy_command = GetProxyCommandObject();
323 return proxy_command->GetSubcommandSP(sub_cmd, matches);
324 return lldb::CommandObjectSP();
327 CommandObject *CommandObjectProxy::GetSubcommandObject(llvm::StringRef sub_cmd,
328 StringList *matches) {
329 CommandObject *proxy_command = GetProxyCommandObject();
331 return proxy_command->GetSubcommandObject(sub_cmd, matches);
335 void CommandObjectProxy::AproposAllSubCommands(llvm::StringRef prefix,
336 llvm::StringRef search_word,
337 StringList &commands_found,
338 StringList &commands_help) {
339 CommandObject *proxy_command = GetProxyCommandObject();
341 return proxy_command->AproposAllSubCommands(prefix, search_word,
342 commands_found, commands_help);
345 bool CommandObjectProxy::LoadSubCommand(
346 llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) {
347 CommandObject *proxy_command = GetProxyCommandObject();
349 return proxy_command->LoadSubCommand(cmd_name, command_sp);
353 bool CommandObjectProxy::WantsRawCommandString() {
354 CommandObject *proxy_command = GetProxyCommandObject();
356 return proxy_command->WantsRawCommandString();
360 bool CommandObjectProxy::WantsCompletion() {
361 CommandObject *proxy_command = GetProxyCommandObject();
363 return proxy_command->WantsCompletion();
367 Options *CommandObjectProxy::GetOptions() {
368 CommandObject *proxy_command = GetProxyCommandObject();
370 return proxy_command->GetOptions();
374 int CommandObjectProxy::HandleCompletion(Args &input, int &cursor_index,
375 int &cursor_char_position,
376 int match_start_point,
377 int max_return_elements,
379 StringList &matches) {
380 CommandObject *proxy_command = GetProxyCommandObject();
382 return proxy_command->HandleCompletion(
383 input, cursor_index, cursor_char_position, match_start_point,
384 max_return_elements, word_complete, matches);
389 int CommandObjectProxy::HandleArgumentCompletion(
390 Args &input, int &cursor_index, int &cursor_char_position,
391 OptionElementVector &opt_element_vector, int match_start_point,
392 int max_return_elements, bool &word_complete, StringList &matches) {
393 CommandObject *proxy_command = GetProxyCommandObject();
395 return proxy_command->HandleArgumentCompletion(
396 input, cursor_index, cursor_char_position, opt_element_vector,
397 match_start_point, max_return_elements, word_complete, matches);
402 const char *CommandObjectProxy::GetRepeatCommand(Args ¤t_command_args,
404 CommandObject *proxy_command = GetProxyCommandObject();
406 return proxy_command->GetRepeatCommand(current_command_args, index);
410 bool CommandObjectProxy::Execute(const char *args_string,
411 CommandReturnObject &result) {
412 CommandObject *proxy_command = GetProxyCommandObject();
414 return proxy_command->Execute(args_string, result);
415 result.AppendError("command is not implemented");
416 result.SetStatus(eReturnStatusFailed);