diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index afc1753e21c46..5e608f8caf42a 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -3283,14 +3283,15 @@ 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 // 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; } } @@ -3310,10 +3311,21 @@ 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) { + io_handler.GetOutputStreamFileSP()->Lock() + << io_handler.GetPrompt() << line << '\n'; + } + 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