llvm-project/lldb/source/Commands/CommandObjectRegexCommand.cpp
Med Ismail Bennani 6a9c3e6115 [lldb/Commands] Add support to auto-completion for user commands
This patch should allow the user to set specific auto-completion type
for their custom commands.

To do so, we had to hoist the `CompletionType` enum so the user can
access it and add a new completion type flag to the CommandScriptAdd
Command Object.

So now, the user can specify which completion type will be used with
their custom command, when they register it.

This also makes the `crashlog` custom commands use disk-file completion
type, to browse through the user file system and load the report.

Differential Revision: https://reviews.llvm.org/D152011

Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
2023-06-06 10:58:34 -07:00

111 lines
4.0 KiB
C++

//===-- CommandObjectRegexCommand.cpp -------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "CommandObjectRegexCommand.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
using namespace lldb;
using namespace lldb_private;
// CommandObjectRegexCommand constructor
CommandObjectRegexCommand::CommandObjectRegexCommand(
CommandInterpreter &interpreter, llvm::StringRef name, llvm::StringRef help,
llvm::StringRef syntax, uint32_t completion_type_mask, bool is_removable)
: CommandObjectRaw(interpreter, name, help, syntax),
m_completion_type_mask(completion_type_mask),
m_is_removable(is_removable) {}
// Destructor
CommandObjectRegexCommand::~CommandObjectRegexCommand() = default;
llvm::Expected<std::string> CommandObjectRegexCommand::SubstituteVariables(
llvm::StringRef input,
const llvm::SmallVectorImpl<llvm::StringRef> &replacements) {
std::string buffer;
llvm::raw_string_ostream output(buffer);
llvm::SmallVector<llvm::StringRef, 4> parts;
input.split(parts, '%');
output << parts[0];
for (llvm::StringRef part : drop_begin(parts)) {
size_t idx = 0;
if (part.consumeInteger(10, idx))
output << '%';
else if (idx < replacements.size())
output << replacements[idx];
else
return llvm::make_error<llvm::StringError>(
llvm::formatv("%{0} is out of range: not enough arguments specified",
idx),
llvm::errc::invalid_argument);
output << part;
}
return output.str();
}
bool CommandObjectRegexCommand::DoExecute(llvm::StringRef command,
CommandReturnObject &result) {
EntryCollection::const_iterator pos, end = m_entries.end();
for (pos = m_entries.begin(); pos != end; ++pos) {
llvm::SmallVector<llvm::StringRef, 4> matches;
if (pos->regex.Execute(command, &matches)) {
llvm::Expected<std::string> new_command =
SubstituteVariables(pos->command, matches);
if (!new_command) {
result.SetError(new_command.takeError());
return false;
}
// Interpret the new command and return this as the result!
if (m_interpreter.GetExpandRegexAliases())
result.GetOutputStream().Printf("%s\n", new_command->c_str());
// We don't have to pass an override_context here, as the command that
// called us should have set up the context appropriately.
bool force_repeat_command = true;
return m_interpreter.HandleCommand(new_command->c_str(), eLazyBoolNo,
result, force_repeat_command);
}
}
result.SetStatus(eReturnStatusFailed);
if (!GetSyntax().empty())
result.AppendError(GetSyntax());
else
result.GetErrorStream() << "Command contents '" << command
<< "' failed to match any "
"regular expression in the '"
<< m_cmd_name << "' regex ";
return false;
}
bool CommandObjectRegexCommand::AddRegexCommand(llvm::StringRef re_cstr,
llvm::StringRef command_cstr) {
m_entries.resize(m_entries.size() + 1);
// Only add the regular expression if it compiles
m_entries.back().regex = RegularExpression(re_cstr);
if (m_entries.back().regex.IsValid()) {
m_entries.back().command = command_cstr.str();
return true;
}
// The regex didn't compile...
m_entries.pop_back();
return false;
}
void CommandObjectRegexCommand::HandleCompletion(CompletionRequest &request) {
if (m_completion_type_mask) {
lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
GetCommandInterpreter(), m_completion_type_mask, request, nullptr);
}
}