int CommandObjectMultiword::HandleCompletion(Args &input, int &cursor_index, int &cursor_char_position, int match_start_point, int max_return_elements, bool &word_complete, StringList &matches) { // Any of the command matches will provide a complete word, otherwise the // individual // completers will override this. word_complete = true; const char *arg0 = input.GetArgumentAtIndex(0); if (cursor_index == 0) { AddNamesMatchingPartialString(m_subcommand_dict, arg0, matches); if (matches.GetSize() == 1 && matches.GetStringAtIndex(0) != nullptr && strcmp(arg0, matches.GetStringAtIndex(0)) == 0) { StringList temp_matches; CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches); if (cmd_obj != nullptr) { if (input.GetArgumentCount() == 1) { word_complete = true; } else { matches.DeleteStringAtIndex(0); input.Shift(); cursor_char_position = 0; input.AppendArgument(""); return cmd_obj->HandleCompletion( input, cursor_index, cursor_char_position, match_start_point, max_return_elements, word_complete, matches); } } } return matches.GetSize(); } else { CommandObject *sub_command_object = GetSubcommandObject(arg0, &matches); if (sub_command_object == nullptr) { return matches.GetSize(); } else { // Remove the one match that we got from calling GetSubcommandObject. matches.DeleteStringAtIndex(0); input.Shift(); cursor_index--; return sub_command_object->HandleCompletion( input, cursor_index, cursor_char_position, match_start_point, max_return_elements, word_complete, matches); } } }
bool CommandObjectMultiword::Execute(const char *args_string, CommandReturnObject &result) { Args args(args_string); const size_t argc = args.GetArgumentCount(); if (argc == 0) { this->CommandObject::GenerateHelpText(result); } else { const char *sub_command = args.GetArgumentAtIndex(0); if (sub_command) { if (::strcasecmp(sub_command, "help") == 0) { this->CommandObject::GenerateHelpText(result); } else if (!m_subcommand_dict.empty()) { StringList matches; CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches); if (sub_cmd_obj != nullptr) { // Now call CommandObject::Execute to process and options in // 'rest_of_line'. From there // the command-specific version of Execute will be called, with the // processed arguments. args.Shift(); sub_cmd_obj->Execute(args_string, result); } else { std::string error_msg; const size_t num_subcmd_matches = matches.GetSize(); if (num_subcmd_matches > 0) error_msg.assign("ambiguous command "); else error_msg.assign("invalid command "); error_msg.append("'"); error_msg.append(GetCommandName()); error_msg.append(" "); error_msg.append(sub_command); error_msg.append("'."); if (num_subcmd_matches > 0) { error_msg.append(" Possible completions:"); for (size_t i = 0; i < num_subcmd_matches; i++) { error_msg.append("\n\t"); error_msg.append(matches.GetStringAtIndex(i)); } } error_msg.append("\n"); result.AppendRawError(error_msg.c_str()); result.SetStatus(eReturnStatusFailed); } } else { result.AppendErrorWithFormat("'%s' does not have any subcommands.\n", GetCommandName()); result.SetStatus(eReturnStatusFailed); } } } return result.Succeeded(); }
void StringList::AppendList (StringList strings) { size_t len = strings.GetSize(); for (size_t i = 0; i < len; ++i) m_strings.push_back (strings.GetStringAtIndex(i)); }
bool REPL::IOHandlerIsInputComplete(IOHandler &io_handler, StringList &lines) { // Check for meta command const size_t num_lines = lines.GetSize(); if (num_lines == 1) { const char *first_line = lines.GetStringAtIndex(0); if (first_line[0] == ':') return true; // Meta command is a single line where that starts with ':' } // Check if REPL input is done std::string source_string(lines.CopyList()); return SourceIsComplete(source_string); }
TEST(CompletionRequest, TestCompletionOwnership) { std::string command = "a bad c"; const unsigned cursor_pos = 3; StringList matches; CompletionResult result; CompletionRequest request(command, cursor_pos, 0, 0, result); std::string Temporary = "bar"; request.AddCompletion(Temporary); // Manipulate our completion. The request should have taken a copy, so that // shouldn't influence anything. Temporary[0] = 'f'; result.GetMatches(matches); EXPECT_EQ(1U, request.GetNumberOfMatches()); EXPECT_STREQ("bar", matches.GetStringAtIndex(0)); }
SBStringList SBDebugger::GetInternalVariableValue (const char *var_name, const char *debugger_instance_name) { SBStringList ret_value; SettableVariableType var_type; Error err; UserSettingsControllerSP root_settings_controller = Debugger::GetSettingsController(); StringList value = root_settings_controller->GetVariable (var_name, var_type, debugger_instance_name, err); if (err.Success()) { for (unsigned i = 0; i != value.GetSize(); ++i) ret_value.AppendString (value.GetStringAtIndex(i)); } else { ret_value.AppendString (err.AsCString()); } return ret_value; }
bool CommandObjectHelp::DoExecute (Args& command, CommandReturnObject &result) { CommandObject::CommandMap::iterator pos; CommandObject *cmd_obj; const size_t argc = command.GetArgumentCount (); // 'help' doesn't take any arguments, other than command names. If argc is 0, we show the user // all commands (aliases and user commands if asked for). Otherwise every argument must be the name of a command or a sub-command. if (argc == 0) { uint32_t cmd_types = CommandInterpreter::eCommandTypesBuiltin; if (m_options.m_show_aliases) cmd_types |= CommandInterpreter::eCommandTypesAliases; if (m_options.m_show_user_defined) cmd_types |= CommandInterpreter::eCommandTypesUserDef; if (m_options.m_show_hidden) cmd_types |= CommandInterpreter::eCommandTypesHidden; result.SetStatus (eReturnStatusSuccessFinishNoResult); m_interpreter.GetHelp (result, cmd_types); // General help } else { // Get command object for the first command argument. Only search built-in command dictionary. StringList matches; cmd_obj = m_interpreter.GetCommandObject (command.GetArgumentAtIndex (0), &matches); bool is_alias_command = m_interpreter.AliasExists (command.GetArgumentAtIndex (0)); std::string alias_name = command.GetArgumentAtIndex(0); if (cmd_obj != nullptr) { StringList matches; bool all_okay = true; CommandObject *sub_cmd_obj = cmd_obj; // Loop down through sub_command dictionaries until we find the command object that corresponds // to the help command entered. std::string sub_command; for (size_t i = 1; i < argc && all_okay; ++i) { sub_command = command.GetArgumentAtIndex(i); matches.Clear(); if (sub_cmd_obj->IsAlias()) sub_cmd_obj = ((CommandAlias*)sub_cmd_obj)->GetUnderlyingCommand().get(); if (! sub_cmd_obj->IsMultiwordObject ()) { all_okay = false; } else { CommandObject *found_cmd; found_cmd = sub_cmd_obj->GetSubcommandObject(sub_command.c_str(), &matches); if (found_cmd == nullptr) all_okay = false; else if (matches.GetSize() > 1) all_okay = false; else sub_cmd_obj = found_cmd; } } if (!all_okay || (sub_cmd_obj == nullptr)) { std::string cmd_string; command.GetCommandString (cmd_string); if (matches.GetSize() >= 2) { StreamString s; s.Printf ("ambiguous command %s", cmd_string.c_str()); size_t num_matches = matches.GetSize(); for (size_t match_idx = 0; match_idx < num_matches; match_idx++) { s.Printf ("\n\t%s", matches.GetStringAtIndex(match_idx)); } s.Printf ("\n"); result.AppendError(s.GetData()); result.SetStatus (eReturnStatusFailed); return false; } else if (!sub_cmd_obj) { StreamString error_msg_stream; GenerateAdditionalHelpAvenuesMessage(&error_msg_stream, cmd_string.c_str(), m_interpreter.GetCommandPrefix(), sub_command.c_str()); result.AppendErrorWithFormat("%s",error_msg_stream.GetData()); result.SetStatus (eReturnStatusFailed); return false; } else { GenerateAdditionalHelpAvenuesMessage(&result.GetOutputStream(), cmd_string.c_str(), m_interpreter.GetCommandPrefix(), sub_command.c_str()); result.GetOutputStream().Printf("\nThe closest match is '%s'. Help on it follows.\n\n", sub_cmd_obj->GetCommandName()); } } sub_cmd_obj->GenerateHelpText(result); if (is_alias_command) { StreamString sstr; m_interpreter.GetAlias(alias_name.c_str())->GetAliasExpansion(sstr); result.GetOutputStream().Printf ("\n'%s' is an abbreviation for %s\n", alias_name.c_str(), sstr.GetData()); } } else if (matches.GetSize() > 0) { Stream &output_strm = result.GetOutputStream(); output_strm.Printf("Help requested with ambiguous command name, possible completions:\n"); const size_t match_count = matches.GetSize(); for (size_t i = 0; i < match_count; i++) { output_strm.Printf("\t%s\n", matches.GetStringAtIndex(i)); } } else { // Maybe the user is asking for help about a command argument rather than a command. const CommandArgumentType arg_type = CommandObject::LookupArgumentName (command.GetArgumentAtIndex (0)); if (arg_type != eArgTypeLastArg) { Stream &output_strm = result.GetOutputStream (); CommandObject::GetArgumentHelp (output_strm, arg_type, m_interpreter); result.SetStatus (eReturnStatusSuccessFinishNoResult); } else { StreamString error_msg_stream; GenerateAdditionalHelpAvenuesMessage(&error_msg_stream, command.GetArgumentAtIndex(0), m_interpreter.GetCommandPrefix()); result.AppendErrorWithFormat("%s",error_msg_stream.GetData()); result.SetStatus (eReturnStatusFailed); } } } return result.Succeeded(); }
int CommandInterpreter::HandleCompletionMatches (Args &parsed_line, int &cursor_index, int &cursor_char_position, int match_start_point, int max_return_elements, bool &word_complete, StringList &matches) { int num_command_matches = 0; bool look_for_subcommand = false; // For any of the command completions a unique match will be a complete word. word_complete = true; if (cursor_index == -1) { // We got nothing on the command line, so return the list of commands bool include_aliases = true; num_command_matches = GetCommandNamesMatchingPartialString ("", include_aliases, matches); } else if (cursor_index == 0) { // The cursor is in the first argument, so just do a lookup in the dictionary. CommandObject *cmd_obj = GetCommandObject (parsed_line.GetArgumentAtIndex(0), &matches); num_command_matches = matches.GetSize(); if (num_command_matches == 1 && cmd_obj && cmd_obj->IsMultiwordObject() && matches.GetStringAtIndex(0) != NULL && strcmp (parsed_line.GetArgumentAtIndex(0), matches.GetStringAtIndex(0)) == 0) { look_for_subcommand = true; num_command_matches = 0; matches.DeleteStringAtIndex(0); parsed_line.AppendArgument (""); cursor_index++; cursor_char_position = 0; } } if (cursor_index > 0 || look_for_subcommand) { // We are completing further on into a commands arguments, so find the command and tell it // to complete the command. // First see if there is a matching initial command: CommandObject *command_object = GetCommandObject (parsed_line.GetArgumentAtIndex(0)); if (command_object == NULL) { return 0; } else { parsed_line.Shift(); cursor_index--; num_command_matches = command_object->HandleCompletion (*this, parsed_line, cursor_index, cursor_char_position, match_start_point, max_return_elements, word_complete, matches); } } return num_command_matches; }
bool CommandInterpreter::HandleCommand ( const char *command_line, bool add_to_history, CommandReturnObject &result, ExecutionContext *override_context ) { // FIXME: there should probably be a mutex to make sure only one thread can // run the interpreter at a time. // TODO: this should be a logging channel in lldb. // if (DebugSelf()) // { // result.AppendMessageWithFormat ("Processing command: %s\n", command_line); // } m_debugger.UpdateExecutionContext (override_context); if (command_line == NULL || command_line[0] == '\0') { if (m_command_history.empty()) { result.AppendError ("empty command"); result.SetStatus(eReturnStatusFailed); return false; } else { command_line = m_repeat_command.c_str(); if (m_repeat_command.empty()) { result.AppendErrorWithFormat("No auto repeat.\n"); result.SetStatus (eReturnStatusFailed); return false; } } add_to_history = false; } Args command_args(command_line); if (command_args.GetArgumentCount() > 0) { const char *command_cstr = command_args.GetArgumentAtIndex(0); if (command_cstr) { // We're looking up the command object here. So first find an exact match to the // command in the commands. CommandObject *command_obj = GetCommandObject(command_cstr); if (command_obj != NULL) { if (command_obj->IsAlias()) { BuildAliasCommandArgs (command_obj, command_cstr, command_args, result); if (!result.Succeeded()) return false; } if (add_to_history) { const char *repeat_command = command_obj->GetRepeatCommand(command_args, 0); if (repeat_command != NULL) m_repeat_command.assign(repeat_command); else m_repeat_command.assign(command_line); m_command_history.push_back (command_line); } if (command_obj->WantsRawCommandString()) { const char *stripped_command = ::strstr (command_line, command_cstr); if (stripped_command) { stripped_command += strlen(command_cstr); while (isspace(*stripped_command)) ++stripped_command; command_obj->ExecuteRawCommandString (*this, stripped_command, result); } } else { // Remove the command from the args. command_args.Shift(); command_obj->ExecuteWithOptions (*this, command_args, result); } } else { // We didn't find the first command object, so complete the first argument. StringList matches; int num_matches; int cursor_index = 0; int cursor_char_position = strlen (command_args.GetArgumentAtIndex(0)); bool word_complete; num_matches = HandleCompletionMatches (command_args, cursor_index, cursor_char_position, 0, -1, word_complete, matches); if (num_matches > 0) { std::string error_msg; error_msg.assign ("ambiguous command '"); error_msg.append(command_cstr); error_msg.append ("'."); error_msg.append (" Possible completions:"); for (int i = 0; i < num_matches; i++) { error_msg.append ("\n\t"); error_msg.append (matches.GetStringAtIndex (i)); } error_msg.append ("\n"); result.AppendRawError (error_msg.c_str(), error_msg.size()); } else result.AppendErrorWithFormat ("Unrecognized command '%s'.\n", command_cstr); result.SetStatus (eReturnStatusFailed); } } } return result.Succeeded(); }
bool CommandObjectHelp::Execute (Args& command, CommandReturnObject &result) { CommandObject::CommandMap::iterator pos; CommandObject *cmd_obj; const int argc = command.GetArgumentCount (); // 'help' doesn't take any options or arguments, other than command names. If argc is 0, we show the user // all commands and aliases. Otherwise every argument must be the name of a command or a sub-command. if (argc == 0) { result.SetStatus (eReturnStatusSuccessFinishNoResult); m_interpreter.GetHelp (result); // General help, for ALL commands. } else { // Get command object for the first command argument. Only search built-in command dictionary. StringList matches; cmd_obj = m_interpreter.GetCommandObject (command.GetArgumentAtIndex (0), &matches); bool is_alias_command = m_interpreter.AliasExists (command.GetArgumentAtIndex (0)); std::string alias_name = command.GetArgumentAtIndex(0); if (cmd_obj != NULL) { StringList matches; bool all_okay = true; CommandObject *sub_cmd_obj = cmd_obj; // Loop down through sub_command dictionaries until we find the command object that corresponds // to the help command entered. for (int i = 1; i < argc && all_okay; ++i) { std::string sub_command = command.GetArgumentAtIndex(i); matches.Clear(); if (! sub_cmd_obj->IsMultiwordObject ()) { all_okay = false; } else { CommandObject *found_cmd; found_cmd = ((CommandObjectMultiword *) sub_cmd_obj)->GetSubcommandObject(sub_command.c_str(), &matches); if (found_cmd == NULL) all_okay = false; else if (matches.GetSize() > 1) all_okay = false; else sub_cmd_obj = found_cmd; } } if (!all_okay || (sub_cmd_obj == NULL)) { std::string cmd_string; command.GetCommandString (cmd_string); if (matches.GetSize() < 2) { result.AppendErrorWithFormat("'%s' is not a known command.\n" "Try 'help' to see a current list of commands.\n", cmd_string.c_str()); } else { StreamString s; s.Printf ("ambiguous command %s", cmd_string.c_str()); size_t num_matches = matches.GetSize(); for (size_t match_idx = 0; match_idx < num_matches; match_idx++) { s.Printf ("\n\t%s", matches.GetStringAtIndex(match_idx)); } s.Printf ("\n"); result.AppendError(s.GetData()); } result.SetStatus (eReturnStatusFailed); } else { Stream &output_strm = result.GetOutputStream(); if (sub_cmd_obj->GetOptions() != NULL) { if (sub_cmd_obj->WantsRawCommandString()) { std::string help_text (sub_cmd_obj->GetHelp()); help_text.append (" This command takes 'raw' input (no need to quote stuff)."); m_interpreter.OutputFormattedHelpText (output_strm, "", "", help_text.c_str(), 1); } else m_interpreter.OutputFormattedHelpText (output_strm, "", "", sub_cmd_obj->GetHelp(), 1); output_strm.Printf ("\nSyntax: %s\n", sub_cmd_obj->GetSyntax()); sub_cmd_obj->GetOptions()->GenerateOptionUsage (m_interpreter, output_strm, sub_cmd_obj); const char *long_help = sub_cmd_obj->GetHelpLong(); if ((long_help != NULL) && (strlen (long_help) > 0)) output_strm.Printf ("\n%s", long_help); // Mark this help command with a success status. if (sub_cmd_obj->WantsRawCommandString()) { m_interpreter.OutputFormattedHelpText (output_strm, "", "", "\nIMPORTANT NOTE: Because this command takes 'raw' input, if you use any command options you must use ' -- ' between the end of the command options and the beginning of the raw input.", 1); } result.SetStatus (eReturnStatusSuccessFinishNoResult); } else if (sub_cmd_obj->IsMultiwordObject()) { if (sub_cmd_obj->WantsRawCommandString()) { std::string help_text (sub_cmd_obj->GetHelp()); help_text.append (" This command takes 'raw' input (no need to quote stuff)."); m_interpreter.OutputFormattedHelpText (output_strm, "", "", help_text.c_str(), 1); } else m_interpreter.OutputFormattedHelpText (output_strm, "", "", sub_cmd_obj->GetHelp(), 1); ((CommandObjectMultiword *) sub_cmd_obj)->GenerateHelpText (result); } else { const char *long_help = sub_cmd_obj->GetHelpLong(); if ((long_help != NULL) && (strlen (long_help) > 0)) output_strm.Printf ("\n%s", long_help); else if (sub_cmd_obj->WantsRawCommandString()) { std::string help_text (sub_cmd_obj->GetHelp()); help_text.append (" This command takes 'raw' input (no need to quote stuff)."); m_interpreter.OutputFormattedHelpText (output_strm, "", "", help_text.c_str(), 1); } else m_interpreter.OutputFormattedHelpText (output_strm, "", "", sub_cmd_obj->GetHelp(), 1); output_strm.Printf ("\nSyntax: %s\n", sub_cmd_obj->GetSyntax()); // Mark this help command with a success status. result.SetStatus (eReturnStatusSuccessFinishNoResult); } } if (is_alias_command) { StreamString sstr; m_interpreter.GetAliasHelp (alias_name.c_str(), cmd_obj->GetCommandName(), sstr); result.GetOutputStream().Printf ("\n'%s' is an abbreviation for %s\n", alias_name.c_str(), sstr.GetData()); } } else if (matches.GetSize() > 0) { Stream &output_strm = result.GetOutputStream(); output_strm.Printf("Help requested with ambiguous command name, possible completions:\n"); const uint32_t match_count = matches.GetSize(); for (uint32_t i = 0; i < match_count; i++) { output_strm.Printf("\t%s\n", matches.GetStringAtIndex(i)); } } else { // Maybe the user is asking for help about a command argument rather than a command. const CommandArgumentType arg_type = CommandObject::LookupArgumentName (command.GetArgumentAtIndex (0)); if (arg_type != eArgTypeLastArg) { Stream &output_strm = result.GetOutputStream (); CommandObject::GetArgumentHelp (output_strm, arg_type, m_interpreter); result.SetStatus (eReturnStatusSuccessFinishNoResult); } else { result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a current list of commands.\n", command.GetArgumentAtIndex(0)); result.SetStatus (eReturnStatusFailed); } } } return result.Succeeded(); }
TEST(CompletionRequest, DuplicateFiltering) { std::string command = "a bad c"; const unsigned cursor_pos = 3; StringList matches; CompletionResult result; CompletionRequest request(command, cursor_pos, 0, 0, result); result.GetMatches(matches); EXPECT_EQ(0U, request.GetNumberOfMatches()); // Add foo twice request.AddCompletion("foo"); result.GetMatches(matches); EXPECT_EQ(1U, request.GetNumberOfMatches()); EXPECT_EQ(1U, matches.GetSize()); EXPECT_STREQ("foo", matches.GetStringAtIndex(0)); request.AddCompletion("foo"); result.GetMatches(matches); EXPECT_EQ(1U, request.GetNumberOfMatches()); EXPECT_EQ(1U, matches.GetSize()); EXPECT_STREQ("foo", matches.GetStringAtIndex(0)); // Add bar twice request.AddCompletion("bar"); result.GetMatches(matches); EXPECT_EQ(2U, request.GetNumberOfMatches()); EXPECT_EQ(2U, matches.GetSize()); EXPECT_STREQ("foo", matches.GetStringAtIndex(0)); EXPECT_STREQ("bar", matches.GetStringAtIndex(1)); request.AddCompletion("bar"); result.GetMatches(matches); EXPECT_EQ(2U, request.GetNumberOfMatches()); EXPECT_EQ(2U, matches.GetSize()); EXPECT_STREQ("foo", matches.GetStringAtIndex(0)); EXPECT_STREQ("bar", matches.GetStringAtIndex(1)); // Add foo again. request.AddCompletion("foo"); result.GetMatches(matches); EXPECT_EQ(2U, request.GetNumberOfMatches()); EXPECT_EQ(2U, matches.GetSize()); EXPECT_STREQ("foo", matches.GetStringAtIndex(0)); EXPECT_STREQ("bar", matches.GetStringAtIndex(1)); // Add something with an existing prefix request.AddCompletion("foobar"); result.GetMatches(matches); EXPECT_EQ(3U, request.GetNumberOfMatches()); EXPECT_EQ(3U, matches.GetSize()); EXPECT_STREQ("foo", matches.GetStringAtIndex(0)); EXPECT_STREQ("bar", matches.GetStringAtIndex(1)); EXPECT_STREQ("foobar", matches.GetStringAtIndex(2)); }