brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.3 KiB · a369557 Raw
453 lines · cpp
1//===-- CommandObjectMultiword.cpp ----------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Interpreter/CommandObjectMultiword.h"10#include "lldb/Interpreter/CommandInterpreter.h"11#include "lldb/Interpreter/CommandReturnObject.h"12#include "lldb/Interpreter/Options.h"13#include <optional>14 15using namespace lldb;16using namespace lldb_private;17 18// CommandObjectMultiword19 20CommandObjectMultiword::CommandObjectMultiword(CommandInterpreter &interpreter,21                                               const char *name,22                                               const char *help,23                                               const char *syntax,24                                               uint32_t flags)25    : CommandObject(interpreter, name, help, syntax, flags),26      m_can_be_removed(false) {}27 28CommandObjectMultiword::~CommandObjectMultiword() = default;29 30CommandObjectSP31CommandObjectMultiword::GetSubcommandSPExact(llvm::StringRef sub_cmd) {32  if (m_subcommand_dict.empty())33    return {};34 35  auto pos = m_subcommand_dict.find(sub_cmd);36  if (pos == m_subcommand_dict.end())37    return {};38 39  return pos->second;40}41 42CommandObjectSP CommandObjectMultiword::GetSubcommandSP(llvm::StringRef sub_cmd,43                                                        StringList *matches) {44  if (m_subcommand_dict.empty())45    return {};46 47  CommandObjectSP return_cmd_sp = GetSubcommandSPExact(sub_cmd);48  if (return_cmd_sp) {49    if (matches)50      matches->AppendString(sub_cmd);51    return return_cmd_sp;52  }53 54  CommandObject::CommandMap::iterator pos;55 56  StringList local_matches;57  if (matches == nullptr)58    matches = &local_matches;59  int num_matches =60      AddNamesMatchingPartialString(m_subcommand_dict, sub_cmd, *matches);61 62  if (num_matches == 1) {63    // Cleaner, but slightly less efficient would be to call back into this64    // function, since I now know I have an exact match...65 66    sub_cmd = matches->GetStringAtIndex(0);67    pos = m_subcommand_dict.find(sub_cmd);68    if (pos != m_subcommand_dict.end())69      return_cmd_sp = pos->second;70  }71 72  return return_cmd_sp;73}74 75CommandObject *76CommandObjectMultiword::GetSubcommandObject(llvm::StringRef sub_cmd,77                                            StringList *matches) {78  return GetSubcommandSP(sub_cmd, matches).get();79}80 81bool CommandObjectMultiword::LoadSubCommand(llvm::StringRef name,82                                            const CommandObjectSP &cmd_obj_sp) {83  if (cmd_obj_sp)84    lldbassert((&GetCommandInterpreter() == &cmd_obj_sp->GetCommandInterpreter()) &&85           "tried to add a CommandObject from a different interpreter");86 87  return m_subcommand_dict.try_emplace(std::string(name), cmd_obj_sp).second;88}89 90llvm::Error CommandObjectMultiword::LoadUserSubcommand(91    llvm::StringRef name, const CommandObjectSP &cmd_obj_sp, bool can_replace) {92  Status result;93  if (cmd_obj_sp)94    lldbassert((&GetCommandInterpreter() == &cmd_obj_sp->GetCommandInterpreter()) &&95           "tried to add a CommandObject from a different interpreter");96  if (!IsUserCommand()) {97    return llvm::createStringError(llvm::inconvertibleErrorCode(),98                              "can't add a user subcommand to a builtin container command.");99  }100  // Make sure this a user command if it isn't already:101  cmd_obj_sp->SetIsUserCommand(true);102 103  std::string str_name(name);104 105  auto [pos, inserted] = m_subcommand_dict.try_emplace(str_name, cmd_obj_sp);106  if (inserted)107    return llvm::Error::success();108 109  const char *error_str = nullptr;110  if (!can_replace)111    error_str = "sub-command already exists";112  if (!(*pos).second->IsUserCommand())113    error_str = "can't replace a builtin subcommand";114 115  if (error_str) {116    return llvm::createStringError(llvm::inconvertibleErrorCode(), error_str);117  }118  pos->second = cmd_obj_sp;119  return llvm::Error::success();120}121 122llvm::Error CommandObjectMultiword::RemoveUserSubcommand(llvm::StringRef cmd_name,123                                                    bool must_be_multiword) {124  CommandMap::iterator pos;125  std::string str_name(cmd_name);126 127  pos = m_subcommand_dict.find(str_name);128  if (pos == m_subcommand_dict.end()) {129    return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' not found.",130                                   str_name.c_str());131  }132  if (!(*pos).second->IsUserCommand()) {133    return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' not a user command.",134                                   str_name.c_str());135  }136 137  if (must_be_multiword && !(*pos).second->IsMultiwordObject()) {138    return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' is not a container command",139                                   str_name.c_str());140  }141  if (!must_be_multiword && (*pos).second->IsMultiwordObject()) {142    return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' is not a user command",143                                   str_name.c_str());144  }145 146  m_subcommand_dict.erase(pos);147 148  return llvm::Error::success();149}150 151void CommandObjectMultiword::Execute(const char *args_string,152                                     CommandReturnObject &result) {153  Args args(args_string);154  const size_t argc = args.GetArgumentCount();155  if (argc == 0) {156    this->CommandObject::GenerateHelpText(result);157    return;158  }159 160  auto sub_command = args[0].ref();161  if (sub_command.empty()) {162    result.AppendError("need to specify a non-empty subcommand");163    return;164  }165 166  if (m_subcommand_dict.empty()) {167    result.AppendErrorWithFormat("'%s' does not have any subcommands.\n",168                                 GetCommandName().str().c_str());169    return;170  }171 172  StringList matches;173  CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches);174  if (sub_cmd_obj != nullptr) {175    // Now call CommandObject::Execute to process options in `rest_of_line`.176    // From there the command-specific version of Execute will be called, with177    // the processed arguments.178 179    args.Shift();180    sub_cmd_obj->Execute(args_string, result);181    return;182  }183 184  std::string error_msg;185  const size_t num_subcmd_matches = matches.GetSize();186  if (num_subcmd_matches > 0) {187    error_msg.assign("ambiguous command ");188    error_msg.append("'");189    error_msg.append(std::string(GetCommandName()));190    error_msg.append(" ");191    error_msg.append(std::string(sub_command));192    error_msg.append("'.");193 194    error_msg.append(" Possible completions:");195    for (const std::string &match : matches) {196      error_msg.append("\n\t");197      error_msg.append(match);198    }199  } else {200    // Try to offer some alternatives to help correct the command.201    error_msg.assign(202        llvm::Twine("\"" + sub_command + "\" is not a valid subcommand of \"" +203                    GetCommandName() + "\"." + GetSubcommandsHintText() +204                    " Use \"help " + GetCommandName() + "\" to find out more.")205            .str());206  }207  error_msg.append("\n");208  result.AppendRawError(error_msg.c_str());209}210 211std::string CommandObjectMultiword::GetSubcommandsHintText() {212  if (m_subcommand_dict.empty())213    return "";214  const size_t maxCount = 5;215  size_t i = 0;216  std::string buffer = " Valid subcommand";217  buffer.append(m_subcommand_dict.size() > 1 ? "s are:" : " is");218  CommandMap::iterator pos;219  for (pos = m_subcommand_dict.begin();220       pos != m_subcommand_dict.end() && i < maxCount; ++pos, ++i) {221    buffer.append(" ");222    buffer.append(pos->first);223    buffer.append(",");224  }225  if (i < m_subcommand_dict.size())226    buffer.append(" and others");227  else228    buffer.pop_back();229 230  buffer.append(".");231  return buffer;232}233 234void CommandObjectMultiword::GenerateHelpText(Stream &output_stream) {235  // First time through here, generate the help text for the object and push it236  // to the return result object as well237 238  CommandObject::GenerateHelpText(output_stream);239  output_stream.PutCString("\nThe following subcommands are supported:\n\n");240 241  CommandMap::iterator pos;242  uint32_t max_len = FindLongestCommandWord(m_subcommand_dict);243 244  if (max_len)245    max_len += 4; // Indent the output by 4 spaces.246 247  for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) {248    std::string indented_command("    ");249    indented_command.append(pos->first);250    if (pos->second->WantsRawCommandString()) {251      std::string help_text(std::string(pos->second->GetHelp()));252      help_text.append("  Expects 'raw' input (see 'help raw-input'.)");253      m_interpreter.OutputFormattedHelpText(output_stream, indented_command,254                                            "--", help_text, max_len);255    } else256      m_interpreter.OutputFormattedHelpText(output_stream, indented_command,257                                            "--", pos->second->GetHelp(),258                                            max_len);259  }260 261  output_stream.PutCString("\nFor more help on any particular subcommand, type "262                           "'help <command> <subcommand>'.\n");263}264 265void CommandObjectMultiword::HandleCompletion(CompletionRequest &request) {266  auto arg0 = request.GetParsedLine()[0].ref();267  if (request.GetCursorIndex() == 0) {268    StringList new_matches, descriptions;269    AddNamesMatchingPartialString(m_subcommand_dict, arg0, new_matches,270                                  &descriptions);271    request.AddCompletions(new_matches, descriptions);272 273    if (new_matches.GetSize() == 1 &&274        new_matches.GetStringAtIndex(0) != nullptr &&275        (arg0 == new_matches.GetStringAtIndex(0))) {276      StringList temp_matches;277      CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches);278      if (cmd_obj != nullptr) {279        if (request.GetParsedLine().GetArgumentCount() != 1) {280          request.GetParsedLine().Shift();281          request.AppendEmptyArgument();282          cmd_obj->HandleCompletion(request);283        }284      }285    }286    return;287  }288 289  StringList new_matches;290  CommandObject *sub_command_object = GetSubcommandObject(arg0, &new_matches);291 292  // The subcommand is ambiguous. The completion isn't meaningful.293  if (!sub_command_object)294    return;295 296  // Remove the one match that we got from calling GetSubcommandObject.297  new_matches.DeleteStringAtIndex(0);298  request.AddCompletions(new_matches);299  request.ShiftArguments();300  sub_command_object->HandleCompletion(request);301}302 303std::optional<std::string>304CommandObjectMultiword::GetRepeatCommand(Args &current_command_args,305                                         uint32_t index) {306  index++;307  if (current_command_args.GetArgumentCount() <= index)308    return std::nullopt;309  CommandObject *sub_command_object =310      GetSubcommandObject(current_command_args[index].ref());311  if (sub_command_object == nullptr)312    return std::nullopt;313  return sub_command_object->GetRepeatCommand(current_command_args, index);314}315 316CommandObjectProxy::CommandObjectProxy(CommandInterpreter &interpreter,317                                       const char *name, const char *help,318                                       const char *syntax, uint32_t flags)319    : CommandObject(interpreter, name, help, syntax, flags) {}320 321CommandObjectProxy::~CommandObjectProxy() = default;322 323Options *CommandObjectProxy::GetOptions() {324  CommandObject *proxy_command = GetProxyCommandObject();325  if (proxy_command)326    return proxy_command->GetOptions();327  return CommandObject::GetOptions();328}329 330llvm::StringRef CommandObjectProxy::GetHelp() {331  CommandObject *proxy_command = GetProxyCommandObject();332  if (proxy_command)333    return proxy_command->GetHelp();334  return CommandObject::GetHelp();335}336 337llvm::StringRef CommandObjectProxy::GetSyntax() {338  CommandObject *proxy_command = GetProxyCommandObject();339  if (proxy_command)340    return proxy_command->GetSyntax();341  return CommandObject::GetSyntax();342}343 344llvm::StringRef CommandObjectProxy::GetHelpLong() {345  CommandObject *proxy_command = GetProxyCommandObject();346  if (proxy_command)347    return proxy_command->GetHelpLong();348  return CommandObject::GetHelpLong();349}350 351bool CommandObjectProxy::IsRemovable() const {352  const CommandObject *proxy_command =353      const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();354  if (proxy_command)355    return proxy_command->IsRemovable();356  return false;357}358 359bool CommandObjectProxy::IsMultiwordObject() {360  CommandObject *proxy_command = GetProxyCommandObject();361  if (proxy_command)362    return proxy_command->IsMultiwordObject();363  return false;364}365 366CommandObjectMultiword *CommandObjectProxy::GetAsMultiwordCommand() {367  CommandObject *proxy_command = GetProxyCommandObject();368  if (proxy_command)369    return proxy_command->GetAsMultiwordCommand();370  return nullptr;371}372 373void CommandObjectProxy::GenerateHelpText(Stream &result) {374  CommandObject *proxy_command = GetProxyCommandObject();375  if (proxy_command)376    proxy_command->GenerateHelpText(result);377  else378    CommandObject::GenerateHelpText(result);379}380 381lldb::CommandObjectSP382CommandObjectProxy::GetSubcommandSP(llvm::StringRef sub_cmd,383                                    StringList *matches) {384  CommandObject *proxy_command = GetProxyCommandObject();385  if (proxy_command)386    return proxy_command->GetSubcommandSP(sub_cmd, matches);387  return lldb::CommandObjectSP();388}389 390CommandObject *CommandObjectProxy::GetSubcommandObject(llvm::StringRef sub_cmd,391                                                       StringList *matches) {392  CommandObject *proxy_command = GetProxyCommandObject();393  if (proxy_command)394    return proxy_command->GetSubcommandObject(sub_cmd, matches);395  return nullptr;396}397 398bool CommandObjectProxy::LoadSubCommand(399    llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) {400  CommandObject *proxy_command = GetProxyCommandObject();401  if (proxy_command)402    return proxy_command->LoadSubCommand(cmd_name, command_sp);403  return false;404}405 406bool CommandObjectProxy::WantsRawCommandString() {407  CommandObject *proxy_command = GetProxyCommandObject();408  if (proxy_command)409    return proxy_command->WantsRawCommandString();410  return false;411}412 413bool CommandObjectProxy::WantsCompletion() {414  CommandObject *proxy_command = GetProxyCommandObject();415  if (proxy_command)416    return proxy_command->WantsCompletion();417  return false;418}419 420void CommandObjectProxy::HandleCompletion(CompletionRequest &request) {421  CommandObject *proxy_command = GetProxyCommandObject();422  if (proxy_command)423    proxy_command->HandleCompletion(request);424}425 426void CommandObjectProxy::HandleArgumentCompletion(427    CompletionRequest &request, OptionElementVector &opt_element_vector) {428  CommandObject *proxy_command = GetProxyCommandObject();429  if (proxy_command)430    proxy_command->HandleArgumentCompletion(request, opt_element_vector);431}432 433std::optional<std::string>434CommandObjectProxy::GetRepeatCommand(Args &current_command_args,435                                     uint32_t index) {436  CommandObject *proxy_command = GetProxyCommandObject();437  if (proxy_command)438    return proxy_command->GetRepeatCommand(current_command_args, index);439  return std::nullopt;440}441 442llvm::StringRef CommandObjectProxy::GetUnsupportedError() {443  return "command is not implemented";444}445 446void CommandObjectProxy::Execute(const char *args_string,447                                 CommandReturnObject &result) {448  if (CommandObject *proxy_command = GetProxyCommandObject())449    proxy_command->Execute(args_string, result);450  else451    result.AppendError(GetUnsupportedError());452}453