blob: ade1a2d01f3824fabadaef37656773a76a3397e0 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- CommandObjectMultiword.cpp ------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Chris Lattner30fdc8d2010-06-08 16:52:24 +000010// C Includes
11// C++ Includes
12// Other libraries and framework includes
13// Project includes
Eugene Zelenko26cac3a2016-02-20 00:58:29 +000014#include "lldb/Interpreter/CommandObjectMultiword.h"
Greg Clayton66111032010-06-23 01:19:29 +000015#include "lldb/Core/Debugger.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000016#include "lldb/Interpreter/CommandInterpreter.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000017#include "lldb/Interpreter/CommandReturnObject.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000018#include "lldb/Interpreter/Options.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000019
20using namespace lldb;
21using namespace lldb_private;
22
23//-------------------------------------------------------------------------
24// CommandObjectMultiword
25//-------------------------------------------------------------------------
26
Eugene Zelenko26cac3a2016-02-20 00:58:29 +000027CommandObjectMultiword::CommandObjectMultiword(CommandInterpreter &interpreter,
28 const char *name,
29 const char *help,
30 const char *syntax,
Kate Stoneb9c1b512016-09-06 20:57:50 +000031 uint32_t flags)
32 : CommandObject(interpreter, name, help, syntax, flags),
33 m_can_be_removed(false) {}
Chris Lattner30fdc8d2010-06-08 16:52:24 +000034
Eugene Zelenko26cac3a2016-02-20 00:58:29 +000035CommandObjectMultiword::~CommandObjectMultiword() = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000036
Zachary Turner98896832016-11-13 02:50:32 +000037CommandObjectSP CommandObjectMultiword::GetSubcommandSP(llvm::StringRef sub_cmd,
Kate Stoneb9c1b512016-09-06 20:57:50 +000038 StringList *matches) {
39 CommandObjectSP return_cmd_sp;
40 CommandObject::CommandMap::iterator pos;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000041
Kate Stoneb9c1b512016-09-06 20:57:50 +000042 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.
46 if (matches)
47 matches->AppendString(sub_cmd);
48 return_cmd_sp = pos->second;
49 } else {
50 StringList local_matches;
51 if (matches == nullptr)
52 matches = &local_matches;
53 int num_matches =
54 AddNamesMatchingPartialString(m_subcommand_dict, sub_cmd, *matches);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000055
Kate Stoneb9c1b512016-09-06 20:57:50 +000056 if (num_matches == 1) {
57 // Cleaner, but slightly less efficient would be to call back into this
Adrian Prantl05097242018-04-30 16:49:04 +000058 // function, since I now know I have an exact match...
Chris Lattner30fdc8d2010-06-08 16:52:24 +000059
Kate Stoneb9c1b512016-09-06 20:57:50 +000060 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;
64 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000065 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000066 }
67 return return_cmd_sp;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000068}
69
70CommandObject *
Zachary Turner98896832016-11-13 02:50:32 +000071CommandObjectMultiword::GetSubcommandObject(llvm::StringRef sub_cmd,
Kate Stoneb9c1b512016-09-06 20:57:50 +000072 StringList *matches) {
73 return GetSubcommandSP(sub_cmd, matches).get();
Chris Lattner30fdc8d2010-06-08 16:52:24 +000074}
75
Zachary Turner98896832016-11-13 02:50:32 +000076bool CommandObjectMultiword::LoadSubCommand(llvm::StringRef name,
Kate Stoneb9c1b512016-09-06 20:57:50 +000077 const CommandObjectSP &cmd_obj) {
78 if (cmd_obj)
79 assert((&GetCommandInterpreter() == &cmd_obj->GetCommandInterpreter()) &&
80 "tried to add a CommandObject from a different interpreter");
Chris Lattner30fdc8d2010-06-08 16:52:24 +000081
Kate Stoneb9c1b512016-09-06 20:57:50 +000082 CommandMap::iterator pos;
83 bool success = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000084
Kate Stoneb9c1b512016-09-06 20:57:50 +000085 pos = m_subcommand_dict.find(name);
86 if (pos == m_subcommand_dict.end()) {
87 m_subcommand_dict[name] = cmd_obj;
88 } else
89 success = false;
90
91 return success;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000092}
93
Kate Stoneb9c1b512016-09-06 20:57:50 +000094bool CommandObjectMultiword::Execute(const char *args_string,
95 CommandReturnObject &result) {
96 Args args(args_string);
97 const size_t argc = args.GetArgumentCount();
98 if (argc == 0) {
99 this->CommandObject::GenerateHelpText(result);
Zachary Turner2c84f902016-12-09 05:46:41 +0000100 return result.Succeeded();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000101 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000102
Zachary Turner2c84f902016-12-09 05:46:41 +0000103 auto sub_command = args[0].ref;
104 if (sub_command.empty())
105 return result.Succeeded();
106
107 if (sub_command.equals_lower("help")) {
108 this->CommandObject::GenerateHelpText(result);
109 return result.Succeeded();
110 }
111
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);
116 return false;
117 }
118
119 StringList matches;
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`.
Adrian Prantl05097242018-04-30 16:49:04 +0000123 // From there the command-specific version of Execute will be called, with
124 // the processed arguments.
Zachary Turner2c84f902016-12-09 05:46:41 +0000125
126 args.Shift();
127 sub_cmd_obj->Execute(args_string, result);
128 return result.Succeeded();
129 }
130
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 ");
135 else
136 error_msg.assign("invalid command ");
137
138 error_msg.append("'");
139 error_msg.append(GetCommandName());
140 error_msg.append(" ");
141 error_msg.append(sub_command);
142 error_msg.append("'.");
143
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));
149 }
150 }
151 error_msg.append("\n");
152 result.AppendRawError(error_msg.c_str());
153 result.SetStatus(eReturnStatusFailed);
154 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000155}
156
Kate Stoneb9c1b512016-09-06 20:57:50 +0000157void CommandObjectMultiword::GenerateHelpText(Stream &output_stream) {
Adrian Prantl05097242018-04-30 16:49:04 +0000158 // First time through here, generate the help text for the object and push it
159 // to the return result object as well
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000160
Kate Stoneb9c1b512016-09-06 20:57:50 +0000161 CommandObject::GenerateHelpText(output_stream);
162 output_stream.PutCString("\nThe following subcommands are supported:\n\n");
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000163
Kate Stoneb9c1b512016-09-06 20:57:50 +0000164 CommandMap::iterator pos;
165 uint32_t max_len = FindLongestCommandWord(m_subcommand_dict);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000166
Kate Stoneb9c1b512016-09-06 20:57:50 +0000167 if (max_len)
168 max_len += 4; // Indent the output by 4 spaces.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000169
Kate Stoneb9c1b512016-09-06 20:57:50 +0000170 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);
179 } else
180 m_interpreter.OutputFormattedHelpText(output_stream,
181 indented_command.c_str(), "--",
182 pos->second->GetHelp(), max_len);
183 }
184
185 output_stream.PutCString("\nFor more help on any particular subcommand, type "
186 "'help <command> <subcommand>'.\n");
187}
188
Raphael Isemann2443bbd2018-07-02 21:29:56 +0000189int CommandObjectMultiword::HandleCompletion(CompletionRequest &request) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000190 // Any of the command matches will provide a complete word, otherwise the
Zachary Turner2c84f902016-12-09 05:46:41 +0000191 // individual completers will override this.
Raphael Isemann2443bbd2018-07-02 21:29:56 +0000192 request.SetWordComplete(true);
193 auto &matches = request.GetMatches();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000194
Raphael Isemann2443bbd2018-07-02 21:29:56 +0000195 auto arg0 = request.GetParsedLine()[0].ref;
196 if (request.GetCursorIndex() == 0) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000197 AddNamesMatchingPartialString(m_subcommand_dict, arg0, matches);
198
199 if (matches.GetSize() == 1 && matches.GetStringAtIndex(0) != nullptr &&
Zachary Turner2c84f902016-12-09 05:46:41 +0000200 (arg0 == matches.GetStringAtIndex(0))) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000201 StringList temp_matches;
202 CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches);
203 if (cmd_obj != nullptr) {
Raphael Isemann2443bbd2018-07-02 21:29:56 +0000204 if (request.GetParsedLine().GetArgumentCount() == 1) {
205 request.SetWordComplete(true);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000206 } else {
207 matches.DeleteStringAtIndex(0);
Raphael Isemann2443bbd2018-07-02 21:29:56 +0000208 request.GetParsedLine().Shift();
209 request.SetCursorCharPosition(0);
210 request.GetParsedLine().AppendArgument(llvm::StringRef());
211 return cmd_obj->HandleCompletion(request);
Caroline Ticee139cf22010-10-01 17:46:38 +0000212 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000213 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000214 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000215 return matches.GetSize();
216 } else {
217 CommandObject *sub_command_object = GetSubcommandObject(arg0, &matches);
218 if (sub_command_object == nullptr) {
219 return matches.GetSize();
220 } else {
221 // Remove the one match that we got from calling GetSubcommandObject.
222 matches.DeleteStringAtIndex(0);
Raphael Isemann2443bbd2018-07-02 21:29:56 +0000223 request.GetParsedLine().Shift();
224 request.SetCursorIndex(request.GetCursorIndex() - 1);
225 return sub_command_object->HandleCompletion(request);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000226 }
227 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000228}
229
Kate Stoneb9c1b512016-09-06 20:57:50 +0000230const char *CommandObjectMultiword::GetRepeatCommand(Args &current_command_args,
231 uint32_t index) {
232 index++;
233 if (current_command_args.GetArgumentCount() <= index)
234 return nullptr;
235 CommandObject *sub_command_object =
Zachary Turner2c84f902016-12-09 05:46:41 +0000236 GetSubcommandObject(current_command_args[index].ref);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000237 if (sub_command_object == nullptr)
238 return nullptr;
239 return sub_command_object->GetRepeatCommand(current_command_args, index);
240}
241
Zachary Turner98896832016-11-13 02:50:32 +0000242void CommandObjectMultiword::AproposAllSubCommands(llvm::StringRef prefix,
243 llvm::StringRef search_word,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000244 StringList &commands_found,
245 StringList &commands_help) {
246 CommandObject::CommandMap::const_iterator pos;
247
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;
252
Zachary Turner03c9f362016-11-14 23:23:31 +0000253 complete_command_name << prefix << " " << command_name;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000254
255 if (sub_cmd_obj->HelpTextContainsWord(search_word)) {
Zachary Turnerc1564272016-11-16 21:15:24 +0000256 commands_found.AppendString(complete_command_name.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000257 commands_help.AppendString(sub_cmd_obj->GetHelp());
258 }
259
260 if (sub_cmd_obj->IsMultiwordObject())
Zachary Turner98896832016-11-13 02:50:32 +0000261 sub_cmd_obj->AproposAllSubCommands(complete_command_name.GetString(),
Kate Stoneb9c1b512016-09-06 20:57:50 +0000262 search_word, commands_found,
263 commands_help);
264 }
265}
266
267CommandObjectProxy::CommandObjectProxy(CommandInterpreter &interpreter,
268 const char *name, const char *help,
269 const char *syntax, uint32_t flags)
270 : CommandObject(interpreter, name, help, syntax, flags) {}
271
272CommandObjectProxy::~CommandObjectProxy() = default;
273
Zachary Turner442f6532016-11-12 20:41:02 +0000274llvm::StringRef CommandObjectProxy::GetHelpLong() {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000275 CommandObject *proxy_command = GetProxyCommandObject();
276 if (proxy_command)
277 return proxy_command->GetHelpLong();
Zachary Turner442f6532016-11-12 20:41:02 +0000278 return llvm::StringRef();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000279}
280
281bool CommandObjectProxy::IsRemovable() const {
282 const CommandObject *proxy_command =
283 const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
284 if (proxy_command)
285 return proxy_command->IsRemovable();
286 return false;
287}
288
289bool CommandObjectProxy::IsMultiwordObject() {
290 CommandObject *proxy_command = GetProxyCommandObject();
291 if (proxy_command)
292 return proxy_command->IsMultiwordObject();
293 return false;
294}
295
296CommandObjectMultiword *CommandObjectProxy::GetAsMultiwordCommand() {
297 CommandObject *proxy_command = GetProxyCommandObject();
298 if (proxy_command)
299 return proxy_command->GetAsMultiwordCommand();
300 return nullptr;
301}
302
303void CommandObjectProxy::GenerateHelpText(Stream &result) {
304 CommandObject *proxy_command = GetProxyCommandObject();
305 if (proxy_command)
306 return proxy_command->GenerateHelpText(result);
307}
308
Zachary Turner98896832016-11-13 02:50:32 +0000309lldb::CommandObjectSP
310CommandObjectProxy::GetSubcommandSP(llvm::StringRef sub_cmd,
311 StringList *matches) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000312 CommandObject *proxy_command = GetProxyCommandObject();
313 if (proxy_command)
314 return proxy_command->GetSubcommandSP(sub_cmd, matches);
315 return lldb::CommandObjectSP();
316}
317
Zachary Turner98896832016-11-13 02:50:32 +0000318CommandObject *CommandObjectProxy::GetSubcommandObject(llvm::StringRef sub_cmd,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000319 StringList *matches) {
320 CommandObject *proxy_command = GetProxyCommandObject();
321 if (proxy_command)
322 return proxy_command->GetSubcommandObject(sub_cmd, matches);
323 return nullptr;
324}
325
Zachary Turner98896832016-11-13 02:50:32 +0000326void CommandObjectProxy::AproposAllSubCommands(llvm::StringRef prefix,
327 llvm::StringRef search_word,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000328 StringList &commands_found,
329 StringList &commands_help) {
330 CommandObject *proxy_command = GetProxyCommandObject();
331 if (proxy_command)
332 return proxy_command->AproposAllSubCommands(prefix, search_word,
333 commands_found, commands_help);
334}
335
336bool CommandObjectProxy::LoadSubCommand(
Zachary Turner98896832016-11-13 02:50:32 +0000337 llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000338 CommandObject *proxy_command = GetProxyCommandObject();
339 if (proxy_command)
340 return proxy_command->LoadSubCommand(cmd_name, command_sp);
341 return false;
342}
343
344bool CommandObjectProxy::WantsRawCommandString() {
345 CommandObject *proxy_command = GetProxyCommandObject();
346 if (proxy_command)
347 return proxy_command->WantsRawCommandString();
348 return false;
349}
350
351bool CommandObjectProxy::WantsCompletion() {
352 CommandObject *proxy_command = GetProxyCommandObject();
353 if (proxy_command)
354 return proxy_command->WantsCompletion();
355 return false;
356}
357
358Options *CommandObjectProxy::GetOptions() {
359 CommandObject *proxy_command = GetProxyCommandObject();
360 if (proxy_command)
361 return proxy_command->GetOptions();
362 return nullptr;
363}
364
Raphael Isemann2443bbd2018-07-02 21:29:56 +0000365int CommandObjectProxy::HandleCompletion(CompletionRequest &request) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000366 CommandObject *proxy_command = GetProxyCommandObject();
367 if (proxy_command)
Raphael Isemann2443bbd2018-07-02 21:29:56 +0000368 return proxy_command->HandleCompletion(request);
369 request.GetMatches().Clear();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000370 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000371}
372
Kate Stoneb9c1b512016-09-06 20:57:50 +0000373int CommandObjectProxy::HandleArgumentCompletion(
Raphael Isemann2443bbd2018-07-02 21:29:56 +0000374 CompletionRequest &request, OptionElementVector &opt_element_vector) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000375 CommandObject *proxy_command = GetProxyCommandObject();
376 if (proxy_command)
Raphael Isemann2443bbd2018-07-02 21:29:56 +0000377 return proxy_command->HandleArgumentCompletion(request, opt_element_vector);
378 request.GetMatches().Clear();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000379 return 0;
Jim Inghamebc09c32010-07-07 03:36:20 +0000380}
381
Kate Stoneb9c1b512016-09-06 20:57:50 +0000382const char *CommandObjectProxy::GetRepeatCommand(Args &current_command_args,
383 uint32_t index) {
384 CommandObject *proxy_command = GetProxyCommandObject();
385 if (proxy_command)
386 return proxy_command->GetRepeatCommand(current_command_args, index);
387 return nullptr;
Greg Clayton998255b2012-10-13 02:07:45 +0000388}
389
Kate Stoneb9c1b512016-09-06 20:57:50 +0000390bool CommandObjectProxy::Execute(const char *args_string,
391 CommandReturnObject &result) {
392 CommandObject *proxy_command = GetProxyCommandObject();
393 if (proxy_command)
394 return proxy_command->Execute(args_string, result);
395 result.AppendError("command is not implemented");
396 result.SetStatus(eReturnStatusFailed);
397 return false;
Greg Clayton998255b2012-10-13 02:07:45 +0000398}