xref: /openbsd-src/gnu/llvm/lldb/source/Commands/CommandObjectMultiword.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
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 &current_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 &current_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