[lldb][repl] fix output interleaving with the status line (#183600)
This patch fixes the REPL's output from interleaving with the status line by locking the stream before printing.
This commit is contained in:
parent
c5f40ef7fe
commit
5007dd9d09
@ -144,7 +144,7 @@ protected:
|
||||
virtual lldb::LanguageType GetLanguage() = 0;
|
||||
|
||||
virtual bool PrintOneVariable(Debugger &debugger,
|
||||
lldb::StreamFileSP &output_sp,
|
||||
lldb::LockableStreamFileSP &output_stream_sp,
|
||||
lldb::ValueObjectSP &valobj_sp,
|
||||
ExpressionVariable *var = nullptr) = 0;
|
||||
|
||||
|
||||
@ -189,29 +189,30 @@ int REPL::IOHandlerFixIndentation(IOHandler &io_handler,
|
||||
}
|
||||
|
||||
static bool ReadCode(const std::string &path, std::string &code,
|
||||
lldb::StreamFileSP &error_sp) {
|
||||
lldb::LockableStreamFileSP &error_stream_sp) {
|
||||
auto &fs = FileSystem::Instance();
|
||||
llvm::Twine pathTwine(path);
|
||||
if (!fs.Exists(pathTwine)) {
|
||||
error_sp->Printf("no such file at path '%s'\n", path.c_str());
|
||||
error_stream_sp->Lock().Printf("no such file at path '%s'\n", path.c_str());
|
||||
return false;
|
||||
}
|
||||
if (!fs.Readable(pathTwine)) {
|
||||
error_sp->Printf("could not read file at path '%s'\n", path.c_str());
|
||||
error_stream_sp->Lock().Printf("could not read file at path '%s'\n",
|
||||
path.c_str());
|
||||
return false;
|
||||
}
|
||||
const size_t file_size = fs.GetByteSize(pathTwine);
|
||||
const size_t max_size = code.max_size();
|
||||
if (file_size > max_size) {
|
||||
error_sp->Printf("file at path '%s' too large: "
|
||||
"file_size = %zu, max_size = %zu\n",
|
||||
path.c_str(), file_size, max_size);
|
||||
error_stream_sp->Lock().Printf("file at path '%s' too large: "
|
||||
"file_size = %zu, max_size = %zu\n",
|
||||
path.c_str(), file_size, max_size);
|
||||
return false;
|
||||
}
|
||||
auto data_sp = fs.CreateDataBuffer(pathTwine);
|
||||
if (data_sp == nullptr) {
|
||||
error_sp->Printf("could not create buffer for file at path '%s'\n",
|
||||
path.c_str());
|
||||
error_stream_sp->Lock().Printf(
|
||||
"could not create buffer for file at path '%s'\n", path.c_str());
|
||||
return false;
|
||||
}
|
||||
code.assign((const char *)data_sp->GetBytes(), data_sp->GetByteSize());
|
||||
@ -219,10 +220,10 @@ static bool ReadCode(const std::string &path, std::string &code,
|
||||
}
|
||||
|
||||
void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
|
||||
lldb::StreamFileSP output_sp = std::make_shared<StreamFile>(
|
||||
io_handler.GetOutputStreamFileSP()->GetUnlockedFileSP());
|
||||
lldb::StreamFileSP error_sp = std::make_shared<StreamFile>(
|
||||
io_handler.GetErrorStreamFileSP()->GetUnlockedFileSP());
|
||||
lldb::LockableStreamFileSP output_stream_sp =
|
||||
io_handler.GetOutputStreamFileSP();
|
||||
lldb::LockableStreamFileSP error_stream_sp =
|
||||
io_handler.GetErrorStreamFileSP();
|
||||
bool extra_line = false;
|
||||
bool did_quit = false;
|
||||
|
||||
@ -258,8 +259,10 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
|
||||
|
||||
// Execute the command
|
||||
CommandReturnObject result(debugger.GetUseColor());
|
||||
result.SetImmediateOutputStream(output_sp);
|
||||
result.SetImmediateErrorStream(error_sp);
|
||||
result.SetImmediateOutputStream(std::make_shared<StreamFile>(
|
||||
output_stream_sp->GetUnlockedFileSP()));
|
||||
result.SetImmediateErrorStream(
|
||||
std::make_shared<StreamFile>(error_stream_sp->GetUnlockedFileSP()));
|
||||
ci.HandleCommand(code.c_str(), eLazyBoolNo, result);
|
||||
|
||||
if (saved_prompt_on_quit)
|
||||
@ -302,7 +305,7 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
|
||||
// User wants to read code from a file.
|
||||
// Interpret rest of line as a literal path.
|
||||
auto path = llvm::StringRef(code.substr(1)).trim().str();
|
||||
if (!ReadCode(path, code, error_sp)) {
|
||||
if (!ReadCode(path, code, error_stream_sp)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -318,7 +321,8 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
|
||||
}
|
||||
}
|
||||
|
||||
const bool colorize_err = error_sp->GetFile().GetIsTerminalWithColors();
|
||||
const bool colorize_err =
|
||||
error_stream_sp->Lock().GetFile().GetIsTerminalWithColors();
|
||||
|
||||
EvaluateExpressionOptions expr_options = m_expr_options;
|
||||
expr_options.SetCoerceToId(m_varobj_options.use_object_desc);
|
||||
@ -347,7 +351,7 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
|
||||
if (llvm::Error err = OnExpressionEvaluated(exe_ctx, code, expr_options,
|
||||
execution_results,
|
||||
result_valobj_sp, error)) {
|
||||
*error_sp << llvm::toString(std::move(err)) << "\n";
|
||||
error_stream_sp->Lock() << llvm::toString(std::move(err)) << "\n";
|
||||
} else if (process_sp && process_sp->IsAlive()) {
|
||||
bool add_to_code = true;
|
||||
bool handled = false;
|
||||
@ -355,11 +359,12 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
|
||||
lldb::Format format = m_format_options.GetFormat();
|
||||
|
||||
if (result_valobj_sp->GetError().Success()) {
|
||||
handled |= PrintOneVariable(debugger, output_sp, result_valobj_sp);
|
||||
handled |=
|
||||
PrintOneVariable(debugger, output_stream_sp, result_valobj_sp);
|
||||
} else if (result_valobj_sp->GetError().GetError() ==
|
||||
UserExpression::kNoResult) {
|
||||
if (format != lldb::eFormatVoid && debugger.GetNotifyVoid()) {
|
||||
error_sp->PutCString("(void)\n");
|
||||
error_stream_sp->Lock().PutCString("(void)\n");
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
@ -372,48 +377,53 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
|
||||
persistent_state->GetVariableAtIndex(vi);
|
||||
lldb::ValueObjectSP valobj_sp = persistent_var_sp->GetValueObject();
|
||||
|
||||
PrintOneVariable(debugger, output_sp, valobj_sp,
|
||||
PrintOneVariable(debugger, output_stream_sp, valobj_sp,
|
||||
persistent_var_sp.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
bool useColors = error_sp->GetFile().GetIsTerminalWithColors();
|
||||
LockedStreamFile locked_error_stream = error_stream_sp->Lock();
|
||||
bool useColors =
|
||||
locked_error_stream.GetFile().GetIsTerminalWithColors();
|
||||
switch (execution_results) {
|
||||
case lldb::eExpressionSetupError:
|
||||
case lldb::eExpressionParseError:
|
||||
add_to_code = false;
|
||||
[[fallthrough]];
|
||||
case lldb::eExpressionDiscarded:
|
||||
error_sp->Printf("%s\n", error.AsCString());
|
||||
locked_error_stream.Printf("%s\n", error.AsCString());
|
||||
break;
|
||||
|
||||
case lldb::eExpressionCompleted:
|
||||
break;
|
||||
case lldb::eExpressionInterrupted:
|
||||
if (useColors) {
|
||||
error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
|
||||
error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
|
||||
locked_error_stream.Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
|
||||
locked_error_stream.Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
|
||||
}
|
||||
error_sp->Printf("Execution interrupted. ");
|
||||
locked_error_stream.Printf("Execution interrupted. ");
|
||||
if (useColors)
|
||||
error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
|
||||
error_sp->Printf("Enter code to recover and continue.\nEnter LLDB "
|
||||
"commands to investigate (type :help for "
|
||||
"assistance.)\n");
|
||||
locked_error_stream.Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
|
||||
locked_error_stream.Printf(
|
||||
"Enter code to recover and continue.\nEnter LLDB "
|
||||
"commands to investigate (type :help for "
|
||||
"assistance.)\n");
|
||||
break;
|
||||
|
||||
case lldb::eExpressionHitBreakpoint:
|
||||
// Breakpoint was hit, drop into LLDB command interpreter
|
||||
if (useColors) {
|
||||
error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
|
||||
error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
|
||||
locked_error_stream.Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
|
||||
locked_error_stream.Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
|
||||
}
|
||||
output_sp->Printf("Execution stopped at breakpoint. ");
|
||||
output_stream_sp->Lock().Printf(
|
||||
"Execution stopped at breakpoint. ");
|
||||
if (useColors)
|
||||
error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
|
||||
output_sp->Printf("Enter LLDB commands to investigate (type help "
|
||||
"for assistance.)\n");
|
||||
locked_error_stream.Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
|
||||
locked_error_stream.Printf(
|
||||
"Enter LLDB commands to investigate (type help "
|
||||
"for assistance.)\n");
|
||||
{
|
||||
lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
|
||||
if (io_handler_sp) {
|
||||
@ -424,24 +434,24 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
|
||||
break;
|
||||
|
||||
case lldb::eExpressionTimedOut:
|
||||
error_sp->Printf("error: timeout\n");
|
||||
locked_error_stream.Printf("error: timeout\n");
|
||||
if (error.AsCString())
|
||||
error_sp->Printf("error: %s\n", error.AsCString());
|
||||
locked_error_stream.Printf("error: %s\n", error.AsCString());
|
||||
break;
|
||||
case lldb::eExpressionResultUnavailable:
|
||||
// Shoulnd't happen???
|
||||
error_sp->Printf("error: could not fetch result -- %s\n",
|
||||
error.AsCString());
|
||||
locked_error_stream.Printf("error: could not fetch result -- %s\n",
|
||||
error.AsCString());
|
||||
break;
|
||||
case lldb::eExpressionStoppedForDebug:
|
||||
// Shoulnd't happen???
|
||||
error_sp->Printf("error: stopped for debug -- %s\n",
|
||||
error.AsCString());
|
||||
locked_error_stream.Printf("error: stopped for debug -- %s\n",
|
||||
error.AsCString());
|
||||
break;
|
||||
case lldb::eExpressionThreadVanished:
|
||||
// Shoulnd't happen???
|
||||
error_sp->Printf("error: expression thread vanished -- %s\n",
|
||||
error.AsCString());
|
||||
locked_error_stream.Printf(
|
||||
"error: expression thread vanished -- %s\n", error.AsCString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -466,8 +476,9 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
|
||||
file.get()->Close();
|
||||
} else {
|
||||
std::string message = llvm::toString(file.takeError());
|
||||
error_sp->Printf("error: couldn't open %s: %s\n",
|
||||
m_repl_source_path.c_str(), message.c_str());
|
||||
error_stream_sp->Lock().Printf("error: couldn't open %s: %s\n",
|
||||
m_repl_source_path.c_str(),
|
||||
message.c_str());
|
||||
}
|
||||
|
||||
// Now set the default file and line to the REPL source file
|
||||
@ -478,16 +489,15 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
|
||||
static_cast<IOHandlerEditline &>(io_handler)
|
||||
.SetBaseLineNumber(m_code.GetSize() + 1);
|
||||
}
|
||||
if (extra_line) {
|
||||
output_sp->Printf("\n");
|
||||
}
|
||||
if (extra_line)
|
||||
output_stream_sp->Lock().Printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Don't complain about the REPL process going away if we are in the
|
||||
// process of quitting.
|
||||
if (!did_quit && (!process_sp || !process_sp->IsAlive())) {
|
||||
error_sp->Printf(
|
||||
error_stream_sp->Lock().Printf(
|
||||
"error: REPL process is no longer alive, exiting REPL\n");
|
||||
io_handler.SetIsDone(true);
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@ lldb::offset_t ClangREPL::GetDesiredIndentation(const StringList &lines,
|
||||
lldb::LanguageType ClangREPL::GetLanguage() { return m_language; }
|
||||
|
||||
bool ClangREPL::PrintOneVariable(Debugger &debugger,
|
||||
lldb::StreamFileSP &output_sp,
|
||||
lldb::LockableStreamFileSP &output_stream_sp,
|
||||
lldb::ValueObjectSP &valobj_sp,
|
||||
ExpressionVariable *var) {
|
||||
// If a ExpressionVariable was passed, check first if that variable is just
|
||||
@ -95,8 +95,15 @@ bool ClangREPL::PrintOneVariable(Debugger &debugger,
|
||||
if (m_implicit_expr_result_regex.Execute(var->GetName().GetStringRef()))
|
||||
return true;
|
||||
}
|
||||
if (llvm::Error error = valobj_sp->Dump(*output_sp))
|
||||
*output_sp << "error: " << toString(std::move(error));
|
||||
|
||||
{
|
||||
// Suspend the statusline while printing to prevent its ANSI cursor
|
||||
// save/restore sequences from interleaving with the output.
|
||||
LockedStreamFile locked_stream = output_stream_sp->Lock();
|
||||
|
||||
if (llvm::Error error = valobj_sp->Dump(locked_stream))
|
||||
locked_stream << "error: " << toString(std::move(error));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -48,7 +48,8 @@ protected:
|
||||
|
||||
lldb::LanguageType GetLanguage() override;
|
||||
|
||||
bool PrintOneVariable(Debugger &debugger, lldb::StreamFileSP &output_sp,
|
||||
bool PrintOneVariable(Debugger &debugger,
|
||||
lldb::LockableStreamFileSP &output_stream_sp,
|
||||
lldb::ValueObjectSP &valobj_sp,
|
||||
ExpressionVariable *var = nullptr) override;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user