forked from OSchip/llvm-project
Added "command history" command to dump the command history.
Also made: (lldb) !<NUM> (lldb) !-<NUM> (lldb) !! work with the history. For added benefit: (lldb) !<NUM><TAB> will insert the command at position <NUM> in the history into the command line to be edited. This is only partial, I still need to sync up editline's history list with the one kept by the interpreter. llvm-svn: 134955
This commit is contained in:
parent
37b7fd0ab2
commit
a5a97ebe3c
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -391,6 +391,7 @@ namespace lldb {
|
|||
eArgTypeThreadID,
|
||||
eArgTypeThreadIndex,
|
||||
eArgTypeThreadName,
|
||||
eArgTypeUnsignedInteger,
|
||||
eArgTypeUnixSignal,
|
||||
eArgTypeVarName,
|
||||
eArgTypeValue,
|
||||
|
|
|
@ -26,6 +26,132 @@
|
|||
using namespace lldb;
|
||||
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
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -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 ()
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue