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; 197 AddNamesMatchingPartialString(m_subcommand_dict, arg0, new_matches); 198 request.AddCompletions(new_matches); 199 200 if (new_matches.GetSize() == 1 && 201 new_matches.GetStringAtIndex(0) != nullptr && 202 (arg0 == new_matches.GetStringAtIndex(0))) { 203 StringList temp_matches; 204 CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches); 205 if (cmd_obj != nullptr) { 206 if (request.GetParsedLine().GetArgumentCount() == 1) { 207 request.SetWordComplete(true); 208 } else { 209 request.GetParsedLine().Shift(); 210 request.SetCursorCharPosition(0); 211 request.GetParsedLine().AppendArgument(llvm::StringRef()); 212 return cmd_obj->HandleCompletion(request); 213 } 214 } 215 } 216 return new_matches.GetSize(); 217 } else { 218 StringList new_matches; 219 CommandObject *sub_command_object = GetSubcommandObject(arg0, &new_matches); 220 if (sub_command_object == nullptr) { 221 request.AddCompletions(new_matches); 222 return request.GetNumberOfMatches(); 223 } else { 224 // Remove the one match that we got from calling GetSubcommandObject. 225 new_matches.DeleteStringAtIndex(0); 226 request.AddCompletions(new_matches); 227 request.GetParsedLine().Shift(); 228 request.SetCursorIndex(request.GetCursorIndex() - 1); 229 return sub_command_object->HandleCompletion(request); 230 } 231 } 232 } 233 234 const char *CommandObjectMultiword::GetRepeatCommand(Args ¤t_command_args, 235 uint32_t index) { 236 index++; 237 if (current_command_args.GetArgumentCount() <= index) 238 return nullptr; 239 CommandObject *sub_command_object = 240 GetSubcommandObject(current_command_args[index].ref); 241 if (sub_command_object == nullptr) 242 return nullptr; 243 return sub_command_object->GetRepeatCommand(current_command_args, index); 244 } 245 246 void CommandObjectMultiword::AproposAllSubCommands(llvm::StringRef prefix, 247 llvm::StringRef search_word, 248 StringList &commands_found, 249 StringList &commands_help) { 250 CommandObject::CommandMap::const_iterator pos; 251 252 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) { 253 const char *command_name = pos->first.c_str(); 254 CommandObject *sub_cmd_obj = pos->second.get(); 255 StreamString complete_command_name; 256 257 complete_command_name << prefix << " " << command_name; 258 259 if (sub_cmd_obj->HelpTextContainsWord(search_word)) { 260 commands_found.AppendString(complete_command_name.GetString()); 261 commands_help.AppendString(sub_cmd_obj->GetHelp()); 262 } 263 264 if (sub_cmd_obj->IsMultiwordObject()) 265 sub_cmd_obj->AproposAllSubCommands(complete_command_name.GetString(), 266 search_word, commands_found, 267 commands_help); 268 } 269 } 270 271 CommandObjectProxy::CommandObjectProxy(CommandInterpreter &interpreter, 272 const char *name, const char *help, 273 const char *syntax, uint32_t flags) 274 : CommandObject(interpreter, name, help, syntax, flags) {} 275 276 CommandObjectProxy::~CommandObjectProxy() = default; 277 278 llvm::StringRef CommandObjectProxy::GetHelpLong() { 279 CommandObject *proxy_command = GetProxyCommandObject(); 280 if (proxy_command) 281 return proxy_command->GetHelpLong(); 282 return llvm::StringRef(); 283 } 284 285 bool CommandObjectProxy::IsRemovable() const { 286 const CommandObject *proxy_command = 287 const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject(); 288 if (proxy_command) 289 return proxy_command->IsRemovable(); 290 return false; 291 } 292 293 bool CommandObjectProxy::IsMultiwordObject() { 294 CommandObject *proxy_command = GetProxyCommandObject(); 295 if (proxy_command) 296 return proxy_command->IsMultiwordObject(); 297 return false; 298 } 299 300 CommandObjectMultiword *CommandObjectProxy::GetAsMultiwordCommand() { 301 CommandObject *proxy_command = GetProxyCommandObject(); 302 if (proxy_command) 303 return proxy_command->GetAsMultiwordCommand(); 304 return nullptr; 305 } 306 307 void CommandObjectProxy::GenerateHelpText(Stream &result) { 308 CommandObject *proxy_command = GetProxyCommandObject(); 309 if (proxy_command) 310 return proxy_command->GenerateHelpText(result); 311 } 312 313 lldb::CommandObjectSP 314 CommandObjectProxy::GetSubcommandSP(llvm::StringRef sub_cmd, 315 StringList *matches) { 316 CommandObject *proxy_command = GetProxyCommandObject(); 317 if (proxy_command) 318 return proxy_command->GetSubcommandSP(sub_cmd, matches); 319 return lldb::CommandObjectSP(); 320 } 321 322 CommandObject *CommandObjectProxy::GetSubcommandObject(llvm::StringRef sub_cmd, 323 StringList *matches) { 324 CommandObject *proxy_command = GetProxyCommandObject(); 325 if (proxy_command) 326 return proxy_command->GetSubcommandObject(sub_cmd, matches); 327 return nullptr; 328 } 329 330 void CommandObjectProxy::AproposAllSubCommands(llvm::StringRef prefix, 331 llvm::StringRef search_word, 332 StringList &commands_found, 333 StringList &commands_help) { 334 CommandObject *proxy_command = GetProxyCommandObject(); 335 if (proxy_command) 336 return proxy_command->AproposAllSubCommands(prefix, search_word, 337 commands_found, commands_help); 338 } 339 340 bool CommandObjectProxy::LoadSubCommand( 341 llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) { 342 CommandObject *proxy_command = GetProxyCommandObject(); 343 if (proxy_command) 344 return proxy_command->LoadSubCommand(cmd_name, command_sp); 345 return false; 346 } 347 348 bool CommandObjectProxy::WantsRawCommandString() { 349 CommandObject *proxy_command = GetProxyCommandObject(); 350 if (proxy_command) 351 return proxy_command->WantsRawCommandString(); 352 return false; 353 } 354 355 bool CommandObjectProxy::WantsCompletion() { 356 CommandObject *proxy_command = GetProxyCommandObject(); 357 if (proxy_command) 358 return proxy_command->WantsCompletion(); 359 return false; 360 } 361 362 Options *CommandObjectProxy::GetOptions() { 363 CommandObject *proxy_command = GetProxyCommandObject(); 364 if (proxy_command) 365 return proxy_command->GetOptions(); 366 return nullptr; 367 } 368 369 int CommandObjectProxy::HandleCompletion(CompletionRequest &request) { 370 CommandObject *proxy_command = GetProxyCommandObject(); 371 if (proxy_command) 372 return proxy_command->HandleCompletion(request); 373 return 0; 374 } 375 376 int CommandObjectProxy::HandleArgumentCompletion( 377 CompletionRequest &request, OptionElementVector &opt_element_vector) { 378 CommandObject *proxy_command = GetProxyCommandObject(); 379 if (proxy_command) 380 return proxy_command->HandleArgumentCompletion(request, opt_element_vector); 381 return 0; 382 } 383 384 const char *CommandObjectProxy::GetRepeatCommand(Args ¤t_command_args, 385 uint32_t index) { 386 CommandObject *proxy_command = GetProxyCommandObject(); 387 if (proxy_command) 388 return proxy_command->GetRepeatCommand(current_command_args, index); 389 return nullptr; 390 } 391 392 bool CommandObjectProxy::Execute(const char *args_string, 393 CommandReturnObject &result) { 394 CommandObject *proxy_command = GetProxyCommandObject(); 395 if (proxy_command) 396 return proxy_command->Execute(args_string, result); 397 result.AppendError("command is not implemented"); 398 result.SetStatus(eReturnStatusFailed); 399 return false; 400 } 401