blob: 44a1320065b1549911508589527a7a8f495a64b9 [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
189int CommandObjectMultiword::HandleCompletion(Args &input, int &cursor_index,
190 int &cursor_char_position,
191 int match_start_point,
192 int max_return_elements,
193 bool &word_complete,
194 StringList &matches) {
195 // Any of the command matches will provide a complete word, otherwise the
Zachary Turner2c84f902016-12-09 05:46:41 +0000196 // individual completers will override this.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000197 word_complete = true;
198
Zachary Turner2c84f902016-12-09 05:46:41 +0000199 auto arg0 = input[0].ref;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000200 if (cursor_index == 0) {
201 AddNamesMatchingPartialString(m_subcommand_dict, arg0, matches);
202
203 if (matches.GetSize() == 1 && matches.GetStringAtIndex(0) != nullptr &&
Zachary Turner2c84f902016-12-09 05:46:41 +0000204 (arg0 == matches.GetStringAtIndex(0))) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000205 StringList temp_matches;
206 CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches);
207 if (cmd_obj != nullptr) {
208 if (input.GetArgumentCount() == 1) {
209 word_complete = true;
210 } else {
211 matches.DeleteStringAtIndex(0);
212 input.Shift();
213 cursor_char_position = 0;
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000214 input.AppendArgument(llvm::StringRef());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000215 return cmd_obj->HandleCompletion(
216 input, cursor_index, cursor_char_position, match_start_point,
217 max_return_elements, word_complete, matches);
Caroline Ticee139cf22010-10-01 17:46:38 +0000218 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000219 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000220 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000221 return matches.GetSize();
222 } else {
223 CommandObject *sub_command_object = GetSubcommandObject(arg0, &matches);
224 if (sub_command_object == nullptr) {
225 return matches.GetSize();
226 } else {
227 // Remove the one match that we got from calling GetSubcommandObject.
228 matches.DeleteStringAtIndex(0);
229 input.Shift();
230 cursor_index--;
231 return sub_command_object->HandleCompletion(
232 input, cursor_index, cursor_char_position, match_start_point,
233 max_return_elements, word_complete, matches);
234 }
235 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000236}
237
Kate Stoneb9c1b512016-09-06 20:57:50 +0000238const char *CommandObjectMultiword::GetRepeatCommand(Args &current_command_args,
239 uint32_t index) {
240 index++;
241 if (current_command_args.GetArgumentCount() <= index)
242 return nullptr;
243 CommandObject *sub_command_object =
Zachary Turner2c84f902016-12-09 05:46:41 +0000244 GetSubcommandObject(current_command_args[index].ref);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000245 if (sub_command_object == nullptr)
246 return nullptr;
247 return sub_command_object->GetRepeatCommand(current_command_args, index);
248}
249
Zachary Turner98896832016-11-13 02:50:32 +0000250void CommandObjectMultiword::AproposAllSubCommands(llvm::StringRef prefix,
251 llvm::StringRef search_word,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000252 StringList &commands_found,
253 StringList &commands_help) {
254 CommandObject::CommandMap::const_iterator pos;
255
256 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) {
257 const char *command_name = pos->first.c_str();
258 CommandObject *sub_cmd_obj = pos->second.get();
259 StreamString complete_command_name;
260
Zachary Turner03c9f362016-11-14 23:23:31 +0000261 complete_command_name << prefix << " " << command_name;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000262
263 if (sub_cmd_obj->HelpTextContainsWord(search_word)) {
Zachary Turnerc1564272016-11-16 21:15:24 +0000264 commands_found.AppendString(complete_command_name.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000265 commands_help.AppendString(sub_cmd_obj->GetHelp());
266 }
267
268 if (sub_cmd_obj->IsMultiwordObject())
Zachary Turner98896832016-11-13 02:50:32 +0000269 sub_cmd_obj->AproposAllSubCommands(complete_command_name.GetString(),
Kate Stoneb9c1b512016-09-06 20:57:50 +0000270 search_word, commands_found,
271 commands_help);
272 }
273}
274
275CommandObjectProxy::CommandObjectProxy(CommandInterpreter &interpreter,
276 const char *name, const char *help,
277 const char *syntax, uint32_t flags)
278 : CommandObject(interpreter, name, help, syntax, flags) {}
279
280CommandObjectProxy::~CommandObjectProxy() = default;
281
Zachary Turner442f6532016-11-12 20:41:02 +0000282llvm::StringRef CommandObjectProxy::GetHelpLong() {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000283 CommandObject *proxy_command = GetProxyCommandObject();
284 if (proxy_command)
285 return proxy_command->GetHelpLong();
Zachary Turner442f6532016-11-12 20:41:02 +0000286 return llvm::StringRef();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000287}
288
289bool CommandObjectProxy::IsRemovable() const {
290 const CommandObject *proxy_command =
291 const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
292 if (proxy_command)
293 return proxy_command->IsRemovable();
294 return false;
295}
296
297bool CommandObjectProxy::IsMultiwordObject() {
298 CommandObject *proxy_command = GetProxyCommandObject();
299 if (proxy_command)
300 return proxy_command->IsMultiwordObject();
301 return false;
302}
303
304CommandObjectMultiword *CommandObjectProxy::GetAsMultiwordCommand() {
305 CommandObject *proxy_command = GetProxyCommandObject();
306 if (proxy_command)
307 return proxy_command->GetAsMultiwordCommand();
308 return nullptr;
309}
310
311void CommandObjectProxy::GenerateHelpText(Stream &result) {
312 CommandObject *proxy_command = GetProxyCommandObject();
313 if (proxy_command)
314 return proxy_command->GenerateHelpText(result);
315}
316
Zachary Turner98896832016-11-13 02:50:32 +0000317lldb::CommandObjectSP
318CommandObjectProxy::GetSubcommandSP(llvm::StringRef sub_cmd,
319 StringList *matches) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000320 CommandObject *proxy_command = GetProxyCommandObject();
321 if (proxy_command)
322 return proxy_command->GetSubcommandSP(sub_cmd, matches);
323 return lldb::CommandObjectSP();
324}
325
Zachary Turner98896832016-11-13 02:50:32 +0000326CommandObject *CommandObjectProxy::GetSubcommandObject(llvm::StringRef sub_cmd,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000327 StringList *matches) {
328 CommandObject *proxy_command = GetProxyCommandObject();
329 if (proxy_command)
330 return proxy_command->GetSubcommandObject(sub_cmd, matches);
331 return nullptr;
332}
333
Zachary Turner98896832016-11-13 02:50:32 +0000334void CommandObjectProxy::AproposAllSubCommands(llvm::StringRef prefix,
335 llvm::StringRef search_word,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000336 StringList &commands_found,
337 StringList &commands_help) {
338 CommandObject *proxy_command = GetProxyCommandObject();
339 if (proxy_command)
340 return proxy_command->AproposAllSubCommands(prefix, search_word,
341 commands_found, commands_help);
342}
343
344bool CommandObjectProxy::LoadSubCommand(
Zachary Turner98896832016-11-13 02:50:32 +0000345 llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000346 CommandObject *proxy_command = GetProxyCommandObject();
347 if (proxy_command)
348 return proxy_command->LoadSubCommand(cmd_name, command_sp);
349 return false;
350}
351
352bool CommandObjectProxy::WantsRawCommandString() {
353 CommandObject *proxy_command = GetProxyCommandObject();
354 if (proxy_command)
355 return proxy_command->WantsRawCommandString();
356 return false;
357}
358
359bool CommandObjectProxy::WantsCompletion() {
360 CommandObject *proxy_command = GetProxyCommandObject();
361 if (proxy_command)
362 return proxy_command->WantsCompletion();
363 return false;
364}
365
366Options *CommandObjectProxy::GetOptions() {
367 CommandObject *proxy_command = GetProxyCommandObject();
368 if (proxy_command)
369 return proxy_command->GetOptions();
370 return nullptr;
371}
372
373int CommandObjectProxy::HandleCompletion(Args &input, int &cursor_index,
Eugene Zelenko26cac3a2016-02-20 00:58:29 +0000374 int &cursor_char_position,
375 int match_start_point,
376 int max_return_elements,
377 bool &word_complete,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000378 StringList &matches) {
379 CommandObject *proxy_command = GetProxyCommandObject();
380 if (proxy_command)
381 return proxy_command->HandleCompletion(
382 input, cursor_index, cursor_char_position, match_start_point,
383 max_return_elements, word_complete, matches);
384 matches.Clear();
385 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000386}
387
Kate Stoneb9c1b512016-09-06 20:57:50 +0000388int CommandObjectProxy::HandleArgumentCompletion(
389 Args &input, int &cursor_index, int &cursor_char_position,
390 OptionElementVector &opt_element_vector, int match_start_point,
391 int max_return_elements, bool &word_complete, StringList &matches) {
392 CommandObject *proxy_command = GetProxyCommandObject();
393 if (proxy_command)
394 return proxy_command->HandleArgumentCompletion(
395 input, cursor_index, cursor_char_position, opt_element_vector,
396 match_start_point, max_return_elements, word_complete, matches);
397 matches.Clear();
398 return 0;
Jim Inghamebc09c32010-07-07 03:36:20 +0000399}
400
Kate Stoneb9c1b512016-09-06 20:57:50 +0000401const char *CommandObjectProxy::GetRepeatCommand(Args &current_command_args,
402 uint32_t index) {
403 CommandObject *proxy_command = GetProxyCommandObject();
404 if (proxy_command)
405 return proxy_command->GetRepeatCommand(current_command_args, index);
406 return nullptr;
Greg Clayton998255b2012-10-13 02:07:45 +0000407}
408
Kate Stoneb9c1b512016-09-06 20:57:50 +0000409bool CommandObjectProxy::Execute(const char *args_string,
410 CommandReturnObject &result) {
411 CommandObject *proxy_command = GetProxyCommandObject();
412 if (proxy_command)
413 return proxy_command->Execute(args_string, result);
414 result.AppendError("command is not implemented");
415 result.SetStatus(eReturnStatusFailed);
416 return false;
Greg Clayton998255b2012-10-13 02:07:45 +0000417}