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