From 409c6fef0b7824ab5256ddb17a1b0312b0afd6ba Mon Sep 17 00:00:00 2001 From: Charles Zablit Date: Tue, 9 Dec 2025 19:06:16 +0000 Subject: [PATCH 1/2] [lldb] improve the heuristics for checking if a terminal supports Unicode --- lldb/include/lldb/Host/Terminal.h | 12 ++++++++++++ .../lldb/Host/common/DiagnosticsRendering.h | 19 ++++++++++++++++++- .../Host/common/DiagnosticsRendering.cpp | 11 +++++------ lldb/source/Host/common/Terminal.cpp | 15 +++++++++++++++ .../Host/common/DiagnosticsRenderingTest.cpp | 2 +- 5 files changed, 51 insertions(+), 8 deletions(-) diff --git a/lldb/include/lldb/Host/Terminal.h b/lldb/include/lldb/Host/Terminal.h index da0d05e8bd265..3d66515c18812 100644 --- a/lldb/include/lldb/Host/Terminal.h +++ b/lldb/include/lldb/Host/Terminal.h @@ -68,6 +68,18 @@ class Terminal { llvm::Error SetHardwareFlowControl(bool enabled); + /// Returns whether or not the current terminal supports Unicode rendering. + /// + /// The value is cached after the first computation. + /// + /// On POSIX systems, we check if the LANG environment variable contains the + /// substring "UTF-8", case insensitive. + /// + /// On Windows, we always return true since we use the `WriteConsoleW` API + /// internally. Note that the default Windows codepage (437) does not support + /// all Unicode characters. This function does not check the codepage. + static bool SupportsUnicode(); + protected: struct Data; diff --git a/lldb/include/lldb/Host/common/DiagnosticsRendering.h b/lldb/include/lldb/Host/common/DiagnosticsRendering.h index dd33d671c24a5..3eea0647da37e 100644 --- a/lldb/include/lldb/Host/common/DiagnosticsRendering.h +++ b/lldb/include/lldb/Host/common/DiagnosticsRendering.h @@ -59,10 +59,27 @@ struct DiagnosticDetail { StructuredData::ObjectSP Serialize(llvm::ArrayRef details); +/// Renders an array of DiagnosticDetail instances. +/// +/// \param[in] stream +/// The stream to render the diagnostics to. +/// \param offset_in_command +/// An optional offset to the column position of the diagnostic in the +/// source. +/// \param show_inline +/// Whether to show the diagnostics inline. +/// \param details +/// The array of DiagnosticsDetail to render. +/// \param force_ascii +/// Whether to force ascii rendering. If false, Unicode characters will be +/// used if the output file supports them. +/// +/// \see lldb_private::Terminal::SupportsUnicode void RenderDiagnosticDetails(Stream &stream, std::optional offset_in_command, bool show_inline, - llvm::ArrayRef details); + llvm::ArrayRef details, + bool force_ascii = false); class DiagnosticError : public llvm::ErrorInfo { diff --git a/lldb/source/Host/common/DiagnosticsRendering.cpp b/lldb/source/Host/common/DiagnosticsRendering.cpp index f2cd3968967fb..2c9d33a6c325c 100644 --- a/lldb/source/Host/common/DiagnosticsRendering.cpp +++ b/lldb/source/Host/common/DiagnosticsRendering.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/common/DiagnosticsRendering.h" +#include "lldb/Host/Terminal.h" + #include using namespace lldb_private; @@ -85,7 +87,8 @@ static llvm::raw_ostream &PrintSeverity(Stream &stream, void RenderDiagnosticDetails(Stream &stream, std::optional offset_in_command, bool show_inline, - llvm::ArrayRef details) { + llvm::ArrayRef details, + bool force_ascii) { if (details.empty()) return; @@ -97,12 +100,8 @@ void RenderDiagnosticDetails(Stream &stream, return; } - // Since there is no other way to find this out, use the color - // attribute as a proxy for whether the terminal supports Unicode - // characters. In the future it might make sense to move this into - // Host so it can be customized for a specific platform. llvm::StringRef cursor, underline, vbar, joint, hbar, spacer; - if (stream.AsRawOstream().colors_enabled()) { + if (Terminal::SupportsUnicode() && !force_ascii) { cursor = "˄"; underline = "˜"; vbar = "│"; diff --git a/lldb/source/Host/common/Terminal.cpp b/lldb/source/Host/common/Terminal.cpp index 436dfd8130d9b..dd1dc75133f45 100644 --- a/lldb/source/Host/common/Terminal.cpp +++ b/lldb/source/Host/common/Terminal.cpp @@ -400,6 +400,21 @@ llvm::Error Terminal::SetHardwareFlowControl(bool enabled) { #endif // LLDB_ENABLE_TERMIOS } +bool Terminal::SupportsUnicode() { + static std::optional result; + if (result) + return result.value(); +#ifdef _WIN32 + return true; +#else + const char *lang_var = std::getenv("LANG"); + if (!lang_var) + return false; + result = llvm::StringRef(lang_var).lower().find("utf-8") != std::string::npos; +#endif + return result.value(); +} + TerminalState::TerminalState(Terminal term, bool save_process_group) : m_tty(term) { Save(term, save_process_group); diff --git a/lldb/unittests/Host/common/DiagnosticsRenderingTest.cpp b/lldb/unittests/Host/common/DiagnosticsRenderingTest.cpp index 851b478def32e..78fc52ae11ad1 100644 --- a/lldb/unittests/Host/common/DiagnosticsRenderingTest.cpp +++ b/lldb/unittests/Host/common/DiagnosticsRenderingTest.cpp @@ -10,7 +10,7 @@ class ErrorDisplayTest : public ::testing::Test {}; std::string Render(std::vector details) { StreamString stream; - RenderDiagnosticDetails(stream, 0, true, details); + RenderDiagnosticDetails(stream, 0, true, details, true); return stream.GetData(); } } // namespace From 27f07b4f0a672ac98ee5ed9b76c5459e693bc791 Mon Sep 17 00:00:00 2001 From: Charles Zablit Date: Wed, 10 Dec 2025 12:50:18 +0000 Subject: [PATCH 2/2] address comments --- lldb/source/Host/common/Terminal.cpp | 11 ++++++----- .../Host/common/DiagnosticsRenderingTest.cpp | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lldb/source/Host/common/Terminal.cpp b/lldb/source/Host/common/Terminal.cpp index dd1dc75133f45..d3647835e3937 100644 --- a/lldb/source/Host/common/Terminal.cpp +++ b/lldb/source/Host/common/Terminal.cpp @@ -401,18 +401,19 @@ llvm::Error Terminal::SetHardwareFlowControl(bool enabled) { } bool Terminal::SupportsUnicode() { - static std::optional result; - if (result) - return result.value(); + static std::optional g_result; + if (g_result) + return g_result.value(); #ifdef _WIN32 return true; #else const char *lang_var = std::getenv("LANG"); if (!lang_var) return false; - result = llvm::StringRef(lang_var).lower().find("utf-8") != std::string::npos; + g_result = + llvm::StringRef(lang_var).lower().find("utf-8") != std::string::npos; #endif - return result.value(); + return g_result.value(); } TerminalState::TerminalState(Terminal term, bool save_process_group) diff --git a/lldb/unittests/Host/common/DiagnosticsRenderingTest.cpp b/lldb/unittests/Host/common/DiagnosticsRenderingTest.cpp index 78fc52ae11ad1..896ce1995fe1c 100644 --- a/lldb/unittests/Host/common/DiagnosticsRenderingTest.cpp +++ b/lldb/unittests/Host/common/DiagnosticsRenderingTest.cpp @@ -10,7 +10,7 @@ class ErrorDisplayTest : public ::testing::Test {}; std::string Render(std::vector details) { StreamString stream; - RenderDiagnosticDetails(stream, 0, true, details, true); + RenderDiagnosticDetails(stream, 0, true, details, /*force_ascii=*/true); return stream.GetData(); } } // namespace