1 //===-- CommandObjectMultiword.cpp ------------------------------*- C++ -*-===// 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-exception 6 // 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 14 using namespace lldb; 15 using namespace lldb_private; 16 17 // CommandObjectMultiword 18 19 CommandObjectMultiword::CommandObjectMultiword(CommandInterpreter &interpreter, 20 const char *name, 21 const char *help, 22 const char *syntax, 23 uint32_t flags) 24 : CommandObject(interpreter, name, help, syntax, flags), 25 m_can_be_removed(false) {} 26 27 CommandObjectMultiword::~CommandObjectMultiword() = default; 28 29 CommandObjectSP CommandObjectMultiword::GetSubcommandSP(llvm::StringRef sub_cmd, 30 StringList *matches) { 31 CommandObjectSP return_cmd_sp; 32 CommandObject::CommandMap::iterator pos; 33 34 if (!m_subcommand_dict.empty()) { 35 pos = m_subcommand_dict.find(sub_cmd); 36 if (pos != m_subcommand_dict.end()) { 37 // An exact match; append the sub_cmd to the 'matches' string list. 38 if (matches) 39 matches->AppendString(sub_cmd); 40 return_cmd_sp = pos->second; 41 } else { 42 StringList local_matches; 43 if (matches == nullptr) 44 matches = &local_matches; 45 int num_matches = 46 AddNamesMatchingPartialString(m_subcommand_dict, sub_cmd, *matches); 47 48 if (num_matches == 1) { 49 // Cleaner, but slightly less efficient would be to call back into this 50 // function, since I now know I have an exact match... 51 52 sub_cmd = matches->GetStringAtIndex(0); 53 pos = m_subcommand_dict.find(sub_cmd); 54 if (pos != m_subcommand_dict.end()) 55 return_cmd_sp = pos->second; 56 } 57 } 58 } 59 return return_cmd_sp; 60 } 61 62 CommandObject * 63 CommandObjectMultiword::GetSubcommandObject(llvm::StringRef sub_cmd, 64 StringList *matches) { 65 return GetSubcommandSP(sub_cmd, matches).get(); 66 } 67 68 bool CommandObjectMultiword::LoadSubCommand(llvm::StringRef name, 69 const CommandObjectSP &cmd_obj) { 70 if (cmd_obj) 71 assert((&GetCommandInterpreter() == &cmd_obj->GetCommandInterpreter()) && 72 "tried to add a CommandObject from a different interpreter"); 73 74 CommandMap::iterator pos; 75 bool success = true; 76 77 pos = m_subcommand_dict.find(name); 78 if (pos == m_subcommand_dict.end()) { 79 m_subcommand_dict[name] = cmd_obj; 80 } else 81 success = false; 82 83 return success; 84 } 85 86 bool CommandObjectMultiword::Execute(const char *args_string, 87 CommandReturnObject &result) { 88 Args args(args_string); 89 const size_t argc = args.GetArgumentCount(); 90 if (argc == 0) { 91 this->CommandObject::GenerateHelpText(result); 92 return result.Succeeded(); 93 } 94 95 auto sub_command = args[0].ref(); 96 if (sub_command.empty()) { 97 result.AppendError("Need to specify a non-empty subcommand."); 98 return result.Succeeded(); 99 } 100 101 if (sub_command.equals_lower("help")) { 102 this->CommandObject::GenerateHelpText(result); 103 return result.Succeeded(); 104 } 105 106 if (m_subcommand_dict.empty()) { 107 result.AppendErrorWithFormat("'%s' does not have any subcommands.\n", 108 GetCommandName().str().c_str()); 109 result.SetStatus(eReturnStatusFailed); 110 return false; 111 } 112 113 StringList matches; 114 CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches); 115 if (sub_cmd_obj != nullptr) { 116 // Now call CommandObject::Execute to process options in `rest_of_line`. 117 // From there the command-specific version of Execute will be called, with 118 // the processed arguments. 119 120 args.Shift(); 121 sub_cmd_obj->Execute(args_string, result); 122 return result.Succeeded(); 123 } 124 125 std::string error_msg; 126 const size_t num_subcmd_matches = matches.GetSize(); 127 if (num_subcmd_matches > 0) 128 error_msg.assign("ambiguous command "); 129 else 130 error_msg.assign("invalid command "); 131 132 error_msg.append("'"); 133 error_msg.append(GetCommandName()); 134 error_msg.append(" "); 135 error_msg.append(sub_command); 136 error_msg.append("'."); 137 138 if (num_subcmd_matches > 0) { 139 error_msg.append(" Possible completions:"); 140 for (const std::string &match : matches) { 141 error_msg.append("\n\t"); 142 error_msg.append(match); 143 } 144 } 145 error_msg.append("\n"); 146 result.AppendRawError(error_msg.c_str()); 147 result.SetStatus(eReturnStatusFailed); 148 return false; 149 } 150 151 void CommandObjectMultiword::GenerateHelpText(Stream &output_stream) { 152 // First time through here, generate the help text for the object and push it 153 // to the return result object as well 154 155 CommandObject::GenerateHelpText(output_stream); 156 output_stream.PutCString("\nThe following subcommands are supported:\n\n"); 157 158 CommandMap::iterator pos; 159 uint32_t max_len = FindLongestCommandWord(m_subcommand_dict); 160 161 if (max_len) 162 max_len += 4; // Indent the output by 4 spaces. 163 164 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) { 165 std::string indented_command(" "); 166 indented_command.append(pos->first); 167 if (pos->second->WantsRawCommandString()) { 168 std::string help_text(pos->second->GetHelp()); 169 help_text.append(" Expects 'raw' input (see 'help raw-input'.)"); 170 m_interpreter.OutputFormattedHelpText(output_stream, 171 indented_command.c_str(), "--", 172 help_text.c_str(), max_len); 173 } else 174 m_interpreter.OutputFormattedHelpText(output_stream, 175 indented_command.c_str(), "--", 176 pos->second->GetHelp(), max_len); 177 } 178 179 output_stream.PutCString("\nFor more help on any particular subcommand, type " 180 "'help <command> <subcommand>'.\n"); 181 } 182 183 void CommandObjectMultiword::HandleCompletion(CompletionRequest &request) { 184 auto arg0 = request.GetParsedLine()[0].ref(); 185 if (request.GetCursorIndex() == 0) { 186 StringList new_matches, descriptions; 187 AddNamesMatchingPartialString(m_subcommand_dict, arg0, new_matches, 188 &descriptions); 189 request.AddCompletions(new_matches, descriptions); 190 191 if (new_matches.GetSize() == 1 && 192 new_matches.GetStringAtIndex(0) != nullptr && 193 (arg0 == new_matches.GetStringAtIndex(0))) { 194 StringList temp_matches; 195 CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches); 196 if (cmd_obj != nullptr) { 197 if (request.GetParsedLine().GetArgumentCount() != 1) { 198 request.GetParsedLine().Shift(); 199 request.AppendEmptyArgument(); 200 cmd_obj->HandleCompletion(request); 201 } 202 } 203 } 204 return; 205 } 206 207 StringList new_matches; 208 CommandObject *sub_command_object = GetSubcommandObject(arg0, &new_matches); 209 if (sub_command_object == nullptr) { 210 request.AddCompletions(new_matches); 211 return; 212 } 213 214 // Remove the one match that we got from calling GetSubcommandObject. 215 new_matches.DeleteStringAtIndex(0); 216 request.AddCompletions(new_matches); 217 request.ShiftArguments(); 218 sub_command_object->HandleCompletion(request); 219 } 220 221 const char *CommandObjectMultiword::GetRepeatCommand(Args ¤t_command_args, 222 uint32_t index) { 223 index++; 224 if (current_command_args.GetArgumentCount() <= index) 225 return nullptr; 226 CommandObject *sub_command_object = 227 GetSubcommandObject(current_command_args[index].ref()); 228 if (sub_command_object == nullptr) 229 return nullptr; 230 return sub_command_object->GetRepeatCommand(current_command_args, index); 231 } 232 233 void CommandObjectMultiword::AproposAllSubCommands(llvm::StringRef prefix, 234 llvm::StringRef search_word, 235 StringList &commands_found, 236 StringList &commands_help) { 237 CommandObject::CommandMap::const_iterator pos; 238 239 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) { 240 const char *command_name = pos->first.c_str(); 241 CommandObject *sub_cmd_obj = pos->second.get(); 242 StreamString complete_command_name; 243 244 complete_command_name << prefix << " " << command_name; 245 246 if (sub_cmd_obj->HelpTextContainsWord(search_word)) { 247 commands_found.AppendString(complete_command_name.GetString()); 248 commands_help.AppendString(sub_cmd_obj->GetHelp()); 249 } 250 251 if (sub_cmd_obj->IsMultiwordObject()) 252 sub_cmd_obj->AproposAllSubCommands(complete_command_name.GetString(), 253 search_word, commands_found, 254 commands_help); 255 } 256 } 257 258 CommandObjectProxy::CommandObjectProxy(CommandInterpreter &interpreter, 259 const char *name, const char *help, 260 const char *syntax, uint32_t flags) 261 : CommandObject(interpreter, name, help, syntax, flags) {} 262 263 CommandObjectProxy::~CommandObjectProxy() = default; 264 265 llvm::StringRef CommandObjectProxy::GetHelpLong() { 266 CommandObject *proxy_command = GetProxyCommandObject(); 267 if (proxy_command) 268 return proxy_command->GetHelpLong(); 269 return llvm::StringRef(); 270 } 271 272 bool CommandObjectProxy::IsRemovable() const { 273 const CommandObject *proxy_command = 274 const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject(); 275 if (proxy_command) 276 return proxy_command->IsRemovable(); 277 return false; 278 } 279 280 bool CommandObjectProxy::IsMultiwordObject() { 281 CommandObject *proxy_command = GetProxyCommandObject(); 282 if (proxy_command) 283 return proxy_command->IsMultiwordObject(); 284 return false; 285 } 286 287 CommandObjectMultiword *CommandObjectProxy::GetAsMultiwordCommand() { 288 CommandObject *proxy_command = GetProxyCommandObject(); 289 if (proxy_command) 290 return proxy_command->GetAsMultiwordCommand(); 291 return nullptr; 292 } 293 294 void CommandObjectProxy::GenerateHelpText(Stream &result) { 295 CommandObject *proxy_command = GetProxyCommandObject(); 296 if (proxy_command) 297 return proxy_command->GenerateHelpText(result); 298 } 299 300 lldb::CommandObjectSP 301 CommandObjectProxy::GetSubcommandSP(llvm::StringRef sub_cmd, 302 StringList *matches) { 303 CommandObject *proxy_command = GetProxyCommandObject(); 304 if (proxy_command) 305 return proxy_command->GetSubcommandSP(sub_cmd, matches); 306 return lldb::CommandObjectSP(); 307 } 308 309 CommandObject *CommandObjectProxy::GetSubcommandObject(llvm::StringRef sub_cmd, 310 StringList *matches) { 311 CommandObject *proxy_command = GetProxyCommandObject(); 312 if (proxy_command) 313 return proxy_command->GetSubcommandObject(sub_cmd, matches); 314 return nullptr; 315 } 316 317 void CommandObjectProxy::AproposAllSubCommands(llvm::StringRef prefix, 318 llvm::StringRef search_word, 319 StringList &commands_found, 320 StringList &commands_help) { 321 CommandObject *proxy_command = GetProxyCommandObject(); 322 if (proxy_command) 323 return proxy_command->AproposAllSubCommands(prefix, search_word, 324 commands_found, commands_help); 325 } 326 327 bool CommandObjectProxy::LoadSubCommand( 328 llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) { 329 CommandObject *proxy_command = GetProxyCommandObject(); 330 if (proxy_command) 331 return proxy_command->LoadSubCommand(cmd_name, command_sp); 332 return false; 333 } 334 335 bool CommandObjectProxy::WantsRawCommandString() { 336 CommandObject *proxy_command = GetProxyCommandObject(); 337 if (proxy_command) 338 return proxy_command->WantsRawCommandString(); 339 return false; 340 } 341 342 bool CommandObjectProxy::WantsCompletion() { 343 CommandObject *proxy_command = GetProxyCommandObject(); 344 if (proxy_command) 345 return proxy_command->WantsCompletion(); 346 return false; 347 } 348 349 Options *CommandObjectProxy::GetOptions() { 350 CommandObject *proxy_command = GetProxyCommandObject(); 351 if (proxy_command) 352 return proxy_command->GetOptions(); 353 return nullptr; 354 } 355 356 void CommandObjectProxy::HandleCompletion(CompletionRequest &request) { 357 CommandObject *proxy_command = GetProxyCommandObject(); 358 if (proxy_command) 359 proxy_command->HandleCompletion(request); 360 } 361 362 void CommandObjectProxy::HandleArgumentCompletion( 363 CompletionRequest &request, OptionElementVector &opt_element_vector) { 364 CommandObject *proxy_command = GetProxyCommandObject(); 365 if (proxy_command) 366 proxy_command->HandleArgumentCompletion(request, opt_element_vector); 367 } 368 369 const char *CommandObjectProxy::GetRepeatCommand(Args ¤t_command_args, 370 uint32_t index) { 371 CommandObject *proxy_command = GetProxyCommandObject(); 372 if (proxy_command) 373 return proxy_command->GetRepeatCommand(current_command_args, index); 374 return nullptr; 375 } 376 377 bool CommandObjectProxy::Execute(const char *args_string, 378 CommandReturnObject &result) { 379 CommandObject *proxy_command = GetProxyCommandObject(); 380 if (proxy_command) 381 return proxy_command->Execute(args_string, result); 382 result.AppendError("command is not implemented"); 383 result.SetStatus(eReturnStatusFailed); 384 return false; 385 } 386