[Lldb-commits] [lldb] [lldb] Still echo the command if we print the error. (PR #171931)

Jonas Devlieghere via lldb-commits lldb-commits at lists.llvm.org
Thu Dec 11 15:59:42 PST 2025


https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/171931

>From e36c4076c4ad4a8441cedcb8e00fdca2dbc27e99 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Thu, 11 Dec 2025 15:37:31 -0800
Subject: [PATCH 1/2] [lldb] Still echo the command if we print the error.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When the command interpreter is asked to not echo commands but still
print errors, a user has no idea what command caused the error.

For example, when I add `bogus` in my `~/.lldbinit`:

```
$ lldb
error: 'bogus' is not a valid command.
```

Things are even more confusing when we have inline diagnostics, which
point to nothing. For example, when I add `settings set target.run-args
-foo` to my `~/.lldbinit`:

```
❯ lldb
                                    ˄˜˜˜
                                    ╰─ error: unknown or ambiguous option
```

We should still echo the command if the command fails, making it obvious
which command caused the failure and fixing the inline diagnostics.

Fixes #171514
---
 .../source/Interpreter/CommandInterpreter.cpp | 22 +++++++++++++++----
 .../Shell/Settings/Inputs/FailedCommand.in    |  4 ++++
 .../Settings/TestEchoFailedCommands.test      | 10 +++++++++
 3 files changed, 32 insertions(+), 4 deletions(-)
 create mode 100644 lldb/test/Shell/Settings/Inputs/FailedCommand.in
 create mode 100644 lldb/test/Shell/Settings/TestEchoFailedCommands.test

diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index afc1753e21c46..1e359f9d08ed5 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -3283,6 +3283,7 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,
     if (line.empty())
       return;
   }
+  bool echoed_command = false;
   if (!is_interactive) {
     // When using a non-interactive file handle (like when sourcing commands
     // from a file) we need to echo the command out so we don't just see the
@@ -3291,6 +3292,7 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,
       LockedStreamFile locked_stream =
           io_handler.GetOutputStreamFileSP()->Lock();
       locked_stream.Printf("%s%s\n", io_handler.GetPrompt(), line.c_str());
+      echoed_command = true;
     }
   }
 
@@ -3310,10 +3312,22 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,
   lldb_private::CommandReturnObject result(m_debugger.GetUseColor());
   HandleCommand(line.c_str(), eLazyBoolCalculate, result);
 
-  // Now emit the command output text from the command we just executed
-  if ((result.Succeeded() &&
-       io_handler.GetFlags().Test(eHandleCommandFlagPrintResult)) ||
-      io_handler.GetFlags().Test(eHandleCommandFlagPrintErrors)) {
+  const bool print_result =
+      result.Succeeded() &&
+      io_handler.GetFlags().Test(eHandleCommandFlagPrintResult);
+  const bool print_error =
+      io_handler.GetFlags().Test(eHandleCommandFlagPrintErrors);
+
+  // Now emit the command output text from the command we just executed.
+  if (print_result || print_error) {
+    // If the command failed and we didn't echo it, echo it now so the user
+    // knows which command produced the error.
+    if (!echoed_command && !result.Succeeded() && print_error) {
+      LockedStreamFile locked_stream =
+          io_handler.GetOutputStreamFileSP()->Lock();
+      locked_stream.Printf("%s%s\n", io_handler.GetPrompt(), line.c_str());
+    }
+
     auto DefaultPrintCallback = [&](const CommandReturnObject &result) {
       // Display any inline diagnostics first.
       const bool inline_diagnostics = !result.GetImmediateErrorStream() &&
diff --git a/lldb/test/Shell/Settings/Inputs/FailedCommand.in b/lldb/test/Shell/Settings/Inputs/FailedCommand.in
new file mode 100644
index 0000000000000..c3bc5c704fe34
--- /dev/null
+++ b/lldb/test/Shell/Settings/Inputs/FailedCommand.in
@@ -0,0 +1,4 @@
+# This should succeed and not be echoed.
+expr 1+2
+# This should fail and be echoed.
+bogus_command
diff --git a/lldb/test/Shell/Settings/TestEchoFailedCommands.test b/lldb/test/Shell/Settings/TestEchoFailedCommands.test
new file mode 100644
index 0000000000000..3bb465707a41d
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestEchoFailedCommands.test
@@ -0,0 +1,10 @@
+# Test that failed commands are echoed even when echoing is disabled.
+# This ensures users can see which command produced an error.
+
+RUN: mkdir -p %t.home
+RUN: cp %S/Inputs/FailedCommand.in %t.home/.lldbinit
+RUN: env HOME=%t.home %lldb-init -b 2>&1 | FileCheck %s
+
+CHECK-NOT: expr 1+2
+CHECK: (lldb) bogus_command
+CHECK: error: 'bogus_command' is not a valid command

>From fe39fd3cb16230b0ccf889caa32c88acce7b426f Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Thu, 11 Dec 2025 15:59:27 -0800
Subject: [PATCH 2/2] Implement Adrian's suggestion

---
 lldb/source/Interpreter/CommandInterpreter.cpp | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index 1e359f9d08ed5..5e608f8caf42a 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -3289,9 +3289,8 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,
     // from a file) we need to echo the command out so we don't just see the
     // command output and no command...
     if (EchoCommandNonInteractive(line, io_handler.GetFlags())) {
-      LockedStreamFile locked_stream =
-          io_handler.GetOutputStreamFileSP()->Lock();
-      locked_stream.Printf("%s%s\n", io_handler.GetPrompt(), line.c_str());
+      io_handler.GetOutputStreamFileSP()->Lock()
+          << io_handler.GetPrompt() << line << '\n';
       echoed_command = true;
     }
   }
@@ -3323,9 +3322,8 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,
     // If the command failed and we didn't echo it, echo it now so the user
     // knows which command produced the error.
     if (!echoed_command && !result.Succeeded() && print_error) {
-      LockedStreamFile locked_stream =
-          io_handler.GetOutputStreamFileSP()->Lock();
-      locked_stream.Printf("%s%s\n", io_handler.GetPrompt(), line.c_str());
+      io_handler.GetOutputStreamFileSP()->Lock()
+          << io_handler.GetPrompt() << line << '\n';
     }
 
     auto DefaultPrintCallback = [&](const CommandReturnObject &result) {



More information about the lldb-commits mailing list