forked from OSchip/llvm-project
[commands] Support autorepeat in SBCommands
Summary: This adds support for commands created through the API to support autorepeat. This covers the case of single word and multiword commands. Comprehensive tests are included as well. Reviewers: labath, clayborg Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D77444
This commit is contained in:
parent
8e40987e18
commit
be3f8a8e1b
|
@ -111,14 +111,86 @@ public:
|
|||
|
||||
lldb::SBCommand AddMultiwordCommand(const char *name, const char *help);
|
||||
|
||||
/// Add a new command to the lldb::CommandInterpreter.
|
||||
///
|
||||
/// The new command won't support autorepeat. If you need this functionality,
|
||||
/// use the override of this function that accepts the \a auto_repeat_command
|
||||
/// parameter.
|
||||
///
|
||||
/// \param[in] name
|
||||
/// The name of the command.
|
||||
///
|
||||
/// \param[in] impl
|
||||
/// The handler of this command.
|
||||
///
|
||||
/// \param[in] help
|
||||
/// The general description to show as part of the help message of this
|
||||
/// command.
|
||||
///
|
||||
/// \return
|
||||
/// A lldb::SBCommand representing the newly created command.
|
||||
lldb::SBCommand AddCommand(const char *name,
|
||||
lldb::SBCommandPluginInterface *impl,
|
||||
const char *help);
|
||||
|
||||
/// Add a new command to the lldb::CommandInterpreter.
|
||||
///
|
||||
/// The new command won't support autorepeat. If you need this functionality,
|
||||
/// use the override of this function that accepts the \a auto_repeat_command
|
||||
/// parameter.
|
||||
///
|
||||
/// \param[in] name
|
||||
/// The name of the command.
|
||||
///
|
||||
/// \param[in] impl
|
||||
/// The handler of this command.
|
||||
///
|
||||
/// \param[in] help
|
||||
/// The general description to show as part of the help message of this
|
||||
/// command.
|
||||
///
|
||||
/// \param[in] syntax
|
||||
/// The syntax to show as part of the help message of this command. This
|
||||
/// could include a description of the different arguments and flags this
|
||||
/// command accepts.
|
||||
///
|
||||
/// \return
|
||||
/// A lldb::SBCommand representing the newly created command.
|
||||
lldb::SBCommand AddCommand(const char *name,
|
||||
lldb::SBCommandPluginInterface *impl,
|
||||
const char *help, const char *syntax);
|
||||
|
||||
/// Add a new command to the lldb::CommandInterpreter.
|
||||
///
|
||||
/// \param[in] name
|
||||
/// The name of the command.
|
||||
///
|
||||
/// \param[in] impl
|
||||
/// The handler of this command.
|
||||
///
|
||||
/// \param[in] help
|
||||
/// The general description to show as part of the help message of this
|
||||
/// command.
|
||||
///
|
||||
/// \param[in] syntax
|
||||
/// The syntax to show as part of the help message of this command. This
|
||||
/// could include a description of the different arguments and flags this
|
||||
/// command accepts.
|
||||
///
|
||||
/// \param[in] auto_repeat_command
|
||||
/// Autorepeating is triggered when the user presses Enter successively
|
||||
/// after executing a command. If \b nullptr is provided, the previous
|
||||
/// exact command will be repeated. If \b "" is provided, autorepeating
|
||||
/// is disabled. Otherwise, the provided string is used as a repeat
|
||||
/// command.
|
||||
///
|
||||
/// \return
|
||||
/// A lldb::SBCommand representing the newly created command.
|
||||
lldb::SBCommand AddCommand(const char *name,
|
||||
lldb::SBCommandPluginInterface *impl,
|
||||
const char *help, const char *syntax,
|
||||
const char *auto_repeat_command);
|
||||
|
||||
void SourceInitFileInHomeDirectory(lldb::SBCommandReturnObject &result);
|
||||
|
||||
void
|
||||
|
@ -283,14 +355,90 @@ public:
|
|||
lldb::SBCommand AddMultiwordCommand(const char *name,
|
||||
const char *help = nullptr);
|
||||
|
||||
/// Add a new subcommand to the lldb::SBCommand.
|
||||
///
|
||||
/// The new command won't support autorepeat. If you need this functionality,
|
||||
/// use the override of this function that accepts the \a auto_repeat
|
||||
/// parameter.
|
||||
///
|
||||
/// \param[in] name
|
||||
/// The name of the command.
|
||||
///
|
||||
/// \param[in] impl
|
||||
/// The handler of this command.
|
||||
///
|
||||
/// \param[in] help
|
||||
/// The general description to show as part of the help message of this
|
||||
/// command.
|
||||
///
|
||||
/// \return
|
||||
/// A lldb::SBCommand representing the newly created command.
|
||||
lldb::SBCommand AddCommand(const char *name,
|
||||
lldb::SBCommandPluginInterface *impl,
|
||||
const char *help = nullptr);
|
||||
|
||||
/// Add a new subcommand to the lldb::SBCommand.
|
||||
///
|
||||
/// The new command won't support autorepeat. If you need this functionality,
|
||||
/// use the override of this function that accepts the \a auto_repeat_command
|
||||
/// parameter.
|
||||
///
|
||||
/// \param[in] name
|
||||
/// The name of the command.
|
||||
///
|
||||
/// \param[in] impl
|
||||
/// The handler of this command.
|
||||
///
|
||||
/// \param[in] help
|
||||
/// The general description to show as part of the help message of this
|
||||
/// command.
|
||||
///
|
||||
/// \param[in] syntax
|
||||
/// The syntax to show as part of the help message of this command. This
|
||||
/// could include a description of the different arguments and flags this
|
||||
/// command accepts.
|
||||
///
|
||||
/// \return
|
||||
/// A lldb::SBCommand representing the newly created command.
|
||||
lldb::SBCommand AddCommand(const char *name,
|
||||
lldb::SBCommandPluginInterface *impl,
|
||||
const char *help, const char *syntax);
|
||||
|
||||
/// Add a new subcommand to the lldb::SBCommand.
|
||||
///
|
||||
/// The new command won't support autorepeat. If you need this functionality,
|
||||
/// use the override of this function that accepts the \a auto_repeat_command
|
||||
/// parameter.
|
||||
///
|
||||
/// \param[in] name
|
||||
/// The name of the command.
|
||||
///
|
||||
/// \param[in] impl
|
||||
/// The handler of this command.
|
||||
///
|
||||
/// \param[in] help
|
||||
/// The general description to show as part of the help message of this
|
||||
/// command.
|
||||
///
|
||||
/// \param[in] syntax
|
||||
/// The syntax to show as part of the help message of this command. This
|
||||
/// could include a description of the different arguments and flags this
|
||||
/// command accepts.
|
||||
///
|
||||
/// \param[in] auto_repeat_command
|
||||
/// Autorepeating is triggered when the user presses Enter successively
|
||||
/// after executing a command. If \b nullptr is provided, the previous
|
||||
/// exact command will be repeated. If \b "" is provided, autorepeating
|
||||
/// is disabled. Otherwise, the provided string is used as a repeat
|
||||
/// command.
|
||||
///
|
||||
/// \return
|
||||
/// A lldb::SBCommand representing the newly created command.
|
||||
lldb::SBCommand AddCommand(const char *name,
|
||||
lldb::SBCommandPluginInterface *impl,
|
||||
const char *help, const char *syntax,
|
||||
const char *auto_repeat_command);
|
||||
|
||||
private:
|
||||
friend class SBDebugger;
|
||||
friend class SBCommandInterpreter;
|
||||
|
|
|
@ -154,12 +154,30 @@ public:
|
|||
lldb::SBCommandPluginInterface *backend,
|
||||
const char *help = nullptr,
|
||||
const char *syntax = nullptr,
|
||||
uint32_t flags = 0)
|
||||
uint32_t flags = 0,
|
||||
const char *auto_repeat_command = "")
|
||||
: CommandObjectParsed(interpreter, name, help, syntax, flags),
|
||||
m_backend(backend) {}
|
||||
m_backend(backend) {
|
||||
m_auto_repeat_command =
|
||||
auto_repeat_command == nullptr
|
||||
? llvm::None
|
||||
: llvm::Optional<std::string>(auto_repeat_command);
|
||||
}
|
||||
|
||||
bool IsRemovable() const override { return true; }
|
||||
|
||||
/// More documentation is available in lldb::CommandObject::GetRepeatCommand,
|
||||
/// but in short, if nullptr is returned, the previous command will be
|
||||
/// repeated, and if an empty string is returned, no commands will be
|
||||
/// executed.
|
||||
const char *GetRepeatCommand(Args ¤t_command_args,
|
||||
uint32_t index) override {
|
||||
if (!m_auto_repeat_command)
|
||||
return nullptr;
|
||||
else
|
||||
return m_auto_repeat_command->c_str();
|
||||
}
|
||||
|
||||
protected:
|
||||
bool DoExecute(Args &command, CommandReturnObject &result) override {
|
||||
SBCommandReturnObject sb_return(result);
|
||||
|
@ -170,6 +188,7 @@ protected:
|
|||
return ret;
|
||||
}
|
||||
std::shared_ptr<lldb::SBCommandPluginInterface> m_backend;
|
||||
llvm::Optional<std::string> m_auto_repeat_command;
|
||||
};
|
||||
|
||||
SBCommandInterpreter::SBCommandInterpreter(CommandInterpreter *interpreter)
|
||||
|
@ -681,14 +700,8 @@ lldb::SBCommand SBCommandInterpreter::AddCommand(
|
|||
(const char *, lldb::SBCommandPluginInterface *, const char *), name,
|
||||
impl, help);
|
||||
|
||||
lldb::CommandObjectSP new_command_sp;
|
||||
new_command_sp = std::make_shared<CommandPluginInterfaceImplementation>(
|
||||
*m_opaque_ptr, name, impl, help);
|
||||
|
||||
if (new_command_sp &&
|
||||
m_opaque_ptr->AddUserCommand(name, new_command_sp, true))
|
||||
return LLDB_RECORD_RESULT(lldb::SBCommand(new_command_sp));
|
||||
return LLDB_RECORD_RESULT(lldb::SBCommand());
|
||||
return LLDB_RECORD_RESULT(AddCommand(name, impl, help, /*syntax=*/nullptr,
|
||||
/*auto_repeat_command=*/""))
|
||||
}
|
||||
|
||||
lldb::SBCommand
|
||||
|
@ -699,10 +712,22 @@ SBCommandInterpreter::AddCommand(const char *name,
|
|||
(const char *, lldb::SBCommandPluginInterface *,
|
||||
const char *, const char *),
|
||||
name, impl, help, syntax);
|
||||
return LLDB_RECORD_RESULT(
|
||||
AddCommand(name, impl, help, syntax, /*auto_repeat_command=*/""))
|
||||
}
|
||||
|
||||
lldb::SBCommand SBCommandInterpreter::AddCommand(
|
||||
const char *name, lldb::SBCommandPluginInterface *impl, const char *help,
|
||||
const char *syntax, const char *auto_repeat_command) {
|
||||
LLDB_RECORD_METHOD(lldb::SBCommand, SBCommandInterpreter, AddCommand,
|
||||
(const char *, lldb::SBCommandPluginInterface *,
|
||||
const char *, const char *, const char *),
|
||||
name, impl, help, syntax, auto_repeat_command);
|
||||
|
||||
lldb::CommandObjectSP new_command_sp;
|
||||
new_command_sp = std::make_shared<CommandPluginInterfaceImplementation>(
|
||||
*m_opaque_ptr, name, impl, help, syntax);
|
||||
*m_opaque_ptr, name, impl, help, syntax, /*flags=*/0,
|
||||
auto_repeat_command);
|
||||
|
||||
if (new_command_sp &&
|
||||
m_opaque_ptr->AddUserCommand(name, new_command_sp, true))
|
||||
|
@ -783,17 +808,8 @@ lldb::SBCommand SBCommand::AddCommand(const char *name,
|
|||
lldb::SBCommand, SBCommand, AddCommand,
|
||||
(const char *, lldb::SBCommandPluginInterface *, const char *), name,
|
||||
impl, help);
|
||||
|
||||
if (!IsValid())
|
||||
return LLDB_RECORD_RESULT(lldb::SBCommand());
|
||||
if (!m_opaque_sp->IsMultiwordObject())
|
||||
return LLDB_RECORD_RESULT(lldb::SBCommand());
|
||||
lldb::CommandObjectSP new_command_sp;
|
||||
new_command_sp = std::make_shared<CommandPluginInterfaceImplementation>(
|
||||
m_opaque_sp->GetCommandInterpreter(), name, impl, help);
|
||||
if (new_command_sp && m_opaque_sp->LoadSubCommand(name, new_command_sp))
|
||||
return LLDB_RECORD_RESULT(lldb::SBCommand(new_command_sp));
|
||||
return LLDB_RECORD_RESULT(lldb::SBCommand());
|
||||
return LLDB_RECORD_RESULT(AddCommand(name, impl, help, /*syntax=*/nullptr,
|
||||
/*auto_repeat_command=*/""))
|
||||
}
|
||||
|
||||
lldb::SBCommand SBCommand::AddCommand(const char *name,
|
||||
|
@ -803,6 +819,18 @@ lldb::SBCommand SBCommand::AddCommand(const char *name,
|
|||
(const char *, lldb::SBCommandPluginInterface *,
|
||||
const char *, const char *),
|
||||
name, impl, help, syntax);
|
||||
return LLDB_RECORD_RESULT(
|
||||
AddCommand(name, impl, help, syntax, /*auto_repeat_command=*/""))
|
||||
}
|
||||
|
||||
lldb::SBCommand SBCommand::AddCommand(const char *name,
|
||||
lldb::SBCommandPluginInterface *impl,
|
||||
const char *help, const char *syntax,
|
||||
const char *auto_repeat_command) {
|
||||
LLDB_RECORD_METHOD(lldb::SBCommand, SBCommand, AddCommand,
|
||||
(const char *, lldb::SBCommandPluginInterface *,
|
||||
const char *, const char *, const char *),
|
||||
name, impl, help, syntax, auto_repeat_command);
|
||||
|
||||
if (!IsValid())
|
||||
return LLDB_RECORD_RESULT(lldb::SBCommand());
|
||||
|
@ -810,7 +838,8 @@ lldb::SBCommand SBCommand::AddCommand(const char *name,
|
|||
return LLDB_RECORD_RESULT(lldb::SBCommand());
|
||||
lldb::CommandObjectSP new_command_sp;
|
||||
new_command_sp = std::make_shared<CommandPluginInterfaceImplementation>(
|
||||
m_opaque_sp->GetCommandInterpreter(), name, impl, help, syntax);
|
||||
m_opaque_sp->GetCommandInterpreter(), name, impl, help, syntax,
|
||||
/*flags=*/0, auto_repeat_command);
|
||||
if (new_command_sp && m_opaque_sp->LoadSubCommand(name, new_command_sp))
|
||||
return LLDB_RECORD_RESULT(lldb::SBCommand(new_command_sp));
|
||||
return LLDB_RECORD_RESULT(lldb::SBCommand());
|
||||
|
@ -946,6 +975,9 @@ void RegisterMethods<SBCommandInterpreterRunOptions>(Registry &R) {
|
|||
LLDB_REGISTER_METHOD(lldb::SBCommand, SBCommandInterpreter, AddCommand,
|
||||
(const char *, lldb::SBCommandPluginInterface *,
|
||||
const char *, const char *));
|
||||
LLDB_REGISTER_METHOD(lldb::SBCommand, SBCommandInterpreter, AddCommand,
|
||||
(const char *, lldb::SBCommandPluginInterface *,
|
||||
const char *, const char *, const char *));
|
||||
LLDB_REGISTER_CONSTRUCTOR(SBCommand, ());
|
||||
LLDB_REGISTER_METHOD(bool, SBCommand, IsValid, ());
|
||||
LLDB_REGISTER_METHOD_CONST(bool, SBCommand, operator bool, ());
|
||||
|
@ -962,6 +994,9 @@ void RegisterMethods<SBCommandInterpreterRunOptions>(Registry &R) {
|
|||
LLDB_REGISTER_METHOD(lldb::SBCommand, SBCommand, AddCommand,
|
||||
(const char *, lldb::SBCommandPluginInterface *,
|
||||
const char *, const char *));
|
||||
LLDB_REGISTER_METHOD(lldb::SBCommand, SBCommand, AddCommand,
|
||||
(const char *, lldb::SBCommandPluginInterface *,
|
||||
const char *, const char *, const char *));
|
||||
LLDB_REGISTER_METHOD(uint32_t, SBCommand, GetFlags, ());
|
||||
LLDB_REGISTER_METHOD(void, SBCommand, SetFlags, (uint32_t));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
add_lldb_unittest(APITests
|
||||
TestSBCommandInterpreterTest.cpp
|
||||
|
||||
LINK_LIBS
|
||||
liblldb
|
||||
)
|
|
@ -0,0 +1,138 @@
|
|||
//===-- TestSBCommandInterpreterTest.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 "gtest/gtest.h"
|
||||
|
||||
#include "lldb/API/SBCommandInterpreter.h"
|
||||
#include "lldb/API/SBCommandReturnObject.h"
|
||||
#include "lldb/API/SBDebugger.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
using namespace lldb;
|
||||
|
||||
class TestSBCommandInterpreterTest : public testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
SBDebugger::Initialize();
|
||||
m_dbg = SBDebugger::Create(/*source_init_files=*/false);
|
||||
m_interp = m_dbg.GetCommandInterpreter();
|
||||
}
|
||||
|
||||
SBDebugger m_dbg;
|
||||
SBCommandInterpreter m_interp;
|
||||
};
|
||||
|
||||
class DummyCommand : public SBCommandPluginInterface {
|
||||
public:
|
||||
DummyCommand(const char *message) : m_message(message) {}
|
||||
|
||||
bool DoExecute(SBDebugger dbg, char **command,
|
||||
SBCommandReturnObject &result) {
|
||||
result.PutCString(m_message.c_str());
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_message;
|
||||
};
|
||||
|
||||
TEST_F(TestSBCommandInterpreterTest, SingleWordCommand) {
|
||||
// We first test a command without autorepeat
|
||||
DummyCommand dummy("It worked");
|
||||
m_interp.AddCommand("dummy", &dummy, /*help=*/nullptr);
|
||||
{
|
||||
SBCommandReturnObject result;
|
||||
m_interp.HandleCommand("dummy", result, /*add_to_history=*/true);
|
||||
EXPECT_TRUE(result.Succeeded());
|
||||
EXPECT_STREQ(result.GetOutput(), "It worked\n");
|
||||
}
|
||||
{
|
||||
SBCommandReturnObject result;
|
||||
m_interp.HandleCommand("", result);
|
||||
EXPECT_FALSE(result.Succeeded());
|
||||
EXPECT_STREQ(result.GetError(), "error: No auto repeat.\n");
|
||||
}
|
||||
|
||||
// Now we test a command with autorepeat
|
||||
m_interp.AddCommand("dummy_with_autorepeat", &dummy, /*help=*/nullptr,
|
||||
/*syntax=*/nullptr, /*auto_repeat_command=*/nullptr);
|
||||
{
|
||||
SBCommandReturnObject result;
|
||||
m_interp.HandleCommand("dummy_with_autorepeat", result,
|
||||
/*add_to_history=*/true);
|
||||
EXPECT_TRUE(result.Succeeded());
|
||||
EXPECT_STREQ(result.GetOutput(), "It worked\n");
|
||||
}
|
||||
{
|
||||
SBCommandReturnObject result;
|
||||
m_interp.HandleCommand("", result);
|
||||
EXPECT_TRUE(result.Succeeded());
|
||||
EXPECT_STREQ(result.GetOutput(), "It worked\n");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestSBCommandInterpreterTest, MultiWordCommand) {
|
||||
auto command = m_interp.AddMultiwordCommand("multicommand", /*help=*/nullptr);
|
||||
// We first test a subcommand without autorepeat
|
||||
DummyCommand subcommand("It worked again");
|
||||
command.AddCommand("subcommand", &subcommand, /*help=*/nullptr);
|
||||
{
|
||||
SBCommandReturnObject result;
|
||||
m_interp.HandleCommand("multicommand subcommand", result,
|
||||
/*add_to_history=*/true);
|
||||
EXPECT_TRUE(result.Succeeded());
|
||||
EXPECT_STREQ(result.GetOutput(), "It worked again\n");
|
||||
}
|
||||
{
|
||||
SBCommandReturnObject result;
|
||||
m_interp.HandleCommand("", result);
|
||||
EXPECT_FALSE(result.Succeeded());
|
||||
EXPECT_STREQ(result.GetError(), "error: No auto repeat.\n");
|
||||
}
|
||||
|
||||
// We first test a subcommand with autorepeat
|
||||
command.AddCommand("subcommand_with_autorepeat", &subcommand,
|
||||
/*help=*/nullptr, /*syntax=*/nullptr,
|
||||
/*auto_repeat_command=*/nullptr);
|
||||
{
|
||||
SBCommandReturnObject result;
|
||||
m_interp.HandleCommand("multicommand subcommand_with_autorepeat", result,
|
||||
/*add_to_history=*/true);
|
||||
EXPECT_TRUE(result.Succeeded());
|
||||
EXPECT_STREQ(result.GetOutput(), "It worked again\n");
|
||||
}
|
||||
{
|
||||
SBCommandReturnObject result;
|
||||
m_interp.HandleCommand("", result);
|
||||
EXPECT_TRUE(result.Succeeded());
|
||||
EXPECT_STREQ(result.GetOutput(), "It worked again\n");
|
||||
}
|
||||
|
||||
DummyCommand subcommand2("It worked again 2");
|
||||
// We now test a subcommand with autorepeat of the command name
|
||||
command.AddCommand(
|
||||
"subcommand_with_custom_autorepeat", &subcommand2, /*help=*/nullptr,
|
||||
/*syntax=*/nullptr,
|
||||
/*auto_repeat_command=*/"multicommand subcommand_with_autorepeat");
|
||||
{
|
||||
SBCommandReturnObject result;
|
||||
m_interp.HandleCommand("multicommand subcommand_with_custom_autorepeat",
|
||||
result, /*add_to_history=*/true);
|
||||
EXPECT_TRUE(result.Succeeded());
|
||||
EXPECT_STREQ(result.GetOutput(), "It worked again 2\n");
|
||||
}
|
||||
{
|
||||
SBCommandReturnObject result;
|
||||
m_interp.HandleCommand("", result);
|
||||
EXPECT_TRUE(result.Succeeded());
|
||||
EXPECT_STREQ(result.GetOutput(), "It worked again\n");
|
||||
}
|
||||
}
|
|
@ -59,6 +59,7 @@ function(add_unittest_inputs test_name inputs)
|
|||
endfunction()
|
||||
|
||||
add_subdirectory(TestingSupport)
|
||||
add_subdirectory(API)
|
||||
add_subdirectory(Breakpoint)
|
||||
add_subdirectory(Core)
|
||||
add_subdirectory(DataFormatter)
|
||||
|
|
Loading…
Reference in New Issue