diff options
-rw-r--r-- | lldb/include/lldb/Interpreter/CommandInterpreter.h | 16 | ||||
-rw-r--r-- | lldb/include/lldb/lldb-enumerations.h | 1 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectCommands.cpp | 127 | ||||
-rw-r--r-- | lldb/source/Interpreter/CommandInterpreter.cpp | 102 | ||||
-rw-r--r-- | lldb/tools/driver/IOChannel.cpp | 6 |
5 files changed, 249 insertions, 3 deletions
diff --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h b/lldb/include/lldb/Interpreter/CommandInterpreter.h index 8d18a0ea2f3..7381f1efcef 100644 --- a/lldb/include/lldb/Interpreter/CommandInterpreter.h +++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -195,8 +195,11 @@ public: // you want returned. Otherwise set max_return_elements to -1. // If you want to start some way into the match list, then set match_start_point to the desired start // point. - // Returns the total number of completions, or -1 if the completion character should be inserted, or + // Returns: + // -1 if the completion character should be inserted + // -2 if the entire command line should be deleted and replaced with matches.GetStringAtIndex(0) // INT_MAX if the number of matches is > max_return_elements, but it is expensive to compute. + // Otherwise, returns the number of matches. // // FIXME: Only max_return_elements == -1 is supported at present. @@ -338,6 +341,16 @@ public: bool GetSynchronous (); + + void + DumpHistory (Stream &stream, uint32_t count) const; + + void + DumpHistory (Stream &stream, uint32_t start, uint32_t end) const; + + const char * + FindHistoryString (const char *input_str) const; + #ifndef SWIG void @@ -396,6 +409,7 @@ private: std::string m_repeat_command; // Stores the command that will be executed for an empty command string. std::auto_ptr<ScriptInterpreter> m_script_interpreter_ap; char m_comment_char; + char m_repeat_char; bool m_batch_command_mode; }; diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index b8a85087fdf..34e2a805734 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -391,6 +391,7 @@ namespace lldb { eArgTypeThreadID, eArgTypeThreadIndex, eArgTypeThreadName, + eArgTypeUnsignedInteger, eArgTypeUnixSignal, eArgTypeVarName, eArgTypeValue, diff --git a/lldb/source/Commands/CommandObjectCommands.cpp b/lldb/source/Commands/CommandObjectCommands.cpp index 03fa8856045..779a4ab3831 100644 --- a/lldb/source/Commands/CommandObjectCommands.cpp +++ b/lldb/source/Commands/CommandObjectCommands.cpp @@ -30,6 +30,132 @@ using namespace lldb_private; // CommandObjectCommandsSource //------------------------------------------------------------------------- +class CommandObjectCommandsHistory : public CommandObject +{ +private: + + class CommandOptions : public Options + { + public: + + CommandOptions (CommandInterpreter &interpreter) : + Options (interpreter) + { + } + + virtual + ~CommandOptions (){} + + virtual Error + SetOptionValue (uint32_t option_idx, const char *option_arg) + { + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + bool success; + + switch (short_option) + { + case 'c': + m_end_idx = Args::StringToUInt32(option_arg, UINT_MAX, 0, &success); + if (!success) + error.SetErrorStringWithFormat("Invalid value for count: %s.\n", option_arg); + if (m_end_idx != 0) + m_end_idx--; + m_start_idx = 0; + break; + case 'e': + m_end_idx = Args::StringToUInt32(option_arg, 0, 0, &success); + if (!success) + error.SetErrorStringWithFormat("Invalid value for end index: %s.\n", option_arg); + break; + case 's': + m_start_idx = Args::StringToUInt32(option_arg, 0, 0, &success); + if (!success) + error.SetErrorStringWithFormat("Invalid value for start index: %s.\n", option_arg); + break; + default: + error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); + break; + } + + return error; + } + + void + OptionParsingStarting () + { + m_start_idx = 0; + m_end_idx = UINT_MAX; + } + + const OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + // Options table: Required for subclasses of Options. + + static OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + uint32_t m_start_idx; + uint32_t m_end_idx; + }; + + CommandOptions m_options; + + virtual Options * + GetOptions () + { + return &m_options; + } + +public: + CommandObjectCommandsHistory(CommandInterpreter &interpreter) : + CommandObject (interpreter, + "command history", + "Dump the history of commands in this session.", + NULL), + m_options (interpreter) + { + } + + ~CommandObjectCommandsHistory () + { + } + + bool + Execute + ( + Args& args, + CommandReturnObject &result + ) + { + + m_interpreter.DumpHistory (result.GetOutputStream(), + m_options.m_start_idx, + m_options.m_end_idx); + return result.Succeeded(); + + } +}; + +OptionDefinition +CommandObjectCommandsHistory::CommandOptions::g_option_table[] = +{ +{ LLDB_OPT_SET_1, false, "count", 'c', required_argument, NULL, 0, eArgTypeUnsignedInteger, "How many history commands to print."}, +{ LLDB_OPT_SET_1, false, "start-index", 's', required_argument, NULL, 0, eArgTypeUnsignedInteger, "Index at which to start printing history commands."}, +{ LLDB_OPT_SET_1, false, "end-index", 'e', required_argument, NULL, 0, eArgTypeUnsignedInteger, "Index at which to stop printing history commands."}, +{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } +}; + + +//------------------------------------------------------------------------- +// CommandObjectCommandsSource +//------------------------------------------------------------------------- + class CommandObjectCommandsSource : public CommandObject { private: @@ -1020,6 +1146,7 @@ CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpret LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter))); LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter))); LoadSubCommand ("regex", CommandObjectSP (new CommandObjectCommandsAddRegex (interpreter))); + LoadSubCommand ("history", CommandObjectSP (new CommandObjectCommandsHistory (interpreter))); } CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands () diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index bd934c3aa07..5d6792804af 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -70,6 +70,7 @@ CommandInterpreter::CommandInterpreter m_skip_lldbinit_files (false), m_script_interpreter_ap (), m_comment_char ('#'), + m_repeat_char ('!'), m_batch_command_mode (false) { const char *dbg_name = debugger.GetInstanceName().AsCString(); @@ -929,6 +930,7 @@ CommandInterpreter::HandleCommand (const char *command_line, std::string next_word; bool wants_raw_input = false; std::string command_string (command_line); + std::string original_command_string (command_line); LogSP log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMANDS)); Host::SetCrashDescriptionWithFormat ("HandleCommand(command = \"%s\")", command_line); @@ -959,6 +961,19 @@ CommandInterpreter::HandleCommand (const char *command_line, empty_command = true; else if (command_string[non_space] == m_comment_char) comment_command = true; + else if (command_string[non_space] == m_repeat_char) + { + const char *history_string = FindHistoryString (command_string.c_str() + non_space); + if (history_string == NULL) + { + result.AppendErrorWithFormat ("Could not find entry: %s in history", command_string.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + add_to_history = false; + command_string = history_string; + original_command_string = history_string; + } } if (empty_command) @@ -975,6 +990,7 @@ CommandInterpreter::HandleCommand (const char *command_line, { command_line = m_repeat_command.c_str(); command_string = command_line; + original_command_string = command_line; if (m_repeat_command.empty()) { result.AppendErrorWithFormat("No auto repeat.\n"); @@ -1119,9 +1135,11 @@ CommandInterpreter::HandleCommand (const char *command_line, if (repeat_command != NULL) m_repeat_command.assign(repeat_command); else - m_repeat_command.assign(command_line); + m_repeat_command.assign(original_command_string.c_str()); - m_command_history.push_back (command_line); + // Don't keep pushing the same command onto the history... + if (m_command_history.size() == 0 || m_command_history.back() != original_command_string) + m_command_history.push_back (original_command_string); } command_string = revised_command_line.GetData(); @@ -1276,6 +1294,29 @@ CommandInterpreter::HandleCompletion (const char *current_line, Args parsed_line(current_line, last_char - current_line); Args partial_parsed_line(current_line, cursor - current_line); + // Don't complete comments, and if the line we are completing is just the history repeat character, + // substitute the appropriate history line. + const char *first_arg = parsed_line.GetArgumentAtIndex(0); + if (first_arg) + { + if (first_arg[0] == m_comment_char) + return 0; + else if (first_arg[0] == m_repeat_char) + { + const char *history_string = FindHistoryString (first_arg); + if (history_string != NULL) + { + matches.Clear(); + matches.InsertStringAtIndex(0, history_string); + return -2; + } + else + return 0; + + } + } + + int num_args = partial_parsed_line.GetArgumentCount(); int cursor_index = partial_parsed_line.GetArgumentCount() - 1; int cursor_char_position; @@ -2154,3 +2195,60 @@ CommandInterpreter::UpdateExecutionContext (ExecutionContext *override_context) } } +void +CommandInterpreter::DumpHistory (Stream &stream, uint32_t count) const +{ + DumpHistory (stream, 0, count - 1); +} + +void +CommandInterpreter::DumpHistory (Stream &stream, uint32_t start, uint32_t end) const +{ + size_t num_history_elements = m_command_history.size(); + if (start > num_history_elements) + return; + for (uint32_t i = start; i < num_history_elements && i <= end; i++) + { + if (!m_command_history[i].empty()) + { + stream.Indent(); + stream.Printf ("%4d: %s\n", i, m_command_history[i].c_str()); + } + } +} + +const char * +CommandInterpreter::FindHistoryString (const char *input_str) const +{ + if (input_str[0] != m_repeat_char) + return NULL; + if (input_str[1] == '-') + { + bool success; + uint32_t idx = Args::StringToUInt32 (input_str+2, 0, 0, &success); + if (!success) + return NULL; + if (idx > m_command_history.size()) + return NULL; + idx = m_command_history.size() - idx; + return m_command_history[idx].c_str(); + + } + else if (input_str[1] == m_repeat_char) + { + if (m_command_history.empty()) + return NULL; + else + return m_command_history.back().c_str(); + } + else + { + bool success; + uint32_t idx = Args::StringToUInt32 (input_str+1, 0, 0, &success); + if (!success) + return NULL; + if (idx >= m_command_history.size()) + return NULL; + return m_command_history[idx].c_str(); + } +} diff --git a/lldb/tools/driver/IOChannel.cpp b/lldb/tools/driver/IOChannel.cpp index 199e72c9adc..6150d5d4871 100644 --- a/lldb/tools/driver/IOChannel.cpp +++ b/lldb/tools/driver/IOChannel.cpp @@ -85,6 +85,12 @@ IOChannel::HandleCompletion (EditLine *e, int ch) el_insertstr (m_edit_line, m_completion_key); return CC_REDISPLAY; } + else if (num_completions == -2) + { + el_deletestr (m_edit_line, line_info->cursor - line_info->buffer); + el_insertstr (m_edit_line, completions.GetStringAtIndex(0)); + return CC_REDISPLAY; + } // If we get a longer match display that first. const char *completion_str = completions.GetStringAtIndex(0); |