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