xref: /llvm-project/lldb/source/Commands/CommandObjectCommands.cpp (revision 867e7d17655367377137393ea7d2fa68268d3001)
1 //===-- CommandObjectCommands.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 
10 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 #include "llvm/ADT/StringRef.h"
14 
15 // Project includes
16 #include "CommandObjectCommands.h"
17 #include "CommandObjectHelp.h"
18 #include "lldb/Core/Debugger.h"
19 #include "lldb/Core/IOHandler.h"
20 #include "lldb/Core/StringList.h"
21 #include "lldb/Interpreter/Args.h"
22 #include "lldb/Interpreter/CommandHistory.h"
23 #include "lldb/Interpreter/CommandInterpreter.h"
24 #include "lldb/Interpreter/CommandObjectRegexCommand.h"
25 #include "lldb/Interpreter/CommandReturnObject.h"
26 #include "lldb/Interpreter/OptionValueBoolean.h"
27 #include "lldb/Interpreter/OptionValueString.h"
28 #include "lldb/Interpreter/OptionValueUInt64.h"
29 #include "lldb/Interpreter/Options.h"
30 #include "lldb/Interpreter/ScriptInterpreter.h"
31 
32 using namespace lldb;
33 using namespace lldb_private;
34 
35 //-------------------------------------------------------------------------
36 // CommandObjectCommandsSource
37 //-------------------------------------------------------------------------
38 
39 static OptionDefinition g_history_options[] = {
40     // clang-format off
41   { LLDB_OPT_SET_1, false, "count",       'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "How many history commands to print." },
42   { LLDB_OPT_SET_1, false, "start-index", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Index at which to start printing history commands (or end to mean tail mode)." },
43   { LLDB_OPT_SET_1, false, "end-index",   'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Index at which to stop printing history commands." },
44   { LLDB_OPT_SET_2, false, "clear",       'C', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeBoolean,         "Clears the current command history." },
45     // clang-format on
46 };
47 
48 class CommandObjectCommandsHistory : public CommandObjectParsed {
49 public:
50   CommandObjectCommandsHistory(CommandInterpreter &interpreter)
51       : CommandObjectParsed(interpreter, "command history",
52                             "Dump the history of commands in this session.",
53                             nullptr),
54         m_options() {}
55 
56   ~CommandObjectCommandsHistory() override = default;
57 
58   Options *GetOptions() override { return &m_options; }
59 
60 protected:
61   class CommandOptions : public Options {
62   public:
63     CommandOptions()
64         : Options(), m_start_idx(0), m_stop_idx(0), m_count(0), m_clear(false) {
65     }
66 
67     ~CommandOptions() override = default;
68 
69     Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
70                          ExecutionContext *execution_context) override {
71       Error error;
72       const int short_option = m_getopt_table[option_idx].val;
73 
74       switch (short_option) {
75       case 'c':
76         error = m_count.SetValueFromString(option_arg, eVarSetOperationAssign);
77         break;
78       case 's':
79         if (option_arg == "end") {
80           m_start_idx.SetCurrentValue(UINT64_MAX);
81           m_start_idx.SetOptionWasSet();
82         } else
83           error = m_start_idx.SetValueFromString(option_arg,
84                                                  eVarSetOperationAssign);
85         break;
86       case 'e':
87         error =
88             m_stop_idx.SetValueFromString(option_arg, eVarSetOperationAssign);
89         break;
90       case 'C':
91         m_clear.SetCurrentValue(true);
92         m_clear.SetOptionWasSet();
93         break;
94       default:
95         error.SetErrorStringWithFormat("unrecognized option '%c'",
96                                        short_option);
97         break;
98       }
99 
100       return error;
101     }
102 
103     void OptionParsingStarting(ExecutionContext *execution_context) override {
104       m_start_idx.Clear();
105       m_stop_idx.Clear();
106       m_count.Clear();
107       m_clear.Clear();
108     }
109 
110     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
111       return llvm::makeArrayRef(g_history_options);
112     }
113 
114     // Instance variables to hold the values for command options.
115 
116     OptionValueUInt64 m_start_idx;
117     OptionValueUInt64 m_stop_idx;
118     OptionValueUInt64 m_count;
119     OptionValueBoolean m_clear;
120   };
121 
122   bool DoExecute(Args &command, CommandReturnObject &result) override {
123     if (m_options.m_clear.GetCurrentValue() &&
124         m_options.m_clear.OptionWasSet()) {
125       m_interpreter.GetCommandHistory().Clear();
126       result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
127     } else {
128       if (m_options.m_start_idx.OptionWasSet() &&
129           m_options.m_stop_idx.OptionWasSet() &&
130           m_options.m_count.OptionWasSet()) {
131         result.AppendError("--count, --start-index and --end-index cannot be "
132                            "all specified in the same invocation");
133         result.SetStatus(lldb::eReturnStatusFailed);
134       } else {
135         std::pair<bool, uint64_t> start_idx(
136             m_options.m_start_idx.OptionWasSet(),
137             m_options.m_start_idx.GetCurrentValue());
138         std::pair<bool, uint64_t> stop_idx(
139             m_options.m_stop_idx.OptionWasSet(),
140             m_options.m_stop_idx.GetCurrentValue());
141         std::pair<bool, uint64_t> count(m_options.m_count.OptionWasSet(),
142                                         m_options.m_count.GetCurrentValue());
143 
144         const CommandHistory &history(m_interpreter.GetCommandHistory());
145 
146         if (start_idx.first && start_idx.second == UINT64_MAX) {
147           if (count.first) {
148             start_idx.second = history.GetSize() - count.second;
149             stop_idx.second = history.GetSize() - 1;
150           } else if (stop_idx.first) {
151             start_idx.second = stop_idx.second;
152             stop_idx.second = history.GetSize() - 1;
153           } else {
154             start_idx.second = 0;
155             stop_idx.second = history.GetSize() - 1;
156           }
157         } else {
158           if (!start_idx.first && !stop_idx.first && !count.first) {
159             start_idx.second = 0;
160             stop_idx.second = history.GetSize() - 1;
161           } else if (start_idx.first) {
162             if (count.first) {
163               stop_idx.second = start_idx.second + count.second - 1;
164             } else if (!stop_idx.first) {
165               stop_idx.second = history.GetSize() - 1;
166             }
167           } else if (stop_idx.first) {
168             if (count.first) {
169               if (stop_idx.second >= count.second)
170                 start_idx.second = stop_idx.second - count.second + 1;
171               else
172                 start_idx.second = 0;
173             }
174           } else /* if (count.first) */
175           {
176             start_idx.second = 0;
177             stop_idx.second = count.second - 1;
178           }
179         }
180         history.Dump(result.GetOutputStream(), start_idx.second,
181                      stop_idx.second);
182       }
183     }
184     return result.Succeeded();
185   }
186 
187   CommandOptions m_options;
188 };
189 
190 //-------------------------------------------------------------------------
191 // CommandObjectCommandsSource
192 //-------------------------------------------------------------------------
193 
194 static OptionDefinition g_source_options[] = {
195     // clang-format off
196   { LLDB_OPT_SET_ALL, false, "stop-on-error",    'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, stop executing commands on error." },
197   { LLDB_OPT_SET_ALL, false, "stop-on-continue", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, stop executing commands on continue." },
198   { LLDB_OPT_SET_ALL, false, "silent-run",       's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true don't echo commands while executing." },
199     // clang-format on
200 };
201 
202 class CommandObjectCommandsSource : public CommandObjectParsed {
203 public:
204   CommandObjectCommandsSource(CommandInterpreter &interpreter)
205       : CommandObjectParsed(
206             interpreter, "command source",
207             "Read and execute LLDB commands from the file <filename>.",
208             nullptr),
209         m_options() {
210     CommandArgumentEntry arg;
211     CommandArgumentData file_arg;
212 
213     // Define the first (and only) variant of this arg.
214     file_arg.arg_type = eArgTypeFilename;
215     file_arg.arg_repetition = eArgRepeatPlain;
216 
217     // There is only one variant this argument could be; put it into the
218     // argument entry.
219     arg.push_back(file_arg);
220 
221     // Push the data for the first argument into the m_arguments vector.
222     m_arguments.push_back(arg);
223   }
224 
225   ~CommandObjectCommandsSource() override = default;
226 
227   const char *GetRepeatCommand(Args &current_command_args,
228                                uint32_t index) override {
229     return "";
230   }
231 
232   int HandleArgumentCompletion(Args &input, int &cursor_index,
233                                int &cursor_char_position,
234                                OptionElementVector &opt_element_vector,
235                                int match_start_point, int max_return_elements,
236                                bool &word_complete,
237                                StringList &matches) override {
238     auto completion_str = input[cursor_index].ref;
239     completion_str = completion_str.take_front(cursor_char_position);
240 
241     CommandCompletions::InvokeCommonCompletionCallbacks(
242         GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
243         completion_str, match_start_point, max_return_elements, nullptr,
244         word_complete, matches);
245     return matches.GetSize();
246   }
247 
248   Options *GetOptions() override { return &m_options; }
249 
250 protected:
251   class CommandOptions : public Options {
252   public:
253     CommandOptions()
254         : Options(), m_stop_on_error(true), m_silent_run(false),
255           m_stop_on_continue(true) {}
256 
257     ~CommandOptions() override = default;
258 
259     Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
260                          ExecutionContext *execution_context) override {
261       Error error;
262       const int short_option = m_getopt_table[option_idx].val;
263 
264       switch (short_option) {
265       case 'e':
266         error = m_stop_on_error.SetValueFromString(option_arg);
267         break;
268 
269       case 'c':
270         error = m_stop_on_continue.SetValueFromString(option_arg);
271         break;
272 
273       case 's':
274         error = m_silent_run.SetValueFromString(option_arg);
275         break;
276 
277       default:
278         error.SetErrorStringWithFormat("unrecognized option '%c'",
279                                        short_option);
280         break;
281       }
282 
283       return error;
284     }
285 
286     void OptionParsingStarting(ExecutionContext *execution_context) override {
287       m_stop_on_error.Clear();
288       m_silent_run.Clear();
289       m_stop_on_continue.Clear();
290     }
291 
292     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
293       return llvm::makeArrayRef(g_source_options);
294     }
295 
296     // Instance variables to hold the values for command options.
297 
298     OptionValueBoolean m_stop_on_error;
299     OptionValueBoolean m_silent_run;
300     OptionValueBoolean m_stop_on_continue;
301   };
302 
303   bool DoExecute(Args &command, CommandReturnObject &result) override {
304     if (command.GetArgumentCount() != 1) {
305       result.AppendErrorWithFormat(
306           "'%s' takes exactly one executable filename argument.\n",
307           GetCommandName().str().c_str());
308       result.SetStatus(eReturnStatusFailed);
309       return false;
310     }
311 
312     FileSpec cmd_file(command[0].ref, true);
313     ExecutionContext *exe_ctx = nullptr; // Just use the default context.
314 
315     // If any options were set, then use them
316     if (m_options.m_stop_on_error.OptionWasSet() ||
317         m_options.m_silent_run.OptionWasSet() ||
318         m_options.m_stop_on_continue.OptionWasSet()) {
319       // Use user set settings
320       CommandInterpreterRunOptions options;
321       options.SetStopOnContinue(m_options.m_stop_on_continue.GetCurrentValue());
322       options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue());
323       options.SetEchoCommands(!m_options.m_silent_run.GetCurrentValue());
324       options.SetPrintResults(!m_options.m_silent_run.GetCurrentValue());
325 
326       m_interpreter.HandleCommandsFromFile(cmd_file, exe_ctx, options, result);
327     } else {
328       // No options were set, inherit any settings from nested "command
329       // source" commands,
330       // or set to sane default settings...
331       CommandInterpreterRunOptions options;
332       m_interpreter.HandleCommandsFromFile(cmd_file, exe_ctx, options, result);
333     }
334     return result.Succeeded();
335   }
336 
337   CommandOptions m_options;
338 };
339 
340 #pragma mark CommandObjectCommandsAlias
341 //-------------------------------------------------------------------------
342 // CommandObjectCommandsAlias
343 //-------------------------------------------------------------------------
344 
345 static OptionDefinition g_alias_options[] = {
346     // clang-format off
347   { LLDB_OPT_SET_ALL, false, "help",      'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "Help text for this command" },
348   { LLDB_OPT_SET_ALL, false, "long-help", 'H', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "Long help text for this command" },
349     // clang-format on
350 };
351 
352 static const char *g_python_command_instructions =
353     "Enter your Python command(s). Type 'DONE' to end.\n"
354     "You must define a Python function with this signature:\n"
355     "def my_command_impl(debugger, args, result, internal_dict):\n";
356 
357 class CommandObjectCommandsAlias : public CommandObjectRaw {
358 protected:
359   class CommandOptions : public OptionGroup {
360   public:
361     CommandOptions() : OptionGroup(), m_help(), m_long_help() {}
362 
363     ~CommandOptions() override = default;
364 
365     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
366       return llvm::makeArrayRef(g_alias_options);
367     }
368 
369     Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
370                          ExecutionContext *execution_context) override {
371       Error error;
372 
373       const int short_option = GetDefinitions()[option_idx].short_option;
374       std::string option_str(option_value);
375 
376       switch (short_option) {
377       case 'h':
378         m_help.SetCurrentValue(option_str);
379         m_help.SetOptionWasSet();
380         break;
381 
382       case 'H':
383         m_long_help.SetCurrentValue(option_str);
384         m_long_help.SetOptionWasSet();
385         break;
386 
387       default:
388         error.SetErrorStringWithFormat("invalid short option character '%c'",
389                                        short_option);
390         break;
391       }
392 
393       return error;
394     }
395 
396     void OptionParsingStarting(ExecutionContext *execution_context) override {
397       m_help.Clear();
398       m_long_help.Clear();
399     }
400 
401     OptionValueString m_help;
402     OptionValueString m_long_help;
403   };
404 
405   OptionGroupOptions m_option_group;
406   CommandOptions m_command_options;
407 
408 public:
409   Options *GetOptions() override { return &m_option_group; }
410 
411   CommandObjectCommandsAlias(CommandInterpreter &interpreter)
412       : CommandObjectRaw(
413             interpreter, "command alias",
414             "Define a custom command in terms of an existing command."),
415         m_option_group(), m_command_options() {
416     m_option_group.Append(&m_command_options);
417     m_option_group.Finalize();
418 
419     SetHelpLong(
420         "'alias' allows the user to create a short-cut or abbreviation for long \
421 commands, multi-word commands, and commands that take particular options.  \
422 Below are some simple examples of how one might use the 'alias' command:"
423         R"(
424 
425 (lldb) command alias sc script
426 
427     Creates the abbreviation 'sc' for the 'script' command.
428 
429 (lldb) command alias bp breakpoint
430 
431 )"
432         "    Creates the abbreviation 'bp' for the 'breakpoint' command.  Since \
433 breakpoint commands are two-word commands, the user would still need to \
434 enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'."
435         R"(
436 
437 (lldb) command alias bpl breakpoint list
438 
439     Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'.
440 
441 )"
442         "An alias can include some options for the command, with the values either \
443 filled in at the time the alias is created, or specified as positional \
444 arguments, to be filled in when the alias is invoked.  The following example \
445 shows how to create aliases with options:"
446         R"(
447 
448 (lldb) command alias bfl breakpoint set -f %1 -l %2
449 
450 )"
451         "    Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \
452 options already part of the alias.  So if the user wants to set a breakpoint \
453 by file and line without explicitly having to use the -f and -l options, the \
454 user can now use 'bfl' instead.  The '%1' and '%2' are positional placeholders \
455 for the actual arguments that will be passed when the alias command is used.  \
456 The number in the placeholder refers to the position/order the actual value \
457 occupies when the alias is used.  All the occurrences of '%1' in the alias \
458 will be replaced with the first argument, all the occurrences of '%2' in the \
459 alias will be replaced with the second argument, and so on.  This also allows \
460 actual arguments to be used multiple times within an alias (see 'process \
461 launch' example below)."
462         R"(
463 
464 )"
465         "Note: the positional arguments must substitute as whole words in the resultant \
466 command, so you can't at present do something like this to append the file extension \
467 \".cpp\":"
468         R"(
469 
470 (lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2
471 
472 )"
473         "For more complex aliasing, use the \"command regex\" command instead.  In the \
474 'bfl' case above, the actual file value will be filled in with the first argument \
475 following 'bfl' and the actual line number value will be filled in with the second \
476 argument.  The user would use this alias as follows:"
477         R"(
478 
479 (lldb) command alias bfl breakpoint set -f %1 -l %2
480 (lldb) bfl my-file.c 137
481 
482 This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'.
483 
484 Another example:
485 
486 (lldb) command alias pltty process launch -s -o %1 -e %1
487 (lldb) pltty /dev/tty0
488 
489     Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0'
490 
491 )"
492         "If the user always wanted to pass the same value to a particular option, the \
493 alias could be defined with that value directly in the alias as a constant, \
494 rather than using a positional placeholder:"
495         R"(
496 
497 (lldb) command alias bl3 breakpoint set -f %1 -l 3
498 
499     Always sets a breakpoint on line 3 of whatever file is indicated.)");
500 
501     CommandArgumentEntry arg1;
502     CommandArgumentEntry arg2;
503     CommandArgumentEntry arg3;
504     CommandArgumentData alias_arg;
505     CommandArgumentData cmd_arg;
506     CommandArgumentData options_arg;
507 
508     // Define the first (and only) variant of this arg.
509     alias_arg.arg_type = eArgTypeAliasName;
510     alias_arg.arg_repetition = eArgRepeatPlain;
511 
512     // There is only one variant this argument could be; put it into the
513     // argument entry.
514     arg1.push_back(alias_arg);
515 
516     // Define the first (and only) variant of this arg.
517     cmd_arg.arg_type = eArgTypeCommandName;
518     cmd_arg.arg_repetition = eArgRepeatPlain;
519 
520     // There is only one variant this argument could be; put it into the
521     // argument entry.
522     arg2.push_back(cmd_arg);
523 
524     // Define the first (and only) variant of this arg.
525     options_arg.arg_type = eArgTypeAliasOptions;
526     options_arg.arg_repetition = eArgRepeatOptional;
527 
528     // There is only one variant this argument could be; put it into the
529     // argument entry.
530     arg3.push_back(options_arg);
531 
532     // Push the data for the first argument into the m_arguments vector.
533     m_arguments.push_back(arg1);
534     m_arguments.push_back(arg2);
535     m_arguments.push_back(arg3);
536   }
537 
538   ~CommandObjectCommandsAlias() override = default;
539 
540 protected:
541   bool DoExecute(const char *raw_command_line,
542                  CommandReturnObject &result) override {
543     if (!raw_command_line || !raw_command_line[0]) {
544       result.AppendError("'command alias' requires at least two arguments");
545       return false;
546     }
547 
548     ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
549     m_option_group.NotifyOptionParsingStarting(&exe_ctx);
550 
551     const char *remainder = nullptr;
552 
553     if (raw_command_line[0] == '-') {
554       // We have some options and these options MUST end with --.
555       const char *end_options = nullptr;
556       const char *s = raw_command_line;
557       while (s && s[0]) {
558         end_options = ::strstr(s, "--");
559         if (end_options) {
560           end_options += 2; // Get past the "--"
561           if (::isspace(end_options[0])) {
562             remainder = end_options;
563             while (::isspace(*remainder))
564               ++remainder;
565             break;
566           }
567         }
568         s = end_options;
569       }
570 
571       if (end_options) {
572         Args args(
573             llvm::StringRef(raw_command_line, end_options - raw_command_line));
574         if (!ParseOptions(args, result))
575           return false;
576 
577         Error error(m_option_group.NotifyOptionParsingFinished(&exe_ctx));
578         if (error.Fail()) {
579           result.AppendError(error.AsCString());
580           result.SetStatus(eReturnStatusFailed);
581           return false;
582         }
583       }
584     }
585     if (nullptr == remainder)
586       remainder = raw_command_line;
587 
588     llvm::StringRef raw_command_string(remainder);
589     Args args(raw_command_string);
590 
591     if (args.GetArgumentCount() < 2) {
592       result.AppendError("'command alias' requires at least two arguments");
593       result.SetStatus(eReturnStatusFailed);
594       return false;
595     }
596 
597     // Get the alias command.
598 
599     auto alias_command = args[0].ref;
600     if (alias_command.startswith("-")) {
601       result.AppendError("aliases starting with a dash are not supported");
602       if (alias_command == "--help" || alias_command == "--long-help") {
603         result.AppendWarning("if trying to pass options to 'command alias' add "
604                              "a -- at the end of the options");
605       }
606       result.SetStatus(eReturnStatusFailed);
607       return false;
608     }
609 
610     // Strip the new alias name off 'raw_command_string'  (leave it on args,
611     // which gets passed to 'Execute', which
612     // does the stripping itself.
613     size_t pos = raw_command_string.find(alias_command);
614     if (pos == 0) {
615       raw_command_string = raw_command_string.substr(alias_command.size());
616       pos = raw_command_string.find_first_not_of(' ');
617       if ((pos != std::string::npos) && (pos > 0))
618         raw_command_string = raw_command_string.substr(pos);
619     } else {
620       result.AppendError("Error parsing command string.  No alias created.");
621       result.SetStatus(eReturnStatusFailed);
622       return false;
623     }
624 
625     // Verify that the command is alias-able.
626     if (m_interpreter.CommandExists(alias_command)) {
627       result.AppendErrorWithFormat(
628           "'%s' is a permanent debugger command and cannot be redefined.\n",
629           args[0].c_str());
630       result.SetStatus(eReturnStatusFailed);
631       return false;
632     }
633 
634     // Get CommandObject that is being aliased. The command name is read from
635     // the front of raw_command_string. raw_command_string is returned with the
636     // name of the command object stripped off the front.
637     llvm::StringRef original_raw_command_string = raw_command_string;
638     CommandObject *cmd_obj =
639         m_interpreter.GetCommandObjectForCommand(raw_command_string);
640 
641     if (!cmd_obj) {
642       result.AppendErrorWithFormat("invalid command given to 'command alias'. "
643                                    "'%s' does not begin with a valid command."
644                                    "  No alias created.",
645                                    original_raw_command_string.str().c_str());
646       result.SetStatus(eReturnStatusFailed);
647       return false;
648     } else if (!cmd_obj->WantsRawCommandString()) {
649       // Note that args was initialized with the original command, and has not
650       // been updated to this point.
651       // Therefore can we pass it to the version of Execute that does not
652       // need/expect raw input in the alias.
653       return HandleAliasingNormalCommand(args, result);
654     } else {
655       return HandleAliasingRawCommand(alias_command, raw_command_string,
656                                       *cmd_obj, result);
657     }
658     return result.Succeeded();
659   }
660 
661   bool HandleAliasingRawCommand(llvm::StringRef alias_command,
662                                 llvm::StringRef raw_command_string,
663                                 CommandObject &cmd_obj,
664                                 CommandReturnObject &result) {
665     // Verify & handle any options/arguments passed to the alias command
666 
667     OptionArgVectorSP option_arg_vector_sp =
668         OptionArgVectorSP(new OptionArgVector);
669 
670     if (CommandObjectSP cmd_obj_sp =
671             m_interpreter.GetCommandSPExact(cmd_obj.GetCommandName(), false)) {
672       if (m_interpreter.AliasExists(alias_command) ||
673           m_interpreter.UserCommandExists(alias_command)) {
674         result.AppendWarningWithFormat(
675             "Overwriting existing definition for '%s'.\n",
676             alias_command.str().c_str());
677       }
678       if (CommandAlias *alias = m_interpreter.AddAlias(
679               alias_command, cmd_obj_sp, raw_command_string)) {
680         if (m_command_options.m_help.OptionWasSet())
681           alias->SetHelp(m_command_options.m_help.GetCurrentValue());
682         if (m_command_options.m_long_help.OptionWasSet())
683           alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
684         result.SetStatus(eReturnStatusSuccessFinishNoResult);
685       } else {
686         result.AppendError("Unable to create requested alias.\n");
687         result.SetStatus(eReturnStatusFailed);
688       }
689 
690     } else {
691       result.AppendError("Unable to create requested alias.\n");
692       result.SetStatus(eReturnStatusFailed);
693     }
694 
695     return result.Succeeded();
696   }
697 
698   bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) {
699     size_t argc = args.GetArgumentCount();
700 
701     if (argc < 2) {
702       result.AppendError("'command alias' requires at least two arguments");
703       result.SetStatus(eReturnStatusFailed);
704       return false;
705     }
706 
707     // Save these in std::strings since we're going to shift them off.
708     const std::string alias_command(args[0].ref);
709     const std::string actual_command(args[1].ref);
710 
711     args.Shift(); // Shift the alias command word off the argument vector.
712     args.Shift(); // Shift the old command word off the argument vector.
713 
714     // Verify that the command is alias'able, and get the appropriate command
715     // object.
716 
717     if (m_interpreter.CommandExists(alias_command)) {
718       result.AppendErrorWithFormat(
719           "'%s' is a permanent debugger command and cannot be redefined.\n",
720           alias_command.c_str());
721       result.SetStatus(eReturnStatusFailed);
722       return false;
723     }
724 
725     CommandObjectSP command_obj_sp(
726         m_interpreter.GetCommandSPExact(actual_command, true));
727     CommandObjectSP subcommand_obj_sp;
728     bool use_subcommand = false;
729     if (!command_obj_sp) {
730       result.AppendErrorWithFormat("'%s' is not an existing command.\n",
731                                    actual_command.c_str());
732       result.SetStatus(eReturnStatusFailed);
733       return false;
734     }
735     CommandObject *cmd_obj = command_obj_sp.get();
736     CommandObject *sub_cmd_obj = nullptr;
737     OptionArgVectorSP option_arg_vector_sp =
738         OptionArgVectorSP(new OptionArgVector);
739 
740     while (cmd_obj->IsMultiwordObject() && !args.empty()) {
741       auto sub_command = args[0].ref;
742       assert(!sub_command.empty());
743       subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command);
744       if (!subcommand_obj_sp) {
745         result.AppendErrorWithFormat(
746             "'%s' is not a valid sub-command of '%s'.  "
747             "Unable to create alias.\n",
748             args[0].c_str(), actual_command.c_str());
749         result.SetStatus(eReturnStatusFailed);
750         return false;
751       }
752 
753       sub_cmd_obj = subcommand_obj_sp.get();
754       use_subcommand = true;
755       args.Shift(); // Shift the sub_command word off the argument vector.
756       cmd_obj = sub_cmd_obj;
757     }
758 
759     // Verify & handle any options/arguments passed to the alias command
760 
761     std::string args_string;
762 
763     if (!args.empty()) {
764       CommandObjectSP tmp_sp =
765           m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName(), false);
766       if (use_subcommand)
767         tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName(),
768                                                  false);
769 
770       args.GetCommandString(args_string);
771     }
772 
773     if (m_interpreter.AliasExists(alias_command) ||
774         m_interpreter.UserCommandExists(alias_command)) {
775       result.AppendWarningWithFormat(
776           "Overwriting existing definition for '%s'.\n", alias_command.c_str());
777     }
778 
779     if (CommandAlias *alias = m_interpreter.AddAlias(
780             alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp,
781             args_string)) {
782       if (m_command_options.m_help.OptionWasSet())
783         alias->SetHelp(m_command_options.m_help.GetCurrentValue());
784       if (m_command_options.m_long_help.OptionWasSet())
785         alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
786       result.SetStatus(eReturnStatusSuccessFinishNoResult);
787     } else {
788       result.AppendError("Unable to create requested alias.\n");
789       result.SetStatus(eReturnStatusFailed);
790       return false;
791     }
792 
793     return result.Succeeded();
794   }
795 };
796 
797 #pragma mark CommandObjectCommandsUnalias
798 //-------------------------------------------------------------------------
799 // CommandObjectCommandsUnalias
800 //-------------------------------------------------------------------------
801 
802 class CommandObjectCommandsUnalias : public CommandObjectParsed {
803 public:
804   CommandObjectCommandsUnalias(CommandInterpreter &interpreter)
805       : CommandObjectParsed(
806             interpreter, "command unalias",
807             "Delete one or more custom commands defined by 'command alias'.",
808             nullptr) {
809     CommandArgumentEntry arg;
810     CommandArgumentData alias_arg;
811 
812     // Define the first (and only) variant of this arg.
813     alias_arg.arg_type = eArgTypeAliasName;
814     alias_arg.arg_repetition = eArgRepeatPlain;
815 
816     // There is only one variant this argument could be; put it into the
817     // argument entry.
818     arg.push_back(alias_arg);
819 
820     // Push the data for the first argument into the m_arguments vector.
821     m_arguments.push_back(arg);
822   }
823 
824   ~CommandObjectCommandsUnalias() override = default;
825 
826 protected:
827   bool DoExecute(Args &args, CommandReturnObject &result) override {
828     CommandObject::CommandMap::iterator pos;
829     CommandObject *cmd_obj;
830 
831     if (args.empty()) {
832       result.AppendError("must call 'unalias' with a valid alias");
833       result.SetStatus(eReturnStatusFailed);
834       return false;
835     }
836 
837     auto command_name = args[0].ref;
838     cmd_obj = m_interpreter.GetCommandObject(command_name);
839     if (!cmd_obj) {
840       result.AppendErrorWithFormat(
841           "'%s' is not a known command.\nTry 'help' to see a "
842           "current list of commands.\n",
843           args[0].c_str());
844       result.SetStatus(eReturnStatusFailed);
845       return false;
846     }
847 
848     if (m_interpreter.CommandExists(command_name)) {
849       if (cmd_obj->IsRemovable()) {
850         result.AppendErrorWithFormat(
851             "'%s' is not an alias, it is a debugger command which can be "
852             "removed using the 'command delete' command.\n",
853             args[0].c_str());
854       } else {
855         result.AppendErrorWithFormat(
856             "'%s' is a permanent debugger command and cannot be removed.\n",
857             args[0].c_str());
858       }
859       result.SetStatus(eReturnStatusFailed);
860       return false;
861     }
862 
863     if (!m_interpreter.RemoveAlias(command_name)) {
864       if (m_interpreter.AliasExists(command_name))
865         result.AppendErrorWithFormat(
866             "Error occurred while attempting to unalias '%s'.\n",
867             args[0].c_str());
868       else
869         result.AppendErrorWithFormat("'%s' is not an existing alias.\n",
870                                      args[0].c_str());
871       result.SetStatus(eReturnStatusFailed);
872       return false;
873     }
874 
875     result.SetStatus(eReturnStatusSuccessFinishNoResult);
876     return result.Succeeded();
877   }
878 };
879 
880 #pragma mark CommandObjectCommandsDelete
881 //-------------------------------------------------------------------------
882 // CommandObjectCommandsDelete
883 //-------------------------------------------------------------------------
884 
885 class CommandObjectCommandsDelete : public CommandObjectParsed {
886 public:
887   CommandObjectCommandsDelete(CommandInterpreter &interpreter)
888       : CommandObjectParsed(
889             interpreter, "command delete",
890             "Delete one or more custom commands defined by 'command regex'.",
891             nullptr) {
892     CommandArgumentEntry arg;
893     CommandArgumentData alias_arg;
894 
895     // Define the first (and only) variant of this arg.
896     alias_arg.arg_type = eArgTypeCommandName;
897     alias_arg.arg_repetition = eArgRepeatPlain;
898 
899     // There is only one variant this argument could be; put it into the
900     // argument entry.
901     arg.push_back(alias_arg);
902 
903     // Push the data for the first argument into the m_arguments vector.
904     m_arguments.push_back(arg);
905   }
906 
907   ~CommandObjectCommandsDelete() override = default;
908 
909 protected:
910   bool DoExecute(Args &args, CommandReturnObject &result) override {
911     CommandObject::CommandMap::iterator pos;
912 
913     if (args.empty()) {
914       result.AppendErrorWithFormat("must call '%s' with one or more valid user "
915                                    "defined regular expression command names",
916                                    GetCommandName().str().c_str());
917       result.SetStatus(eReturnStatusFailed);
918     }
919 
920     auto command_name = args[0].ref;
921     if (!m_interpreter.CommandExists(command_name)) {
922       StreamString error_msg_stream;
923       const bool generate_apropos = true;
924       const bool generate_type_lookup = false;
925       CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
926           &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(),
927           generate_apropos, generate_type_lookup);
928       result.AppendError(error_msg_stream.GetString());
929       result.SetStatus(eReturnStatusFailed);
930       return false;
931     }
932 
933     if (!m_interpreter.RemoveCommand(command_name)) {
934       result.AppendErrorWithFormat(
935           "'%s' is a permanent debugger command and cannot be removed.\n",
936           args[0].c_str());
937       result.SetStatus(eReturnStatusFailed);
938       return false;
939     }
940 
941     result.SetStatus(eReturnStatusSuccessFinishNoResult);
942     return true;
943   }
944 };
945 
946 //-------------------------------------------------------------------------
947 // CommandObjectCommandsAddRegex
948 //-------------------------------------------------------------------------
949 
950 static OptionDefinition g_regex_options[] = {
951     // clang-format off
952   { LLDB_OPT_SET_1, false, "help"  , 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "The help text to display for this command." },
953   { LLDB_OPT_SET_1, false, "syntax", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "A syntax string showing the typical usage syntax." },
954     // clang-format on
955 };
956 
957 #pragma mark CommandObjectCommandsAddRegex
958 
959 class CommandObjectCommandsAddRegex : public CommandObjectParsed,
960                                       public IOHandlerDelegateMultiline {
961 public:
962   CommandObjectCommandsAddRegex(CommandInterpreter &interpreter)
963       : CommandObjectParsed(
964             interpreter, "command regex", "Define a custom command in terms of "
965                                           "existing commands by matching "
966                                           "regular expressions.",
967             "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
968         IOHandlerDelegateMultiline("",
969                                    IOHandlerDelegate::Completion::LLDBCommand),
970         m_options() {
971     SetHelpLong(
972         R"(
973 )"
974         "This command allows the user to create powerful regular expression commands \
975 with substitutions. The regular expressions and substitutions are specified \
976 using the regular expression substitution format of:"
977         R"(
978 
979     s/<regex>/<subst>/
980 
981 )"
982         "<regex> is a regular expression that can use parenthesis to capture regular \
983 expression input and substitute the captured matches in the output using %1 \
984 for the first match, %2 for the second, and so on."
985         R"(
986 
987 )"
988         "The regular expressions can all be specified on the command line if more than \
989 one argument is provided. If just the command name is provided on the command \
990 line, then the regular expressions and substitutions can be entered on separate \
991 lines, followed by an empty line to terminate the command definition."
992         R"(
993 
994 EXAMPLES
995 
996 )"
997         "The following example will define a regular expression command named 'f' that \
998 will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \
999 a number follows 'f':"
1000         R"(
1001 
1002     (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')");
1003   }
1004 
1005   ~CommandObjectCommandsAddRegex() override = default;
1006 
1007 protected:
1008   void IOHandlerActivated(IOHandler &io_handler) override {
1009     StreamFileSP output_sp(io_handler.GetOutputStreamFile());
1010     if (output_sp) {
1011       output_sp->PutCString("Enter one of more sed substitution commands in "
1012                             "the form: 's/<regex>/<subst>/'.\nTerminate the "
1013                             "substitution list with an empty line.\n");
1014       output_sp->Flush();
1015     }
1016   }
1017 
1018   void IOHandlerInputComplete(IOHandler &io_handler,
1019                               std::string &data) override {
1020     io_handler.SetIsDone(true);
1021     if (m_regex_cmd_ap) {
1022       StringList lines;
1023       if (lines.SplitIntoLines(data)) {
1024         const size_t num_lines = lines.GetSize();
1025         bool check_only = false;
1026         for (size_t i = 0; i < num_lines; ++i) {
1027           llvm::StringRef bytes_strref(lines[i]);
1028           Error error = AppendRegexSubstitution(bytes_strref, check_only);
1029           if (error.Fail()) {
1030             if (!m_interpreter.GetDebugger()
1031                      .GetCommandInterpreter()
1032                      .GetBatchCommandMode()) {
1033               StreamSP out_stream =
1034                   m_interpreter.GetDebugger().GetAsyncOutputStream();
1035               out_stream->Printf("error: %s\n", error.AsCString());
1036             }
1037           }
1038         }
1039       }
1040       if (m_regex_cmd_ap->HasRegexEntries()) {
1041         CommandObjectSP cmd_sp(m_regex_cmd_ap.release());
1042         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
1043       }
1044     }
1045   }
1046 
1047   bool DoExecute(Args &command, CommandReturnObject &result) override {
1048     const size_t argc = command.GetArgumentCount();
1049     if (argc == 0) {
1050       result.AppendError("usage: 'command regex <command-name> "
1051                          "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
1052       result.SetStatus(eReturnStatusFailed);
1053       return false;
1054     }
1055 
1056     Error error;
1057     auto name = command[0].ref;
1058     m_regex_cmd_ap = llvm::make_unique<CommandObjectRegexCommand>(
1059         m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 10, 0,
1060         true);
1061 
1062     if (argc == 1) {
1063       Debugger &debugger = m_interpreter.GetDebugger();
1064       bool color_prompt = debugger.GetUseColor();
1065       const bool multiple_lines = true; // Get multiple lines
1066       IOHandlerSP io_handler_sp(new IOHandlerEditline(
1067           debugger, IOHandler::Type::Other,
1068           "lldb-regex",          // Name of input reader for history
1069           llvm::StringRef("> "), // Prompt
1070           llvm::StringRef(),     // Continuation prompt
1071           multiple_lines, color_prompt,
1072           0, // Don't show line numbers
1073           *this));
1074 
1075       if (io_handler_sp) {
1076         debugger.PushIOHandler(io_handler_sp);
1077         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1078       }
1079     } else {
1080       for (auto &entry : command.entries().drop_front()) {
1081         bool check_only = false;
1082         error = AppendRegexSubstitution(entry.ref, check_only);
1083         if (error.Fail())
1084           break;
1085       }
1086 
1087       if (error.Success()) {
1088         AddRegexCommandToInterpreter();
1089       }
1090     }
1091     if (error.Fail()) {
1092       result.AppendError(error.AsCString());
1093       result.SetStatus(eReturnStatusFailed);
1094     }
1095 
1096     return result.Succeeded();
1097   }
1098 
1099   Error AppendRegexSubstitution(const llvm::StringRef &regex_sed,
1100                                 bool check_only) {
1101     Error error;
1102 
1103     if (!m_regex_cmd_ap) {
1104       error.SetErrorStringWithFormat(
1105           "invalid regular expression command object for: '%.*s'",
1106           (int)regex_sed.size(), regex_sed.data());
1107       return error;
1108     }
1109 
1110     size_t regex_sed_size = regex_sed.size();
1111 
1112     if (regex_sed_size <= 1) {
1113       error.SetErrorStringWithFormat(
1114           "regular expression substitution string is too short: '%.*s'",
1115           (int)regex_sed.size(), regex_sed.data());
1116       return error;
1117     }
1118 
1119     if (regex_sed[0] != 's') {
1120       error.SetErrorStringWithFormat("regular expression substitution string "
1121                                      "doesn't start with 's': '%.*s'",
1122                                      (int)regex_sed.size(), regex_sed.data());
1123       return error;
1124     }
1125     const size_t first_separator_char_pos = 1;
1126     // use the char that follows 's' as the regex separator character
1127     // so we can have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
1128     const char separator_char = regex_sed[first_separator_char_pos];
1129     const size_t second_separator_char_pos =
1130         regex_sed.find(separator_char, first_separator_char_pos + 1);
1131 
1132     if (second_separator_char_pos == std::string::npos) {
1133       error.SetErrorStringWithFormat(
1134           "missing second '%c' separator char after '%.*s' in '%.*s'",
1135           separator_char,
1136           (int)(regex_sed.size() - first_separator_char_pos - 1),
1137           regex_sed.data() + (first_separator_char_pos + 1),
1138           (int)regex_sed.size(), regex_sed.data());
1139       return error;
1140     }
1141 
1142     const size_t third_separator_char_pos =
1143         regex_sed.find(separator_char, second_separator_char_pos + 1);
1144 
1145     if (third_separator_char_pos == std::string::npos) {
1146       error.SetErrorStringWithFormat(
1147           "missing third '%c' separator char after '%.*s' in '%.*s'",
1148           separator_char,
1149           (int)(regex_sed.size() - second_separator_char_pos - 1),
1150           regex_sed.data() + (second_separator_char_pos + 1),
1151           (int)regex_sed.size(), regex_sed.data());
1152       return error;
1153     }
1154 
1155     if (third_separator_char_pos != regex_sed_size - 1) {
1156       // Make sure that everything that follows the last regex
1157       // separator char
1158       if (regex_sed.find_first_not_of("\t\n\v\f\r ",
1159                                       third_separator_char_pos + 1) !=
1160           std::string::npos) {
1161         error.SetErrorStringWithFormat(
1162             "extra data found after the '%.*s' regular expression substitution "
1163             "string: '%.*s'",
1164             (int)third_separator_char_pos + 1, regex_sed.data(),
1165             (int)(regex_sed.size() - third_separator_char_pos - 1),
1166             regex_sed.data() + (third_separator_char_pos + 1));
1167         return error;
1168       }
1169     } else if (first_separator_char_pos + 1 == second_separator_char_pos) {
1170       error.SetErrorStringWithFormat(
1171           "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
1172           separator_char, separator_char, separator_char, (int)regex_sed.size(),
1173           regex_sed.data());
1174       return error;
1175     } else if (second_separator_char_pos + 1 == third_separator_char_pos) {
1176       error.SetErrorStringWithFormat(
1177           "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
1178           separator_char, separator_char, separator_char, (int)regex_sed.size(),
1179           regex_sed.data());
1180       return error;
1181     }
1182 
1183     if (!check_only) {
1184       std::string regex(regex_sed.substr(first_separator_char_pos + 1,
1185                                          second_separator_char_pos -
1186                                              first_separator_char_pos - 1));
1187       std::string subst(regex_sed.substr(second_separator_char_pos + 1,
1188                                          third_separator_char_pos -
1189                                              second_separator_char_pos - 1));
1190       m_regex_cmd_ap->AddRegexCommand(regex.c_str(), subst.c_str());
1191     }
1192     return error;
1193   }
1194 
1195   void AddRegexCommandToInterpreter() {
1196     if (m_regex_cmd_ap) {
1197       if (m_regex_cmd_ap->HasRegexEntries()) {
1198         CommandObjectSP cmd_sp(m_regex_cmd_ap.release());
1199         m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
1200       }
1201     }
1202   }
1203 
1204 private:
1205   std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_ap;
1206 
1207   class CommandOptions : public Options {
1208   public:
1209     CommandOptions() : Options() {}
1210 
1211     ~CommandOptions() override = default;
1212 
1213     Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1214                          ExecutionContext *execution_context) override {
1215       Error error;
1216       const int short_option = m_getopt_table[option_idx].val;
1217 
1218       switch (short_option) {
1219       case 'h':
1220         m_help.assign(option_arg);
1221         break;
1222       case 's':
1223         m_syntax.assign(option_arg);
1224         break;
1225       default:
1226         error.SetErrorStringWithFormat("unrecognized option '%c'",
1227                                        short_option);
1228         break;
1229       }
1230 
1231       return error;
1232     }
1233 
1234     void OptionParsingStarting(ExecutionContext *execution_context) override {
1235       m_help.clear();
1236       m_syntax.clear();
1237     }
1238 
1239     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1240       return llvm::makeArrayRef(g_regex_options);
1241     }
1242 
1243     // TODO: Convert these functions to return StringRefs.
1244     const char *GetHelp() {
1245       return (m_help.empty() ? nullptr : m_help.c_str());
1246     }
1247 
1248     const char *GetSyntax() {
1249       return (m_syntax.empty() ? nullptr : m_syntax.c_str());
1250     }
1251 
1252   protected:
1253     // Instance variables to hold the values for command options.
1254 
1255     std::string m_help;
1256     std::string m_syntax;
1257   };
1258 
1259   Options *GetOptions() override { return &m_options; }
1260 
1261   CommandOptions m_options;
1262 };
1263 
1264 class CommandObjectPythonFunction : public CommandObjectRaw {
1265 public:
1266   CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name,
1267                               std::string funct, std::string help,
1268                               ScriptedCommandSynchronicity synch)
1269       : CommandObjectRaw(interpreter, name),
1270         m_function_name(funct), m_synchro(synch), m_fetched_help_long(false) {
1271     if (!help.empty())
1272       SetHelp(help);
1273     else {
1274       StreamString stream;
1275       stream.Printf("For more information run 'help %s'", name.c_str());
1276       SetHelp(stream.GetString());
1277     }
1278   }
1279 
1280   ~CommandObjectPythonFunction() override = default;
1281 
1282   bool IsRemovable() const override { return true; }
1283 
1284   const std::string &GetFunctionName() { return m_function_name; }
1285 
1286   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1287 
1288   llvm::StringRef GetHelpLong() override {
1289     if (m_fetched_help_long)
1290       return CommandObjectRaw::GetHelpLong();
1291 
1292     ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter();
1293     if (!scripter)
1294       return CommandObjectRaw::GetHelpLong();
1295 
1296     std::string docstring;
1297     m_fetched_help_long =
1298         scripter->GetDocumentationForItem(m_function_name.c_str(), docstring);
1299     if (!docstring.empty())
1300       SetHelpLong(docstring);
1301     return CommandObjectRaw::GetHelpLong();
1302   }
1303 
1304 protected:
1305   bool DoExecute(const char *raw_command_line,
1306                  CommandReturnObject &result) override {
1307     ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter();
1308 
1309     Error error;
1310 
1311     result.SetStatus(eReturnStatusInvalid);
1312 
1313     if (!scripter ||
1314         !scripter->RunScriptBasedCommand(m_function_name.c_str(),
1315                                          raw_command_line, m_synchro, result,
1316                                          error, m_exe_ctx)) {
1317       result.AppendError(error.AsCString());
1318       result.SetStatus(eReturnStatusFailed);
1319     } else {
1320       // Don't change the status if the command already set it...
1321       if (result.GetStatus() == eReturnStatusInvalid) {
1322         if (result.GetOutputData().empty())
1323           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1324         else
1325           result.SetStatus(eReturnStatusSuccessFinishResult);
1326       }
1327     }
1328 
1329     return result.Succeeded();
1330   }
1331 
1332 private:
1333   std::string m_function_name;
1334   ScriptedCommandSynchronicity m_synchro;
1335   bool m_fetched_help_long;
1336 };
1337 
1338 class CommandObjectScriptingObject : public CommandObjectRaw {
1339 public:
1340   CommandObjectScriptingObject(CommandInterpreter &interpreter,
1341                                std::string name,
1342                                StructuredData::GenericSP cmd_obj_sp,
1343                                ScriptedCommandSynchronicity synch)
1344       : CommandObjectRaw(interpreter, name),
1345         m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch), m_fetched_help_short(false),
1346         m_fetched_help_long(false) {
1347     StreamString stream;
1348     stream.Printf("For more information run 'help %s'", name.c_str());
1349     SetHelp(stream.GetString());
1350     if (ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter())
1351       GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
1352   }
1353 
1354   ~CommandObjectScriptingObject() override = default;
1355 
1356   bool IsRemovable() const override { return true; }
1357 
1358   StructuredData::GenericSP GetImplementingObject() { return m_cmd_obj_sp; }
1359 
1360   ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
1361 
1362   llvm::StringRef GetHelp() override {
1363     if (m_fetched_help_short)
1364       return CommandObjectRaw::GetHelp();
1365     ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter();
1366     if (!scripter)
1367       return CommandObjectRaw::GetHelp();
1368     std::string docstring;
1369     m_fetched_help_short =
1370         scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
1371     if (!docstring.empty())
1372       SetHelp(docstring);
1373 
1374     return CommandObjectRaw::GetHelp();
1375   }
1376 
1377   llvm::StringRef GetHelpLong() override {
1378     if (m_fetched_help_long)
1379       return CommandObjectRaw::GetHelpLong();
1380 
1381     ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter();
1382     if (!scripter)
1383       return CommandObjectRaw::GetHelpLong();
1384 
1385     std::string docstring;
1386     m_fetched_help_long =
1387         scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
1388     if (!docstring.empty())
1389       SetHelpLong(docstring);
1390     return CommandObjectRaw::GetHelpLong();
1391   }
1392 
1393 protected:
1394   bool DoExecute(const char *raw_command_line,
1395                  CommandReturnObject &result) override {
1396     ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter();
1397 
1398     Error error;
1399 
1400     result.SetStatus(eReturnStatusInvalid);
1401 
1402     if (!scripter ||
1403         !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line,
1404                                          m_synchro, result, error, m_exe_ctx)) {
1405       result.AppendError(error.AsCString());
1406       result.SetStatus(eReturnStatusFailed);
1407     } else {
1408       // Don't change the status if the command already set it...
1409       if (result.GetStatus() == eReturnStatusInvalid) {
1410         if (result.GetOutputData().empty())
1411           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1412         else
1413           result.SetStatus(eReturnStatusSuccessFinishResult);
1414       }
1415     }
1416 
1417     return result.Succeeded();
1418   }
1419 
1420 private:
1421   StructuredData::GenericSP m_cmd_obj_sp;
1422   ScriptedCommandSynchronicity m_synchro;
1423   bool m_fetched_help_short : 1;
1424   bool m_fetched_help_long : 1;
1425 };
1426 
1427 //-------------------------------------------------------------------------
1428 // CommandObjectCommandsScriptImport
1429 //-------------------------------------------------------------------------
1430 
1431 OptionDefinition g_script_import_options[] = {
1432     // clang-format off
1433   { LLDB_OPT_SET_1, false, "allow-reload", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allow the script to be loaded even if it was already loaded before. This argument exists for backwards compatibility, but reloading is always allowed, whether you specify it or not." },
1434     // clang-format on
1435 };
1436 
1437 class CommandObjectCommandsScriptImport : public CommandObjectParsed {
1438 public:
1439   CommandObjectCommandsScriptImport(CommandInterpreter &interpreter)
1440       : CommandObjectParsed(interpreter, "command script import",
1441                             "Import a scripting module in LLDB.", nullptr),
1442         m_options() {
1443     CommandArgumentEntry arg1;
1444     CommandArgumentData cmd_arg;
1445 
1446     // Define the first (and only) variant of this arg.
1447     cmd_arg.arg_type = eArgTypeFilename;
1448     cmd_arg.arg_repetition = eArgRepeatPlus;
1449 
1450     // There is only one variant this argument could be; put it into the
1451     // argument entry.
1452     arg1.push_back(cmd_arg);
1453 
1454     // Push the data for the first argument into the m_arguments vector.
1455     m_arguments.push_back(arg1);
1456   }
1457 
1458   ~CommandObjectCommandsScriptImport() override = default;
1459 
1460   int HandleArgumentCompletion(Args &input, int &cursor_index,
1461                                int &cursor_char_position,
1462                                OptionElementVector &opt_element_vector,
1463                                int match_start_point, int max_return_elements,
1464                                bool &word_complete,
1465                                StringList &matches) override {
1466     llvm::StringRef completion_str = input[cursor_index].ref;
1467     completion_str = completion_str.take_front(cursor_char_position);
1468 
1469     CommandCompletions::InvokeCommonCompletionCallbacks(
1470         GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
1471         completion_str, match_start_point, max_return_elements, nullptr,
1472         word_complete, matches);
1473     return matches.GetSize();
1474   }
1475 
1476   Options *GetOptions() override { return &m_options; }
1477 
1478 protected:
1479   class CommandOptions : public Options {
1480   public:
1481     CommandOptions() : Options() {}
1482 
1483     ~CommandOptions() override = default;
1484 
1485     Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1486                          ExecutionContext *execution_context) override {
1487       Error error;
1488       const int short_option = m_getopt_table[option_idx].val;
1489 
1490       switch (short_option) {
1491       case 'r':
1492         m_allow_reload = true;
1493         break;
1494       default:
1495         error.SetErrorStringWithFormat("unrecognized option '%c'",
1496                                        short_option);
1497         break;
1498       }
1499 
1500       return error;
1501     }
1502 
1503     void OptionParsingStarting(ExecutionContext *execution_context) override {
1504       m_allow_reload = true;
1505     }
1506 
1507     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1508       return llvm::makeArrayRef(g_script_import_options);
1509     }
1510 
1511     // Instance variables to hold the values for command options.
1512 
1513     bool m_allow_reload;
1514   };
1515 
1516   bool DoExecute(Args &command, CommandReturnObject &result) override {
1517     if (m_interpreter.GetDebugger().GetScriptLanguage() !=
1518         lldb::eScriptLanguagePython) {
1519       result.AppendError("only scripting language supported for module "
1520                          "importing is currently Python");
1521       result.SetStatus(eReturnStatusFailed);
1522       return false;
1523     }
1524 
1525     if (command.empty()) {
1526       result.AppendError("command script import needs one or more arguments");
1527       result.SetStatus(eReturnStatusFailed);
1528       return false;
1529     }
1530 
1531     for (auto &entry : command.entries()) {
1532       Error error;
1533 
1534       const bool init_session = true;
1535       // FIXME: this is necessary because CommandObject::CheckRequirements()
1536       // assumes that commands won't ever be recursively invoked, but it's
1537       // actually possible to craft a Python script that does other "command
1538       // script imports" in __lldb_init_module the real fix is to have recursive
1539       // commands possible with a CommandInvocation object separate from the
1540       // CommandObject itself, so that recursive command invocations won't stomp
1541       // on each other (wrt to execution contents, options, and more)
1542       m_exe_ctx.Clear();
1543       if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule(
1544               entry.c_str(), m_options.m_allow_reload, init_session, error)) {
1545         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1546       } else {
1547         result.AppendErrorWithFormat("module importing failed: %s",
1548                                      error.AsCString());
1549         result.SetStatus(eReturnStatusFailed);
1550       }
1551     }
1552 
1553     return result.Succeeded();
1554   }
1555 
1556   CommandOptions m_options;
1557 };
1558 
1559 //-------------------------------------------------------------------------
1560 // CommandObjectCommandsScriptAdd
1561 //-------------------------------------------------------------------------
1562 
1563 static OptionEnumValueElement g_script_synchro_type[] = {
1564     {eScriptedCommandSynchronicitySynchronous, "synchronous",
1565      "Run synchronous"},
1566     {eScriptedCommandSynchronicityAsynchronous, "asynchronous",
1567      "Run asynchronous"},
1568     {eScriptedCommandSynchronicityCurrentValue, "current",
1569      "Do not alter current setting"},
1570     {0, nullptr, nullptr}};
1571 
1572 static OptionDefinition g_script_add_options[] = {
1573     // clang-format off
1574   { LLDB_OPT_SET_1,   false, "function",      'f', OptionParser::eRequiredArgument, nullptr, nullptr,               0, eArgTypePythonFunction,               "Name of the Python function to bind to this command name." },
1575   { LLDB_OPT_SET_2,   false, "class",         'c', OptionParser::eRequiredArgument, nullptr, nullptr,               0, eArgTypePythonClass,                  "Name of the Python class to bind to this command name." },
1576   { LLDB_OPT_SET_1,   false, "help"  ,        'h', OptionParser::eRequiredArgument, nullptr, nullptr,               0, eArgTypeHelpText,                     "The help text to display for this command." },
1577   { LLDB_OPT_SET_ALL, false, "synchronicity", 's', OptionParser::eRequiredArgument, nullptr, g_script_synchro_type, 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system." },
1578     // clang-format on
1579 };
1580 
1581 class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
1582                                        public IOHandlerDelegateMultiline {
1583 public:
1584   CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter)
1585       : CommandObjectParsed(interpreter, "command script add",
1586                             "Add a scripted function as an LLDB command.",
1587                             nullptr),
1588         IOHandlerDelegateMultiline("DONE"), m_options() {
1589     CommandArgumentEntry arg1;
1590     CommandArgumentData cmd_arg;
1591 
1592     // Define the first (and only) variant of this arg.
1593     cmd_arg.arg_type = eArgTypeCommandName;
1594     cmd_arg.arg_repetition = eArgRepeatPlain;
1595 
1596     // There is only one variant this argument could be; put it into the
1597     // argument entry.
1598     arg1.push_back(cmd_arg);
1599 
1600     // Push the data for the first argument into the m_arguments vector.
1601     m_arguments.push_back(arg1);
1602   }
1603 
1604   ~CommandObjectCommandsScriptAdd() override = default;
1605 
1606   Options *GetOptions() override { return &m_options; }
1607 
1608 protected:
1609   class CommandOptions : public Options {
1610   public:
1611     CommandOptions()
1612         : Options(), m_class_name(), m_funct_name(), m_short_help(),
1613           m_synchronicity(eScriptedCommandSynchronicitySynchronous) {}
1614 
1615     ~CommandOptions() override = default;
1616 
1617     Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1618                          ExecutionContext *execution_context) override {
1619       Error error;
1620       const int short_option = m_getopt_table[option_idx].val;
1621 
1622       switch (short_option) {
1623       case 'f':
1624         if (!option_arg.empty())
1625           m_funct_name = option_arg;
1626         break;
1627       case 'c':
1628         if (!option_arg.empty())
1629           m_class_name = option_arg;
1630         break;
1631       case 'h':
1632         if (!option_arg.empty())
1633           m_short_help = option_arg;
1634         break;
1635       case 's':
1636         m_synchronicity =
1637             (ScriptedCommandSynchronicity)Args::StringToOptionEnum(
1638                 option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
1639         if (!error.Success())
1640           error.SetErrorStringWithFormat(
1641               "unrecognized value for synchronicity '%s'",
1642               option_arg.str().c_str());
1643         break;
1644       default:
1645         error.SetErrorStringWithFormat("unrecognized option '%c'",
1646                                        short_option);
1647         break;
1648       }
1649 
1650       return error;
1651     }
1652 
1653     void OptionParsingStarting(ExecutionContext *execution_context) override {
1654       m_class_name.clear();
1655       m_funct_name.clear();
1656       m_short_help.clear();
1657       m_synchronicity = eScriptedCommandSynchronicitySynchronous;
1658     }
1659 
1660     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1661       return llvm::makeArrayRef(g_script_add_options);
1662     }
1663 
1664     // Instance variables to hold the values for command options.
1665 
1666     std::string m_class_name;
1667     std::string m_funct_name;
1668     std::string m_short_help;
1669     ScriptedCommandSynchronicity m_synchronicity;
1670   };
1671 
1672   void IOHandlerActivated(IOHandler &io_handler) override {
1673     StreamFileSP output_sp(io_handler.GetOutputStreamFile());
1674     if (output_sp) {
1675       output_sp->PutCString(g_python_command_instructions);
1676       output_sp->Flush();
1677     }
1678   }
1679 
1680   void IOHandlerInputComplete(IOHandler &io_handler,
1681                               std::string &data) override {
1682     StreamFileSP error_sp = io_handler.GetErrorStreamFile();
1683 
1684     ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
1685     if (interpreter) {
1686 
1687       StringList lines;
1688       lines.SplitIntoLines(data);
1689       if (lines.GetSize() > 0) {
1690         std::string funct_name_str;
1691         if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) {
1692           if (funct_name_str.empty()) {
1693             error_sp->Printf("error: unable to obtain a function name, didn't "
1694                              "add python command.\n");
1695             error_sp->Flush();
1696           } else {
1697             // everything should be fine now, let's add this alias
1698 
1699             CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(
1700                 m_interpreter, m_cmd_name, funct_name_str, m_short_help,
1701                 m_synchronicity));
1702 
1703             if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp,
1704                                               true)) {
1705               error_sp->Printf("error: unable to add selected command, didn't "
1706                                "add python command.\n");
1707               error_sp->Flush();
1708             }
1709           }
1710         } else {
1711           error_sp->Printf(
1712               "error: unable to create function, didn't add python command.\n");
1713           error_sp->Flush();
1714         }
1715       } else {
1716         error_sp->Printf("error: empty function, didn't add python command.\n");
1717         error_sp->Flush();
1718       }
1719     } else {
1720       error_sp->Printf(
1721           "error: script interpreter missing, didn't add python command.\n");
1722       error_sp->Flush();
1723     }
1724 
1725     io_handler.SetIsDone(true);
1726   }
1727 
1728 protected:
1729   bool DoExecute(Args &command, CommandReturnObject &result) override {
1730     if (m_interpreter.GetDebugger().GetScriptLanguage() !=
1731         lldb::eScriptLanguagePython) {
1732       result.AppendError("only scripting language supported for scripted "
1733                          "commands is currently Python");
1734       result.SetStatus(eReturnStatusFailed);
1735       return false;
1736     }
1737 
1738     if (command.GetArgumentCount() != 1) {
1739       result.AppendError("'command script add' requires one argument");
1740       result.SetStatus(eReturnStatusFailed);
1741       return false;
1742     }
1743 
1744     // Store the options in case we get multi-line input
1745     m_cmd_name = command[0].ref;
1746     m_short_help.assign(m_options.m_short_help);
1747     m_synchronicity = m_options.m_synchronicity;
1748 
1749     if (m_options.m_class_name.empty()) {
1750       if (m_options.m_funct_name.empty()) {
1751         m_interpreter.GetPythonCommandsFromIOHandler(
1752             "     ",  // Prompt
1753             *this,    // IOHandlerDelegate
1754             true,     // Run IOHandler in async mode
1755             nullptr); // Baton for the "io_handler" that will be passed back
1756                       // into our IOHandlerDelegate functions
1757       } else {
1758         CommandObjectSP new_cmd(new CommandObjectPythonFunction(
1759             m_interpreter, m_cmd_name, m_options.m_funct_name,
1760             m_options.m_short_help, m_synchronicity));
1761         if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) {
1762           result.SetStatus(eReturnStatusSuccessFinishNoResult);
1763         } else {
1764           result.AppendError("cannot add command");
1765           result.SetStatus(eReturnStatusFailed);
1766         }
1767       }
1768     } else {
1769       ScriptInterpreter *interpreter =
1770           GetCommandInterpreter().GetScriptInterpreter();
1771       if (!interpreter) {
1772         result.AppendError("cannot find ScriptInterpreter");
1773         result.SetStatus(eReturnStatusFailed);
1774         return false;
1775       }
1776 
1777       auto cmd_obj_sp = interpreter->CreateScriptCommandObject(
1778           m_options.m_class_name.c_str());
1779       if (!cmd_obj_sp) {
1780         result.AppendError("cannot create helper object");
1781         result.SetStatus(eReturnStatusFailed);
1782         return false;
1783       }
1784 
1785       CommandObjectSP new_cmd(new CommandObjectScriptingObject(
1786           m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity));
1787       if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) {
1788         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1789       } else {
1790         result.AppendError("cannot add command");
1791         result.SetStatus(eReturnStatusFailed);
1792       }
1793     }
1794 
1795     return result.Succeeded();
1796   }
1797 
1798   CommandOptions m_options;
1799   std::string m_cmd_name;
1800   std::string m_short_help;
1801   ScriptedCommandSynchronicity m_synchronicity;
1802 };
1803 
1804 //-------------------------------------------------------------------------
1805 // CommandObjectCommandsScriptList
1806 //-------------------------------------------------------------------------
1807 
1808 class CommandObjectCommandsScriptList : public CommandObjectParsed {
1809 public:
1810   CommandObjectCommandsScriptList(CommandInterpreter &interpreter)
1811       : CommandObjectParsed(interpreter, "command script list",
1812                             "List defined scripted commands.", nullptr) {}
1813 
1814   ~CommandObjectCommandsScriptList() override = default;
1815 
1816   bool DoExecute(Args &command, CommandReturnObject &result) override {
1817     m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
1818 
1819     result.SetStatus(eReturnStatusSuccessFinishResult);
1820 
1821     return true;
1822   }
1823 };
1824 
1825 //-------------------------------------------------------------------------
1826 // CommandObjectCommandsScriptClear
1827 //-------------------------------------------------------------------------
1828 
1829 class CommandObjectCommandsScriptClear : public CommandObjectParsed {
1830 public:
1831   CommandObjectCommandsScriptClear(CommandInterpreter &interpreter)
1832       : CommandObjectParsed(interpreter, "command script clear",
1833                             "Delete all scripted commands.", nullptr) {}
1834 
1835   ~CommandObjectCommandsScriptClear() override = default;
1836 
1837 protected:
1838   bool DoExecute(Args &command, CommandReturnObject &result) override {
1839     m_interpreter.RemoveAllUser();
1840 
1841     result.SetStatus(eReturnStatusSuccessFinishResult);
1842 
1843     return true;
1844   }
1845 };
1846 
1847 //-------------------------------------------------------------------------
1848 // CommandObjectCommandsScriptDelete
1849 //-------------------------------------------------------------------------
1850 
1851 class CommandObjectCommandsScriptDelete : public CommandObjectParsed {
1852 public:
1853   CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter)
1854       : CommandObjectParsed(interpreter, "command script delete",
1855                             "Delete a scripted command.", nullptr) {
1856     CommandArgumentEntry arg1;
1857     CommandArgumentData cmd_arg;
1858 
1859     // Define the first (and only) variant of this arg.
1860     cmd_arg.arg_type = eArgTypeCommandName;
1861     cmd_arg.arg_repetition = eArgRepeatPlain;
1862 
1863     // There is only one variant this argument could be; put it into the
1864     // argument entry.
1865     arg1.push_back(cmd_arg);
1866 
1867     // Push the data for the first argument into the m_arguments vector.
1868     m_arguments.push_back(arg1);
1869   }
1870 
1871   ~CommandObjectCommandsScriptDelete() override = default;
1872 
1873 protected:
1874   bool DoExecute(Args &command, CommandReturnObject &result) override {
1875 
1876     if (command.GetArgumentCount() != 1) {
1877       result.AppendError("'command script delete' requires one argument");
1878       result.SetStatus(eReturnStatusFailed);
1879       return false;
1880     }
1881 
1882     auto cmd_name = command[0].ref;
1883 
1884     if (cmd_name.empty() || !m_interpreter.HasUserCommands() ||
1885         !m_interpreter.UserCommandExists(cmd_name)) {
1886       result.AppendErrorWithFormat("command %s not found", command[0].c_str());
1887       result.SetStatus(eReturnStatusFailed);
1888       return false;
1889     }
1890 
1891     m_interpreter.RemoveUser(cmd_name);
1892     result.SetStatus(eReturnStatusSuccessFinishResult);
1893     return true;
1894   }
1895 };
1896 
1897 #pragma mark CommandObjectMultiwordCommandsScript
1898 
1899 //-------------------------------------------------------------------------
1900 // CommandObjectMultiwordCommandsScript
1901 //-------------------------------------------------------------------------
1902 
1903 class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword {
1904 public:
1905   CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter)
1906       : CommandObjectMultiword(
1907             interpreter, "command script", "Commands for managing custom "
1908                                            "commands implemented by "
1909                                            "interpreter scripts.",
1910             "command script <subcommand> [<subcommand-options>]") {
1911     LoadSubCommand("add", CommandObjectSP(
1912                               new CommandObjectCommandsScriptAdd(interpreter)));
1913     LoadSubCommand(
1914         "delete",
1915         CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter)));
1916     LoadSubCommand(
1917         "clear",
1918         CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter)));
1919     LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList(
1920                                interpreter)));
1921     LoadSubCommand(
1922         "import",
1923         CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter)));
1924   }
1925 
1926   ~CommandObjectMultiwordCommandsScript() override = default;
1927 };
1928 
1929 #pragma mark CommandObjectMultiwordCommands
1930 
1931 //-------------------------------------------------------------------------
1932 // CommandObjectMultiwordCommands
1933 //-------------------------------------------------------------------------
1934 
1935 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(
1936     CommandInterpreter &interpreter)
1937     : CommandObjectMultiword(interpreter, "command",
1938                              "Commands for managing custom LLDB commands.",
1939                              "command <subcommand> [<subcommand-options>]") {
1940   LoadSubCommand("source",
1941                  CommandObjectSP(new CommandObjectCommandsSource(interpreter)));
1942   LoadSubCommand("alias",
1943                  CommandObjectSP(new CommandObjectCommandsAlias(interpreter)));
1944   LoadSubCommand("unalias", CommandObjectSP(
1945                                 new CommandObjectCommandsUnalias(interpreter)));
1946   LoadSubCommand("delete",
1947                  CommandObjectSP(new CommandObjectCommandsDelete(interpreter)));
1948   LoadSubCommand(
1949       "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter)));
1950   LoadSubCommand("history", CommandObjectSP(
1951                                 new CommandObjectCommandsHistory(interpreter)));
1952   LoadSubCommand(
1953       "script",
1954       CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter)));
1955 }
1956 
1957 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default;
1958