1dda28197Spatrick //===-- CommandObjectMultiword.cpp ----------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Interpreter/CommandObjectMultiword.h"
10061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
11061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
12061da546Spatrick #include "lldb/Interpreter/Options.h"
13*f6aab3d8Srobert #include <optional>
14061da546Spatrick
15061da546Spatrick using namespace lldb;
16061da546Spatrick using namespace lldb_private;
17061da546Spatrick
18061da546Spatrick // CommandObjectMultiword
19061da546Spatrick
CommandObjectMultiword(CommandInterpreter & interpreter,const char * name,const char * help,const char * syntax,uint32_t flags)20061da546Spatrick CommandObjectMultiword::CommandObjectMultiword(CommandInterpreter &interpreter,
21061da546Spatrick const char *name,
22061da546Spatrick const char *help,
23061da546Spatrick const char *syntax,
24061da546Spatrick uint32_t flags)
25061da546Spatrick : CommandObject(interpreter, name, help, syntax, flags),
26061da546Spatrick m_can_be_removed(false) {}
27061da546Spatrick
28061da546Spatrick CommandObjectMultiword::~CommandObjectMultiword() = default;
29061da546Spatrick
30*f6aab3d8Srobert CommandObjectSP
GetSubcommandSPExact(llvm::StringRef sub_cmd)31*f6aab3d8Srobert CommandObjectMultiword::GetSubcommandSPExact(llvm::StringRef sub_cmd) {
32*f6aab3d8Srobert if (m_subcommand_dict.empty())
33*f6aab3d8Srobert return {};
34*f6aab3d8Srobert
35*f6aab3d8Srobert auto pos = m_subcommand_dict.find(std::string(sub_cmd));
36*f6aab3d8Srobert if (pos == m_subcommand_dict.end())
37*f6aab3d8Srobert return {};
38*f6aab3d8Srobert
39*f6aab3d8Srobert return pos->second;
40*f6aab3d8Srobert }
41*f6aab3d8Srobert
GetSubcommandSP(llvm::StringRef sub_cmd,StringList * matches)42061da546Spatrick CommandObjectSP CommandObjectMultiword::GetSubcommandSP(llvm::StringRef sub_cmd,
43061da546Spatrick StringList *matches) {
44*f6aab3d8Srobert if (m_subcommand_dict.empty())
45*f6aab3d8Srobert return {};
46061da546Spatrick
47*f6aab3d8Srobert CommandObjectSP return_cmd_sp = GetSubcommandSPExact(sub_cmd);
48*f6aab3d8Srobert if (return_cmd_sp) {
49061da546Spatrick if (matches)
50061da546Spatrick matches->AppendString(sub_cmd);
51*f6aab3d8Srobert return return_cmd_sp;
52*f6aab3d8Srobert }
53*f6aab3d8Srobert
54*f6aab3d8Srobert CommandObject::CommandMap::iterator pos;
55*f6aab3d8Srobert
56061da546Spatrick StringList local_matches;
57061da546Spatrick if (matches == nullptr)
58061da546Spatrick matches = &local_matches;
59061da546Spatrick int num_matches =
60061da546Spatrick AddNamesMatchingPartialString(m_subcommand_dict, sub_cmd, *matches);
61061da546Spatrick
62061da546Spatrick if (num_matches == 1) {
63061da546Spatrick // Cleaner, but slightly less efficient would be to call back into this
64061da546Spatrick // function, since I now know I have an exact match...
65061da546Spatrick
66061da546Spatrick sub_cmd = matches->GetStringAtIndex(0);
67dda28197Spatrick pos = m_subcommand_dict.find(std::string(sub_cmd));
68061da546Spatrick if (pos != m_subcommand_dict.end())
69061da546Spatrick return_cmd_sp = pos->second;
70061da546Spatrick }
71*f6aab3d8Srobert
72061da546Spatrick return return_cmd_sp;
73061da546Spatrick }
74061da546Spatrick
75061da546Spatrick CommandObject *
GetSubcommandObject(llvm::StringRef sub_cmd,StringList * matches)76061da546Spatrick CommandObjectMultiword::GetSubcommandObject(llvm::StringRef sub_cmd,
77061da546Spatrick StringList *matches) {
78061da546Spatrick return GetSubcommandSP(sub_cmd, matches).get();
79061da546Spatrick }
80061da546Spatrick
LoadSubCommand(llvm::StringRef name,const CommandObjectSP & cmd_obj_sp)81061da546Spatrick bool CommandObjectMultiword::LoadSubCommand(llvm::StringRef name,
82*f6aab3d8Srobert const CommandObjectSP &cmd_obj_sp) {
83*f6aab3d8Srobert if (cmd_obj_sp)
84*f6aab3d8Srobert lldbassert((&GetCommandInterpreter() == &cmd_obj_sp->GetCommandInterpreter()) &&
85061da546Spatrick "tried to add a CommandObject from a different interpreter");
86061da546Spatrick
87061da546Spatrick CommandMap::iterator pos;
88061da546Spatrick bool success = true;
89061da546Spatrick
90dda28197Spatrick pos = m_subcommand_dict.find(std::string(name));
91061da546Spatrick if (pos == m_subcommand_dict.end()) {
92*f6aab3d8Srobert m_subcommand_dict[std::string(name)] = cmd_obj_sp;
93061da546Spatrick } else
94061da546Spatrick success = false;
95061da546Spatrick
96061da546Spatrick return success;
97061da546Spatrick }
98061da546Spatrick
LoadUserSubcommand(llvm::StringRef name,const CommandObjectSP & cmd_obj_sp,bool can_replace)99*f6aab3d8Srobert llvm::Error CommandObjectMultiword::LoadUserSubcommand(
100*f6aab3d8Srobert llvm::StringRef name, const CommandObjectSP &cmd_obj_sp, bool can_replace) {
101*f6aab3d8Srobert Status result;
102*f6aab3d8Srobert if (cmd_obj_sp)
103*f6aab3d8Srobert lldbassert((&GetCommandInterpreter() == &cmd_obj_sp->GetCommandInterpreter()) &&
104*f6aab3d8Srobert "tried to add a CommandObject from a different interpreter");
105*f6aab3d8Srobert if (!IsUserCommand()) {
106*f6aab3d8Srobert return llvm::createStringError(llvm::inconvertibleErrorCode(),
107*f6aab3d8Srobert "can't add a user subcommand to a builtin container command.");
108*f6aab3d8Srobert }
109*f6aab3d8Srobert // Make sure this a user command if it isn't already:
110*f6aab3d8Srobert cmd_obj_sp->SetIsUserCommand(true);
111*f6aab3d8Srobert
112*f6aab3d8Srobert std::string str_name(name);
113*f6aab3d8Srobert
114*f6aab3d8Srobert auto pos = m_subcommand_dict.find(str_name);
115*f6aab3d8Srobert if (pos == m_subcommand_dict.end()) {
116*f6aab3d8Srobert m_subcommand_dict[str_name] = cmd_obj_sp;
117*f6aab3d8Srobert return llvm::Error::success();
118*f6aab3d8Srobert }
119*f6aab3d8Srobert
120*f6aab3d8Srobert const char *error_str = nullptr;
121*f6aab3d8Srobert if (!can_replace)
122*f6aab3d8Srobert error_str = "sub-command already exists";
123*f6aab3d8Srobert if (!(*pos).second->IsUserCommand())
124*f6aab3d8Srobert error_str = "can't replace a builtin subcommand";
125*f6aab3d8Srobert
126*f6aab3d8Srobert if (error_str) {
127*f6aab3d8Srobert return llvm::createStringError(llvm::inconvertibleErrorCode(), error_str);
128*f6aab3d8Srobert }
129*f6aab3d8Srobert m_subcommand_dict[str_name] = cmd_obj_sp;
130*f6aab3d8Srobert return llvm::Error::success();
131*f6aab3d8Srobert }
132*f6aab3d8Srobert
RemoveUserSubcommand(llvm::StringRef cmd_name,bool must_be_multiword)133*f6aab3d8Srobert llvm::Error CommandObjectMultiword::RemoveUserSubcommand(llvm::StringRef cmd_name,
134*f6aab3d8Srobert bool must_be_multiword) {
135*f6aab3d8Srobert CommandMap::iterator pos;
136*f6aab3d8Srobert std::string str_name(cmd_name);
137*f6aab3d8Srobert
138*f6aab3d8Srobert pos = m_subcommand_dict.find(str_name);
139*f6aab3d8Srobert if (pos == m_subcommand_dict.end()) {
140*f6aab3d8Srobert return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' not found.",
141*f6aab3d8Srobert str_name.c_str());
142*f6aab3d8Srobert }
143*f6aab3d8Srobert if (!(*pos).second->IsUserCommand()) {
144*f6aab3d8Srobert return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' not a user command.",
145*f6aab3d8Srobert str_name.c_str());
146*f6aab3d8Srobert }
147*f6aab3d8Srobert
148*f6aab3d8Srobert if (must_be_multiword && !(*pos).second->IsMultiwordObject()) {
149*f6aab3d8Srobert return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' is not a container command",
150*f6aab3d8Srobert str_name.c_str());
151*f6aab3d8Srobert }
152*f6aab3d8Srobert if (!must_be_multiword && (*pos).second->IsMultiwordObject()) {
153*f6aab3d8Srobert return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' is not a user command",
154*f6aab3d8Srobert str_name.c_str());
155*f6aab3d8Srobert }
156*f6aab3d8Srobert
157*f6aab3d8Srobert m_subcommand_dict.erase(pos);
158*f6aab3d8Srobert
159*f6aab3d8Srobert return llvm::Error::success();
160*f6aab3d8Srobert }
161*f6aab3d8Srobert
Execute(const char * args_string,CommandReturnObject & result)162061da546Spatrick bool CommandObjectMultiword::Execute(const char *args_string,
163061da546Spatrick CommandReturnObject &result) {
164061da546Spatrick Args args(args_string);
165061da546Spatrick const size_t argc = args.GetArgumentCount();
166061da546Spatrick if (argc == 0) {
167061da546Spatrick this->CommandObject::GenerateHelpText(result);
168061da546Spatrick return result.Succeeded();
169061da546Spatrick }
170061da546Spatrick
171061da546Spatrick auto sub_command = args[0].ref();
172061da546Spatrick if (sub_command.empty()) {
173061da546Spatrick result.AppendError("Need to specify a non-empty subcommand.");
174061da546Spatrick return result.Succeeded();
175061da546Spatrick }
176061da546Spatrick
177061da546Spatrick if (m_subcommand_dict.empty()) {
178061da546Spatrick result.AppendErrorWithFormat("'%s' does not have any subcommands.\n",
179061da546Spatrick GetCommandName().str().c_str());
180061da546Spatrick return false;
181061da546Spatrick }
182061da546Spatrick
183061da546Spatrick StringList matches;
184061da546Spatrick CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches);
185061da546Spatrick if (sub_cmd_obj != nullptr) {
186061da546Spatrick // Now call CommandObject::Execute to process options in `rest_of_line`.
187061da546Spatrick // From there the command-specific version of Execute will be called, with
188061da546Spatrick // the processed arguments.
189061da546Spatrick
190061da546Spatrick args.Shift();
191061da546Spatrick sub_cmd_obj->Execute(args_string, result);
192061da546Spatrick return result.Succeeded();
193061da546Spatrick }
194061da546Spatrick
195061da546Spatrick std::string error_msg;
196061da546Spatrick const size_t num_subcmd_matches = matches.GetSize();
197061da546Spatrick if (num_subcmd_matches > 0)
198061da546Spatrick error_msg.assign("ambiguous command ");
199061da546Spatrick else
200061da546Spatrick error_msg.assign("invalid command ");
201061da546Spatrick
202061da546Spatrick error_msg.append("'");
203dda28197Spatrick error_msg.append(std::string(GetCommandName()));
204061da546Spatrick error_msg.append(" ");
205dda28197Spatrick error_msg.append(std::string(sub_command));
206061da546Spatrick error_msg.append("'.");
207061da546Spatrick
208061da546Spatrick if (num_subcmd_matches > 0) {
209061da546Spatrick error_msg.append(" Possible completions:");
210061da546Spatrick for (const std::string &match : matches) {
211061da546Spatrick error_msg.append("\n\t");
212061da546Spatrick error_msg.append(match);
213061da546Spatrick }
214061da546Spatrick }
215061da546Spatrick error_msg.append("\n");
216061da546Spatrick result.AppendRawError(error_msg.c_str());
217061da546Spatrick return false;
218061da546Spatrick }
219061da546Spatrick
GenerateHelpText(Stream & output_stream)220061da546Spatrick void CommandObjectMultiword::GenerateHelpText(Stream &output_stream) {
221061da546Spatrick // First time through here, generate the help text for the object and push it
222061da546Spatrick // to the return result object as well
223061da546Spatrick
224061da546Spatrick CommandObject::GenerateHelpText(output_stream);
225061da546Spatrick output_stream.PutCString("\nThe following subcommands are supported:\n\n");
226061da546Spatrick
227061da546Spatrick CommandMap::iterator pos;
228061da546Spatrick uint32_t max_len = FindLongestCommandWord(m_subcommand_dict);
229061da546Spatrick
230061da546Spatrick if (max_len)
231061da546Spatrick max_len += 4; // Indent the output by 4 spaces.
232061da546Spatrick
233061da546Spatrick for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) {
234061da546Spatrick std::string indented_command(" ");
235061da546Spatrick indented_command.append(pos->first);
236061da546Spatrick if (pos->second->WantsRawCommandString()) {
237dda28197Spatrick std::string help_text(std::string(pos->second->GetHelp()));
238061da546Spatrick help_text.append(" Expects 'raw' input (see 'help raw-input'.)");
239dda28197Spatrick m_interpreter.OutputFormattedHelpText(output_stream, indented_command,
240dda28197Spatrick "--", help_text, max_len);
241061da546Spatrick } else
242dda28197Spatrick m_interpreter.OutputFormattedHelpText(output_stream, indented_command,
243dda28197Spatrick "--", pos->second->GetHelp(),
244dda28197Spatrick max_len);
245061da546Spatrick }
246061da546Spatrick
247061da546Spatrick output_stream.PutCString("\nFor more help on any particular subcommand, type "
248061da546Spatrick "'help <command> <subcommand>'.\n");
249061da546Spatrick }
250061da546Spatrick
HandleCompletion(CompletionRequest & request)251061da546Spatrick void CommandObjectMultiword::HandleCompletion(CompletionRequest &request) {
252061da546Spatrick auto arg0 = request.GetParsedLine()[0].ref();
253061da546Spatrick if (request.GetCursorIndex() == 0) {
254061da546Spatrick StringList new_matches, descriptions;
255061da546Spatrick AddNamesMatchingPartialString(m_subcommand_dict, arg0, new_matches,
256061da546Spatrick &descriptions);
257061da546Spatrick request.AddCompletions(new_matches, descriptions);
258061da546Spatrick
259061da546Spatrick if (new_matches.GetSize() == 1 &&
260061da546Spatrick new_matches.GetStringAtIndex(0) != nullptr &&
261061da546Spatrick (arg0 == new_matches.GetStringAtIndex(0))) {
262061da546Spatrick StringList temp_matches;
263061da546Spatrick CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches);
264061da546Spatrick if (cmd_obj != nullptr) {
265061da546Spatrick if (request.GetParsedLine().GetArgumentCount() != 1) {
266061da546Spatrick request.GetParsedLine().Shift();
267061da546Spatrick request.AppendEmptyArgument();
268061da546Spatrick cmd_obj->HandleCompletion(request);
269061da546Spatrick }
270061da546Spatrick }
271061da546Spatrick }
272061da546Spatrick return;
273061da546Spatrick }
274061da546Spatrick
275061da546Spatrick StringList new_matches;
276061da546Spatrick CommandObject *sub_command_object = GetSubcommandObject(arg0, &new_matches);
277061da546Spatrick if (sub_command_object == nullptr) {
278061da546Spatrick request.AddCompletions(new_matches);
279061da546Spatrick return;
280061da546Spatrick }
281061da546Spatrick
282061da546Spatrick // Remove the one match that we got from calling GetSubcommandObject.
283061da546Spatrick new_matches.DeleteStringAtIndex(0);
284061da546Spatrick request.AddCompletions(new_matches);
285061da546Spatrick request.ShiftArguments();
286061da546Spatrick sub_command_object->HandleCompletion(request);
287061da546Spatrick }
288061da546Spatrick
289*f6aab3d8Srobert std::optional<std::string>
GetRepeatCommand(Args & current_command_args,uint32_t index)290*f6aab3d8Srobert CommandObjectMultiword::GetRepeatCommand(Args ¤t_command_args,
291061da546Spatrick uint32_t index) {
292061da546Spatrick index++;
293061da546Spatrick if (current_command_args.GetArgumentCount() <= index)
294*f6aab3d8Srobert return std::nullopt;
295061da546Spatrick CommandObject *sub_command_object =
296061da546Spatrick GetSubcommandObject(current_command_args[index].ref());
297061da546Spatrick if (sub_command_object == nullptr)
298*f6aab3d8Srobert return std::nullopt;
299061da546Spatrick return sub_command_object->GetRepeatCommand(current_command_args, index);
300061da546Spatrick }
301061da546Spatrick
CommandObjectProxy(CommandInterpreter & interpreter,const char * name,const char * help,const char * syntax,uint32_t flags)302061da546Spatrick CommandObjectProxy::CommandObjectProxy(CommandInterpreter &interpreter,
303061da546Spatrick const char *name, const char *help,
304061da546Spatrick const char *syntax, uint32_t flags)
305061da546Spatrick : CommandObject(interpreter, name, help, syntax, flags) {}
306061da546Spatrick
307061da546Spatrick CommandObjectProxy::~CommandObjectProxy() = default;
308061da546Spatrick
GetOptions()309be691f3bSpatrick Options *CommandObjectProxy::GetOptions() {
310be691f3bSpatrick CommandObject *proxy_command = GetProxyCommandObject();
311be691f3bSpatrick if (proxy_command)
312be691f3bSpatrick return proxy_command->GetOptions();
313be691f3bSpatrick return CommandObject::GetOptions();
314be691f3bSpatrick }
315be691f3bSpatrick
GetHelp()316be691f3bSpatrick llvm::StringRef CommandObjectProxy::GetHelp() {
317be691f3bSpatrick CommandObject *proxy_command = GetProxyCommandObject();
318be691f3bSpatrick if (proxy_command)
319be691f3bSpatrick return proxy_command->GetHelp();
320be691f3bSpatrick return CommandObject::GetHelp();
321be691f3bSpatrick }
322be691f3bSpatrick
GetSyntax()323be691f3bSpatrick llvm::StringRef CommandObjectProxy::GetSyntax() {
324be691f3bSpatrick CommandObject *proxy_command = GetProxyCommandObject();
325be691f3bSpatrick if (proxy_command)
326be691f3bSpatrick return proxy_command->GetSyntax();
327be691f3bSpatrick return CommandObject::GetSyntax();
328be691f3bSpatrick }
329be691f3bSpatrick
GetHelpLong()330061da546Spatrick llvm::StringRef CommandObjectProxy::GetHelpLong() {
331061da546Spatrick CommandObject *proxy_command = GetProxyCommandObject();
332061da546Spatrick if (proxy_command)
333061da546Spatrick return proxy_command->GetHelpLong();
334be691f3bSpatrick return CommandObject::GetHelpLong();
335061da546Spatrick }
336061da546Spatrick
IsRemovable() const337061da546Spatrick bool CommandObjectProxy::IsRemovable() const {
338061da546Spatrick const CommandObject *proxy_command =
339061da546Spatrick const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
340061da546Spatrick if (proxy_command)
341061da546Spatrick return proxy_command->IsRemovable();
342061da546Spatrick return false;
343061da546Spatrick }
344061da546Spatrick
IsMultiwordObject()345061da546Spatrick bool CommandObjectProxy::IsMultiwordObject() {
346061da546Spatrick CommandObject *proxy_command = GetProxyCommandObject();
347061da546Spatrick if (proxy_command)
348061da546Spatrick return proxy_command->IsMultiwordObject();
349061da546Spatrick return false;
350061da546Spatrick }
351061da546Spatrick
GetAsMultiwordCommand()352061da546Spatrick CommandObjectMultiword *CommandObjectProxy::GetAsMultiwordCommand() {
353061da546Spatrick CommandObject *proxy_command = GetProxyCommandObject();
354061da546Spatrick if (proxy_command)
355061da546Spatrick return proxy_command->GetAsMultiwordCommand();
356061da546Spatrick return nullptr;
357061da546Spatrick }
358061da546Spatrick
GenerateHelpText(Stream & result)359061da546Spatrick void CommandObjectProxy::GenerateHelpText(Stream &result) {
360061da546Spatrick CommandObject *proxy_command = GetProxyCommandObject();
361061da546Spatrick if (proxy_command)
362be691f3bSpatrick proxy_command->GenerateHelpText(result);
363be691f3bSpatrick else
364be691f3bSpatrick CommandObject::GenerateHelpText(result);
365061da546Spatrick }
366061da546Spatrick
367061da546Spatrick lldb::CommandObjectSP
GetSubcommandSP(llvm::StringRef sub_cmd,StringList * matches)368061da546Spatrick CommandObjectProxy::GetSubcommandSP(llvm::StringRef sub_cmd,
369061da546Spatrick StringList *matches) {
370061da546Spatrick CommandObject *proxy_command = GetProxyCommandObject();
371061da546Spatrick if (proxy_command)
372061da546Spatrick return proxy_command->GetSubcommandSP(sub_cmd, matches);
373061da546Spatrick return lldb::CommandObjectSP();
374061da546Spatrick }
375061da546Spatrick
GetSubcommandObject(llvm::StringRef sub_cmd,StringList * matches)376061da546Spatrick CommandObject *CommandObjectProxy::GetSubcommandObject(llvm::StringRef sub_cmd,
377061da546Spatrick StringList *matches) {
378061da546Spatrick CommandObject *proxy_command = GetProxyCommandObject();
379061da546Spatrick if (proxy_command)
380061da546Spatrick return proxy_command->GetSubcommandObject(sub_cmd, matches);
381061da546Spatrick return nullptr;
382061da546Spatrick }
383061da546Spatrick
LoadSubCommand(llvm::StringRef cmd_name,const lldb::CommandObjectSP & command_sp)384061da546Spatrick bool CommandObjectProxy::LoadSubCommand(
385061da546Spatrick llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) {
386061da546Spatrick CommandObject *proxy_command = GetProxyCommandObject();
387061da546Spatrick if (proxy_command)
388061da546Spatrick return proxy_command->LoadSubCommand(cmd_name, command_sp);
389061da546Spatrick return false;
390061da546Spatrick }
391061da546Spatrick
WantsRawCommandString()392061da546Spatrick bool CommandObjectProxy::WantsRawCommandString() {
393061da546Spatrick CommandObject *proxy_command = GetProxyCommandObject();
394061da546Spatrick if (proxy_command)
395061da546Spatrick return proxy_command->WantsRawCommandString();
396061da546Spatrick return false;
397061da546Spatrick }
398061da546Spatrick
WantsCompletion()399061da546Spatrick bool CommandObjectProxy::WantsCompletion() {
400061da546Spatrick CommandObject *proxy_command = GetProxyCommandObject();
401061da546Spatrick if (proxy_command)
402061da546Spatrick return proxy_command->WantsCompletion();
403061da546Spatrick return false;
404061da546Spatrick }
405061da546Spatrick
HandleCompletion(CompletionRequest & request)406061da546Spatrick void CommandObjectProxy::HandleCompletion(CompletionRequest &request) {
407061da546Spatrick CommandObject *proxy_command = GetProxyCommandObject();
408061da546Spatrick if (proxy_command)
409061da546Spatrick proxy_command->HandleCompletion(request);
410061da546Spatrick }
411061da546Spatrick
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)412061da546Spatrick void CommandObjectProxy::HandleArgumentCompletion(
413061da546Spatrick CompletionRequest &request, OptionElementVector &opt_element_vector) {
414061da546Spatrick CommandObject *proxy_command = GetProxyCommandObject();
415061da546Spatrick if (proxy_command)
416061da546Spatrick proxy_command->HandleArgumentCompletion(request, opt_element_vector);
417061da546Spatrick }
418061da546Spatrick
419*f6aab3d8Srobert std::optional<std::string>
GetRepeatCommand(Args & current_command_args,uint32_t index)420*f6aab3d8Srobert CommandObjectProxy::GetRepeatCommand(Args ¤t_command_args,
421061da546Spatrick uint32_t index) {
422061da546Spatrick CommandObject *proxy_command = GetProxyCommandObject();
423061da546Spatrick if (proxy_command)
424061da546Spatrick return proxy_command->GetRepeatCommand(current_command_args, index);
425*f6aab3d8Srobert return std::nullopt;
426061da546Spatrick }
427061da546Spatrick
GetUnsupportedError()428be691f3bSpatrick llvm::StringRef CommandObjectProxy::GetUnsupportedError() {
429be691f3bSpatrick return "command is not implemented";
430be691f3bSpatrick }
431be691f3bSpatrick
Execute(const char * args_string,CommandReturnObject & result)432061da546Spatrick bool CommandObjectProxy::Execute(const char *args_string,
433061da546Spatrick CommandReturnObject &result) {
434061da546Spatrick CommandObject *proxy_command = GetProxyCommandObject();
435061da546Spatrick if (proxy_command)
436061da546Spatrick return proxy_command->Execute(args_string, result);
437be691f3bSpatrick result.AppendError(GetUnsupportedError());
438061da546Spatrick return false;
439061da546Spatrick }
440