Author: Ebuka Ezike Date: 2025-04-25T02:32:52+01:00 New Revision: fb01f19f3cf6b3317983b06a7dbf5ed143072990
URL: https://github.com/llvm/llvm-project/commit/fb01f19f3cf6b3317983b06a7dbf5ed143072990 DIFF: https://github.com/llvm/llvm-project/commit/fb01f19f3cf6b3317983b06a7dbf5ed143072990.diff LOG: [lldb][lldb-dap] fix repeating commands in repl mode (#135008) Fixes #131589 Add a new parameter to the RunCommands functions to control the echoing of commands --------- Signed-off-by: Ebuka Ezike <yerimy...@gmail.com> Co-authored-by: Walter Erquinigo <a20012...@gmail.com> Added: Modified: lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py lldb/tools/lldb-dap/DAP.cpp lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp lldb/tools/lldb-dap/LLDBUtils.cpp lldb/tools/lldb-dap/LLDBUtils.h Removed: ################################################################################ diff --git a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py index 251d77d79d080..e2f843bd337a6 100644 --- a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py +++ b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py @@ -101,7 +101,7 @@ def run_test_evaluate_expressions( if context == "repl": # In the repl context expressions may be interpreted as lldb # commands since no variables have the same name as the command. - self.assertEvaluate("list", r"\(lldb\) list\n.*") + self.assertEvaluate("list", r".*") else: self.assertEvaluateFailure("list") # local variable of a_function diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py index 1599ee5de7075..4303f2d3a5193 100644 --- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py +++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py @@ -523,11 +523,9 @@ def test_version(self): ) version_eval_output = version_eval_response["body"]["result"] - # The first line is the prompt line like "(lldb) version", so we skip it. - version_eval_output_without_prompt_line = version_eval_output.splitlines()[1:] version_string = self.dap_server.get_initialize_value("$__lldb_version") self.assertEqual( - version_eval_output_without_prompt_line, + version_eval_output.splitlines(), version_string.splitlines(), "version string does not match", ) diff --git a/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py b/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py index 7c77fc8541b93..c6f59949d668e 100644 --- a/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py +++ b/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py @@ -28,15 +28,12 @@ def test_completions(self): self.set_source_breakpoints(source, [breakpoint1_line, breakpoint2_line]) - self.assertEvaluate( - "`command regex user_command s/^$/platform/", r"\(lldb\) command regex" - ) - self.assertEvaluate( - "`command alias alias_command platform", r"\(lldb\) command alias" - ) + # The result of the commands should return the empty string. + self.assertEvaluate("`command regex user_command s/^$/platform/", r"^$") + self.assertEvaluate("`command alias alias_command platform", r"^$") self.assertEvaluate( "`command alias alias_command_with_arg platform select --sysroot %1 remote-linux", - r"\(lldb\) command alias", + r"^$", ) self.continue_to_next_stop() diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 134762711b89d..20ef27f6054ec 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -594,8 +594,9 @@ ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression, bool DAP::RunLLDBCommands(llvm::StringRef prefix, llvm::ArrayRef<std::string> commands) { bool required_command_failed = false; - std::string output = - ::RunLLDBCommands(debugger, prefix, commands, required_command_failed); + std::string output = ::RunLLDBCommands( + debugger, prefix, commands, required_command_failed, + /*parse_command_directives*/ true, /*echo_commands*/ true); SendOutput(OutputType::Console, output); return !required_command_failed; } diff --git a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp index 8ed09fa2a931a..5ce133c33b7e1 100644 --- a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp @@ -163,8 +163,12 @@ void EvaluateRequestHandler::operator()( if (frame.IsValid()) { dap.focus_tid = frame.GetThread().GetThreadID(); } - auto result = RunLLDBCommandsVerbatim(dap.debugger, llvm::StringRef(), - {std::string(expression)}); + + bool required_command_failed = false; + std::string result = RunLLDBCommands( + dap.debugger, llvm::StringRef(), {expression}, required_command_failed, + /*parse_command_directives=*/false, /*echo_commands=*/false); + EmplaceSafeString(body, "result", result); body.try_emplace("variablesReference", (int64_t)0); } else { diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp index a27beff0b030d..f096477cc7b49 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ b/lldb/tools/lldb-dap/LLDBUtils.cpp @@ -17,12 +17,29 @@ namespace lldb_dap { bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix, const llvm::ArrayRef<std::string> &commands, - llvm::raw_ostream &strm, bool parse_command_directives) { + llvm::raw_ostream &strm, bool parse_command_directives, + bool echo_commands) { if (commands.empty()) return true; bool did_print_prefix = false; + // We only need the prompt when echoing commands. + std::string prompt_string; + if (echo_commands) { + prompt_string = "(lldb) "; + + // Get the current prompt from settings. + if (const lldb::SBStructuredData prompt = debugger.GetSetting("prompt")) { + const size_t prompt_length = prompt.GetStringValue(nullptr, 0); + + if (prompt_length != 0) { + prompt_string.resize(prompt_length + 1); + prompt.GetStringValue(prompt_string.data(), prompt_string.length()); + } + } + } + lldb::SBCommandInterpreter interp = debugger.GetCommandInterpreter(); for (llvm::StringRef command : commands) { lldb::SBCommandReturnObject result; @@ -60,7 +77,10 @@ bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix, strm << prefix << "\n"; did_print_prefix = true; } - strm << "(lldb) " << command << "\n"; + + if (echo_commands) + strm << prompt_string.c_str() << command << '\n'; + auto output_len = result.GetOutputSize(); if (output_len) { const char *output = result.GetOutput(); @@ -81,23 +101,16 @@ bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix, std::string RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix, const llvm::ArrayRef<std::string> &commands, bool &required_command_failed, - bool parse_command_directives) { + bool parse_command_directives, bool echo_commands) { required_command_failed = false; std::string s; llvm::raw_string_ostream strm(s); - required_command_failed = !RunLLDBCommands(debugger, prefix, commands, strm, - parse_command_directives); + required_command_failed = + !RunLLDBCommands(debugger, prefix, commands, strm, + parse_command_directives, echo_commands); return s; } -std::string -RunLLDBCommandsVerbatim(lldb::SBDebugger &debugger, llvm::StringRef prefix, - const llvm::ArrayRef<std::string> &commands) { - bool required_command_failed = false; - return RunLLDBCommands(debugger, prefix, commands, required_command_failed, - /*parse_command_directives=*/false); -} - bool ThreadHasStopReason(lldb::SBThread &thread) { switch (thread.GetStopReason()) { case lldb::eStopReasonTrace: diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h index 2c57847303cb3..e4d2818a31605 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.h +++ b/lldb/tools/lldb-dap/LLDBUtils.h @@ -51,12 +51,16 @@ namespace lldb_dap { /// If \b false, then command prefixes like \b ! or \b ? are not parsed and /// each command is executed verbatim. /// +/// \param[in] echo_commands +/// If \b true, the command are echoed to the stream. +/// /// \return /// \b true, unless a command prefixed with \b ! fails and parsing of /// command directives is enabled. bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix, const llvm::ArrayRef<std::string> &commands, - llvm::raw_ostream &strm, bool parse_command_directives); + llvm::raw_ostream &strm, bool parse_command_directives, + bool echo_commands); /// Run a list of LLDB commands in the LLDB command interpreter. /// @@ -81,18 +85,17 @@ bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix, /// If \b false, then command prefixes like \b ! or \b ? are not parsed and /// each command is executed verbatim. /// +/// \param[in] echo_commands +/// If \b true, the command are echoed to the stream. +/// /// \return /// A std::string that contains the prefix and all commands and /// command output. std::string RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix, const llvm::ArrayRef<std::string> &commands, bool &required_command_failed, - bool parse_command_directives = true); - -/// Similar to the method above, but without parsing command directives. -std::string -RunLLDBCommandsVerbatim(lldb::SBDebugger &debugger, llvm::StringRef prefix, - const llvm::ArrayRef<std::string> &commands); + bool parse_command_directives = true, + bool echo_commands = false); /// Check if a thread has a stop reason. /// _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits