wallace created this revision.
wallace added reviewers: labath, clayborg.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.
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.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D77444
Files:
lldb/include/lldb/API/SBCommandInterpreter.h
lldb/source/API/SBCommandInterpreter.cpp
lldb/test/API/api/auto-repeat-command/Makefile
lldb/test/API/api/auto-repeat-command/TestSBCommandAutoRepeat.py
lldb/test/API/api/auto-repeat-command/main.cpp
Index: lldb/test/API/api/auto-repeat-command/main.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/api/auto-repeat-command/main.cpp
@@ -0,0 +1,109 @@
+#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBCommandReturnObject.h"
+#include "lldb/API/SBDebugger.h"
+
+#include <cassert>
+#include <cstring>
+#include <string>
+
+using namespace lldb;
+
+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;
+};
+
+void testSingleWordCommand(SBCommandInterpreter &interp, SBDebugger &dbg) {
+ // We first test a command without autorepeat
+ DummyCommand dummy("It worked");
+ interp.AddCommand("dummy", &dummy, nullptr /*help*/);
+ {
+ SBCommandReturnObject result;
+ dbg.GetCommandInterpreter().HandleCommand("dummy", result,
+ true /*add_to_history*/);
+ assert(result.Succeeded());
+ assert(strcmp(result.GetOutput(), "It worked\n") == 0);
+ }
+ {
+ SBCommandReturnObject result;
+ dbg.GetCommandInterpreter().HandleCommand("", result);
+ assert(!result.Succeeded() &&
+ "The command should fail as a repeated command");
+ assert(strcmp(result.GetError(), "error: No auto repeat.\n") == 0);
+ }
+
+ // Now we test a command with autorepeat
+ interp.AddCommand("dummy_with_autorepeat", &dummy, nullptr /*help*/,
+ nullptr /*syntax*/, true /*autorepeat*/);
+ {
+ SBCommandReturnObject result;
+ dbg.GetCommandInterpreter().HandleCommand("dummy_with_autorepeat", result,
+ true /*add_to_history*/);
+ assert(result.Succeeded());
+ assert(strcmp(result.GetOutput(), "It worked\n") == 0);
+ }
+ {
+ SBCommandReturnObject result;
+ dbg.GetCommandInterpreter().HandleCommand("", result);
+ assert(result.Succeeded());
+ assert(strcmp(result.GetOutput(), "It worked\n") == 0);
+ }
+}
+
+void testMultiWordCommand(SBCommandInterpreter &interp, SBDebugger &dbg) {
+ auto command = interp.AddMultiwordCommand("multicommand", nullptr /*help*/);
+ // We first test a subcommand without autorepeat
+ DummyCommand subcommand("It worked again");
+ command.AddCommand("subcommand", &subcommand, nullptr /*help*/);
+ {
+ SBCommandReturnObject result;
+ dbg.GetCommandInterpreter().HandleCommand("multicommand subcommand", result,
+ true /*add_to_history*/);
+ assert(result.Succeeded());
+ assert(strcmp(result.GetOutput(), "It worked again\n") == 0);
+ }
+ {
+ SBCommandReturnObject result;
+ dbg.GetCommandInterpreter().HandleCommand("", result);
+ assert(!result.Succeeded() &&
+ "The command should fail as a repeated command");
+ assert(strcmp(result.GetError(), "error: No auto repeat.\n") == 0);
+ }
+
+ // We first test a subcommand with autorepeat
+ command.AddCommand("subcommand_with_autorepeat", &subcommand,
+ nullptr /*help*/, nullptr /*syntax*/, true /*autorepeat*/);
+ {
+ SBCommandReturnObject result;
+ dbg.GetCommandInterpreter().HandleCommand(
+ "multicommand subcommand_with_autorepeat", result,
+ true /*add_to_history*/);
+ assert(result.Succeeded());
+ assert(strcmp(result.GetOutput(), "It worked again\n") == 0);
+ }
+ {
+ SBCommandReturnObject result;
+ dbg.GetCommandInterpreter().HandleCommand("", result);
+ assert(result.Succeeded());
+ assert(strcmp(result.GetOutput(), "It worked again\n") == 0);
+ }
+}
+
+int main() {
+ SBDebugger::Initialize();
+ SBDebugger dbg = SBDebugger::Create(false /*source_init_files*/);
+ SBCommandInterpreter interp = dbg.GetCommandInterpreter();
+
+ testSingleWordCommand(interp, dbg);
+ testMultiWordCommand(interp, dbg);
+}
Index: lldb/test/API/api/auto-repeat-command/TestSBCommandAutoRepeat.py
===================================================================
--- /dev/null
+++ lldb/test/API/api/auto-repeat-command/TestSBCommandAutoRepeat.py
@@ -0,0 +1,34 @@
+"""Test the lldb public C++ api for returning SBCommandReturnObject."""
+
+from __future__ import print_function
+
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestSBCommandAutoRepeat(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+ NO_DEBUG_INFO_TESTCASE = True
+
+ @skipIfNoSBHeaders
+ @expectedFailureAll(
+ oslist=["windows"],
+ bugnumber="llvm.org/pr43570")
+ def test_sb_command_return_object(self):
+ env = {self.dylibPath: self.getLLDBLibraryEnvVal()}
+
+ self.driver_exe = self.getBuildArtifact("auto-repeat-command")
+ self.buildDriver('main.cpp', self.driver_exe)
+ self.addTearDownHook(lambda: os.remove(self.driver_exe))
+ self.signBinary(self.driver_exe)
+
+ if self.TraceOn():
+ print("Running test %s" % self.driver_exe)
+ check_call([self.driver_exe, self.driver_exe], env=env)
+ else:
+ with open(os.devnull, 'w') as fnull:
+ check_call([self.driver_exe, self.driver_exe],
+ env=env, stdout=fnull, stderr=fnull)
Index: lldb/test/API/api/auto-repeat-command/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/api/auto-repeat-command/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
Index: lldb/source/API/SBCommandInterpreter.cpp
===================================================================
--- lldb/source/API/SBCommandInterpreter.cpp
+++ lldb/source/API/SBCommandInterpreter.cpp
@@ -154,12 +154,22 @@
lldb::SBCommandPluginInterface *backend,
const char *help = nullptr,
const char *syntax = nullptr,
- uint32_t flags = 0)
+ uint32_t flags = 0,
+ bool auto_repeat = false)
: CommandObjectParsed(interpreter, name, help, syntax, flags),
- m_backend(backend) {}
+ m_backend(backend), m_auto_repeat(auto_repeat) {}
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 {
+ return m_auto_repeat ? nullptr : "";
+ }
+
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override {
SBCommandReturnObject sb_return(result);
@@ -170,6 +180,7 @@
return ret;
}
std::shared_ptr<lldb::SBCommandPluginInterface> m_backend;
+ bool m_auto_repeat;
};
SBCommandInterpreter::SBCommandInterpreter(CommandInterpreter *interpreter)
@@ -710,6 +721,24 @@
return LLDB_RECORD_RESULT(lldb::SBCommand());
}
+lldb::SBCommand SBCommandInterpreter::AddCommand(
+ const char *name, lldb::SBCommandPluginInterface *impl, const char *help,
+ const char *syntax, bool auto_repeat) {
+ LLDB_RECORD_METHOD(lldb::SBCommand, SBCommandInterpreter, AddCommand,
+ (const char *, lldb::SBCommandPluginInterface *,
+ const char *, const char *, bool),
+ name, impl, help, syntax, auto_repeat);
+
+ lldb::CommandObjectSP new_command_sp;
+ new_command_sp = std::make_shared<CommandPluginInterfaceImplementation>(
+ *m_opaque_ptr, name, impl, help, syntax, 0 /*flags*/, auto_repeat);
+
+ 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());
+}
+
SBCommand::SBCommand() { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBCommand); }
SBCommand::SBCommand(lldb::CommandObjectSP cmd_sp) : m_opaque_sp(cmd_sp) {}
@@ -816,6 +845,28 @@
return LLDB_RECORD_RESULT(lldb::SBCommand());
}
+lldb::SBCommand SBCommand::AddCommand(const char *name,
+ lldb::SBCommandPluginInterface *impl,
+ const char *help, const char *syntax,
+ bool auto_repeat) {
+ LLDB_RECORD_METHOD(lldb::SBCommand, SBCommand, AddCommand,
+ (const char *, lldb::SBCommandPluginInterface *,
+ const char *, const char *, bool),
+ name, impl, help, syntax, auto_repeat);
+
+ 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, syntax,
+ 0 /*flags*/, auto_repeat);
+ 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());
+}
+
uint32_t SBCommand::GetFlags() {
LLDB_RECORD_METHOD_NO_ARGS(uint32_t, SBCommand, GetFlags);
@@ -946,6 +997,9 @@
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 *, bool));
LLDB_REGISTER_CONSTRUCTOR(SBCommand, ());
LLDB_REGISTER_METHOD(bool, SBCommand, IsValid, ());
LLDB_REGISTER_METHOD_CONST(bool, SBCommand, operator bool, ());
@@ -962,6 +1016,9 @@
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 *, bool));
LLDB_REGISTER_METHOD(uint32_t, SBCommand, GetFlags, ());
LLDB_REGISTER_METHOD(void, SBCommand, SetFlags, (uint32_t));
}
Index: lldb/include/lldb/API/SBCommandInterpreter.h
===================================================================
--- lldb/include/lldb/API/SBCommandInterpreter.h
+++ lldb/include/lldb/API/SBCommandInterpreter.h
@@ -111,14 +111,84 @@
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
+ /// 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
+ /// 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
+ /// Flag that controls whether to accept autorepeating or not.
+ /// Autorepeating is triggered when the user presses Enter successively
+ /// after executing a 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,
+ bool auto_repeat);
+
void SourceInitFileInHomeDirectory(lldb::SBCommandReturnObject &result);
void
@@ -283,14 +353,88 @@
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
+ /// 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
+ /// 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
+ /// Flag that controls whether to accept autorepeating or not.
+ /// Autorepeating is triggered when the user presses Enter successively
+ /// after executing a 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,
+ bool auto_repeat);
+
private:
friend class SBDebugger;
friend class SBCommandInterpreter;
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits