llvm-project/lldb/source/Commands/CommandObjectSession.cpp
jimingham 21631494b0
Centralize the handling of completion for simple argument lists. (#82085)
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.
2024-02-19 16:43:08 -08:00

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)));
}