15ffd83dbSDimitry Andric //===-- CommandObjectCommands.cpp -----------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "CommandObjectCommands.h"
100b57cec5SDimitry Andric #include "CommandObjectHelp.h"
11e8d8bef9SDimitry Andric #include "CommandObjectRegexCommand.h"
120b57cec5SDimitry Andric #include "lldb/Core/Debugger.h"
130b57cec5SDimitry Andric #include "lldb/Core/IOHandler.h"
140b57cec5SDimitry Andric #include "lldb/Interpreter/CommandHistory.h"
150b57cec5SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h"
16fcaf7f86SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h"
170b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
180b57cec5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
190b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueBoolean.h"
200b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueString.h"
210b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueUInt64.h"
220b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h"
230b57cec5SDimitry Andric #include "lldb/Interpreter/ScriptInterpreter.h"
240b57cec5SDimitry Andric #include "lldb/Utility/Args.h"
250b57cec5SDimitry Andric #include "lldb/Utility/StringList.h"
26e8d8bef9SDimitry Andric #include "llvm/ADT/StringRef.h"
27bdd1243dSDimitry Andric #include <optional>
280b57cec5SDimitry Andric
290b57cec5SDimitry Andric using namespace lldb;
300b57cec5SDimitry Andric using namespace lldb_private;
310b57cec5SDimitry Andric
320b57cec5SDimitry Andric // CommandObjectCommandsSource
330b57cec5SDimitry Andric
349dba64beSDimitry Andric #define LLDB_OPTIONS_source
359dba64beSDimitry Andric #include "CommandOptions.inc"
360b57cec5SDimitry Andric
370b57cec5SDimitry Andric class CommandObjectCommandsSource : public CommandObjectParsed {
380b57cec5SDimitry Andric public:
CommandObjectCommandsSource(CommandInterpreter & interpreter)390b57cec5SDimitry Andric CommandObjectCommandsSource(CommandInterpreter &interpreter)
400b57cec5SDimitry Andric : CommandObjectParsed(
410b57cec5SDimitry Andric interpreter, "command source",
420b57cec5SDimitry Andric "Read and execute LLDB commands from the file <filename>.",
4304eeddc0SDimitry Andric nullptr) {
440b57cec5SDimitry Andric CommandArgumentEntry arg;
450b57cec5SDimitry Andric CommandArgumentData file_arg;
460b57cec5SDimitry Andric
470b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
480b57cec5SDimitry Andric file_arg.arg_type = eArgTypeFilename;
490b57cec5SDimitry Andric file_arg.arg_repetition = eArgRepeatPlain;
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
520b57cec5SDimitry Andric // argument entry.
530b57cec5SDimitry Andric arg.push_back(file_arg);
540b57cec5SDimitry Andric
550b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
560b57cec5SDimitry Andric m_arguments.push_back(arg);
570b57cec5SDimitry Andric }
580b57cec5SDimitry Andric
590b57cec5SDimitry Andric ~CommandObjectCommandsSource() override = default;
600b57cec5SDimitry Andric
GetRepeatCommand(Args & current_command_args,uint32_t index)61bdd1243dSDimitry Andric std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,
620b57cec5SDimitry Andric uint32_t index) override {
6381ad6265SDimitry Andric return std::string("");
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric
669dba64beSDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)679dba64beSDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
680b57cec5SDimitry Andric OptionElementVector &opt_element_vector) override {
69fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
70fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);
710b57cec5SDimitry Andric }
720b57cec5SDimitry Andric
GetOptions()730b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; }
740b57cec5SDimitry Andric
750b57cec5SDimitry Andric protected:
760b57cec5SDimitry Andric class CommandOptions : public Options {
770b57cec5SDimitry Andric public:
CommandOptions()780b57cec5SDimitry Andric CommandOptions()
7904eeddc0SDimitry Andric : m_stop_on_error(true), m_silent_run(false), m_stop_on_continue(true),
8004eeddc0SDimitry Andric m_cmd_relative_to_command_file(false) {}
810b57cec5SDimitry Andric
820b57cec5SDimitry Andric ~CommandOptions() override = default;
830b57cec5SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)840b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
850b57cec5SDimitry Andric ExecutionContext *execution_context) override {
860b57cec5SDimitry Andric Status error;
870b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
880b57cec5SDimitry Andric
890b57cec5SDimitry Andric switch (short_option) {
900b57cec5SDimitry Andric case 'e':
910b57cec5SDimitry Andric error = m_stop_on_error.SetValueFromString(option_arg);
920b57cec5SDimitry Andric break;
930b57cec5SDimitry Andric
940b57cec5SDimitry Andric case 'c':
950b57cec5SDimitry Andric error = m_stop_on_continue.SetValueFromString(option_arg);
960b57cec5SDimitry Andric break;
970b57cec5SDimitry Andric
98349cc55cSDimitry Andric case 'C':
99349cc55cSDimitry Andric m_cmd_relative_to_command_file = true;
100349cc55cSDimitry Andric break;
101349cc55cSDimitry Andric
1020b57cec5SDimitry Andric case 's':
1030b57cec5SDimitry Andric error = m_silent_run.SetValueFromString(option_arg);
1040b57cec5SDimitry Andric break;
1050b57cec5SDimitry Andric
1060b57cec5SDimitry Andric default:
1079dba64beSDimitry Andric llvm_unreachable("Unimplemented option");
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric
1100b57cec5SDimitry Andric return error;
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)1130b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
1140b57cec5SDimitry Andric m_stop_on_error.Clear();
1150b57cec5SDimitry Andric m_silent_run.Clear();
1160b57cec5SDimitry Andric m_stop_on_continue.Clear();
117349cc55cSDimitry Andric m_cmd_relative_to_command_file.Clear();
1180b57cec5SDimitry Andric }
1190b57cec5SDimitry Andric
GetDefinitions()1200b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
121bdd1243dSDimitry Andric return llvm::ArrayRef(g_source_options);
1220b57cec5SDimitry Andric }
1230b57cec5SDimitry Andric
1240b57cec5SDimitry Andric // Instance variables to hold the values for command options.
1250b57cec5SDimitry Andric
1260b57cec5SDimitry Andric OptionValueBoolean m_stop_on_error;
1270b57cec5SDimitry Andric OptionValueBoolean m_silent_run;
1280b57cec5SDimitry Andric OptionValueBoolean m_stop_on_continue;
129349cc55cSDimitry Andric OptionValueBoolean m_cmd_relative_to_command_file;
1300b57cec5SDimitry Andric };
1310b57cec5SDimitry Andric
DoExecute(Args & command,CommandReturnObject & result)132*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
1330b57cec5SDimitry Andric if (command.GetArgumentCount() != 1) {
1340b57cec5SDimitry Andric result.AppendErrorWithFormat(
1350b57cec5SDimitry Andric "'%s' takes exactly one executable filename argument.\n",
1360b57cec5SDimitry Andric GetCommandName().str().c_str());
137*c9157d92SDimitry Andric return;
1380b57cec5SDimitry Andric }
1390b57cec5SDimitry Andric
140349cc55cSDimitry Andric FileSpec source_dir = {};
141349cc55cSDimitry Andric if (m_options.m_cmd_relative_to_command_file) {
142349cc55cSDimitry Andric source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
143349cc55cSDimitry Andric if (!source_dir) {
144349cc55cSDimitry Andric result.AppendError("command source -C can only be specified "
145349cc55cSDimitry Andric "from a command file");
146349cc55cSDimitry Andric result.SetStatus(eReturnStatusFailed);
147*c9157d92SDimitry Andric return;
148349cc55cSDimitry Andric }
149349cc55cSDimitry Andric }
150349cc55cSDimitry Andric
1519dba64beSDimitry Andric FileSpec cmd_file(command[0].ref());
152349cc55cSDimitry Andric if (source_dir) {
153349cc55cSDimitry Andric // Prepend the source_dir to the cmd_file path:
154349cc55cSDimitry Andric if (!cmd_file.IsRelative()) {
155349cc55cSDimitry Andric result.AppendError("command source -C can only be used "
156349cc55cSDimitry Andric "with a relative path.");
157349cc55cSDimitry Andric result.SetStatus(eReturnStatusFailed);
158*c9157d92SDimitry Andric return;
159349cc55cSDimitry Andric }
160349cc55cSDimitry Andric cmd_file.MakeAbsolute(source_dir);
161349cc55cSDimitry Andric }
162349cc55cSDimitry Andric
1630b57cec5SDimitry Andric FileSystem::Instance().Resolve(cmd_file);
1640b57cec5SDimitry Andric
165fe6060f1SDimitry Andric CommandInterpreterRunOptions options;
1660b57cec5SDimitry Andric // If any options were set, then use them
1670b57cec5SDimitry Andric if (m_options.m_stop_on_error.OptionWasSet() ||
1680b57cec5SDimitry Andric m_options.m_silent_run.OptionWasSet() ||
1690b57cec5SDimitry Andric m_options.m_stop_on_continue.OptionWasSet()) {
1700b57cec5SDimitry Andric if (m_options.m_stop_on_continue.OptionWasSet())
1710b57cec5SDimitry Andric options.SetStopOnContinue(
1720b57cec5SDimitry Andric m_options.m_stop_on_continue.GetCurrentValue());
1730b57cec5SDimitry Andric
1740b57cec5SDimitry Andric if (m_options.m_stop_on_error.OptionWasSet())
1750b57cec5SDimitry Andric options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue());
1760b57cec5SDimitry Andric
1770b57cec5SDimitry Andric // Individual silent setting is override for global command echo settings.
1780b57cec5SDimitry Andric if (m_options.m_silent_run.GetCurrentValue()) {
1790b57cec5SDimitry Andric options.SetSilent(true);
1800b57cec5SDimitry Andric } else {
1810b57cec5SDimitry Andric options.SetPrintResults(true);
1820b57cec5SDimitry Andric options.SetPrintErrors(true);
1830b57cec5SDimitry Andric options.SetEchoCommands(m_interpreter.GetEchoCommands());
1840b57cec5SDimitry Andric options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands());
1850b57cec5SDimitry Andric }
1860b57cec5SDimitry Andric }
187fe6060f1SDimitry Andric
188fe6060f1SDimitry Andric m_interpreter.HandleCommandsFromFile(cmd_file, options, result);
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric
1910b57cec5SDimitry Andric CommandOptions m_options;
1920b57cec5SDimitry Andric };
1930b57cec5SDimitry Andric
1940b57cec5SDimitry Andric #pragma mark CommandObjectCommandsAlias
1950b57cec5SDimitry Andric // CommandObjectCommandsAlias
1960b57cec5SDimitry Andric
1979dba64beSDimitry Andric #define LLDB_OPTIONS_alias
1989dba64beSDimitry Andric #include "CommandOptions.inc"
1990b57cec5SDimitry Andric
2000b57cec5SDimitry Andric static const char *g_python_command_instructions =
2010b57cec5SDimitry Andric "Enter your Python command(s). Type 'DONE' to end.\n"
2020b57cec5SDimitry Andric "You must define a Python function with this signature:\n"
203bdd1243dSDimitry Andric "def my_command_impl(debugger, args, exe_ctx, result, internal_dict):\n";
2040b57cec5SDimitry Andric
2050b57cec5SDimitry Andric class CommandObjectCommandsAlias : public CommandObjectRaw {
2060b57cec5SDimitry Andric protected:
2070b57cec5SDimitry Andric class CommandOptions : public OptionGroup {
2080b57cec5SDimitry Andric public:
20981ad6265SDimitry Andric CommandOptions() = default;
2100b57cec5SDimitry Andric
2110b57cec5SDimitry Andric ~CommandOptions() override = default;
2120b57cec5SDimitry Andric
GetDefinitions()2130b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
214bdd1243dSDimitry Andric return llvm::ArrayRef(g_alias_options);
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)2170b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
2180b57cec5SDimitry Andric ExecutionContext *execution_context) override {
2190b57cec5SDimitry Andric Status error;
2200b57cec5SDimitry Andric
2210b57cec5SDimitry Andric const int short_option = GetDefinitions()[option_idx].short_option;
2220b57cec5SDimitry Andric std::string option_str(option_value);
2230b57cec5SDimitry Andric
2240b57cec5SDimitry Andric switch (short_option) {
2250b57cec5SDimitry Andric case 'h':
2260b57cec5SDimitry Andric m_help.SetCurrentValue(option_str);
2270b57cec5SDimitry Andric m_help.SetOptionWasSet();
2280b57cec5SDimitry Andric break;
2290b57cec5SDimitry Andric
2300b57cec5SDimitry Andric case 'H':
2310b57cec5SDimitry Andric m_long_help.SetCurrentValue(option_str);
2320b57cec5SDimitry Andric m_long_help.SetOptionWasSet();
2330b57cec5SDimitry Andric break;
2340b57cec5SDimitry Andric
2350b57cec5SDimitry Andric default:
2369dba64beSDimitry Andric llvm_unreachable("Unimplemented option");
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric
2390b57cec5SDimitry Andric return error;
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)2420b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
2430b57cec5SDimitry Andric m_help.Clear();
2440b57cec5SDimitry Andric m_long_help.Clear();
2450b57cec5SDimitry Andric }
2460b57cec5SDimitry Andric
2470b57cec5SDimitry Andric OptionValueString m_help;
2480b57cec5SDimitry Andric OptionValueString m_long_help;
2490b57cec5SDimitry Andric };
2500b57cec5SDimitry Andric
2510b57cec5SDimitry Andric OptionGroupOptions m_option_group;
2520b57cec5SDimitry Andric CommandOptions m_command_options;
2530b57cec5SDimitry Andric
2540b57cec5SDimitry Andric public:
GetOptions()2550b57cec5SDimitry Andric Options *GetOptions() override { return &m_option_group; }
2560b57cec5SDimitry Andric
CommandObjectCommandsAlias(CommandInterpreter & interpreter)2570b57cec5SDimitry Andric CommandObjectCommandsAlias(CommandInterpreter &interpreter)
2580b57cec5SDimitry Andric : CommandObjectRaw(
2590b57cec5SDimitry Andric interpreter, "command alias",
26004eeddc0SDimitry Andric "Define a custom command in terms of an existing command.") {
2610b57cec5SDimitry Andric m_option_group.Append(&m_command_options);
2620b57cec5SDimitry Andric m_option_group.Finalize();
2630b57cec5SDimitry Andric
2640b57cec5SDimitry Andric SetHelpLong(
2650b57cec5SDimitry Andric "'alias' allows the user to create a short-cut or abbreviation for long \
2660b57cec5SDimitry Andric commands, multi-word commands, and commands that take particular options. \
2670b57cec5SDimitry Andric Below are some simple examples of how one might use the 'alias' command:"
2680b57cec5SDimitry Andric R"(
2690b57cec5SDimitry Andric
2700b57cec5SDimitry Andric (lldb) command alias sc script
2710b57cec5SDimitry Andric
2720b57cec5SDimitry Andric Creates the abbreviation 'sc' for the 'script' command.
2730b57cec5SDimitry Andric
2740b57cec5SDimitry Andric (lldb) command alias bp breakpoint
2750b57cec5SDimitry Andric
2760b57cec5SDimitry Andric )"
2770b57cec5SDimitry Andric " Creates the abbreviation 'bp' for the 'breakpoint' command. Since \
2780b57cec5SDimitry Andric breakpoint commands are two-word commands, the user would still need to \
2790b57cec5SDimitry Andric enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'."
2800b57cec5SDimitry Andric R"(
2810b57cec5SDimitry Andric
2820b57cec5SDimitry Andric (lldb) command alias bpl breakpoint list
2830b57cec5SDimitry Andric
2840b57cec5SDimitry Andric Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'.
2850b57cec5SDimitry Andric
2860b57cec5SDimitry Andric )"
2870b57cec5SDimitry Andric "An alias can include some options for the command, with the values either \
2880b57cec5SDimitry Andric filled in at the time the alias is created, or specified as positional \
2890b57cec5SDimitry Andric arguments, to be filled in when the alias is invoked. The following example \
2900b57cec5SDimitry Andric shows how to create aliases with options:"
2910b57cec5SDimitry Andric R"(
2920b57cec5SDimitry Andric
2930b57cec5SDimitry Andric (lldb) command alias bfl breakpoint set -f %1 -l %2
2940b57cec5SDimitry Andric
2950b57cec5SDimitry Andric )"
2960b57cec5SDimitry Andric " Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \
2970b57cec5SDimitry Andric options already part of the alias. So if the user wants to set a breakpoint \
2980b57cec5SDimitry Andric by file and line without explicitly having to use the -f and -l options, the \
2990b57cec5SDimitry Andric user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \
3000b57cec5SDimitry Andric for the actual arguments that will be passed when the alias command is used. \
3010b57cec5SDimitry Andric The number in the placeholder refers to the position/order the actual value \
3020b57cec5SDimitry Andric occupies when the alias is used. All the occurrences of '%1' in the alias \
3030b57cec5SDimitry Andric will be replaced with the first argument, all the occurrences of '%2' in the \
3040b57cec5SDimitry Andric alias will be replaced with the second argument, and so on. This also allows \
3050b57cec5SDimitry Andric actual arguments to be used multiple times within an alias (see 'process \
3060b57cec5SDimitry Andric launch' example below)."
3070b57cec5SDimitry Andric R"(
3080b57cec5SDimitry Andric
3090b57cec5SDimitry Andric )"
3100b57cec5SDimitry Andric "Note: the positional arguments must substitute as whole words in the resultant \
3110b57cec5SDimitry Andric command, so you can't at present do something like this to append the file extension \
3120b57cec5SDimitry Andric \".cpp\":"
3130b57cec5SDimitry Andric R"(
3140b57cec5SDimitry Andric
3150b57cec5SDimitry Andric (lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2
3160b57cec5SDimitry Andric
3170b57cec5SDimitry Andric )"
3180b57cec5SDimitry Andric "For more complex aliasing, use the \"command regex\" command instead. In the \
3190b57cec5SDimitry Andric 'bfl' case above, the actual file value will be filled in with the first argument \
3200b57cec5SDimitry Andric following 'bfl' and the actual line number value will be filled in with the second \
3210b57cec5SDimitry Andric argument. The user would use this alias as follows:"
3220b57cec5SDimitry Andric R"(
3230b57cec5SDimitry Andric
3240b57cec5SDimitry Andric (lldb) command alias bfl breakpoint set -f %1 -l %2
3250b57cec5SDimitry Andric (lldb) bfl my-file.c 137
3260b57cec5SDimitry Andric
3270b57cec5SDimitry Andric This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'.
3280b57cec5SDimitry Andric
3290b57cec5SDimitry Andric Another example:
3300b57cec5SDimitry Andric
3310b57cec5SDimitry Andric (lldb) command alias pltty process launch -s -o %1 -e %1
3320b57cec5SDimitry Andric (lldb) pltty /dev/tty0
3330b57cec5SDimitry Andric
3340b57cec5SDimitry Andric Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0'
3350b57cec5SDimitry Andric
3360b57cec5SDimitry Andric )"
3370b57cec5SDimitry Andric "If the user always wanted to pass the same value to a particular option, the \
3380b57cec5SDimitry Andric alias could be defined with that value directly in the alias as a constant, \
3390b57cec5SDimitry Andric rather than using a positional placeholder:"
3400b57cec5SDimitry Andric R"(
3410b57cec5SDimitry Andric
3420b57cec5SDimitry Andric (lldb) command alias bl3 breakpoint set -f %1 -l 3
3430b57cec5SDimitry Andric
3440b57cec5SDimitry Andric Always sets a breakpoint on line 3 of whatever file is indicated.)");
3450b57cec5SDimitry Andric
3460b57cec5SDimitry Andric CommandArgumentEntry arg1;
3470b57cec5SDimitry Andric CommandArgumentEntry arg2;
3480b57cec5SDimitry Andric CommandArgumentEntry arg3;
3490b57cec5SDimitry Andric CommandArgumentData alias_arg;
3500b57cec5SDimitry Andric CommandArgumentData cmd_arg;
3510b57cec5SDimitry Andric CommandArgumentData options_arg;
3520b57cec5SDimitry Andric
3530b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
3540b57cec5SDimitry Andric alias_arg.arg_type = eArgTypeAliasName;
3550b57cec5SDimitry Andric alias_arg.arg_repetition = eArgRepeatPlain;
3560b57cec5SDimitry Andric
3570b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
3580b57cec5SDimitry Andric // argument entry.
3590b57cec5SDimitry Andric arg1.push_back(alias_arg);
3600b57cec5SDimitry Andric
3610b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
3620b57cec5SDimitry Andric cmd_arg.arg_type = eArgTypeCommandName;
3630b57cec5SDimitry Andric cmd_arg.arg_repetition = eArgRepeatPlain;
3640b57cec5SDimitry Andric
3650b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
3660b57cec5SDimitry Andric // argument entry.
3670b57cec5SDimitry Andric arg2.push_back(cmd_arg);
3680b57cec5SDimitry Andric
3690b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
3700b57cec5SDimitry Andric options_arg.arg_type = eArgTypeAliasOptions;
3710b57cec5SDimitry Andric options_arg.arg_repetition = eArgRepeatOptional;
3720b57cec5SDimitry Andric
3730b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
3740b57cec5SDimitry Andric // argument entry.
3750b57cec5SDimitry Andric arg3.push_back(options_arg);
3760b57cec5SDimitry Andric
3770b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
3780b57cec5SDimitry Andric m_arguments.push_back(arg1);
3790b57cec5SDimitry Andric m_arguments.push_back(arg2);
3800b57cec5SDimitry Andric m_arguments.push_back(arg3);
3810b57cec5SDimitry Andric }
3820b57cec5SDimitry Andric
3830b57cec5SDimitry Andric ~CommandObjectCommandsAlias() override = default;
3840b57cec5SDimitry Andric
3850b57cec5SDimitry Andric protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)386*c9157d92SDimitry Andric void DoExecute(llvm::StringRef raw_command_line,
3870b57cec5SDimitry Andric CommandReturnObject &result) override {
3880b57cec5SDimitry Andric if (raw_command_line.empty()) {
3890b57cec5SDimitry Andric result.AppendError("'command alias' requires at least two arguments");
390*c9157d92SDimitry Andric return;
3910b57cec5SDimitry Andric }
3920b57cec5SDimitry Andric
3930b57cec5SDimitry Andric ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
3940b57cec5SDimitry Andric m_option_group.NotifyOptionParsingStarting(&exe_ctx);
3950b57cec5SDimitry Andric
3960b57cec5SDimitry Andric OptionsWithRaw args_with_suffix(raw_command_line);
3970b57cec5SDimitry Andric
3980b57cec5SDimitry Andric if (args_with_suffix.HasArgs())
3990b57cec5SDimitry Andric if (!ParseOptionsAndNotify(args_with_suffix.GetArgs(), result,
4000b57cec5SDimitry Andric m_option_group, exe_ctx))
401*c9157d92SDimitry Andric return;
4020b57cec5SDimitry Andric
4035ffd83dbSDimitry Andric llvm::StringRef raw_command_string = args_with_suffix.GetRawPart();
4040b57cec5SDimitry Andric Args args(raw_command_string);
4050b57cec5SDimitry Andric
4060b57cec5SDimitry Andric if (args.GetArgumentCount() < 2) {
4070b57cec5SDimitry Andric result.AppendError("'command alias' requires at least two arguments");
408*c9157d92SDimitry Andric return;
4090b57cec5SDimitry Andric }
4100b57cec5SDimitry Andric
4110b57cec5SDimitry Andric // Get the alias command.
4120b57cec5SDimitry Andric
4139dba64beSDimitry Andric auto alias_command = args[0].ref();
414*c9157d92SDimitry Andric if (alias_command.starts_with("-")) {
4150b57cec5SDimitry Andric result.AppendError("aliases starting with a dash are not supported");
4160b57cec5SDimitry Andric if (alias_command == "--help" || alias_command == "--long-help") {
4170b57cec5SDimitry Andric result.AppendWarning("if trying to pass options to 'command alias' add "
4180b57cec5SDimitry Andric "a -- at the end of the options");
4190b57cec5SDimitry Andric }
420*c9157d92SDimitry Andric return;
4210b57cec5SDimitry Andric }
4220b57cec5SDimitry Andric
4230b57cec5SDimitry Andric // Strip the new alias name off 'raw_command_string' (leave it on args,
4240b57cec5SDimitry Andric // which gets passed to 'Execute', which does the stripping itself.
4250b57cec5SDimitry Andric size_t pos = raw_command_string.find(alias_command);
4260b57cec5SDimitry Andric if (pos == 0) {
4270b57cec5SDimitry Andric raw_command_string = raw_command_string.substr(alias_command.size());
4280b57cec5SDimitry Andric pos = raw_command_string.find_first_not_of(' ');
4290b57cec5SDimitry Andric if ((pos != std::string::npos) && (pos > 0))
4300b57cec5SDimitry Andric raw_command_string = raw_command_string.substr(pos);
4310b57cec5SDimitry Andric } else {
4320b57cec5SDimitry Andric result.AppendError("Error parsing command string. No alias created.");
433*c9157d92SDimitry Andric return;
4340b57cec5SDimitry Andric }
4350b57cec5SDimitry Andric
4360b57cec5SDimitry Andric // Verify that the command is alias-able.
4370b57cec5SDimitry Andric if (m_interpreter.CommandExists(alias_command)) {
4380b57cec5SDimitry Andric result.AppendErrorWithFormat(
4390b57cec5SDimitry Andric "'%s' is a permanent debugger command and cannot be redefined.\n",
4400b57cec5SDimitry Andric args[0].c_str());
441*c9157d92SDimitry Andric return;
4420b57cec5SDimitry Andric }
4430b57cec5SDimitry Andric
444349cc55cSDimitry Andric if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
445349cc55cSDimitry Andric result.AppendErrorWithFormat(
446349cc55cSDimitry Andric "'%s' is a user container command and cannot be overwritten.\n"
447349cc55cSDimitry Andric "Delete it first with 'command container delete'\n",
448349cc55cSDimitry Andric args[0].c_str());
449*c9157d92SDimitry Andric return;
450349cc55cSDimitry Andric }
451349cc55cSDimitry Andric
4520b57cec5SDimitry Andric // Get CommandObject that is being aliased. The command name is read from
4530b57cec5SDimitry Andric // the front of raw_command_string. raw_command_string is returned with the
4540b57cec5SDimitry Andric // name of the command object stripped off the front.
4550b57cec5SDimitry Andric llvm::StringRef original_raw_command_string = raw_command_string;
4560b57cec5SDimitry Andric CommandObject *cmd_obj =
4570b57cec5SDimitry Andric m_interpreter.GetCommandObjectForCommand(raw_command_string);
4580b57cec5SDimitry Andric
4590b57cec5SDimitry Andric if (!cmd_obj) {
4600b57cec5SDimitry Andric result.AppendErrorWithFormat("invalid command given to 'command alias'. "
4610b57cec5SDimitry Andric "'%s' does not begin with a valid command."
4620b57cec5SDimitry Andric " No alias created.",
4630b57cec5SDimitry Andric original_raw_command_string.str().c_str());
4640b57cec5SDimitry Andric } else if (!cmd_obj->WantsRawCommandString()) {
4650b57cec5SDimitry Andric // Note that args was initialized with the original command, and has not
4660b57cec5SDimitry Andric // been updated to this point. Therefore can we pass it to the version of
4670b57cec5SDimitry Andric // Execute that does not need/expect raw input in the alias.
468*c9157d92SDimitry Andric HandleAliasingNormalCommand(args, result);
4690b57cec5SDimitry Andric } else {
470*c9157d92SDimitry Andric HandleAliasingRawCommand(alias_command, raw_command_string, *cmd_obj,
471*c9157d92SDimitry Andric result);
4720b57cec5SDimitry Andric }
4730b57cec5SDimitry Andric }
4740b57cec5SDimitry Andric
HandleAliasingRawCommand(llvm::StringRef alias_command,llvm::StringRef raw_command_string,CommandObject & cmd_obj,CommandReturnObject & result)4750b57cec5SDimitry Andric bool HandleAliasingRawCommand(llvm::StringRef alias_command,
4760b57cec5SDimitry Andric llvm::StringRef raw_command_string,
4770b57cec5SDimitry Andric CommandObject &cmd_obj,
4780b57cec5SDimitry Andric CommandReturnObject &result) {
4790b57cec5SDimitry Andric // Verify & handle any options/arguments passed to the alias command
4800b57cec5SDimitry Andric
4810b57cec5SDimitry Andric OptionArgVectorSP option_arg_vector_sp =
4820b57cec5SDimitry Andric OptionArgVectorSP(new OptionArgVector);
4830b57cec5SDimitry Andric
48404eeddc0SDimitry Andric const bool include_aliases = true;
485bdd1243dSDimitry Andric // Look up the command using command's name first. This is to resolve
486bdd1243dSDimitry Andric // aliases when you are making nested aliases. But if you don't find
487bdd1243dSDimitry Andric // it that way, then it wasn't an alias and we can just use the object
488bdd1243dSDimitry Andric // we were passed in.
489bdd1243dSDimitry Andric CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact(
490bdd1243dSDimitry Andric cmd_obj.GetCommandName(), include_aliases);
491bdd1243dSDimitry Andric if (!cmd_obj_sp)
492bdd1243dSDimitry Andric cmd_obj_sp = cmd_obj.shared_from_this();
493bdd1243dSDimitry Andric
4940b57cec5SDimitry Andric if (m_interpreter.AliasExists(alias_command) ||
4950b57cec5SDimitry Andric m_interpreter.UserCommandExists(alias_command)) {
4960b57cec5SDimitry Andric result.AppendWarningWithFormat(
4970b57cec5SDimitry Andric "Overwriting existing definition for '%s'.\n",
4980b57cec5SDimitry Andric alias_command.str().c_str());
4990b57cec5SDimitry Andric }
5000b57cec5SDimitry Andric if (CommandAlias *alias = m_interpreter.AddAlias(
5010b57cec5SDimitry Andric alias_command, cmd_obj_sp, raw_command_string)) {
5020b57cec5SDimitry Andric if (m_command_options.m_help.OptionWasSet())
5030b57cec5SDimitry Andric alias->SetHelp(m_command_options.m_help.GetCurrentValue());
5040b57cec5SDimitry Andric if (m_command_options.m_long_help.OptionWasSet())
5050b57cec5SDimitry Andric alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
5060b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
5070b57cec5SDimitry Andric } else {
5080b57cec5SDimitry Andric result.AppendError("Unable to create requested alias.\n");
5090b57cec5SDimitry Andric }
5100b57cec5SDimitry Andric return result.Succeeded();
5110b57cec5SDimitry Andric }
5120b57cec5SDimitry Andric
HandleAliasingNormalCommand(Args & args,CommandReturnObject & result)5130b57cec5SDimitry Andric bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) {
5140b57cec5SDimitry Andric size_t argc = args.GetArgumentCount();
5150b57cec5SDimitry Andric
5160b57cec5SDimitry Andric if (argc < 2) {
5170b57cec5SDimitry Andric result.AppendError("'command alias' requires at least two arguments");
5180b57cec5SDimitry Andric return false;
5190b57cec5SDimitry Andric }
5200b57cec5SDimitry Andric
5210b57cec5SDimitry Andric // Save these in std::strings since we're going to shift them off.
5225ffd83dbSDimitry Andric const std::string alias_command(std::string(args[0].ref()));
5235ffd83dbSDimitry Andric const std::string actual_command(std::string(args[1].ref()));
5240b57cec5SDimitry Andric
5250b57cec5SDimitry Andric args.Shift(); // Shift the alias command word off the argument vector.
5260b57cec5SDimitry Andric args.Shift(); // Shift the old command word off the argument vector.
5270b57cec5SDimitry Andric
5280b57cec5SDimitry Andric // Verify that the command is alias'able, and get the appropriate command
5290b57cec5SDimitry Andric // object.
5300b57cec5SDimitry Andric
5310b57cec5SDimitry Andric if (m_interpreter.CommandExists(alias_command)) {
5320b57cec5SDimitry Andric result.AppendErrorWithFormat(
5330b57cec5SDimitry Andric "'%s' is a permanent debugger command and cannot be redefined.\n",
5340b57cec5SDimitry Andric alias_command.c_str());
5350b57cec5SDimitry Andric return false;
5360b57cec5SDimitry Andric }
5370b57cec5SDimitry Andric
538349cc55cSDimitry Andric if (m_interpreter.UserMultiwordCommandExists(alias_command)) {
539349cc55cSDimitry Andric result.AppendErrorWithFormat(
540349cc55cSDimitry Andric "'%s' is user container command and cannot be overwritten.\n"
541349cc55cSDimitry Andric "Delete it first with 'command container delete'",
542349cc55cSDimitry Andric alias_command.c_str());
543349cc55cSDimitry Andric return false;
544349cc55cSDimitry Andric }
545349cc55cSDimitry Andric
5460b57cec5SDimitry Andric CommandObjectSP command_obj_sp(
5470b57cec5SDimitry Andric m_interpreter.GetCommandSPExact(actual_command, true));
5480b57cec5SDimitry Andric CommandObjectSP subcommand_obj_sp;
5490b57cec5SDimitry Andric bool use_subcommand = false;
5500b57cec5SDimitry Andric if (!command_obj_sp) {
5510b57cec5SDimitry Andric result.AppendErrorWithFormat("'%s' is not an existing command.\n",
5520b57cec5SDimitry Andric actual_command.c_str());
5530b57cec5SDimitry Andric return false;
5540b57cec5SDimitry Andric }
5550b57cec5SDimitry Andric CommandObject *cmd_obj = command_obj_sp.get();
5560b57cec5SDimitry Andric CommandObject *sub_cmd_obj = nullptr;
5570b57cec5SDimitry Andric OptionArgVectorSP option_arg_vector_sp =
5580b57cec5SDimitry Andric OptionArgVectorSP(new OptionArgVector);
5590b57cec5SDimitry Andric
5600b57cec5SDimitry Andric while (cmd_obj->IsMultiwordObject() && !args.empty()) {
5619dba64beSDimitry Andric auto sub_command = args[0].ref();
5620b57cec5SDimitry Andric assert(!sub_command.empty());
5630b57cec5SDimitry Andric subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command);
5640b57cec5SDimitry Andric if (!subcommand_obj_sp) {
5650b57cec5SDimitry Andric result.AppendErrorWithFormat(
5660b57cec5SDimitry Andric "'%s' is not a valid sub-command of '%s'. "
5670b57cec5SDimitry Andric "Unable to create alias.\n",
5680b57cec5SDimitry Andric args[0].c_str(), actual_command.c_str());
5690b57cec5SDimitry Andric return false;
5700b57cec5SDimitry Andric }
5710b57cec5SDimitry Andric
5720b57cec5SDimitry Andric sub_cmd_obj = subcommand_obj_sp.get();
5730b57cec5SDimitry Andric use_subcommand = true;
5740b57cec5SDimitry Andric args.Shift(); // Shift the sub_command word off the argument vector.
5750b57cec5SDimitry Andric cmd_obj = sub_cmd_obj;
5760b57cec5SDimitry Andric }
5770b57cec5SDimitry Andric
5780b57cec5SDimitry Andric // Verify & handle any options/arguments passed to the alias command
5790b57cec5SDimitry Andric
5800b57cec5SDimitry Andric std::string args_string;
5810b57cec5SDimitry Andric
5820b57cec5SDimitry Andric if (!args.empty()) {
5830b57cec5SDimitry Andric CommandObjectSP tmp_sp =
584e8d8bef9SDimitry Andric m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName());
5850b57cec5SDimitry Andric if (use_subcommand)
586e8d8bef9SDimitry Andric tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName());
5870b57cec5SDimitry Andric
5880b57cec5SDimitry Andric args.GetCommandString(args_string);
5890b57cec5SDimitry Andric }
5900b57cec5SDimitry Andric
5910b57cec5SDimitry Andric if (m_interpreter.AliasExists(alias_command) ||
5920b57cec5SDimitry Andric m_interpreter.UserCommandExists(alias_command)) {
5930b57cec5SDimitry Andric result.AppendWarningWithFormat(
5940b57cec5SDimitry Andric "Overwriting existing definition for '%s'.\n", alias_command.c_str());
5950b57cec5SDimitry Andric }
5960b57cec5SDimitry Andric
5970b57cec5SDimitry Andric if (CommandAlias *alias = m_interpreter.AddAlias(
5980b57cec5SDimitry Andric alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp,
5990b57cec5SDimitry Andric args_string)) {
6000b57cec5SDimitry Andric if (m_command_options.m_help.OptionWasSet())
6010b57cec5SDimitry Andric alias->SetHelp(m_command_options.m_help.GetCurrentValue());
6020b57cec5SDimitry Andric if (m_command_options.m_long_help.OptionWasSet())
6030b57cec5SDimitry Andric alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
6040b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
6050b57cec5SDimitry Andric } else {
6060b57cec5SDimitry Andric result.AppendError("Unable to create requested alias.\n");
6070b57cec5SDimitry Andric return false;
6080b57cec5SDimitry Andric }
6090b57cec5SDimitry Andric
6100b57cec5SDimitry Andric return result.Succeeded();
6110b57cec5SDimitry Andric }
6120b57cec5SDimitry Andric };
6130b57cec5SDimitry Andric
6140b57cec5SDimitry Andric #pragma mark CommandObjectCommandsUnalias
6150b57cec5SDimitry Andric // CommandObjectCommandsUnalias
6160b57cec5SDimitry Andric
6170b57cec5SDimitry Andric class CommandObjectCommandsUnalias : public CommandObjectParsed {
6180b57cec5SDimitry Andric public:
CommandObjectCommandsUnalias(CommandInterpreter & interpreter)6190b57cec5SDimitry Andric CommandObjectCommandsUnalias(CommandInterpreter &interpreter)
6200b57cec5SDimitry Andric : CommandObjectParsed(
6210b57cec5SDimitry Andric interpreter, "command unalias",
6220b57cec5SDimitry Andric "Delete one or more custom commands defined by 'command alias'.",
6230b57cec5SDimitry Andric nullptr) {
6240b57cec5SDimitry Andric CommandArgumentEntry arg;
6250b57cec5SDimitry Andric CommandArgumentData alias_arg;
6260b57cec5SDimitry Andric
6270b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
6280b57cec5SDimitry Andric alias_arg.arg_type = eArgTypeAliasName;
6290b57cec5SDimitry Andric alias_arg.arg_repetition = eArgRepeatPlain;
6300b57cec5SDimitry Andric
6310b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
6320b57cec5SDimitry Andric // argument entry.
6330b57cec5SDimitry Andric arg.push_back(alias_arg);
6340b57cec5SDimitry Andric
6350b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
6360b57cec5SDimitry Andric m_arguments.push_back(arg);
6370b57cec5SDimitry Andric }
6380b57cec5SDimitry Andric
6390b57cec5SDimitry Andric ~CommandObjectCommandsUnalias() override = default;
6400b57cec5SDimitry Andric
641e8d8bef9SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)642e8d8bef9SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
643e8d8bef9SDimitry Andric OptionElementVector &opt_element_vector) override {
644e8d8bef9SDimitry Andric if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
645e8d8bef9SDimitry Andric return;
646e8d8bef9SDimitry Andric
647e8d8bef9SDimitry Andric for (const auto &ent : m_interpreter.GetAliases()) {
648e8d8bef9SDimitry Andric request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
649e8d8bef9SDimitry Andric }
650e8d8bef9SDimitry Andric }
651e8d8bef9SDimitry Andric
6520b57cec5SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)653*c9157d92SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
6540b57cec5SDimitry Andric CommandObject::CommandMap::iterator pos;
6550b57cec5SDimitry Andric CommandObject *cmd_obj;
6560b57cec5SDimitry Andric
6570b57cec5SDimitry Andric if (args.empty()) {
6580b57cec5SDimitry Andric result.AppendError("must call 'unalias' with a valid alias");
659*c9157d92SDimitry Andric return;
6600b57cec5SDimitry Andric }
6610b57cec5SDimitry Andric
6629dba64beSDimitry Andric auto command_name = args[0].ref();
6630b57cec5SDimitry Andric cmd_obj = m_interpreter.GetCommandObject(command_name);
6640b57cec5SDimitry Andric if (!cmd_obj) {
6650b57cec5SDimitry Andric result.AppendErrorWithFormat(
6660b57cec5SDimitry Andric "'%s' is not a known command.\nTry 'help' to see a "
6670b57cec5SDimitry Andric "current list of commands.\n",
6680b57cec5SDimitry Andric args[0].c_str());
669*c9157d92SDimitry Andric return;
6700b57cec5SDimitry Andric }
6710b57cec5SDimitry Andric
6720b57cec5SDimitry Andric if (m_interpreter.CommandExists(command_name)) {
6730b57cec5SDimitry Andric if (cmd_obj->IsRemovable()) {
6740b57cec5SDimitry Andric result.AppendErrorWithFormat(
6750b57cec5SDimitry Andric "'%s' is not an alias, it is a debugger command which can be "
6760b57cec5SDimitry Andric "removed using the 'command delete' command.\n",
6770b57cec5SDimitry Andric args[0].c_str());
6780b57cec5SDimitry Andric } else {
6790b57cec5SDimitry Andric result.AppendErrorWithFormat(
6800b57cec5SDimitry Andric "'%s' is a permanent debugger command and cannot be removed.\n",
6810b57cec5SDimitry Andric args[0].c_str());
6820b57cec5SDimitry Andric }
683*c9157d92SDimitry Andric return;
6840b57cec5SDimitry Andric }
6850b57cec5SDimitry Andric
6860b57cec5SDimitry Andric if (!m_interpreter.RemoveAlias(command_name)) {
6870b57cec5SDimitry Andric if (m_interpreter.AliasExists(command_name))
6880b57cec5SDimitry Andric result.AppendErrorWithFormat(
6890b57cec5SDimitry Andric "Error occurred while attempting to unalias '%s'.\n",
6900b57cec5SDimitry Andric args[0].c_str());
6910b57cec5SDimitry Andric else
6920b57cec5SDimitry Andric result.AppendErrorWithFormat("'%s' is not an existing alias.\n",
6930b57cec5SDimitry Andric args[0].c_str());
694*c9157d92SDimitry Andric return;
6950b57cec5SDimitry Andric }
6960b57cec5SDimitry Andric
6970b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
6980b57cec5SDimitry Andric }
6990b57cec5SDimitry Andric };
7000b57cec5SDimitry Andric
7010b57cec5SDimitry Andric #pragma mark CommandObjectCommandsDelete
7020b57cec5SDimitry Andric // CommandObjectCommandsDelete
7030b57cec5SDimitry Andric
7040b57cec5SDimitry Andric class CommandObjectCommandsDelete : public CommandObjectParsed {
7050b57cec5SDimitry Andric public:
CommandObjectCommandsDelete(CommandInterpreter & interpreter)7060b57cec5SDimitry Andric CommandObjectCommandsDelete(CommandInterpreter &interpreter)
7070b57cec5SDimitry Andric : CommandObjectParsed(
7080b57cec5SDimitry Andric interpreter, "command delete",
7090b57cec5SDimitry Andric "Delete one or more custom commands defined by 'command regex'.",
7100b57cec5SDimitry Andric nullptr) {
7110b57cec5SDimitry Andric CommandArgumentEntry arg;
7120b57cec5SDimitry Andric CommandArgumentData alias_arg;
7130b57cec5SDimitry Andric
7140b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
7150b57cec5SDimitry Andric alias_arg.arg_type = eArgTypeCommandName;
7160b57cec5SDimitry Andric alias_arg.arg_repetition = eArgRepeatPlain;
7170b57cec5SDimitry Andric
7180b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
7190b57cec5SDimitry Andric // argument entry.
7200b57cec5SDimitry Andric arg.push_back(alias_arg);
7210b57cec5SDimitry Andric
7220b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
7230b57cec5SDimitry Andric m_arguments.push_back(arg);
7240b57cec5SDimitry Andric }
7250b57cec5SDimitry Andric
7260b57cec5SDimitry Andric ~CommandObjectCommandsDelete() override = default;
7270b57cec5SDimitry Andric
728e8d8bef9SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)729e8d8bef9SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
730e8d8bef9SDimitry Andric OptionElementVector &opt_element_vector) override {
731e8d8bef9SDimitry Andric if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0)
732e8d8bef9SDimitry Andric return;
733e8d8bef9SDimitry Andric
734e8d8bef9SDimitry Andric for (const auto &ent : m_interpreter.GetCommands()) {
735e8d8bef9SDimitry Andric if (ent.second->IsRemovable())
736e8d8bef9SDimitry Andric request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp());
737e8d8bef9SDimitry Andric }
738e8d8bef9SDimitry Andric }
739e8d8bef9SDimitry Andric
7400b57cec5SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)741*c9157d92SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
7420b57cec5SDimitry Andric CommandObject::CommandMap::iterator pos;
7430b57cec5SDimitry Andric
7440b57cec5SDimitry Andric if (args.empty()) {
7450b57cec5SDimitry Andric result.AppendErrorWithFormat("must call '%s' with one or more valid user "
7460b57cec5SDimitry Andric "defined regular expression command names",
7470b57cec5SDimitry Andric GetCommandName().str().c_str());
748*c9157d92SDimitry Andric return;
7490b57cec5SDimitry Andric }
7500b57cec5SDimitry Andric
7519dba64beSDimitry Andric auto command_name = args[0].ref();
7520b57cec5SDimitry Andric if (!m_interpreter.CommandExists(command_name)) {
7530b57cec5SDimitry Andric StreamString error_msg_stream;
7540b57cec5SDimitry Andric const bool generate_upropos = true;
7550b57cec5SDimitry Andric const bool generate_type_lookup = false;
7560b57cec5SDimitry Andric CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(
7570b57cec5SDimitry Andric &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(),
7580b57cec5SDimitry Andric generate_upropos, generate_type_lookup);
7590b57cec5SDimitry Andric result.AppendError(error_msg_stream.GetString());
760*c9157d92SDimitry Andric return;
7610b57cec5SDimitry Andric }
7620b57cec5SDimitry Andric
7630b57cec5SDimitry Andric if (!m_interpreter.RemoveCommand(command_name)) {
7640b57cec5SDimitry Andric result.AppendErrorWithFormat(
7650b57cec5SDimitry Andric "'%s' is a permanent debugger command and cannot be removed.\n",
7660b57cec5SDimitry Andric args[0].c_str());
767*c9157d92SDimitry Andric return;
7680b57cec5SDimitry Andric }
7690b57cec5SDimitry Andric
7700b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
7710b57cec5SDimitry Andric }
7720b57cec5SDimitry Andric };
7730b57cec5SDimitry Andric
7740b57cec5SDimitry Andric // CommandObjectCommandsAddRegex
7750b57cec5SDimitry Andric
7769dba64beSDimitry Andric #define LLDB_OPTIONS_regex
7779dba64beSDimitry Andric #include "CommandOptions.inc"
7780b57cec5SDimitry Andric
7790b57cec5SDimitry Andric #pragma mark CommandObjectCommandsAddRegex
7800b57cec5SDimitry Andric
7810b57cec5SDimitry Andric class CommandObjectCommandsAddRegex : public CommandObjectParsed,
7820b57cec5SDimitry Andric public IOHandlerDelegateMultiline {
7830b57cec5SDimitry Andric public:
CommandObjectCommandsAddRegex(CommandInterpreter & interpreter)7840b57cec5SDimitry Andric CommandObjectCommandsAddRegex(CommandInterpreter &interpreter)
7850b57cec5SDimitry Andric : CommandObjectParsed(
786480093f4SDimitry Andric interpreter, "command regex",
787480093f4SDimitry Andric "Define a custom command in terms of "
7880b57cec5SDimitry Andric "existing commands by matching "
7890b57cec5SDimitry Andric "regular expressions.",
7900b57cec5SDimitry Andric "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
7910b57cec5SDimitry Andric IOHandlerDelegateMultiline("",
79204eeddc0SDimitry Andric IOHandlerDelegate::Completion::LLDBCommand) {
7930b57cec5SDimitry Andric SetHelpLong(
7940b57cec5SDimitry Andric R"(
7950b57cec5SDimitry Andric )"
7960b57cec5SDimitry Andric "This command allows the user to create powerful regular expression commands \
7970b57cec5SDimitry Andric with substitutions. The regular expressions and substitutions are specified \
7980b57cec5SDimitry Andric using the regular expression substitution format of:"
7990b57cec5SDimitry Andric R"(
8000b57cec5SDimitry Andric
8010b57cec5SDimitry Andric s/<regex>/<subst>/
8020b57cec5SDimitry Andric
8030b57cec5SDimitry Andric )"
8040b57cec5SDimitry Andric "<regex> is a regular expression that can use parenthesis to capture regular \
8050b57cec5SDimitry Andric expression input and substitute the captured matches in the output using %1 \
8060b57cec5SDimitry Andric for the first match, %2 for the second, and so on."
8070b57cec5SDimitry Andric R"(
8080b57cec5SDimitry Andric
8090b57cec5SDimitry Andric )"
8100b57cec5SDimitry Andric "The regular expressions can all be specified on the command line if more than \
8110b57cec5SDimitry Andric one argument is provided. If just the command name is provided on the command \
8120b57cec5SDimitry Andric line, then the regular expressions and substitutions can be entered on separate \
8130b57cec5SDimitry Andric lines, followed by an empty line to terminate the command definition."
8140b57cec5SDimitry Andric R"(
8150b57cec5SDimitry Andric
8160b57cec5SDimitry Andric EXAMPLES
8170b57cec5SDimitry Andric
8180b57cec5SDimitry Andric )"
8190b57cec5SDimitry Andric "The following example will define a regular expression command named 'f' that \
8200b57cec5SDimitry Andric will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \
8210b57cec5SDimitry Andric a number follows 'f':"
8220b57cec5SDimitry Andric R"(
8230b57cec5SDimitry Andric
8240b57cec5SDimitry Andric (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')");
82581ad6265SDimitry Andric CommandArgumentData thread_arg{eArgTypeSEDStylePair, eArgRepeatOptional};
82681ad6265SDimitry Andric m_arguments.push_back({thread_arg});
8270b57cec5SDimitry Andric }
8280b57cec5SDimitry Andric
8290b57cec5SDimitry Andric ~CommandObjectCommandsAddRegex() override = default;
8300b57cec5SDimitry Andric
8310b57cec5SDimitry Andric protected:
IOHandlerActivated(IOHandler & io_handler,bool interactive)8320b57cec5SDimitry Andric void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
8339dba64beSDimitry Andric StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
8340b57cec5SDimitry Andric if (output_sp && interactive) {
8350b57cec5SDimitry Andric output_sp->PutCString("Enter one or more sed substitution commands in "
8360b57cec5SDimitry Andric "the form: 's/<regex>/<subst>/'.\nTerminate the "
8370b57cec5SDimitry Andric "substitution list with an empty line.\n");
8380b57cec5SDimitry Andric output_sp->Flush();
8390b57cec5SDimitry Andric }
8400b57cec5SDimitry Andric }
8410b57cec5SDimitry Andric
IOHandlerInputComplete(IOHandler & io_handler,std::string & data)8420b57cec5SDimitry Andric void IOHandlerInputComplete(IOHandler &io_handler,
8430b57cec5SDimitry Andric std::string &data) override {
8440b57cec5SDimitry Andric io_handler.SetIsDone(true);
8450b57cec5SDimitry Andric if (m_regex_cmd_up) {
8460b57cec5SDimitry Andric StringList lines;
8470b57cec5SDimitry Andric if (lines.SplitIntoLines(data)) {
8480b57cec5SDimitry Andric bool check_only = false;
8499dba64beSDimitry Andric for (const std::string &line : lines) {
8509dba64beSDimitry Andric Status error = AppendRegexSubstitution(line, check_only);
8510b57cec5SDimitry Andric if (error.Fail()) {
8520b57cec5SDimitry Andric if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) {
8530b57cec5SDimitry Andric StreamSP out_stream = GetDebugger().GetAsyncOutputStream();
8540b57cec5SDimitry Andric out_stream->Printf("error: %s\n", error.AsCString());
8550b57cec5SDimitry Andric }
8560b57cec5SDimitry Andric }
8570b57cec5SDimitry Andric }
8580b57cec5SDimitry Andric }
8590b57cec5SDimitry Andric if (m_regex_cmd_up->HasRegexEntries()) {
8600b57cec5SDimitry Andric CommandObjectSP cmd_sp(m_regex_cmd_up.release());
8610b57cec5SDimitry Andric m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
8620b57cec5SDimitry Andric }
8630b57cec5SDimitry Andric }
8640b57cec5SDimitry Andric }
8650b57cec5SDimitry Andric
DoExecute(Args & command,CommandReturnObject & result)866*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
8670b57cec5SDimitry Andric const size_t argc = command.GetArgumentCount();
8680b57cec5SDimitry Andric if (argc == 0) {
8690b57cec5SDimitry Andric result.AppendError("usage: 'command regex <command-name> "
8700b57cec5SDimitry Andric "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
871*c9157d92SDimitry Andric return;
8720b57cec5SDimitry Andric }
8730b57cec5SDimitry Andric
8740b57cec5SDimitry Andric Status error;
8759dba64beSDimitry Andric auto name = command[0].ref();
8769dba64beSDimitry Andric m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>(
877fe013be4SDimitry Andric m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 0,
8780b57cec5SDimitry Andric true);
8790b57cec5SDimitry Andric
8800b57cec5SDimitry Andric if (argc == 1) {
8810b57cec5SDimitry Andric Debugger &debugger = GetDebugger();
8820b57cec5SDimitry Andric bool color_prompt = debugger.GetUseColor();
8830b57cec5SDimitry Andric const bool multiple_lines = true; // Get multiple lines
8840b57cec5SDimitry Andric IOHandlerSP io_handler_sp(new IOHandlerEditline(
8850b57cec5SDimitry Andric debugger, IOHandler::Type::Other,
8860b57cec5SDimitry Andric "lldb-regex", // Name of input reader for history
8870b57cec5SDimitry Andric llvm::StringRef("> "), // Prompt
8880b57cec5SDimitry Andric llvm::StringRef(), // Continuation prompt
8890b57cec5SDimitry Andric multiple_lines, color_prompt,
8900b57cec5SDimitry Andric 0, // Don't show line numbers
891bdd1243dSDimitry Andric *this));
8920b57cec5SDimitry Andric
8930b57cec5SDimitry Andric if (io_handler_sp) {
8945ffd83dbSDimitry Andric debugger.RunIOHandlerAsync(io_handler_sp);
8950b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
8960b57cec5SDimitry Andric }
8970b57cec5SDimitry Andric } else {
8980b57cec5SDimitry Andric for (auto &entry : command.entries().drop_front()) {
8990b57cec5SDimitry Andric bool check_only = false;
9009dba64beSDimitry Andric error = AppendRegexSubstitution(entry.ref(), check_only);
9010b57cec5SDimitry Andric if (error.Fail())
9020b57cec5SDimitry Andric break;
9030b57cec5SDimitry Andric }
9040b57cec5SDimitry Andric
9050b57cec5SDimitry Andric if (error.Success()) {
9060b57cec5SDimitry Andric AddRegexCommandToInterpreter();
9070b57cec5SDimitry Andric }
9080b57cec5SDimitry Andric }
9090b57cec5SDimitry Andric if (error.Fail()) {
9100b57cec5SDimitry Andric result.AppendError(error.AsCString());
9110b57cec5SDimitry Andric }
9120b57cec5SDimitry Andric }
9130b57cec5SDimitry Andric
AppendRegexSubstitution(const llvm::StringRef & regex_sed,bool check_only)9140b57cec5SDimitry Andric Status AppendRegexSubstitution(const llvm::StringRef ®ex_sed,
9150b57cec5SDimitry Andric bool check_only) {
9160b57cec5SDimitry Andric Status error;
9170b57cec5SDimitry Andric
9180b57cec5SDimitry Andric if (!m_regex_cmd_up) {
9190b57cec5SDimitry Andric error.SetErrorStringWithFormat(
9200b57cec5SDimitry Andric "invalid regular expression command object for: '%.*s'",
9210b57cec5SDimitry Andric (int)regex_sed.size(), regex_sed.data());
9220b57cec5SDimitry Andric return error;
9230b57cec5SDimitry Andric }
9240b57cec5SDimitry Andric
9250b57cec5SDimitry Andric size_t regex_sed_size = regex_sed.size();
9260b57cec5SDimitry Andric
9270b57cec5SDimitry Andric if (regex_sed_size <= 1) {
9280b57cec5SDimitry Andric error.SetErrorStringWithFormat(
9290b57cec5SDimitry Andric "regular expression substitution string is too short: '%.*s'",
9300b57cec5SDimitry Andric (int)regex_sed.size(), regex_sed.data());
9310b57cec5SDimitry Andric return error;
9320b57cec5SDimitry Andric }
9330b57cec5SDimitry Andric
9340b57cec5SDimitry Andric if (regex_sed[0] != 's') {
9350b57cec5SDimitry Andric error.SetErrorStringWithFormat("regular expression substitution string "
9360b57cec5SDimitry Andric "doesn't start with 's': '%.*s'",
9370b57cec5SDimitry Andric (int)regex_sed.size(), regex_sed.data());
9380b57cec5SDimitry Andric return error;
9390b57cec5SDimitry Andric }
9400b57cec5SDimitry Andric const size_t first_separator_char_pos = 1;
9410b57cec5SDimitry Andric // use the char that follows 's' as the regex separator character so we can
9420b57cec5SDimitry Andric // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
9430b57cec5SDimitry Andric const char separator_char = regex_sed[first_separator_char_pos];
9440b57cec5SDimitry Andric const size_t second_separator_char_pos =
9450b57cec5SDimitry Andric regex_sed.find(separator_char, first_separator_char_pos + 1);
9460b57cec5SDimitry Andric
9470b57cec5SDimitry Andric if (second_separator_char_pos == std::string::npos) {
9480b57cec5SDimitry Andric error.SetErrorStringWithFormat(
9490b57cec5SDimitry Andric "missing second '%c' separator char after '%.*s' in '%.*s'",
9500b57cec5SDimitry Andric separator_char,
9510b57cec5SDimitry Andric (int)(regex_sed.size() - first_separator_char_pos - 1),
9520b57cec5SDimitry Andric regex_sed.data() + (first_separator_char_pos + 1),
9530b57cec5SDimitry Andric (int)regex_sed.size(), regex_sed.data());
9540b57cec5SDimitry Andric return error;
9550b57cec5SDimitry Andric }
9560b57cec5SDimitry Andric
9570b57cec5SDimitry Andric const size_t third_separator_char_pos =
9580b57cec5SDimitry Andric regex_sed.find(separator_char, second_separator_char_pos + 1);
9590b57cec5SDimitry Andric
9600b57cec5SDimitry Andric if (third_separator_char_pos == std::string::npos) {
9610b57cec5SDimitry Andric error.SetErrorStringWithFormat(
9620b57cec5SDimitry Andric "missing third '%c' separator char after '%.*s' in '%.*s'",
9630b57cec5SDimitry Andric separator_char,
9640b57cec5SDimitry Andric (int)(regex_sed.size() - second_separator_char_pos - 1),
9650b57cec5SDimitry Andric regex_sed.data() + (second_separator_char_pos + 1),
9660b57cec5SDimitry Andric (int)regex_sed.size(), regex_sed.data());
9670b57cec5SDimitry Andric return error;
9680b57cec5SDimitry Andric }
9690b57cec5SDimitry Andric
9700b57cec5SDimitry Andric if (third_separator_char_pos != regex_sed_size - 1) {
9710b57cec5SDimitry Andric // Make sure that everything that follows the last regex separator char
9720b57cec5SDimitry Andric if (regex_sed.find_first_not_of("\t\n\v\f\r ",
9730b57cec5SDimitry Andric third_separator_char_pos + 1) !=
9740b57cec5SDimitry Andric std::string::npos) {
9750b57cec5SDimitry Andric error.SetErrorStringWithFormat(
9760b57cec5SDimitry Andric "extra data found after the '%.*s' regular expression substitution "
9770b57cec5SDimitry Andric "string: '%.*s'",
9780b57cec5SDimitry Andric (int)third_separator_char_pos + 1, regex_sed.data(),
9790b57cec5SDimitry Andric (int)(regex_sed.size() - third_separator_char_pos - 1),
9800b57cec5SDimitry Andric regex_sed.data() + (third_separator_char_pos + 1));
9810b57cec5SDimitry Andric return error;
9820b57cec5SDimitry Andric }
9830b57cec5SDimitry Andric } else if (first_separator_char_pos + 1 == second_separator_char_pos) {
9840b57cec5SDimitry Andric error.SetErrorStringWithFormat(
9850b57cec5SDimitry Andric "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
9860b57cec5SDimitry Andric separator_char, separator_char, separator_char, (int)regex_sed.size(),
9870b57cec5SDimitry Andric regex_sed.data());
9880b57cec5SDimitry Andric return error;
9890b57cec5SDimitry Andric } else if (second_separator_char_pos + 1 == third_separator_char_pos) {
9900b57cec5SDimitry Andric error.SetErrorStringWithFormat(
9910b57cec5SDimitry Andric "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
9920b57cec5SDimitry Andric separator_char, separator_char, separator_char, (int)regex_sed.size(),
9930b57cec5SDimitry Andric regex_sed.data());
9940b57cec5SDimitry Andric return error;
9950b57cec5SDimitry Andric }
9960b57cec5SDimitry Andric
9970b57cec5SDimitry Andric if (!check_only) {
9985ffd83dbSDimitry Andric std::string regex(std::string(regex_sed.substr(
9995ffd83dbSDimitry Andric first_separator_char_pos + 1,
10005ffd83dbSDimitry Andric second_separator_char_pos - first_separator_char_pos - 1)));
10015ffd83dbSDimitry Andric std::string subst(std::string(regex_sed.substr(
10025ffd83dbSDimitry Andric second_separator_char_pos + 1,
10035ffd83dbSDimitry Andric third_separator_char_pos - second_separator_char_pos - 1)));
1004e8d8bef9SDimitry Andric m_regex_cmd_up->AddRegexCommand(regex, subst);
10050b57cec5SDimitry Andric }
10060b57cec5SDimitry Andric return error;
10070b57cec5SDimitry Andric }
10080b57cec5SDimitry Andric
AddRegexCommandToInterpreter()10090b57cec5SDimitry Andric void AddRegexCommandToInterpreter() {
10100b57cec5SDimitry Andric if (m_regex_cmd_up) {
10110b57cec5SDimitry Andric if (m_regex_cmd_up->HasRegexEntries()) {
10120b57cec5SDimitry Andric CommandObjectSP cmd_sp(m_regex_cmd_up.release());
10130b57cec5SDimitry Andric m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
10140b57cec5SDimitry Andric }
10150b57cec5SDimitry Andric }
10160b57cec5SDimitry Andric }
10170b57cec5SDimitry Andric
10180b57cec5SDimitry Andric private:
10190b57cec5SDimitry Andric std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up;
10200b57cec5SDimitry Andric
10210b57cec5SDimitry Andric class CommandOptions : public Options {
10220b57cec5SDimitry Andric public:
102381ad6265SDimitry Andric CommandOptions() = default;
10240b57cec5SDimitry Andric
10250b57cec5SDimitry Andric ~CommandOptions() override = default;
10260b57cec5SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)10270b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
10280b57cec5SDimitry Andric ExecutionContext *execution_context) override {
10290b57cec5SDimitry Andric Status error;
10300b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
10310b57cec5SDimitry Andric
10320b57cec5SDimitry Andric switch (short_option) {
10330b57cec5SDimitry Andric case 'h':
10345ffd83dbSDimitry Andric m_help.assign(std::string(option_arg));
10350b57cec5SDimitry Andric break;
10360b57cec5SDimitry Andric case 's':
10375ffd83dbSDimitry Andric m_syntax.assign(std::string(option_arg));
10380b57cec5SDimitry Andric break;
10390b57cec5SDimitry Andric default:
10409dba64beSDimitry Andric llvm_unreachable("Unimplemented option");
10410b57cec5SDimitry Andric }
10420b57cec5SDimitry Andric
10430b57cec5SDimitry Andric return error;
10440b57cec5SDimitry Andric }
10450b57cec5SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)10460b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
10470b57cec5SDimitry Andric m_help.clear();
10480b57cec5SDimitry Andric m_syntax.clear();
10490b57cec5SDimitry Andric }
10500b57cec5SDimitry Andric
GetDefinitions()10510b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1052bdd1243dSDimitry Andric return llvm::ArrayRef(g_regex_options);
10530b57cec5SDimitry Andric }
10540b57cec5SDimitry Andric
GetHelp()10555ffd83dbSDimitry Andric llvm::StringRef GetHelp() { return m_help; }
10560b57cec5SDimitry Andric
GetSyntax()10575ffd83dbSDimitry Andric llvm::StringRef GetSyntax() { return m_syntax; }
10580b57cec5SDimitry Andric
10590b57cec5SDimitry Andric protected:
10600b57cec5SDimitry Andric // Instance variables to hold the values for command options.
10610b57cec5SDimitry Andric
10620b57cec5SDimitry Andric std::string m_help;
10630b57cec5SDimitry Andric std::string m_syntax;
10640b57cec5SDimitry Andric };
10650b57cec5SDimitry Andric
GetOptions()10660b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; }
10670b57cec5SDimitry Andric
10680b57cec5SDimitry Andric CommandOptions m_options;
10690b57cec5SDimitry Andric };
10700b57cec5SDimitry Andric
10710b57cec5SDimitry Andric class CommandObjectPythonFunction : public CommandObjectRaw {
10720b57cec5SDimitry Andric public:
CommandObjectPythonFunction(CommandInterpreter & interpreter,std::string name,std::string funct,std::string help,ScriptedCommandSynchronicity synch,CompletionType completion_type)10730b57cec5SDimitry Andric CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name,
10740b57cec5SDimitry Andric std::string funct, std::string help,
1075fe013be4SDimitry Andric ScriptedCommandSynchronicity synch,
1076fe013be4SDimitry Andric CompletionType completion_type)
1077480093f4SDimitry Andric : CommandObjectRaw(interpreter, name), m_function_name(funct),
1078fe013be4SDimitry Andric m_synchro(synch), m_completion_type(completion_type) {
10790b57cec5SDimitry Andric if (!help.empty())
10800b57cec5SDimitry Andric SetHelp(help);
10810b57cec5SDimitry Andric else {
10820b57cec5SDimitry Andric StreamString stream;
10830b57cec5SDimitry Andric stream.Printf("For more information run 'help %s'", name.c_str());
10840b57cec5SDimitry Andric SetHelp(stream.GetString());
10850b57cec5SDimitry Andric }
10860b57cec5SDimitry Andric }
10870b57cec5SDimitry Andric
10880b57cec5SDimitry Andric ~CommandObjectPythonFunction() override = default;
10890b57cec5SDimitry Andric
IsRemovable() const10900b57cec5SDimitry Andric bool IsRemovable() const override { return true; }
10910b57cec5SDimitry Andric
GetFunctionName()10920b57cec5SDimitry Andric const std::string &GetFunctionName() { return m_function_name; }
10930b57cec5SDimitry Andric
GetSynchronicity()10940b57cec5SDimitry Andric ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
10950b57cec5SDimitry Andric
GetHelpLong()10960b57cec5SDimitry Andric llvm::StringRef GetHelpLong() override {
10970b57cec5SDimitry Andric if (m_fetched_help_long)
10980b57cec5SDimitry Andric return CommandObjectRaw::GetHelpLong();
10990b57cec5SDimitry Andric
11000b57cec5SDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
11010b57cec5SDimitry Andric if (!scripter)
11020b57cec5SDimitry Andric return CommandObjectRaw::GetHelpLong();
11030b57cec5SDimitry Andric
11040b57cec5SDimitry Andric std::string docstring;
11050b57cec5SDimitry Andric m_fetched_help_long =
11060b57cec5SDimitry Andric scripter->GetDocumentationForItem(m_function_name.c_str(), docstring);
11070b57cec5SDimitry Andric if (!docstring.empty())
11080b57cec5SDimitry Andric SetHelpLong(docstring);
11090b57cec5SDimitry Andric return CommandObjectRaw::GetHelpLong();
11100b57cec5SDimitry Andric }
11110b57cec5SDimitry Andric
1112fe013be4SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1113fe013be4SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
1114fe013be4SDimitry Andric OptionElementVector &opt_element_vector) override {
1115fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1116fe013be4SDimitry Andric GetCommandInterpreter(), m_completion_type, request, nullptr);
1117fe013be4SDimitry Andric }
1118fe013be4SDimitry Andric
WantsCompletion()1119fe013be4SDimitry Andric bool WantsCompletion() override { return true; }
1120fe013be4SDimitry Andric
11210b57cec5SDimitry Andric protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)1122*c9157d92SDimitry Andric void DoExecute(llvm::StringRef raw_command_line,
11230b57cec5SDimitry Andric CommandReturnObject &result) override {
11240b57cec5SDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
11250b57cec5SDimitry Andric
11260b57cec5SDimitry Andric Status error;
11270b57cec5SDimitry Andric
11280b57cec5SDimitry Andric result.SetStatus(eReturnStatusInvalid);
11290b57cec5SDimitry Andric
1130480093f4SDimitry Andric if (!scripter || !scripter->RunScriptBasedCommand(
1131480093f4SDimitry Andric m_function_name.c_str(), raw_command_line, m_synchro,
1132480093f4SDimitry Andric result, error, m_exe_ctx)) {
11330b57cec5SDimitry Andric result.AppendError(error.AsCString());
11340b57cec5SDimitry Andric } else {
11350b57cec5SDimitry Andric // Don't change the status if the command already set it...
11360b57cec5SDimitry Andric if (result.GetStatus() == eReturnStatusInvalid) {
11370b57cec5SDimitry Andric if (result.GetOutputData().empty())
11380b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
11390b57cec5SDimitry Andric else
11400b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
11410b57cec5SDimitry Andric }
11420b57cec5SDimitry Andric }
11430b57cec5SDimitry Andric }
11440b57cec5SDimitry Andric
11450b57cec5SDimitry Andric private:
11460b57cec5SDimitry Andric std::string m_function_name;
11470b57cec5SDimitry Andric ScriptedCommandSynchronicity m_synchro;
114881ad6265SDimitry Andric bool m_fetched_help_long = false;
1149fe013be4SDimitry Andric CompletionType m_completion_type = eNoCompletion;
11500b57cec5SDimitry Andric };
11510b57cec5SDimitry Andric
11520b57cec5SDimitry Andric class CommandObjectScriptingObject : public CommandObjectRaw {
11530b57cec5SDimitry Andric public:
CommandObjectScriptingObject(CommandInterpreter & interpreter,std::string name,StructuredData::GenericSP cmd_obj_sp,ScriptedCommandSynchronicity synch,CompletionType completion_type)11540b57cec5SDimitry Andric CommandObjectScriptingObject(CommandInterpreter &interpreter,
11550b57cec5SDimitry Andric std::string name,
11560b57cec5SDimitry Andric StructuredData::GenericSP cmd_obj_sp,
1157fe013be4SDimitry Andric ScriptedCommandSynchronicity synch,
1158fe013be4SDimitry Andric CompletionType completion_type)
1159480093f4SDimitry Andric : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp),
1160480093f4SDimitry Andric m_synchro(synch), m_fetched_help_short(false),
1161fe013be4SDimitry Andric m_fetched_help_long(false), m_completion_type(completion_type) {
11620b57cec5SDimitry Andric StreamString stream;
11630b57cec5SDimitry Andric stream.Printf("For more information run 'help %s'", name.c_str());
11640b57cec5SDimitry Andric SetHelp(stream.GetString());
11650b57cec5SDimitry Andric if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter())
11660b57cec5SDimitry Andric GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
11670b57cec5SDimitry Andric }
11680b57cec5SDimitry Andric
11690b57cec5SDimitry Andric ~CommandObjectScriptingObject() override = default;
11700b57cec5SDimitry Andric
1171fe013be4SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1172fe013be4SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
1173fe013be4SDimitry Andric OptionElementVector &opt_element_vector) override {
1174fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1175fe013be4SDimitry Andric GetCommandInterpreter(), m_completion_type, request, nullptr);
1176fe013be4SDimitry Andric }
1177fe013be4SDimitry Andric
WantsCompletion()1178fe013be4SDimitry Andric bool WantsCompletion() override { return true; }
1179fe013be4SDimitry Andric
IsRemovable() const11800b57cec5SDimitry Andric bool IsRemovable() const override { return true; }
11810b57cec5SDimitry Andric
GetSynchronicity()11820b57cec5SDimitry Andric ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; }
11830b57cec5SDimitry Andric
GetHelp()11840b57cec5SDimitry Andric llvm::StringRef GetHelp() override {
11850b57cec5SDimitry Andric if (m_fetched_help_short)
11860b57cec5SDimitry Andric return CommandObjectRaw::GetHelp();
11870b57cec5SDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
11880b57cec5SDimitry Andric if (!scripter)
11890b57cec5SDimitry Andric return CommandObjectRaw::GetHelp();
11900b57cec5SDimitry Andric std::string docstring;
11910b57cec5SDimitry Andric m_fetched_help_short =
11920b57cec5SDimitry Andric scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
11930b57cec5SDimitry Andric if (!docstring.empty())
11940b57cec5SDimitry Andric SetHelp(docstring);
11950b57cec5SDimitry Andric
11960b57cec5SDimitry Andric return CommandObjectRaw::GetHelp();
11970b57cec5SDimitry Andric }
11980b57cec5SDimitry Andric
GetHelpLong()11990b57cec5SDimitry Andric llvm::StringRef GetHelpLong() override {
12000b57cec5SDimitry Andric if (m_fetched_help_long)
12010b57cec5SDimitry Andric return CommandObjectRaw::GetHelpLong();
12020b57cec5SDimitry Andric
12030b57cec5SDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
12040b57cec5SDimitry Andric if (!scripter)
12050b57cec5SDimitry Andric return CommandObjectRaw::GetHelpLong();
12060b57cec5SDimitry Andric
12070b57cec5SDimitry Andric std::string docstring;
12080b57cec5SDimitry Andric m_fetched_help_long =
12090b57cec5SDimitry Andric scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
12100b57cec5SDimitry Andric if (!docstring.empty())
12110b57cec5SDimitry Andric SetHelpLong(docstring);
12120b57cec5SDimitry Andric return CommandObjectRaw::GetHelpLong();
12130b57cec5SDimitry Andric }
12140b57cec5SDimitry Andric
12150b57cec5SDimitry Andric protected:
DoExecute(llvm::StringRef raw_command_line,CommandReturnObject & result)1216*c9157d92SDimitry Andric void DoExecute(llvm::StringRef raw_command_line,
12170b57cec5SDimitry Andric CommandReturnObject &result) override {
12180b57cec5SDimitry Andric ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
12190b57cec5SDimitry Andric
12200b57cec5SDimitry Andric Status error;
12210b57cec5SDimitry Andric
12220b57cec5SDimitry Andric result.SetStatus(eReturnStatusInvalid);
12230b57cec5SDimitry Andric
12240b57cec5SDimitry Andric if (!scripter ||
12250b57cec5SDimitry Andric !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line,
12260b57cec5SDimitry Andric m_synchro, result, error, m_exe_ctx)) {
12270b57cec5SDimitry Andric result.AppendError(error.AsCString());
12280b57cec5SDimitry Andric } else {
12290b57cec5SDimitry Andric // Don't change the status if the command already set it...
12300b57cec5SDimitry Andric if (result.GetStatus() == eReturnStatusInvalid) {
12310b57cec5SDimitry Andric if (result.GetOutputData().empty())
12320b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
12330b57cec5SDimitry Andric else
12340b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
12350b57cec5SDimitry Andric }
12360b57cec5SDimitry Andric }
12370b57cec5SDimitry Andric }
12380b57cec5SDimitry Andric
12390b57cec5SDimitry Andric private:
12400b57cec5SDimitry Andric StructuredData::GenericSP m_cmd_obj_sp;
12410b57cec5SDimitry Andric ScriptedCommandSynchronicity m_synchro;
12420b57cec5SDimitry Andric bool m_fetched_help_short : 1;
12430b57cec5SDimitry Andric bool m_fetched_help_long : 1;
1244fe013be4SDimitry Andric CompletionType m_completion_type = eNoCompletion;
12450b57cec5SDimitry Andric };
12460b57cec5SDimitry Andric
12470b57cec5SDimitry Andric // CommandObjectCommandsScriptImport
12489dba64beSDimitry Andric #define LLDB_OPTIONS_script_import
12499dba64beSDimitry Andric #include "CommandOptions.inc"
12500b57cec5SDimitry Andric
12510b57cec5SDimitry Andric class CommandObjectCommandsScriptImport : public CommandObjectParsed {
12520b57cec5SDimitry Andric public:
CommandObjectCommandsScriptImport(CommandInterpreter & interpreter)12530b57cec5SDimitry Andric CommandObjectCommandsScriptImport(CommandInterpreter &interpreter)
12540b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "command script import",
125504eeddc0SDimitry Andric "Import a scripting module in LLDB.", nullptr) {
12560b57cec5SDimitry Andric CommandArgumentEntry arg1;
12570b57cec5SDimitry Andric CommandArgumentData cmd_arg;
12580b57cec5SDimitry Andric
12590b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
12600b57cec5SDimitry Andric cmd_arg.arg_type = eArgTypeFilename;
12610b57cec5SDimitry Andric cmd_arg.arg_repetition = eArgRepeatPlus;
12620b57cec5SDimitry Andric
12630b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
12640b57cec5SDimitry Andric // argument entry.
12650b57cec5SDimitry Andric arg1.push_back(cmd_arg);
12660b57cec5SDimitry Andric
12670b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
12680b57cec5SDimitry Andric m_arguments.push_back(arg1);
12690b57cec5SDimitry Andric }
12700b57cec5SDimitry Andric
12710b57cec5SDimitry Andric ~CommandObjectCommandsScriptImport() override = default;
12720b57cec5SDimitry Andric
12739dba64beSDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)12749dba64beSDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
12750b57cec5SDimitry Andric OptionElementVector &opt_element_vector) override {
1276fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1277fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);
12780b57cec5SDimitry Andric }
12790b57cec5SDimitry Andric
GetOptions()12800b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; }
12810b57cec5SDimitry Andric
12820b57cec5SDimitry Andric protected:
12830b57cec5SDimitry Andric class CommandOptions : public Options {
12840b57cec5SDimitry Andric public:
128581ad6265SDimitry Andric CommandOptions() = default;
12860b57cec5SDimitry Andric
12870b57cec5SDimitry Andric ~CommandOptions() override = default;
12880b57cec5SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)12890b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
12900b57cec5SDimitry Andric ExecutionContext *execution_context) override {
12910b57cec5SDimitry Andric Status error;
12920b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
12930b57cec5SDimitry Andric
12940b57cec5SDimitry Andric switch (short_option) {
12950b57cec5SDimitry Andric case 'r':
1296480093f4SDimitry Andric // NO-OP
12970b57cec5SDimitry Andric break;
1298e8d8bef9SDimitry Andric case 'c':
1299e8d8bef9SDimitry Andric relative_to_command_file = true;
1300e8d8bef9SDimitry Andric break;
1301fe6060f1SDimitry Andric case 's':
1302fe6060f1SDimitry Andric silent = true;
1303fe6060f1SDimitry Andric break;
13040b57cec5SDimitry Andric default:
13059dba64beSDimitry Andric llvm_unreachable("Unimplemented option");
13060b57cec5SDimitry Andric }
13070b57cec5SDimitry Andric
13080b57cec5SDimitry Andric return error;
13090b57cec5SDimitry Andric }
13100b57cec5SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)13110b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
1312e8d8bef9SDimitry Andric relative_to_command_file = false;
13130b57cec5SDimitry Andric }
13140b57cec5SDimitry Andric
GetDefinitions()13150b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1316bdd1243dSDimitry Andric return llvm::ArrayRef(g_script_import_options);
13170b57cec5SDimitry Andric }
1318e8d8bef9SDimitry Andric bool relative_to_command_file = false;
1319fe6060f1SDimitry Andric bool silent = false;
13200b57cec5SDimitry Andric };
13210b57cec5SDimitry Andric
DoExecute(Args & command,CommandReturnObject & result)1322*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
13230b57cec5SDimitry Andric if (command.empty()) {
13240b57cec5SDimitry Andric result.AppendError("command script import needs one or more arguments");
1325*c9157d92SDimitry Andric return;
13260b57cec5SDimitry Andric }
13270b57cec5SDimitry Andric
1328e8d8bef9SDimitry Andric FileSpec source_dir = {};
1329e8d8bef9SDimitry Andric if (m_options.relative_to_command_file) {
1330e8d8bef9SDimitry Andric source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir();
1331e8d8bef9SDimitry Andric if (!source_dir) {
1332e8d8bef9SDimitry Andric result.AppendError("command script import -c can only be specified "
1333e8d8bef9SDimitry Andric "from a command file");
1334*c9157d92SDimitry Andric return;
1335e8d8bef9SDimitry Andric }
1336e8d8bef9SDimitry Andric }
1337e8d8bef9SDimitry Andric
13380b57cec5SDimitry Andric for (auto &entry : command.entries()) {
13390b57cec5SDimitry Andric Status error;
13400b57cec5SDimitry Andric
1341fe6060f1SDimitry Andric LoadScriptOptions options;
1342fe6060f1SDimitry Andric options.SetInitSession(true);
1343fe6060f1SDimitry Andric options.SetSilent(m_options.silent);
1344fe6060f1SDimitry Andric
13450b57cec5SDimitry Andric // FIXME: this is necessary because CommandObject::CheckRequirements()
13460b57cec5SDimitry Andric // assumes that commands won't ever be recursively invoked, but it's
13470b57cec5SDimitry Andric // actually possible to craft a Python script that does other "command
13480b57cec5SDimitry Andric // script imports" in __lldb_init_module the real fix is to have
13490b57cec5SDimitry Andric // recursive commands possible with a CommandInvocation object separate
13500b57cec5SDimitry Andric // from the CommandObject itself, so that recursive command invocations
13510b57cec5SDimitry Andric // won't stomp on each other (wrt to execution contents, options, and
13520b57cec5SDimitry Andric // more)
13530b57cec5SDimitry Andric m_exe_ctx.Clear();
13540b57cec5SDimitry Andric if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule(
1355fe6060f1SDimitry Andric entry.c_str(), options, error, /*module_sp=*/nullptr,
1356fe6060f1SDimitry Andric source_dir)) {
13570b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
13580b57cec5SDimitry Andric } else {
13590b57cec5SDimitry Andric result.AppendErrorWithFormat("module importing failed: %s",
13600b57cec5SDimitry Andric error.AsCString());
13610b57cec5SDimitry Andric }
13620b57cec5SDimitry Andric }
13630b57cec5SDimitry Andric }
13640b57cec5SDimitry Andric
13650b57cec5SDimitry Andric CommandOptions m_options;
13660b57cec5SDimitry Andric };
13670b57cec5SDimitry Andric
13689dba64beSDimitry Andric #define LLDB_OPTIONS_script_add
13699dba64beSDimitry Andric #include "CommandOptions.inc"
13700b57cec5SDimitry Andric
13710b57cec5SDimitry Andric class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
13720b57cec5SDimitry Andric public IOHandlerDelegateMultiline {
13730b57cec5SDimitry Andric public:
CommandObjectCommandsScriptAdd(CommandInterpreter & interpreter)13740b57cec5SDimitry Andric CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter)
13750b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "command script add",
13760b57cec5SDimitry Andric "Add a scripted function as an LLDB command.",
1377349cc55cSDimitry Andric "Add a scripted function as an lldb command. "
1378349cc55cSDimitry Andric "If you provide a single argument, the command "
1379349cc55cSDimitry Andric "will be added at the root level of the command "
1380349cc55cSDimitry Andric "hierarchy. If there are more arguments they "
1381349cc55cSDimitry Andric "must be a path to a user-added container "
1382349cc55cSDimitry Andric "command, and the last element will be the new "
1383349cc55cSDimitry Andric "command name."),
138404eeddc0SDimitry Andric IOHandlerDelegateMultiline("DONE") {
13850b57cec5SDimitry Andric CommandArgumentEntry arg1;
13860b57cec5SDimitry Andric CommandArgumentData cmd_arg;
13870b57cec5SDimitry Andric
1388349cc55cSDimitry Andric // This is one or more command names, which form the path to the command
1389349cc55cSDimitry Andric // you want to add.
1390349cc55cSDimitry Andric cmd_arg.arg_type = eArgTypeCommand;
1391349cc55cSDimitry Andric cmd_arg.arg_repetition = eArgRepeatPlus;
13920b57cec5SDimitry Andric
13930b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
13940b57cec5SDimitry Andric // argument entry.
13950b57cec5SDimitry Andric arg1.push_back(cmd_arg);
13960b57cec5SDimitry Andric
13970b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
13980b57cec5SDimitry Andric m_arguments.push_back(arg1);
13990b57cec5SDimitry Andric }
14000b57cec5SDimitry Andric
14010b57cec5SDimitry Andric ~CommandObjectCommandsScriptAdd() override = default;
14020b57cec5SDimitry Andric
GetOptions()14030b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; }
14040b57cec5SDimitry Andric
1405349cc55cSDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1406349cc55cSDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
1407349cc55cSDimitry Andric OptionElementVector &opt_element_vector) override {
1408349cc55cSDimitry Andric CommandCompletions::CompleteModifiableCmdPathArgs(m_interpreter, request,
1409349cc55cSDimitry Andric opt_element_vector);
1410349cc55cSDimitry Andric }
1411349cc55cSDimitry Andric
14120b57cec5SDimitry Andric protected:
14130b57cec5SDimitry Andric class CommandOptions : public Options {
14140b57cec5SDimitry Andric public:
141581ad6265SDimitry Andric CommandOptions() = default;
14160b57cec5SDimitry Andric
14170b57cec5SDimitry Andric ~CommandOptions() override = default;
14180b57cec5SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)14190b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
14200b57cec5SDimitry Andric ExecutionContext *execution_context) override {
14210b57cec5SDimitry Andric Status error;
14220b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
14230b57cec5SDimitry Andric
14240b57cec5SDimitry Andric switch (short_option) {
14250b57cec5SDimitry Andric case 'f':
14260b57cec5SDimitry Andric if (!option_arg.empty())
14275ffd83dbSDimitry Andric m_funct_name = std::string(option_arg);
14280b57cec5SDimitry Andric break;
14290b57cec5SDimitry Andric case 'c':
14300b57cec5SDimitry Andric if (!option_arg.empty())
14315ffd83dbSDimitry Andric m_class_name = std::string(option_arg);
14320b57cec5SDimitry Andric break;
14330b57cec5SDimitry Andric case 'h':
14340b57cec5SDimitry Andric if (!option_arg.empty())
14355ffd83dbSDimitry Andric m_short_help = std::string(option_arg);
14360b57cec5SDimitry Andric break;
1437349cc55cSDimitry Andric case 'o':
143881ad6265SDimitry Andric m_overwrite_lazy = eLazyBoolYes;
1439349cc55cSDimitry Andric break;
14400b57cec5SDimitry Andric case 's':
14410b57cec5SDimitry Andric m_synchronicity =
14420b57cec5SDimitry Andric (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum(
14430b57cec5SDimitry Andric option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
14440b57cec5SDimitry Andric if (!error.Success())
14450b57cec5SDimitry Andric error.SetErrorStringWithFormat(
14460b57cec5SDimitry Andric "unrecognized value for synchronicity '%s'",
14470b57cec5SDimitry Andric option_arg.str().c_str());
14480b57cec5SDimitry Andric break;
1449fe013be4SDimitry Andric case 'C': {
1450fe013be4SDimitry Andric Status error;
1451fe013be4SDimitry Andric OptionDefinition definition = GetDefinitions()[option_idx];
1452fe013be4SDimitry Andric lldb::CompletionType completion_type =
1453fe013be4SDimitry Andric static_cast<lldb::CompletionType>(OptionArgParser::ToOptionEnum(
1454fe013be4SDimitry Andric option_arg, definition.enum_values, eNoCompletion, error));
1455fe013be4SDimitry Andric if (!error.Success())
1456fe013be4SDimitry Andric error.SetErrorStringWithFormat(
1457fe013be4SDimitry Andric "unrecognized value for command completion type '%s'",
1458fe013be4SDimitry Andric option_arg.str().c_str());
1459fe013be4SDimitry Andric m_completion_type = completion_type;
1460fe013be4SDimitry Andric } break;
14610b57cec5SDimitry Andric default:
14629dba64beSDimitry Andric llvm_unreachable("Unimplemented option");
14630b57cec5SDimitry Andric }
14640b57cec5SDimitry Andric
14650b57cec5SDimitry Andric return error;
14660b57cec5SDimitry Andric }
14670b57cec5SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)14680b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
14690b57cec5SDimitry Andric m_class_name.clear();
14700b57cec5SDimitry Andric m_funct_name.clear();
14710b57cec5SDimitry Andric m_short_help.clear();
1472fe013be4SDimitry Andric m_completion_type = eNoCompletion;
147381ad6265SDimitry Andric m_overwrite_lazy = eLazyBoolCalculate;
14740b57cec5SDimitry Andric m_synchronicity = eScriptedCommandSynchronicitySynchronous;
14750b57cec5SDimitry Andric }
14760b57cec5SDimitry Andric
GetDefinitions()14770b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1478bdd1243dSDimitry Andric return llvm::ArrayRef(g_script_add_options);
14790b57cec5SDimitry Andric }
14800b57cec5SDimitry Andric
14810b57cec5SDimitry Andric // Instance variables to hold the values for command options.
14820b57cec5SDimitry Andric
14830b57cec5SDimitry Andric std::string m_class_name;
14840b57cec5SDimitry Andric std::string m_funct_name;
14850b57cec5SDimitry Andric std::string m_short_help;
148681ad6265SDimitry Andric LazyBool m_overwrite_lazy = eLazyBoolCalculate;
1487fe6060f1SDimitry Andric ScriptedCommandSynchronicity m_synchronicity =
1488fe6060f1SDimitry Andric eScriptedCommandSynchronicitySynchronous;
1489fe013be4SDimitry Andric CompletionType m_completion_type = eNoCompletion;
14900b57cec5SDimitry Andric };
14910b57cec5SDimitry Andric
IOHandlerActivated(IOHandler & io_handler,bool interactive)14920b57cec5SDimitry Andric void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
14939dba64beSDimitry Andric StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
14940b57cec5SDimitry Andric if (output_sp && interactive) {
14950b57cec5SDimitry Andric output_sp->PutCString(g_python_command_instructions);
14960b57cec5SDimitry Andric output_sp->Flush();
14970b57cec5SDimitry Andric }
14980b57cec5SDimitry Andric }
14990b57cec5SDimitry Andric
IOHandlerInputComplete(IOHandler & io_handler,std::string & data)15000b57cec5SDimitry Andric void IOHandlerInputComplete(IOHandler &io_handler,
15010b57cec5SDimitry Andric std::string &data) override {
15029dba64beSDimitry Andric StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
15030b57cec5SDimitry Andric
15040b57cec5SDimitry Andric ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
15050b57cec5SDimitry Andric if (interpreter) {
15060b57cec5SDimitry Andric StringList lines;
15070b57cec5SDimitry Andric lines.SplitIntoLines(data);
15080b57cec5SDimitry Andric if (lines.GetSize() > 0) {
15090b57cec5SDimitry Andric std::string funct_name_str;
15100b57cec5SDimitry Andric if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) {
15110b57cec5SDimitry Andric if (funct_name_str.empty()) {
15120b57cec5SDimitry Andric error_sp->Printf("error: unable to obtain a function name, didn't "
15130b57cec5SDimitry Andric "add python command.\n");
15140b57cec5SDimitry Andric error_sp->Flush();
15150b57cec5SDimitry Andric } else {
15160b57cec5SDimitry Andric // everything should be fine now, let's add this alias
15170b57cec5SDimitry Andric
15180b57cec5SDimitry Andric CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(
15190b57cec5SDimitry Andric m_interpreter, m_cmd_name, funct_name_str, m_short_help,
1520fe013be4SDimitry Andric m_synchronicity, m_completion_type));
1521349cc55cSDimitry Andric if (!m_container) {
1522349cc55cSDimitry Andric Status error = m_interpreter.AddUserCommand(
1523349cc55cSDimitry Andric m_cmd_name, command_obj_sp, m_overwrite);
1524349cc55cSDimitry Andric if (error.Fail()) {
1525349cc55cSDimitry Andric error_sp->Printf("error: unable to add selected command: '%s'",
1526349cc55cSDimitry Andric error.AsCString());
15270b57cec5SDimitry Andric error_sp->Flush();
15280b57cec5SDimitry Andric }
1529349cc55cSDimitry Andric } else {
1530349cc55cSDimitry Andric llvm::Error llvm_error = m_container->LoadUserSubcommand(
1531349cc55cSDimitry Andric m_cmd_name, command_obj_sp, m_overwrite);
1532349cc55cSDimitry Andric if (llvm_error) {
1533349cc55cSDimitry Andric error_sp->Printf("error: unable to add selected command: '%s'",
1534349cc55cSDimitry Andric llvm::toString(std::move(llvm_error)).c_str());
1535349cc55cSDimitry Andric error_sp->Flush();
1536349cc55cSDimitry Andric }
1537349cc55cSDimitry Andric }
15380b57cec5SDimitry Andric }
15390b57cec5SDimitry Andric } else {
15400b57cec5SDimitry Andric error_sp->Printf(
1541349cc55cSDimitry Andric "error: unable to create function, didn't add python command\n");
15420b57cec5SDimitry Andric error_sp->Flush();
15430b57cec5SDimitry Andric }
15440b57cec5SDimitry Andric } else {
1545349cc55cSDimitry Andric error_sp->Printf("error: empty function, didn't add python command\n");
15460b57cec5SDimitry Andric error_sp->Flush();
15470b57cec5SDimitry Andric }
15480b57cec5SDimitry Andric } else {
15490b57cec5SDimitry Andric error_sp->Printf(
1550349cc55cSDimitry Andric "error: script interpreter missing, didn't add python command\n");
15510b57cec5SDimitry Andric error_sp->Flush();
15520b57cec5SDimitry Andric }
15530b57cec5SDimitry Andric
15540b57cec5SDimitry Andric io_handler.SetIsDone(true);
15550b57cec5SDimitry Andric }
15560b57cec5SDimitry Andric
DoExecute(Args & command,CommandReturnObject & result)1557*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
15580b57cec5SDimitry Andric if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) {
15590b57cec5SDimitry Andric result.AppendError("only scripting language supported for scripted "
15600b57cec5SDimitry Andric "commands is currently Python");
1561*c9157d92SDimitry Andric return;
15620b57cec5SDimitry Andric }
15630b57cec5SDimitry Andric
1564349cc55cSDimitry Andric if (command.GetArgumentCount() == 0) {
1565349cc55cSDimitry Andric result.AppendError("'command script add' requires at least one argument");
1566*c9157d92SDimitry Andric return;
1567349cc55cSDimitry Andric }
156881ad6265SDimitry Andric // Store the options in case we get multi-line input, also figure out the
156981ad6265SDimitry Andric // default if not user supplied:
157081ad6265SDimitry Andric switch (m_options.m_overwrite_lazy) {
157181ad6265SDimitry Andric case eLazyBoolCalculate:
157281ad6265SDimitry Andric m_overwrite = !GetDebugger().GetCommandInterpreter().GetRequireCommandOverwrite();
157381ad6265SDimitry Andric break;
157481ad6265SDimitry Andric case eLazyBoolYes:
157581ad6265SDimitry Andric m_overwrite = true;
157681ad6265SDimitry Andric break;
157781ad6265SDimitry Andric case eLazyBoolNo:
157881ad6265SDimitry Andric m_overwrite = false;
157981ad6265SDimitry Andric }
158081ad6265SDimitry Andric
1581349cc55cSDimitry Andric Status path_error;
1582349cc55cSDimitry Andric m_container = GetCommandInterpreter().VerifyUserMultiwordCmdPath(
1583349cc55cSDimitry Andric command, true, path_error);
1584349cc55cSDimitry Andric
1585349cc55cSDimitry Andric if (path_error.Fail()) {
1586349cc55cSDimitry Andric result.AppendErrorWithFormat("error in command path: %s",
1587349cc55cSDimitry Andric path_error.AsCString());
1588*c9157d92SDimitry Andric return;
15890b57cec5SDimitry Andric }
15900b57cec5SDimitry Andric
1591349cc55cSDimitry Andric if (!m_container) {
1592349cc55cSDimitry Andric // This is getting inserted into the root of the interpreter.
15935ffd83dbSDimitry Andric m_cmd_name = std::string(command[0].ref());
1594349cc55cSDimitry Andric } else {
1595349cc55cSDimitry Andric size_t num_args = command.GetArgumentCount();
1596349cc55cSDimitry Andric m_cmd_name = std::string(command[num_args - 1].ref());
1597349cc55cSDimitry Andric }
1598349cc55cSDimitry Andric
15990b57cec5SDimitry Andric m_short_help.assign(m_options.m_short_help);
16000b57cec5SDimitry Andric m_synchronicity = m_options.m_synchronicity;
1601fe013be4SDimitry Andric m_completion_type = m_options.m_completion_type;
16020b57cec5SDimitry Andric
1603349cc55cSDimitry Andric // Handle the case where we prompt for the script code first:
1604349cc55cSDimitry Andric if (m_options.m_class_name.empty() && m_options.m_funct_name.empty()) {
1605349cc55cSDimitry Andric m_interpreter.GetPythonCommandsFromIOHandler(" ", // Prompt
1606480093f4SDimitry Andric *this); // IOHandlerDelegate
1607*c9157d92SDimitry Andric return;
1608349cc55cSDimitry Andric }
1609349cc55cSDimitry Andric
1610349cc55cSDimitry Andric CommandObjectSP new_cmd_sp;
1611349cc55cSDimitry Andric if (m_options.m_class_name.empty()) {
1612349cc55cSDimitry Andric new_cmd_sp.reset(new CommandObjectPythonFunction(
16130b57cec5SDimitry Andric m_interpreter, m_cmd_name, m_options.m_funct_name,
1614fe013be4SDimitry Andric m_options.m_short_help, m_synchronicity, m_completion_type));
16150b57cec5SDimitry Andric } else {
16160b57cec5SDimitry Andric ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
16170b57cec5SDimitry Andric if (!interpreter) {
16180b57cec5SDimitry Andric result.AppendError("cannot find ScriptInterpreter");
1619*c9157d92SDimitry Andric return;
16200b57cec5SDimitry Andric }
16210b57cec5SDimitry Andric
16220b57cec5SDimitry Andric auto cmd_obj_sp = interpreter->CreateScriptCommandObject(
16230b57cec5SDimitry Andric m_options.m_class_name.c_str());
16240b57cec5SDimitry Andric if (!cmd_obj_sp) {
1625fe013be4SDimitry Andric result.AppendErrorWithFormatv("cannot create helper object for: "
1626fe013be4SDimitry Andric "'{0}'", m_options.m_class_name);
1627*c9157d92SDimitry Andric return;
16280b57cec5SDimitry Andric }
16290b57cec5SDimitry Andric
1630349cc55cSDimitry Andric new_cmd_sp.reset(new CommandObjectScriptingObject(
1631fe013be4SDimitry Andric m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity,
1632fe013be4SDimitry Andric m_completion_type));
16330b57cec5SDimitry Andric }
16340b57cec5SDimitry Andric
1635349cc55cSDimitry Andric // Assume we're going to succeed...
1636349cc55cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
1637349cc55cSDimitry Andric if (!m_container) {
1638349cc55cSDimitry Andric Status add_error =
1639349cc55cSDimitry Andric m_interpreter.AddUserCommand(m_cmd_name, new_cmd_sp, m_overwrite);
1640349cc55cSDimitry Andric if (add_error.Fail())
1641349cc55cSDimitry Andric result.AppendErrorWithFormat("cannot add command: %s",
1642349cc55cSDimitry Andric add_error.AsCString());
1643349cc55cSDimitry Andric } else {
1644349cc55cSDimitry Andric llvm::Error llvm_error =
1645349cc55cSDimitry Andric m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite);
1646349cc55cSDimitry Andric if (llvm_error)
1647349cc55cSDimitry Andric result.AppendErrorWithFormat("cannot add command: %s",
1648349cc55cSDimitry Andric llvm::toString(std::move(llvm_error)).c_str());
1649349cc55cSDimitry Andric }
16500b57cec5SDimitry Andric }
16510b57cec5SDimitry Andric
16520b57cec5SDimitry Andric CommandOptions m_options;
16530b57cec5SDimitry Andric std::string m_cmd_name;
1654349cc55cSDimitry Andric CommandObjectMultiword *m_container = nullptr;
16550b57cec5SDimitry Andric std::string m_short_help;
165681ad6265SDimitry Andric bool m_overwrite = false;
165781ad6265SDimitry Andric ScriptedCommandSynchronicity m_synchronicity =
165881ad6265SDimitry Andric eScriptedCommandSynchronicitySynchronous;
1659fe013be4SDimitry Andric CompletionType m_completion_type = eNoCompletion;
16600b57cec5SDimitry Andric };
16610b57cec5SDimitry Andric
16620b57cec5SDimitry Andric // CommandObjectCommandsScriptList
16630b57cec5SDimitry Andric
16640b57cec5SDimitry Andric class CommandObjectCommandsScriptList : public CommandObjectParsed {
16650b57cec5SDimitry Andric public:
CommandObjectCommandsScriptList(CommandInterpreter & interpreter)16660b57cec5SDimitry Andric CommandObjectCommandsScriptList(CommandInterpreter &interpreter)
16670b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "command script list",
1668349cc55cSDimitry Andric "List defined top-level scripted commands.",
1669349cc55cSDimitry Andric nullptr) {}
16700b57cec5SDimitry Andric
16710b57cec5SDimitry Andric ~CommandObjectCommandsScriptList() override = default;
16720b57cec5SDimitry Andric
DoExecute(Args & command,CommandReturnObject & result)1673*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
16740b57cec5SDimitry Andric m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
16750b57cec5SDimitry Andric
16760b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
16770b57cec5SDimitry Andric }
16780b57cec5SDimitry Andric };
16790b57cec5SDimitry Andric
16800b57cec5SDimitry Andric // CommandObjectCommandsScriptClear
16810b57cec5SDimitry Andric
16820b57cec5SDimitry Andric class CommandObjectCommandsScriptClear : public CommandObjectParsed {
16830b57cec5SDimitry Andric public:
CommandObjectCommandsScriptClear(CommandInterpreter & interpreter)16840b57cec5SDimitry Andric CommandObjectCommandsScriptClear(CommandInterpreter &interpreter)
16850b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "command script clear",
16860b57cec5SDimitry Andric "Delete all scripted commands.", nullptr) {}
16870b57cec5SDimitry Andric
16880b57cec5SDimitry Andric ~CommandObjectCommandsScriptClear() override = default;
16890b57cec5SDimitry Andric
16900b57cec5SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)1691*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
16920b57cec5SDimitry Andric m_interpreter.RemoveAllUser();
16930b57cec5SDimitry Andric
16940b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
16950b57cec5SDimitry Andric }
16960b57cec5SDimitry Andric };
16970b57cec5SDimitry Andric
16980b57cec5SDimitry Andric // CommandObjectCommandsScriptDelete
16990b57cec5SDimitry Andric
17000b57cec5SDimitry Andric class CommandObjectCommandsScriptDelete : public CommandObjectParsed {
17010b57cec5SDimitry Andric public:
CommandObjectCommandsScriptDelete(CommandInterpreter & interpreter)17020b57cec5SDimitry Andric CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter)
1703349cc55cSDimitry Andric : CommandObjectParsed(
1704349cc55cSDimitry Andric interpreter, "command script delete",
1705349cc55cSDimitry Andric "Delete a scripted command by specifying the path to the command.",
1706349cc55cSDimitry Andric nullptr) {
17070b57cec5SDimitry Andric CommandArgumentEntry arg1;
17080b57cec5SDimitry Andric CommandArgumentData cmd_arg;
17090b57cec5SDimitry Andric
1710349cc55cSDimitry Andric // This is a list of command names forming the path to the command
1711349cc55cSDimitry Andric // to be deleted.
1712349cc55cSDimitry Andric cmd_arg.arg_type = eArgTypeCommand;
1713349cc55cSDimitry Andric cmd_arg.arg_repetition = eArgRepeatPlus;
17140b57cec5SDimitry Andric
17150b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
17160b57cec5SDimitry Andric // argument entry.
17170b57cec5SDimitry Andric arg1.push_back(cmd_arg);
17180b57cec5SDimitry Andric
17190b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
17200b57cec5SDimitry Andric m_arguments.push_back(arg1);
17210b57cec5SDimitry Andric }
17220b57cec5SDimitry Andric
17230b57cec5SDimitry Andric ~CommandObjectCommandsScriptDelete() override = default;
17240b57cec5SDimitry Andric
17255ffd83dbSDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)17265ffd83dbSDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
17275ffd83dbSDimitry Andric OptionElementVector &opt_element_vector) override {
1728fe013be4SDimitry Andric lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
1729fe013be4SDimitry Andric m_interpreter, request, opt_element_vector);
17305ffd83dbSDimitry Andric }
17315ffd83dbSDimitry Andric
17320b57cec5SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)1733*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
17340b57cec5SDimitry Andric
1735349cc55cSDimitry Andric llvm::StringRef root_cmd = command[0].ref();
1736349cc55cSDimitry Andric size_t num_args = command.GetArgumentCount();
1737349cc55cSDimitry Andric
1738349cc55cSDimitry Andric if (root_cmd.empty()) {
1739349cc55cSDimitry Andric result.AppendErrorWithFormat("empty root command name");
1740*c9157d92SDimitry Andric return;
1741349cc55cSDimitry Andric }
1742349cc55cSDimitry Andric if (!m_interpreter.HasUserCommands() &&
1743349cc55cSDimitry Andric !m_interpreter.HasUserMultiwordCommands()) {
1744349cc55cSDimitry Andric result.AppendErrorWithFormat("can only delete user defined commands, "
1745349cc55cSDimitry Andric "but no user defined commands found");
1746*c9157d92SDimitry Andric return;
17470b57cec5SDimitry Andric }
17480b57cec5SDimitry Andric
1749349cc55cSDimitry Andric CommandObjectSP cmd_sp = m_interpreter.GetCommandSPExact(root_cmd);
1750349cc55cSDimitry Andric if (!cmd_sp) {
1751349cc55cSDimitry Andric result.AppendErrorWithFormat("command '%s' not found.",
1752349cc55cSDimitry Andric command[0].c_str());
1753*c9157d92SDimitry Andric return;
1754349cc55cSDimitry Andric }
1755349cc55cSDimitry Andric if (!cmd_sp->IsUserCommand()) {
1756349cc55cSDimitry Andric result.AppendErrorWithFormat("command '%s' is not a user command.",
1757349cc55cSDimitry Andric command[0].c_str());
1758*c9157d92SDimitry Andric return;
1759349cc55cSDimitry Andric }
1760349cc55cSDimitry Andric if (cmd_sp->GetAsMultiwordCommand() && num_args == 1) {
1761349cc55cSDimitry Andric result.AppendErrorWithFormat("command '%s' is a multi-word command.\n "
1762349cc55cSDimitry Andric "Delete with \"command container delete\"",
1763349cc55cSDimitry Andric command[0].c_str());
1764*c9157d92SDimitry Andric return;
17650b57cec5SDimitry Andric }
17660b57cec5SDimitry Andric
1767349cc55cSDimitry Andric if (command.GetArgumentCount() == 1) {
1768349cc55cSDimitry Andric m_interpreter.RemoveUser(root_cmd);
1769349cc55cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
1770*c9157d92SDimitry Andric return;
1771349cc55cSDimitry Andric }
1772349cc55cSDimitry Andric // We're deleting a command from a multiword command. Verify the command
1773349cc55cSDimitry Andric // path:
1774349cc55cSDimitry Andric Status error;
1775349cc55cSDimitry Andric CommandObjectMultiword *container =
1776349cc55cSDimitry Andric GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
1777349cc55cSDimitry Andric error);
1778349cc55cSDimitry Andric if (error.Fail()) {
1779349cc55cSDimitry Andric result.AppendErrorWithFormat("could not resolve command path: %s",
1780349cc55cSDimitry Andric error.AsCString());
1781*c9157d92SDimitry Andric return;
1782349cc55cSDimitry Andric }
1783349cc55cSDimitry Andric if (!container) {
1784349cc55cSDimitry Andric // This means that command only had a leaf command, so the container is
1785349cc55cSDimitry Andric // the root. That should have been handled above.
1786349cc55cSDimitry Andric result.AppendErrorWithFormat("could not find a container for '%s'",
1787349cc55cSDimitry Andric command[0].c_str());
1788*c9157d92SDimitry Andric return;
1789349cc55cSDimitry Andric }
1790349cc55cSDimitry Andric const char *leaf_cmd = command[num_args - 1].c_str();
1791349cc55cSDimitry Andric llvm::Error llvm_error = container->RemoveUserSubcommand(leaf_cmd,
1792349cc55cSDimitry Andric /* multiword not okay */ false);
1793349cc55cSDimitry Andric if (llvm_error) {
1794349cc55cSDimitry Andric result.AppendErrorWithFormat("could not delete command '%s': %s",
1795349cc55cSDimitry Andric leaf_cmd,
1796349cc55cSDimitry Andric llvm::toString(std::move(llvm_error)).c_str());
1797*c9157d92SDimitry Andric return;
1798349cc55cSDimitry Andric }
1799349cc55cSDimitry Andric
1800349cc55cSDimitry Andric Stream &out_stream = result.GetOutputStream();
1801349cc55cSDimitry Andric
1802349cc55cSDimitry Andric out_stream << "Deleted command:";
1803349cc55cSDimitry Andric for (size_t idx = 0; idx < num_args; idx++) {
1804349cc55cSDimitry Andric out_stream << ' ';
1805349cc55cSDimitry Andric out_stream << command[idx].c_str();
1806349cc55cSDimitry Andric }
1807349cc55cSDimitry Andric out_stream << '\n';
18080b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
18090b57cec5SDimitry Andric }
18100b57cec5SDimitry Andric };
18110b57cec5SDimitry Andric
18120b57cec5SDimitry Andric #pragma mark CommandObjectMultiwordCommandsScript
18130b57cec5SDimitry Andric
18140b57cec5SDimitry Andric // CommandObjectMultiwordCommandsScript
18150b57cec5SDimitry Andric
18160b57cec5SDimitry Andric class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword {
18170b57cec5SDimitry Andric public:
CommandObjectMultiwordCommandsScript(CommandInterpreter & interpreter)18180b57cec5SDimitry Andric CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter)
18190b57cec5SDimitry Andric : CommandObjectMultiword(
1820480093f4SDimitry Andric interpreter, "command script",
1821480093f4SDimitry Andric "Commands for managing custom "
18220b57cec5SDimitry Andric "commands implemented by "
18230b57cec5SDimitry Andric "interpreter scripts.",
18240b57cec5SDimitry Andric "command script <subcommand> [<subcommand-options>]") {
18250b57cec5SDimitry Andric LoadSubCommand("add", CommandObjectSP(
18260b57cec5SDimitry Andric new CommandObjectCommandsScriptAdd(interpreter)));
18270b57cec5SDimitry Andric LoadSubCommand(
18280b57cec5SDimitry Andric "delete",
18290b57cec5SDimitry Andric CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter)));
18300b57cec5SDimitry Andric LoadSubCommand(
18310b57cec5SDimitry Andric "clear",
18320b57cec5SDimitry Andric CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter)));
18330b57cec5SDimitry Andric LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList(
18340b57cec5SDimitry Andric interpreter)));
18350b57cec5SDimitry Andric LoadSubCommand(
18360b57cec5SDimitry Andric "import",
18370b57cec5SDimitry Andric CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter)));
18380b57cec5SDimitry Andric }
18390b57cec5SDimitry Andric
18400b57cec5SDimitry Andric ~CommandObjectMultiwordCommandsScript() override = default;
18410b57cec5SDimitry Andric };
18420b57cec5SDimitry Andric
1843349cc55cSDimitry Andric #pragma mark CommandObjectCommandContainer
1844349cc55cSDimitry Andric #define LLDB_OPTIONS_container_add
1845349cc55cSDimitry Andric #include "CommandOptions.inc"
1846349cc55cSDimitry Andric
1847349cc55cSDimitry Andric class CommandObjectCommandsContainerAdd : public CommandObjectParsed {
1848349cc55cSDimitry Andric public:
CommandObjectCommandsContainerAdd(CommandInterpreter & interpreter)1849349cc55cSDimitry Andric CommandObjectCommandsContainerAdd(CommandInterpreter &interpreter)
1850349cc55cSDimitry Andric : CommandObjectParsed(
1851349cc55cSDimitry Andric interpreter, "command container add",
1852349cc55cSDimitry Andric "Add a container command to lldb. Adding to built-"
1853349cc55cSDimitry Andric "in container commands is not allowed.",
1854349cc55cSDimitry Andric "command container add [[path1]...] container-name") {
1855349cc55cSDimitry Andric CommandArgumentEntry arg1;
1856349cc55cSDimitry Andric CommandArgumentData cmd_arg;
1857349cc55cSDimitry Andric
1858349cc55cSDimitry Andric // This is one or more command names, which form the path to the command
1859349cc55cSDimitry Andric // you want to add.
1860349cc55cSDimitry Andric cmd_arg.arg_type = eArgTypeCommand;
1861349cc55cSDimitry Andric cmd_arg.arg_repetition = eArgRepeatPlus;
1862349cc55cSDimitry Andric
1863349cc55cSDimitry Andric // There is only one variant this argument could be; put it into the
1864349cc55cSDimitry Andric // argument entry.
1865349cc55cSDimitry Andric arg1.push_back(cmd_arg);
1866349cc55cSDimitry Andric
1867349cc55cSDimitry Andric // Push the data for the first argument into the m_arguments vector.
1868349cc55cSDimitry Andric m_arguments.push_back(arg1);
1869349cc55cSDimitry Andric }
1870349cc55cSDimitry Andric
1871349cc55cSDimitry Andric ~CommandObjectCommandsContainerAdd() override = default;
1872349cc55cSDimitry Andric
GetOptions()1873349cc55cSDimitry Andric Options *GetOptions() override { return &m_options; }
1874349cc55cSDimitry Andric
1875349cc55cSDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1876349cc55cSDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
1877349cc55cSDimitry Andric OptionElementVector &opt_element_vector) override {
1878fe013be4SDimitry Andric lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
1879fe013be4SDimitry Andric m_interpreter, request, opt_element_vector);
1880349cc55cSDimitry Andric }
1881349cc55cSDimitry Andric
1882349cc55cSDimitry Andric protected:
1883349cc55cSDimitry Andric class CommandOptions : public Options {
1884349cc55cSDimitry Andric public:
188581ad6265SDimitry Andric CommandOptions() = default;
1886349cc55cSDimitry Andric
1887349cc55cSDimitry Andric ~CommandOptions() override = default;
1888349cc55cSDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1889349cc55cSDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1890349cc55cSDimitry Andric ExecutionContext *execution_context) override {
1891349cc55cSDimitry Andric Status error;
1892349cc55cSDimitry Andric const int short_option = m_getopt_table[option_idx].val;
1893349cc55cSDimitry Andric
1894349cc55cSDimitry Andric switch (short_option) {
1895349cc55cSDimitry Andric case 'h':
1896349cc55cSDimitry Andric if (!option_arg.empty())
1897349cc55cSDimitry Andric m_short_help = std::string(option_arg);
1898349cc55cSDimitry Andric break;
1899349cc55cSDimitry Andric case 'o':
1900349cc55cSDimitry Andric m_overwrite = true;
1901349cc55cSDimitry Andric break;
1902349cc55cSDimitry Andric case 'H':
1903349cc55cSDimitry Andric if (!option_arg.empty())
1904349cc55cSDimitry Andric m_long_help = std::string(option_arg);
1905349cc55cSDimitry Andric break;
1906349cc55cSDimitry Andric default:
1907349cc55cSDimitry Andric llvm_unreachable("Unimplemented option");
1908349cc55cSDimitry Andric }
1909349cc55cSDimitry Andric
1910349cc55cSDimitry Andric return error;
1911349cc55cSDimitry Andric }
1912349cc55cSDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)1913349cc55cSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
1914349cc55cSDimitry Andric m_short_help.clear();
1915349cc55cSDimitry Andric m_long_help.clear();
1916349cc55cSDimitry Andric m_overwrite = false;
1917349cc55cSDimitry Andric }
1918349cc55cSDimitry Andric
GetDefinitions()1919349cc55cSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1920bdd1243dSDimitry Andric return llvm::ArrayRef(g_container_add_options);
1921349cc55cSDimitry Andric }
1922349cc55cSDimitry Andric
1923349cc55cSDimitry Andric // Instance variables to hold the values for command options.
1924349cc55cSDimitry Andric
1925349cc55cSDimitry Andric std::string m_short_help;
1926349cc55cSDimitry Andric std::string m_long_help;
1927349cc55cSDimitry Andric bool m_overwrite = false;
1928349cc55cSDimitry Andric };
DoExecute(Args & command,CommandReturnObject & result)1929*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
1930349cc55cSDimitry Andric size_t num_args = command.GetArgumentCount();
1931349cc55cSDimitry Andric
1932349cc55cSDimitry Andric if (num_args == 0) {
1933349cc55cSDimitry Andric result.AppendError("no command was specified");
1934*c9157d92SDimitry Andric return;
1935349cc55cSDimitry Andric }
1936349cc55cSDimitry Andric
1937349cc55cSDimitry Andric if (num_args == 1) {
1938349cc55cSDimitry Andric // We're adding this as a root command, so use the interpreter.
1939349cc55cSDimitry Andric const char *cmd_name = command.GetArgumentAtIndex(0);
1940349cc55cSDimitry Andric auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
1941349cc55cSDimitry Andric GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
1942349cc55cSDimitry Andric m_options.m_long_help.c_str()));
1943349cc55cSDimitry Andric cmd_sp->GetAsMultiwordCommand()->SetRemovable(true);
1944349cc55cSDimitry Andric Status add_error = GetCommandInterpreter().AddUserCommand(
1945349cc55cSDimitry Andric cmd_name, cmd_sp, m_options.m_overwrite);
1946349cc55cSDimitry Andric if (add_error.Fail()) {
1947349cc55cSDimitry Andric result.AppendErrorWithFormat("error adding command: %s",
1948349cc55cSDimitry Andric add_error.AsCString());
1949*c9157d92SDimitry Andric return;
1950349cc55cSDimitry Andric }
1951349cc55cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
1952*c9157d92SDimitry Andric return;
1953349cc55cSDimitry Andric }
1954349cc55cSDimitry Andric
1955349cc55cSDimitry Andric // We're adding this to a subcommand, first find the subcommand:
1956349cc55cSDimitry Andric Status path_error;
1957349cc55cSDimitry Andric CommandObjectMultiword *add_to_me =
1958349cc55cSDimitry Andric GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
1959349cc55cSDimitry Andric path_error);
1960349cc55cSDimitry Andric
1961349cc55cSDimitry Andric if (!add_to_me) {
1962349cc55cSDimitry Andric result.AppendErrorWithFormat("error adding command: %s",
1963349cc55cSDimitry Andric path_error.AsCString());
1964*c9157d92SDimitry Andric return;
1965349cc55cSDimitry Andric }
1966349cc55cSDimitry Andric
1967349cc55cSDimitry Andric const char *cmd_name = command.GetArgumentAtIndex(num_args - 1);
1968349cc55cSDimitry Andric auto cmd_sp = CommandObjectSP(new CommandObjectMultiword(
1969349cc55cSDimitry Andric GetCommandInterpreter(), cmd_name, m_options.m_short_help.c_str(),
1970349cc55cSDimitry Andric m_options.m_long_help.c_str()));
1971349cc55cSDimitry Andric llvm::Error llvm_error =
1972349cc55cSDimitry Andric add_to_me->LoadUserSubcommand(cmd_name, cmd_sp, m_options.m_overwrite);
1973349cc55cSDimitry Andric if (llvm_error) {
1974349cc55cSDimitry Andric result.AppendErrorWithFormat("error adding subcommand: %s",
1975349cc55cSDimitry Andric llvm::toString(std::move(llvm_error)).c_str());
1976*c9157d92SDimitry Andric return;
1977349cc55cSDimitry Andric }
1978349cc55cSDimitry Andric
1979349cc55cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
1980349cc55cSDimitry Andric }
1981349cc55cSDimitry Andric
1982349cc55cSDimitry Andric private:
1983349cc55cSDimitry Andric CommandOptions m_options;
1984349cc55cSDimitry Andric };
1985349cc55cSDimitry Andric
1986349cc55cSDimitry Andric #define LLDB_OPTIONS_multiword_delete
1987349cc55cSDimitry Andric #include "CommandOptions.inc"
1988349cc55cSDimitry Andric class CommandObjectCommandsContainerDelete : public CommandObjectParsed {
1989349cc55cSDimitry Andric public:
CommandObjectCommandsContainerDelete(CommandInterpreter & interpreter)1990349cc55cSDimitry Andric CommandObjectCommandsContainerDelete(CommandInterpreter &interpreter)
1991349cc55cSDimitry Andric : CommandObjectParsed(
1992349cc55cSDimitry Andric interpreter, "command container delete",
1993349cc55cSDimitry Andric "Delete a container command previously added to "
1994349cc55cSDimitry Andric "lldb.",
1995349cc55cSDimitry Andric "command container delete [[path1] ...] container-cmd") {
1996349cc55cSDimitry Andric CommandArgumentEntry arg1;
1997349cc55cSDimitry Andric CommandArgumentData cmd_arg;
1998349cc55cSDimitry Andric
1999349cc55cSDimitry Andric // This is one or more command names, which form the path to the command
2000349cc55cSDimitry Andric // you want to add.
2001349cc55cSDimitry Andric cmd_arg.arg_type = eArgTypeCommand;
2002349cc55cSDimitry Andric cmd_arg.arg_repetition = eArgRepeatPlus;
2003349cc55cSDimitry Andric
2004349cc55cSDimitry Andric // There is only one variant this argument could be; put it into the
2005349cc55cSDimitry Andric // argument entry.
2006349cc55cSDimitry Andric arg1.push_back(cmd_arg);
2007349cc55cSDimitry Andric
2008349cc55cSDimitry Andric // Push the data for the first argument into the m_arguments vector.
2009349cc55cSDimitry Andric m_arguments.push_back(arg1);
2010349cc55cSDimitry Andric }
2011349cc55cSDimitry Andric
2012349cc55cSDimitry Andric ~CommandObjectCommandsContainerDelete() override = default;
2013349cc55cSDimitry Andric
2014349cc55cSDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2015349cc55cSDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
2016349cc55cSDimitry Andric OptionElementVector &opt_element_vector) override {
2017fe013be4SDimitry Andric lldb_private::CommandCompletions::CompleteModifiableCmdPathArgs(
2018fe013be4SDimitry Andric m_interpreter, request, opt_element_vector);
2019349cc55cSDimitry Andric }
2020349cc55cSDimitry Andric
2021349cc55cSDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)2022*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
2023349cc55cSDimitry Andric size_t num_args = command.GetArgumentCount();
2024349cc55cSDimitry Andric
2025349cc55cSDimitry Andric if (num_args == 0) {
2026349cc55cSDimitry Andric result.AppendError("No command was specified.");
2027*c9157d92SDimitry Andric return;
2028349cc55cSDimitry Andric }
2029349cc55cSDimitry Andric
2030349cc55cSDimitry Andric if (num_args == 1) {
2031349cc55cSDimitry Andric // We're removing a root command, so we need to delete it from the
2032349cc55cSDimitry Andric // interpreter.
2033349cc55cSDimitry Andric const char *cmd_name = command.GetArgumentAtIndex(0);
2034349cc55cSDimitry Andric // Let's do a little more work here so we can do better error reporting.
2035349cc55cSDimitry Andric CommandInterpreter &interp = GetCommandInterpreter();
2036349cc55cSDimitry Andric CommandObjectSP cmd_sp = interp.GetCommandSPExact(cmd_name);
2037349cc55cSDimitry Andric if (!cmd_sp) {
2038349cc55cSDimitry Andric result.AppendErrorWithFormat("container command %s doesn't exist.",
2039349cc55cSDimitry Andric cmd_name);
2040*c9157d92SDimitry Andric return;
2041349cc55cSDimitry Andric }
2042349cc55cSDimitry Andric if (!cmd_sp->IsUserCommand()) {
2043349cc55cSDimitry Andric result.AppendErrorWithFormat(
2044349cc55cSDimitry Andric "container command %s is not a user command", cmd_name);
2045*c9157d92SDimitry Andric return;
2046349cc55cSDimitry Andric }
2047349cc55cSDimitry Andric if (!cmd_sp->GetAsMultiwordCommand()) {
2048349cc55cSDimitry Andric result.AppendErrorWithFormat("command %s is not a container command",
2049349cc55cSDimitry Andric cmd_name);
2050*c9157d92SDimitry Andric return;
2051349cc55cSDimitry Andric }
2052349cc55cSDimitry Andric
2053349cc55cSDimitry Andric bool did_remove = GetCommandInterpreter().RemoveUserMultiword(cmd_name);
2054349cc55cSDimitry Andric if (!did_remove) {
2055349cc55cSDimitry Andric result.AppendErrorWithFormat("error removing command %s.", cmd_name);
2056*c9157d92SDimitry Andric return;
2057349cc55cSDimitry Andric }
2058349cc55cSDimitry Andric
2059349cc55cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
2060*c9157d92SDimitry Andric return;
2061349cc55cSDimitry Andric }
2062349cc55cSDimitry Andric
2063349cc55cSDimitry Andric // We're removing a subcommand, first find the subcommand's owner:
2064349cc55cSDimitry Andric Status path_error;
2065349cc55cSDimitry Andric CommandObjectMultiword *container =
2066349cc55cSDimitry Andric GetCommandInterpreter().VerifyUserMultiwordCmdPath(command, true,
2067349cc55cSDimitry Andric path_error);
2068349cc55cSDimitry Andric
2069349cc55cSDimitry Andric if (!container) {
2070349cc55cSDimitry Andric result.AppendErrorWithFormat("error removing container command: %s",
2071349cc55cSDimitry Andric path_error.AsCString());
2072*c9157d92SDimitry Andric return;
2073349cc55cSDimitry Andric }
2074349cc55cSDimitry Andric const char *leaf = command.GetArgumentAtIndex(num_args - 1);
2075349cc55cSDimitry Andric llvm::Error llvm_error =
2076349cc55cSDimitry Andric container->RemoveUserSubcommand(leaf, /* multiword okay */ true);
2077349cc55cSDimitry Andric if (llvm_error) {
2078349cc55cSDimitry Andric result.AppendErrorWithFormat("error removing container command: %s",
2079349cc55cSDimitry Andric llvm::toString(std::move(llvm_error)).c_str());
2080*c9157d92SDimitry Andric return;
2081349cc55cSDimitry Andric }
2082349cc55cSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
2083349cc55cSDimitry Andric }
2084349cc55cSDimitry Andric };
2085349cc55cSDimitry Andric
2086349cc55cSDimitry Andric class CommandObjectCommandContainer : public CommandObjectMultiword {
2087349cc55cSDimitry Andric public:
CommandObjectCommandContainer(CommandInterpreter & interpreter)2088349cc55cSDimitry Andric CommandObjectCommandContainer(CommandInterpreter &interpreter)
2089349cc55cSDimitry Andric : CommandObjectMultiword(
2090349cc55cSDimitry Andric interpreter, "command container",
2091349cc55cSDimitry Andric "Commands for adding container commands to lldb. "
2092349cc55cSDimitry Andric "Container commands are containers for other commands. You can "
209381ad6265SDimitry Andric "add nested container commands by specifying a command path, "
2094349cc55cSDimitry Andric "but you can't add commands into the built-in command hierarchy.",
2095349cc55cSDimitry Andric "command container <subcommand> [<subcommand-options>]") {
2096349cc55cSDimitry Andric LoadSubCommand("add", CommandObjectSP(new CommandObjectCommandsContainerAdd(
2097349cc55cSDimitry Andric interpreter)));
2098349cc55cSDimitry Andric LoadSubCommand(
2099349cc55cSDimitry Andric "delete",
2100349cc55cSDimitry Andric CommandObjectSP(new CommandObjectCommandsContainerDelete(interpreter)));
2101349cc55cSDimitry Andric }
2102349cc55cSDimitry Andric
2103349cc55cSDimitry Andric ~CommandObjectCommandContainer() override = default;
2104349cc55cSDimitry Andric };
2105349cc55cSDimitry Andric
21060b57cec5SDimitry Andric #pragma mark CommandObjectMultiwordCommands
21070b57cec5SDimitry Andric
21080b57cec5SDimitry Andric // CommandObjectMultiwordCommands
21090b57cec5SDimitry Andric
CommandObjectMultiwordCommands(CommandInterpreter & interpreter)21100b57cec5SDimitry Andric CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(
21110b57cec5SDimitry Andric CommandInterpreter &interpreter)
21120b57cec5SDimitry Andric : CommandObjectMultiword(interpreter, "command",
21130b57cec5SDimitry Andric "Commands for managing custom LLDB commands.",
21140b57cec5SDimitry Andric "command <subcommand> [<subcommand-options>]") {
21150b57cec5SDimitry Andric LoadSubCommand("source",
21160b57cec5SDimitry Andric CommandObjectSP(new CommandObjectCommandsSource(interpreter)));
21170b57cec5SDimitry Andric LoadSubCommand("alias",
21180b57cec5SDimitry Andric CommandObjectSP(new CommandObjectCommandsAlias(interpreter)));
21190b57cec5SDimitry Andric LoadSubCommand("unalias", CommandObjectSP(
21200b57cec5SDimitry Andric new CommandObjectCommandsUnalias(interpreter)));
21210b57cec5SDimitry Andric LoadSubCommand("delete",
21220b57cec5SDimitry Andric CommandObjectSP(new CommandObjectCommandsDelete(interpreter)));
2123349cc55cSDimitry Andric LoadSubCommand("container", CommandObjectSP(new CommandObjectCommandContainer(
2124349cc55cSDimitry Andric interpreter)));
21250b57cec5SDimitry Andric LoadSubCommand(
21260b57cec5SDimitry Andric "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter)));
21270b57cec5SDimitry Andric LoadSubCommand(
21280b57cec5SDimitry Andric "script",
21290b57cec5SDimitry Andric CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter)));
21300b57cec5SDimitry Andric }
21310b57cec5SDimitry Andric
21320b57cec5SDimitry Andric CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default;
2133