
Most commands were adding argument completion handling by themselves, resulting in a lot of unnecessary boilerplate. In many cases, this could be done generically given the argument definition and the entries in the g_argument_table. I'm going to address this in a couple passes. In this first pass, I added handling of commands that have only one argument list, with one argument type, either single or repeated, and changed all the commands that are of this sort (and don't have other bits of business in their completers.) I also added some missing connections between arg types and completions to the table, and added a RemoteFilename and RemotePath to use in places where we were using the Remote completers. Those arguments used to say they were "files" but they were in fact remote files. I also added a module arg type to use where we were using the module completer. In that case, we should call the argument module.
198 lines
7.0 KiB
C++
198 lines
7.0 KiB
C++
#include "CommandObjectSession.h"
|
|
#include "lldb/Host/OptionParser.h"
|
|
#include "lldb/Interpreter/CommandInterpreter.h"
|
|
#include "lldb/Interpreter/CommandOptionArgumentTable.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;
|
|
|
|
class CommandObjectSessionSave : public CommandObjectParsed {
|
|
public:
|
|
CommandObjectSessionSave(CommandInterpreter &interpreter)
|
|
: CommandObjectParsed(interpreter, "session save",
|
|
"Save the current session transcripts to a file.\n"
|
|
"If no file if specified, transcripts will be "
|
|
"saved to a temporary file.",
|
|
"session save [file]") {
|
|
CommandArgumentEntry arg1;
|
|
arg1.emplace_back(eArgTypePath, eArgRepeatOptional);
|
|
m_arguments.push_back(arg1);
|
|
}
|
|
|
|
~CommandObjectSessionSave() override = default;
|
|
|
|
protected:
|
|
void DoExecute(Args &args, CommandReturnObject &result) override {
|
|
llvm::StringRef file_path;
|
|
|
|
if (!args.empty())
|
|
file_path = args[0].ref();
|
|
|
|
if (m_interpreter.SaveTranscript(result, file_path.str()))
|
|
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
|
else
|
|
result.SetStatus(eReturnStatusFailed);
|
|
}
|
|
};
|
|
|
|
#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) {}
|
|
|
|
~CommandObjectSessionHistory() override = default;
|
|
|
|
Options *GetOptions() override { return &m_options; }
|
|
|
|
protected:
|
|
class CommandOptions : public Options {
|
|
public:
|
|
CommandOptions()
|
|
: 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::ArrayRef(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;
|
|
};
|
|
|
|
void 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
CommandOptions m_options;
|
|
};
|
|
|
|
CommandObjectSession::CommandObjectSession(CommandInterpreter &interpreter)
|
|
: CommandObjectMultiword(interpreter, "session",
|
|
"Commands controlling LLDB session.",
|
|
"session <subcommand> [<command-options>]") {
|
|
LoadSubCommand("save",
|
|
CommandObjectSP(new CommandObjectSessionSave(interpreter)));
|
|
LoadSubCommand("history",
|
|
CommandObjectSP(new CommandObjectSessionHistory(interpreter)));
|
|
}
|