[Lldb-commits] [lldb] be3f8a8 - [commands] Support autorepeat in SBCommands
Walter Erquinigo via lldb-commits
lldb-commits at lists.llvm.org
Wed Apr 8 10:59:48 PDT 2020
Author: Walter Erquinigo
Date: 2020-04-08T10:54:14-07:00
New Revision: be3f8a8e1b95db1a8bdcc7a66ba27f8a6ea65469
URL: https://github.com/llvm/llvm-project/commit/be3f8a8e1b95db1a8bdcc7a66ba27f8a6ea65469
DIFF: https://github.com/llvm/llvm-project/commit/be3f8a8e1b95db1a8bdcc7a66ba27f8a6ea65469.diff
LOG: [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
Added:
lldb/unittests/API/CMakeLists.txt
lldb/unittests/API/TestSBCommandInterpreterTest.cpp
Modified:
lldb/include/lldb/API/SBCommandInterpreter.h
lldb/source/API/SBCommandInterpreter.cpp
lldb/unittests/CMakeLists.txt
Removed:
################################################################################
diff --git a/lldb/include/lldb/API/SBCommandInterpreter.h b/lldb/include/lldb/API/SBCommandInterpreter.h
index 485d4ca58de0..e07eeb58bf6a 100644
--- a/lldb/include/lldb/API/SBCommandInterpreter.h
+++ b/lldb/include/lldb/API/SBCommandInterpreter.h
@@ -111,14 +111,86 @@ class SBCommandInterpreter {
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
diff erent 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
diff erent 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 @@ class SBCommand {
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
diff erent 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
diff erent 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;
diff --git a/lldb/source/API/SBCommandInterpreter.cpp b/lldb/source/API/SBCommandInterpreter.cpp
index 4198ecc3c73f..14d738b27680 100644
--- a/lldb/source/API/SBCommandInterpreter.cpp
+++ b/lldb/source/API/SBCommandInterpreter.cpp
@@ -154,12 +154,30 @@ class CommandPluginInterfaceImplementation : public CommandObjectParsed {
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 @@ class CommandPluginInterfaceImplementation : public CommandObjectParsed {
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));
}
diff --git a/lldb/unittests/API/CMakeLists.txt b/lldb/unittests/API/CMakeLists.txt
new file mode 100644
index 000000000000..50ec47bfe00f
--- /dev/null
+++ b/lldb/unittests/API/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_lldb_unittest(APITests
+ TestSBCommandInterpreterTest.cpp
+
+ LINK_LIBS
+ liblldb
+ )
diff --git a/lldb/unittests/API/TestSBCommandInterpreterTest.cpp b/lldb/unittests/API/TestSBCommandInterpreterTest.cpp
new file mode 100644
index 000000000000..6194b6536a27
--- /dev/null
+++ b/lldb/unittests/API/TestSBCommandInterpreterTest.cpp
@@ -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");
+ }
+}
diff --git a/lldb/unittests/CMakeLists.txt b/lldb/unittests/CMakeLists.txt
index bf117030dd4b..eab053f03650 100644
--- a/lldb/unittests/CMakeLists.txt
+++ b/lldb/unittests/CMakeLists.txt
@@ -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)
More information about the lldb-commits
mailing list