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 < num_subcmd_matches; 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);
193 auto &matches = request.GetMatches();
195 auto arg0 = request.GetParsedLine()[0].ref;
196 if (request.GetCursorIndex() == 0) {
197 AddNamesMatchingPartialString(m_subcommand_dict, arg0, matches);
199 if (matches.GetSize() == 1 && matches.GetStringAtIndex(0) != nullptr &&
200 (arg0 == matches.GetStringAtIndex(0))) {
201 StringList temp_matches;
202 CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches);
203 if (cmd_obj != nullptr) {
204 if (request.GetParsedLine().GetArgumentCount() == 1) {
205 request.SetWordComplete(true);
207 matches.DeleteStringAtIndex(0);
208 request.GetParsedLine().Shift();
209 request.SetCursorCharPosition(0);
210 request.GetParsedLine().AppendArgument(llvm::StringRef());
211 return cmd_obj->HandleCompletion(request);
215 return matches.GetSize();
217 CommandObject *sub_command_object = GetSubcommandObject(arg0, &matches);
218 if (sub_command_object == nullptr) {
219 return matches.GetSize();
221 // Remove the one match that we got from calling GetSubcommandObject.
222 matches.DeleteStringAtIndex(0);
223 request.GetParsedLine().Shift();
224 request.SetCursorIndex(request.GetCursorIndex() - 1);
225 return sub_command_object->HandleCompletion(request);
230 const char *CommandObjectMultiword::GetRepeatCommand(Args ¤t_command_args,
233 if (current_command_args.GetArgumentCount() <= index)
235 CommandObject *sub_command_object =
236 GetSubcommandObject(current_command_args[index].ref);
237 if (sub_command_object == nullptr)
239 return sub_command_object->GetRepeatCommand(current_command_args, index);
242 void CommandObjectMultiword::AproposAllSubCommands(llvm::StringRef prefix,
243 llvm::StringRef search_word,
244 StringList &commands_found,
245 StringList &commands_help) {
246 CommandObject::CommandMap::const_iterator pos;
248 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) {
249 const char *command_name = pos->first.c_str();
250 CommandObject *sub_cmd_obj = pos->second.get();
251 StreamString complete_command_name;
253 complete_command_name << prefix << " " << command_name;
255 if (sub_cmd_obj->HelpTextContainsWord(search_word)) {
256 commands_found.AppendString(complete_command_name.GetString());
257 commands_help.AppendString(sub_cmd_obj->GetHelp());
260 if (sub_cmd_obj->IsMultiwordObject())
261 sub_cmd_obj->AproposAllSubCommands(complete_command_name.GetString(),
262 search_word, commands_found,
267 CommandObjectProxy::CommandObjectProxy(CommandInterpreter &interpreter,
268 const char *name, const char *help,
269 const char *syntax, uint32_t flags)
270 : CommandObject(interpreter, name, help, syntax, flags) {}
272 CommandObjectProxy::~CommandObjectProxy() = default;
274 llvm::StringRef CommandObjectProxy::GetHelpLong() {
275 CommandObject *proxy_command = GetProxyCommandObject();
277 return proxy_command->GetHelpLong();
278 return llvm::StringRef();
281 bool CommandObjectProxy::IsRemovable() const {
282 const CommandObject *proxy_command =
283 const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
285 return proxy_command->IsRemovable();
289 bool CommandObjectProxy::IsMultiwordObject() {
290 CommandObject *proxy_command = GetProxyCommandObject();
292 return proxy_command->IsMultiwordObject();
296 CommandObjectMultiword *CommandObjectProxy::GetAsMultiwordCommand() {
297 CommandObject *proxy_command = GetProxyCommandObject();
299 return proxy_command->GetAsMultiwordCommand();
303 void CommandObjectProxy::GenerateHelpText(Stream &result) {
304 CommandObject *proxy_command = GetProxyCommandObject();
306 return proxy_command->GenerateHelpText(result);
309 lldb::CommandObjectSP
310 CommandObjectProxy::GetSubcommandSP(llvm::StringRef sub_cmd,
311 StringList *matches) {
312 CommandObject *proxy_command = GetProxyCommandObject();
314 return proxy_command->GetSubcommandSP(sub_cmd, matches);
315 return lldb::CommandObjectSP();
318 CommandObject *CommandObjectProxy::GetSubcommandObject(llvm::StringRef sub_cmd,
319 StringList *matches) {
320 CommandObject *proxy_command = GetProxyCommandObject();
322 return proxy_command->GetSubcommandObject(sub_cmd, matches);
326 void CommandObjectProxy::AproposAllSubCommands(llvm::StringRef prefix,
327 llvm::StringRef search_word,
328 StringList &commands_found,
329 StringList &commands_help) {
330 CommandObject *proxy_command = GetProxyCommandObject();
332 return proxy_command->AproposAllSubCommands(prefix, search_word,
333 commands_found, commands_help);
336 bool CommandObjectProxy::LoadSubCommand(
337 llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) {
338 CommandObject *proxy_command = GetProxyCommandObject();
340 return proxy_command->LoadSubCommand(cmd_name, command_sp);
344 bool CommandObjectProxy::WantsRawCommandString() {
345 CommandObject *proxy_command = GetProxyCommandObject();
347 return proxy_command->WantsRawCommandString();
351 bool CommandObjectProxy::WantsCompletion() {
352 CommandObject *proxy_command = GetProxyCommandObject();
354 return proxy_command->WantsCompletion();
358 Options *CommandObjectProxy::GetOptions() {
359 CommandObject *proxy_command = GetProxyCommandObject();
361 return proxy_command->GetOptions();
365 int CommandObjectProxy::HandleCompletion(CompletionRequest &request) {
366 CommandObject *proxy_command = GetProxyCommandObject();
368 return proxy_command->HandleCompletion(request);
369 request.GetMatches().Clear();
373 int CommandObjectProxy::HandleArgumentCompletion(
374 CompletionRequest &request, OptionElementVector &opt_element_vector) {
375 CommandObject *proxy_command = GetProxyCommandObject();
377 return proxy_command->HandleArgumentCompletion(request, opt_element_vector);
378 request.GetMatches().Clear();
382 const char *CommandObjectProxy::GetRepeatCommand(Args ¤t_command_args,
384 CommandObject *proxy_command = GetProxyCommandObject();
386 return proxy_command->GetRepeatCommand(current_command_args, index);
390 bool CommandObjectProxy::Execute(const char *args_string,
391 CommandReturnObject &result) {
392 CommandObject *proxy_command = GetProxyCommandObject();
394 return proxy_command->Execute(args_string, result);
395 result.AppendError("command is not implemented");
396 result.SetStatus(eReturnStatusFailed);