forked from OSchip/llvm-project
[lldb/interpreter] Move the history subcommand to session (NFCI)
This patch moves the `history` subcommand from the `command` to `session` command. I think it makes more sense to have it there because as the `command` usage suggests, it should be used to manage custom LLDB commands. However, `history` is essentially tied to a debugging session and holds all the commands (not specifically custom ones). This also makes it more discoverable by adding an alias for it (mimicking the shell builtin). Differential Revision: https://reviews.llvm.org/D84307 Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
This commit is contained in:
parent
f758d72eb8
commit
85fbb08fa2
|
@ -30,155 +30,6 @@ using namespace lldb_private;
|
|||
|
||||
// CommandObjectCommandsSource
|
||||
|
||||
#define LLDB_OPTIONS_history
|
||||
#include "CommandOptions.inc"
|
||||
|
||||
class CommandObjectCommandsHistory : public CommandObjectParsed {
|
||||
public:
|
||||
CommandObjectCommandsHistory(CommandInterpreter &interpreter)
|
||||
: CommandObjectParsed(interpreter, "command history",
|
||||
"Dump the history of commands in this session.\n"
|
||||
"Commands in the history list can be run again "
|
||||
"using \"!<INDEX>\". \"!-<OFFSET>\" will re-run "
|
||||
"the command that is <OFFSET> commands from the end"
|
||||
" of the list (counting the current command).",
|
||||
nullptr),
|
||||
m_options() {}
|
||||
|
||||
~CommandObjectCommandsHistory() override = default;
|
||||
|
||||
Options *GetOptions() override { return &m_options; }
|
||||
|
||||
protected:
|
||||
class CommandOptions : public Options {
|
||||
public:
|
||||
CommandOptions()
|
||||
: Options(), m_start_idx(0), m_stop_idx(0), m_count(0), m_clear(false) {
|
||||
}
|
||||
|
||||
~CommandOptions() override = default;
|
||||
|
||||
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
|
||||
ExecutionContext *execution_context) override {
|
||||
Status error;
|
||||
const int short_option = m_getopt_table[option_idx].val;
|
||||
|
||||
switch (short_option) {
|
||||
case 'c':
|
||||
error = m_count.SetValueFromString(option_arg, eVarSetOperationAssign);
|
||||
break;
|
||||
case 's':
|
||||
if (option_arg == "end") {
|
||||
m_start_idx.SetCurrentValue(UINT64_MAX);
|
||||
m_start_idx.SetOptionWasSet();
|
||||
} else
|
||||
error = m_start_idx.SetValueFromString(option_arg,
|
||||
eVarSetOperationAssign);
|
||||
break;
|
||||
case 'e':
|
||||
error =
|
||||
m_stop_idx.SetValueFromString(option_arg, eVarSetOperationAssign);
|
||||
break;
|
||||
case 'C':
|
||||
m_clear.SetCurrentValue(true);
|
||||
m_clear.SetOptionWasSet();
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Unimplemented option");
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
||||
m_start_idx.Clear();
|
||||
m_stop_idx.Clear();
|
||||
m_count.Clear();
|
||||
m_clear.Clear();
|
||||
}
|
||||
|
||||
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
||||
return llvm::makeArrayRef(g_history_options);
|
||||
}
|
||||
|
||||
// Instance variables to hold the values for command options.
|
||||
|
||||
OptionValueUInt64 m_start_idx;
|
||||
OptionValueUInt64 m_stop_idx;
|
||||
OptionValueUInt64 m_count;
|
||||
OptionValueBoolean m_clear;
|
||||
};
|
||||
|
||||
bool DoExecute(Args &command, CommandReturnObject &result) override {
|
||||
if (m_options.m_clear.GetCurrentValue() &&
|
||||
m_options.m_clear.OptionWasSet()) {
|
||||
m_interpreter.GetCommandHistory().Clear();
|
||||
result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
|
||||
} else {
|
||||
if (m_options.m_start_idx.OptionWasSet() &&
|
||||
m_options.m_stop_idx.OptionWasSet() &&
|
||||
m_options.m_count.OptionWasSet()) {
|
||||
result.AppendError("--count, --start-index and --end-index cannot be "
|
||||
"all specified in the same invocation");
|
||||
result.SetStatus(lldb::eReturnStatusFailed);
|
||||
} else {
|
||||
std::pair<bool, uint64_t> start_idx(
|
||||
m_options.m_start_idx.OptionWasSet(),
|
||||
m_options.m_start_idx.GetCurrentValue());
|
||||
std::pair<bool, uint64_t> stop_idx(
|
||||
m_options.m_stop_idx.OptionWasSet(),
|
||||
m_options.m_stop_idx.GetCurrentValue());
|
||||
std::pair<bool, uint64_t> count(m_options.m_count.OptionWasSet(),
|
||||
m_options.m_count.GetCurrentValue());
|
||||
|
||||
const CommandHistory &history(m_interpreter.GetCommandHistory());
|
||||
|
||||
if (start_idx.first && start_idx.second == UINT64_MAX) {
|
||||
if (count.first) {
|
||||
start_idx.second = history.GetSize() - count.second;
|
||||
stop_idx.second = history.GetSize() - 1;
|
||||
} else if (stop_idx.first) {
|
||||
start_idx.second = stop_idx.second;
|
||||
stop_idx.second = history.GetSize() - 1;
|
||||
} else {
|
||||
start_idx.second = 0;
|
||||
stop_idx.second = history.GetSize() - 1;
|
||||
}
|
||||
} else {
|
||||
if (!start_idx.first && !stop_idx.first && !count.first) {
|
||||
start_idx.second = 0;
|
||||
stop_idx.second = history.GetSize() - 1;
|
||||
} else if (start_idx.first) {
|
||||
if (count.first) {
|
||||
stop_idx.second = start_idx.second + count.second - 1;
|
||||
} else if (!stop_idx.first) {
|
||||
stop_idx.second = history.GetSize() - 1;
|
||||
}
|
||||
} else if (stop_idx.first) {
|
||||
if (count.first) {
|
||||
if (stop_idx.second >= count.second)
|
||||
start_idx.second = stop_idx.second - count.second + 1;
|
||||
else
|
||||
start_idx.second = 0;
|
||||
}
|
||||
} else /* if (count.first) */
|
||||
{
|
||||
start_idx.second = 0;
|
||||
stop_idx.second = count.second - 1;
|
||||
}
|
||||
}
|
||||
history.Dump(result.GetOutputStream(), start_idx.second,
|
||||
stop_idx.second);
|
||||
}
|
||||
}
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
||||
CommandOptions m_options;
|
||||
};
|
||||
|
||||
// CommandObjectCommandsSource
|
||||
|
||||
#define LLDB_OPTIONS_source
|
||||
#include "CommandOptions.inc"
|
||||
|
||||
|
@ -1850,8 +1701,6 @@ CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(
|
|||
CommandObjectSP(new CommandObjectCommandsDelete(interpreter)));
|
||||
LoadSubCommand(
|
||||
"regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter)));
|
||||
LoadSubCommand("history", CommandObjectSP(
|
||||
new CommandObjectCommandsHistory(interpreter)));
|
||||
LoadSubCommand(
|
||||
"script",
|
||||
CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter)));
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
#include "CommandObjectSession.h"
|
||||
#include "lldb/Host/OptionParser.h"
|
||||
#include "lldb/Interpreter/CommandInterpreter.h"
|
||||
#include "lldb/Interpreter/CommandReturnObject.h"
|
||||
#include "lldb/Interpreter/OptionArgParser.h"
|
||||
#include "lldb/Interpreter/OptionValue.h"
|
||||
#include "lldb/Interpreter/OptionValueBoolean.h"
|
||||
#include "lldb/Interpreter/OptionValueString.h"
|
||||
#include "lldb/Interpreter/OptionValueUInt64.h"
|
||||
#include "lldb/Interpreter/Options.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
@ -43,11 +50,159 @@ protected:
|
|||
}
|
||||
};
|
||||
|
||||
#define LLDB_OPTIONS_history
|
||||
#include "CommandOptions.inc"
|
||||
|
||||
class CommandObjectSessionHistory : public CommandObjectParsed {
|
||||
public:
|
||||
CommandObjectSessionHistory(CommandInterpreter &interpreter)
|
||||
: CommandObjectParsed(interpreter, "session history",
|
||||
"Dump the history of commands in this session.\n"
|
||||
"Commands in the history list can be run again "
|
||||
"using \"!<INDEX>\". \"!-<OFFSET>\" will re-run "
|
||||
"the command that is <OFFSET> commands from the end"
|
||||
" of the list (counting the current command).",
|
||||
nullptr),
|
||||
m_options() {}
|
||||
|
||||
~CommandObjectSessionHistory() override = default;
|
||||
|
||||
Options *GetOptions() override { return &m_options; }
|
||||
|
||||
protected:
|
||||
class CommandOptions : public Options {
|
||||
public:
|
||||
CommandOptions()
|
||||
: Options(), m_start_idx(0), m_stop_idx(0), m_count(0), m_clear(false) {
|
||||
}
|
||||
|
||||
~CommandOptions() override = default;
|
||||
|
||||
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
|
||||
ExecutionContext *execution_context) override {
|
||||
Status error;
|
||||
const int short_option = m_getopt_table[option_idx].val;
|
||||
|
||||
switch (short_option) {
|
||||
case 'c':
|
||||
error = m_count.SetValueFromString(option_arg, eVarSetOperationAssign);
|
||||
break;
|
||||
case 's':
|
||||
if (option_arg == "end") {
|
||||
m_start_idx.SetCurrentValue(UINT64_MAX);
|
||||
m_start_idx.SetOptionWasSet();
|
||||
} else
|
||||
error = m_start_idx.SetValueFromString(option_arg,
|
||||
eVarSetOperationAssign);
|
||||
break;
|
||||
case 'e':
|
||||
error =
|
||||
m_stop_idx.SetValueFromString(option_arg, eVarSetOperationAssign);
|
||||
break;
|
||||
case 'C':
|
||||
m_clear.SetCurrentValue(true);
|
||||
m_clear.SetOptionWasSet();
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Unimplemented option");
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
||||
m_start_idx.Clear();
|
||||
m_stop_idx.Clear();
|
||||
m_count.Clear();
|
||||
m_clear.Clear();
|
||||
}
|
||||
|
||||
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
||||
return llvm::makeArrayRef(g_history_options);
|
||||
}
|
||||
|
||||
// Instance variables to hold the values for command options.
|
||||
|
||||
OptionValueUInt64 m_start_idx;
|
||||
OptionValueUInt64 m_stop_idx;
|
||||
OptionValueUInt64 m_count;
|
||||
OptionValueBoolean m_clear;
|
||||
};
|
||||
|
||||
bool DoExecute(Args &command, CommandReturnObject &result) override {
|
||||
if (m_options.m_clear.GetCurrentValue() &&
|
||||
m_options.m_clear.OptionWasSet()) {
|
||||
m_interpreter.GetCommandHistory().Clear();
|
||||
result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
|
||||
} else {
|
||||
if (m_options.m_start_idx.OptionWasSet() &&
|
||||
m_options.m_stop_idx.OptionWasSet() &&
|
||||
m_options.m_count.OptionWasSet()) {
|
||||
result.AppendError("--count, --start-index and --end-index cannot be "
|
||||
"all specified in the same invocation");
|
||||
result.SetStatus(lldb::eReturnStatusFailed);
|
||||
} else {
|
||||
std::pair<bool, uint64_t> start_idx(
|
||||
m_options.m_start_idx.OptionWasSet(),
|
||||
m_options.m_start_idx.GetCurrentValue());
|
||||
std::pair<bool, uint64_t> stop_idx(
|
||||
m_options.m_stop_idx.OptionWasSet(),
|
||||
m_options.m_stop_idx.GetCurrentValue());
|
||||
std::pair<bool, uint64_t> count(m_options.m_count.OptionWasSet(),
|
||||
m_options.m_count.GetCurrentValue());
|
||||
|
||||
const CommandHistory &history(m_interpreter.GetCommandHistory());
|
||||
|
||||
if (start_idx.first && start_idx.second == UINT64_MAX) {
|
||||
if (count.first) {
|
||||
start_idx.second = history.GetSize() - count.second;
|
||||
stop_idx.second = history.GetSize() - 1;
|
||||
} else if (stop_idx.first) {
|
||||
start_idx.second = stop_idx.second;
|
||||
stop_idx.second = history.GetSize() - 1;
|
||||
} else {
|
||||
start_idx.second = 0;
|
||||
stop_idx.second = history.GetSize() - 1;
|
||||
}
|
||||
} else {
|
||||
if (!start_idx.first && !stop_idx.first && !count.first) {
|
||||
start_idx.second = 0;
|
||||
stop_idx.second = history.GetSize() - 1;
|
||||
} else if (start_idx.first) {
|
||||
if (count.first) {
|
||||
stop_idx.second = start_idx.second + count.second - 1;
|
||||
} else if (!stop_idx.first) {
|
||||
stop_idx.second = history.GetSize() - 1;
|
||||
}
|
||||
} else if (stop_idx.first) {
|
||||
if (count.first) {
|
||||
if (stop_idx.second >= count.second)
|
||||
start_idx.second = stop_idx.second - count.second + 1;
|
||||
else
|
||||
start_idx.second = 0;
|
||||
}
|
||||
} else /* if (count.first) */
|
||||
{
|
||||
start_idx.second = 0;
|
||||
stop_idx.second = count.second - 1;
|
||||
}
|
||||
}
|
||||
history.Dump(result.GetOutputStream(), start_idx.second,
|
||||
stop_idx.second);
|
||||
}
|
||||
}
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
||||
CommandOptions m_options;
|
||||
};
|
||||
|
||||
CommandObjectSession::CommandObjectSession(CommandInterpreter &interpreter)
|
||||
: CommandObjectMultiword(interpreter, "session",
|
||||
"Commands controlling LLDB session.",
|
||||
"session <subcommand> [<command-options>]") {
|
||||
LoadSubCommand("save",
|
||||
CommandObjectSP(new CommandObjectSessionSave(interpreter)));
|
||||
// TODO: Move 'history' subcommand from CommandObjectCommands.
|
||||
LoadSubCommand("history",
|
||||
CommandObjectSP(new CommandObjectSessionHistory(interpreter)));
|
||||
}
|
||||
|
|
|
@ -457,6 +457,11 @@ void CommandInterpreter::Initialize() {
|
|||
if (cmd_obj_sp) {
|
||||
AddAlias("re", cmd_obj_sp);
|
||||
}
|
||||
|
||||
cmd_obj_sp = GetCommandSPExact("session history", false);
|
||||
if (cmd_obj_sp) {
|
||||
AddAlias("history", cmd_obj_sp);
|
||||
}
|
||||
}
|
||||
|
||||
void CommandInterpreter::Clear() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
Test the command history mechanism
|
||||
Test the session history command
|
||||
"""
|
||||
|
||||
|
||||
|
@ -10,13 +10,13 @@ from lldbsuite.test.lldbtest import *
|
|||
from lldbsuite.test import lldbutil
|
||||
|
||||
|
||||
class CommandHistoryTestCase(TestBase):
|
||||
class SessionHistoryTestCase(TestBase):
|
||||
|
||||
mydir = TestBase.compute_mydir(__file__)
|
||||
|
||||
@no_debug_info_test
|
||||
def test_history(self):
|
||||
self.runCmd('command history --clear', inHistory=False)
|
||||
self.runCmd('session history --clear', inHistory=False)
|
||||
self.runCmd('breakpoint list', check=False, inHistory=True) # 0
|
||||
self.runCmd('register read', check=False, inHistory=True) # 1
|
||||
self.runCmd('apropos hello', check=False, inHistory=True) # 2
|
||||
|
@ -32,31 +32,31 @@ class CommandHistoryTestCase(TestBase):
|
|||
self.runCmd('frame select 1', check=False, inHistory=True) # 9
|
||||
|
||||
self.expect(
|
||||
"command history -s 3 -c 3",
|
||||
"session history -s 3 -c 3",
|
||||
inHistory=True,
|
||||
substrs=[
|
||||
'3: memory write',
|
||||
'4: log list',
|
||||
'5: disassemble'])
|
||||
|
||||
self.expect("command history -s 3 -e 3", inHistory=True,
|
||||
self.expect("session history -s 3 -e 3", inHistory=True,
|
||||
substrs=['3: memory write'])
|
||||
|
||||
self.expect(
|
||||
"command history -s 6 -e 7",
|
||||
"session history -s 6 -e 7",
|
||||
inHistory=True,
|
||||
substrs=[
|
||||
'6: expression 1',
|
||||
'7: type summary list -w default'])
|
||||
|
||||
self.expect("command history -c 2", inHistory=True,
|
||||
self.expect("session history -c 2", inHistory=True,
|
||||
substrs=['0: breakpoint list', '1: register read'])
|
||||
|
||||
self.expect("command history -e 3 -c 1", inHistory=True,
|
||||
self.expect("session history -e 3 -c 1", inHistory=True,
|
||||
substrs=['3: memory write'])
|
||||
|
||||
self.expect(
|
||||
"command history -e 2",
|
||||
"session history -e 2",
|
||||
inHistory=True,
|
||||
substrs=[
|
||||
'0: breakpoint list',
|
||||
|
@ -64,43 +64,43 @@ class CommandHistoryTestCase(TestBase):
|
|||
'2: apropos hello'])
|
||||
|
||||
self.expect(
|
||||
"command history -s 12",
|
||||
"session history -s 12",
|
||||
inHistory=True,
|
||||
substrs=[
|
||||
'12: command history -s 6 -e 7',
|
||||
'13: command history -c 2',
|
||||
'14: command history -e 3 -c 1',
|
||||
'15: command history -e 2',
|
||||
'16: command history -s 12'])
|
||||
'12: session history -s 6 -e 7',
|
||||
'13: session history -c 2',
|
||||
'14: session history -e 3 -c 1',
|
||||
'15: session history -e 2',
|
||||
'16: session history -s 12'])
|
||||
|
||||
self.expect(
|
||||
"command history -s end -c 3",
|
||||
"session history -s end -c 3",
|
||||
inHistory=True,
|
||||
substrs=[
|
||||
'15: command history -e 2',
|
||||
'16: command history -s 12',
|
||||
'17: command history -s end -c 3'])
|
||||
'15: session history -e 2',
|
||||
'16: session history -s 12',
|
||||
'17: session history -s end -c 3'])
|
||||
|
||||
self.expect(
|
||||
"command history -s end -e 15",
|
||||
"session history -s end -e 15",
|
||||
inHistory=True,
|
||||
substrs=[
|
||||
'15: command history -e 2',
|
||||
'16: command history -s 12',
|
||||
'17: command history -s end -c 3',
|
||||
'command history -s end -e 15'])
|
||||
'15: session history -e 2',
|
||||
'16: session history -s 12',
|
||||
'17: session history -s end -c 3',
|
||||
'session history -s end -e 15'])
|
||||
|
||||
self.expect("command history -s 5 -c 1", inHistory=True,
|
||||
self.expect("session history -s 5 -c 1", inHistory=True,
|
||||
substrs=['5: disassemble'])
|
||||
|
||||
self.expect("command history -c 1 -s 5", inHistory=True,
|
||||
self.expect("session history -c 1 -s 5", inHistory=True,
|
||||
substrs=['5: disassemble'])
|
||||
|
||||
self.expect("command history -c 1 -e 3", inHistory=True,
|
||||
self.expect("session history -c 1 -e 3", inHistory=True,
|
||||
substrs=['3: memory write'])
|
||||
|
||||
self.expect(
|
||||
"command history -c 1 -e 3 -s 5",
|
||||
"session history -c 1 -e 3 -s 5",
|
||||
error=True,
|
||||
inHistory=True,
|
||||
substrs=['error: --count, --start-index and --end-index cannot be all specified in the same invocation'])
|
Loading…
Reference in New Issue