[lldb/Interpreter] Add `interpreter.repeat-previous-command` setting
authorMed Ismail Bennani <medismail.bennani@gmail.com>
Fri, 5 Mar 2021 18:30:48 +0000 (18:30 +0000)
committerMed Ismail Bennani <medismail.bennani@gmail.com>
Fri, 5 Mar 2021 18:33:32 +0000 (19:33 +0100)
This patch introduces a new interpreter setting to prevent LLDB from
re-executing the previous command when passing an empty command.

This can be very useful when performing actions that requires a long
time to complete.

To preserve the original behaviour, the setting defaults to `true`.

rdar://74983516

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

Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
lldb/include/lldb/Interpreter/CommandInterpreter.h
lldb/source/Interpreter/CommandInterpreter.cpp
lldb/source/Interpreter/InterpreterProperties.td
lldb/test/API/commands/settings/TestSettings.py

index 7f897bf..5b5f145 100644 (file)
@@ -504,6 +504,8 @@ public:
   bool GetEchoCommentCommands() const;
   void SetEchoCommentCommands(bool enable);
 
+  bool GetRepeatPreviousCommand() const;
+
   const CommandObject::CommandMap &GetUserCommands() const {
     return m_user_dict;
   }
index b0ff634..eeef14b 100644 (file)
@@ -223,6 +223,12 @@ bool CommandInterpreter::GetSpaceReplPrompts() const {
       nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
 }
 
+bool CommandInterpreter::GetRepeatPreviousCommand() const {
+  const uint32_t idx = ePropertyRepeatPreviousCommand;
+  return m_collection_sp->GetPropertyAtIndexAsBoolean(
+      nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
+}
+
 void CommandInterpreter::Initialize() {
   LLDB_SCOPED_TIMER();
 
@@ -1695,6 +1701,11 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
   }
 
   if (empty_command) {
+    if (!GetRepeatPreviousCommand()) {
+      result.SetStatus(eReturnStatusSuccessFinishNoResult);
+      return true;
+    }
+
     if (m_command_history.IsEmpty()) {
       result.AppendError("empty command");
       result.SetStatus(eReturnStatusFailed);
index e5346d1..1148c1b 100644 (file)
@@ -29,4 +29,8 @@ let Definition = "interpreter" in {
     Global,
     DefaultTrue,
     Desc<"If true, commands will be echoed even if they are pure comment lines.">;
+  def RepeatPreviousCommand: Property<"repeat-previous-command", "Boolean">,
+    Global,
+    DefaultTrue,
+    Desc<"If true, LLDB will repeat the previous command if no command was passed to the interpreter. If false, LLDB won't repeat the previous command but only return a new prompt.">;
 }
index c3cfdab..7eab23a 100644 (file)
@@ -25,6 +25,42 @@ class SettingsCommandTestCase(TestBase):
                              "environment variables",
                              "executable's environment"])
 
+    def test_set_interpreter_repeat_prev_command(self):
+        """Test the `interpreter.repeat-previous-command` setting."""
+        self.build()
+
+        exe = self.getBuildArtifact("a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+        setting = "interpreter.repeat-previous-command"
+
+        def cleanup(setting):
+            self.runCmd(
+                "settings clear %s" %
+                setting, check=False)
+
+        # Execute the cleanup function during test case tear down.
+        self.addTearDownHook(cleanup(setting))
+
+        # First, check for the setting default value.
+        self.expect("setting show %s" % setting,
+                    substrs=["interpreter.repeat-previous-command (boolean) = true"])
+
+        # Then, invert the setting, and check that was set correctly
+        self.runCmd("setting set %s false" % setting)
+        self.expect("setting show %s" % setting,
+                    substrs=["interpreter.repeat-previous-command (boolean) = false"])
+
+
+        ci  = self.dbg.GetCommandInterpreter()
+        self.assertTrue(ci.IsValid(), "Invalid command interpreter.")
+        # Now, test the functionnality
+        res = lldb.SBCommandReturnObject()
+        ci.HandleCommand('breakpoint set -n main', res)
+        self.assertTrue(res.Succeeded(), "Command failed.")
+        ci.HandleCommand('', res)
+        self.assertTrue(res.Succeeded(), "Empty command failed.")
+        self.assertEqual(self.dbg.GetSelectedTarget().GetNumBreakpoints(), 1)
+
     def test_append_target_env_vars(self):
         """Test that 'append target.run-args' works."""
         # Append the env-vars.