
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>
111 lines
4.0 KiB
C++
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);
|
|
}
|
|
}
|