Skip to content

Commit 71e8e6a

Browse files
charles-zablitgithub-actions[bot]
authored andcommitted
Automerge: [lldb] improve the heuristics for checking if a terminal supports Unicode (#171832)
This patch improves the way lldb checks if the terminal it's opened in (if any) supports Unicode or not. On POSIX systems, we check if `LANG` contains `UTF-8`. On Windows, we always return `true` since we use the `WriteToConsoleW` api. This is a relanding of llvm/llvm-project#168603. The tests failed because the bots support Unicode but the tests expect ASCII. To avoid different outputs depending on the environment the tests are running in, this patch always force ASCII in the tests.
2 parents f1da82e + 7345233 commit 71e8e6a

File tree

8 files changed

+70
-25
lines changed

8 files changed

+70
-25
lines changed

lldb/include/lldb/Host/Terminal.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,18 @@ class Terminal {
6868

6969
llvm::Error SetHardwareFlowControl(bool enabled);
7070

71+
/// Returns whether or not the current terminal supports Unicode rendering.
72+
///
73+
/// The value is cached after the first computation.
74+
///
75+
/// On POSIX systems, we check if the LANG environment variable contains the
76+
/// substring "UTF-8", case insensitive.
77+
///
78+
/// On Windows, we always return true since we use the `WriteConsoleW` API
79+
/// internally. Note that the default Windows codepage (437) does not support
80+
/// all Unicode characters. This function does not check the codepage.
81+
static bool SupportsUnicode();
82+
7183
protected:
7284
struct Data;
7385

lldb/include/lldb/Host/common/DiagnosticsRendering.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,27 @@ struct DiagnosticDetail {
5959

6060
StructuredData::ObjectSP Serialize(llvm::ArrayRef<DiagnosticDetail> details);
6161

62+
/// Renders an array of DiagnosticDetail instances.
63+
///
64+
/// \param[in] stream
65+
/// The stream to render the diagnostics to.
66+
/// \param offset_in_command
67+
/// An optional offset to the column position of the diagnostic in the
68+
/// source.
69+
/// \param show_inline
70+
/// Whether to show the diagnostics inline.
71+
/// \param details
72+
/// The array of DiagnosticsDetail to render.
73+
/// \param force_ascii
74+
/// Whether to force ascii rendering. If false, Unicode characters will be
75+
/// used if the output file supports them.
76+
///
77+
/// \see lldb_private::Terminal::SupportsUnicode
6278
void RenderDiagnosticDetails(Stream &stream,
6379
std::optional<uint16_t> offset_in_command,
6480
bool show_inline,
65-
llvm::ArrayRef<DiagnosticDetail> details);
81+
llvm::ArrayRef<DiagnosticDetail> details,
82+
bool force_ascii = false);
6683

6784
class DiagnosticError
6885
: public llvm::ErrorInfo<DiagnosticError, CloneableECError> {

lldb/source/Host/common/DiagnosticsRendering.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "lldb/Host/common/DiagnosticsRendering.h"
10+
#include "lldb/Host/Terminal.h"
11+
1012
#include <cstdint>
1113

1214
using namespace lldb_private;
@@ -85,7 +87,8 @@ static llvm::raw_ostream &PrintSeverity(Stream &stream,
8587
void RenderDiagnosticDetails(Stream &stream,
8688
std::optional<uint16_t> offset_in_command,
8789
bool show_inline,
88-
llvm::ArrayRef<DiagnosticDetail> details) {
90+
llvm::ArrayRef<DiagnosticDetail> details,
91+
bool force_ascii) {
8992
if (details.empty())
9093
return;
9194

@@ -97,12 +100,8 @@ void RenderDiagnosticDetails(Stream &stream,
97100
return;
98101
}
99102

100-
// Since there is no other way to find this out, use the color
101-
// attribute as a proxy for whether the terminal supports Unicode
102-
// characters. In the future it might make sense to move this into
103-
// Host so it can be customized for a specific platform.
104103
llvm::StringRef cursor, underline, vbar, joint, hbar, spacer;
105-
if (stream.AsRawOstream().colors_enabled()) {
104+
if (Terminal::SupportsUnicode() && !force_ascii) {
106105
cursor = "˄";
107106
underline = "˜";
108107
vbar = "";

lldb/source/Host/common/Terminal.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,23 @@ llvm::Error Terminal::SetHardwareFlowControl(bool enabled) {
400400
#endif // LLDB_ENABLE_TERMIOS
401401
}
402402

403+
bool Terminal::SupportsUnicode() {
404+
#ifdef _WIN32
405+
return true;
406+
#else
407+
static std::optional<bool> g_result;
408+
if (g_result)
409+
return g_result.value();
410+
411+
const char *lang_var = std::getenv("LANG");
412+
if (!lang_var)
413+
return false;
414+
g_result =
415+
llvm::StringRef(lang_var).lower().find("utf-8") != std::string::npos;
416+
return g_result.value();
417+
#endif
418+
}
419+
403420
TerminalState::TerminalState(Terminal term, bool save_process_group)
404421
: m_tty(term) {
405422
Save(term, save_process_group);
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
# RUN: echo quit | %lldb -o "dwim-print a" \
22
# RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK1
33
# (lldb) dwim-print a
4-
# CHECK1:{{^ \^}}
5-
# CHECK1: {{^ error: use of undeclared identifier 'a'}}
4+
# CHECK1:{{^ (\^|˄)}}
5+
# CHECK1: {{^ (╰─ )?error: use of undeclared identifier 'a'}}
66
# RUN: echo quit | %lldb -o "p a" \
77
# RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK2
88
# (lldb) p a
9-
# CHECK2:{{^ \^}}
9+
# CHECK2:{{^ (\^|˄)}}
1010
# RUN: echo quit | %lldb -o "dwim-print -- a" \
1111
# RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK3
1212
# (lldb) dwim-print -- a
13-
# CHECK3:{{^ \^}}
13+
# CHECK3:{{^ (\^|˄)}}
1414
# RUN: echo quit | %lldb -o "settings set show-inline-diagnostics false" \
1515
# RUN: -o "dwim-print a" 2>&1 | FileCheck %s --check-prefix=CHECK4
1616
# CHECK4: error: <user expression 0>:1:1: use of undeclared identifier

lldb/test/Shell/Commands/command-expr-diagnostics.test

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,28 @@
22
# RUN: echo quit | %lldb -o "expression a+b" \
33
# RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK1
44
# (lldb) expression a+b
5-
# CHECK1:{{^ \^ \^}}
6-
# CHECK1: {{^ | error: use of undeclared identifier 'b'}}
7-
# CHECK1: {{^ error: use of undeclared identifier 'a'}}
5+
# CHECK1:{{^ (\^|˄) (\^|˄)}}
6+
# CHECK1: {{^ (\||│) (╰─ )?error: use of undeclared identifier 'b'}}
7+
# CHECK1: {{^ (╰─ )?error: use of undeclared identifier 'a'}}
88

99
# RUN: echo quit | %lldb -o "expr a" \
1010
# RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK2
1111
# (lldb) expr a
12-
# CHECK2:{{^ \^}}
12+
# CHECK2:{{^ (\^|˄)}}
1313

1414
# RUN: echo quit | %lldb -o "expr -i 0 -o 0 -- a" \
1515
# RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK3
1616
# (lldb) expr -i 0 -o 0 -- a
17-
# CHECK3:{{^ \^}}
18-
# CHECK3: {{^ error: use of undeclared identifier 'a'}}
17+
# CHECK3:{{^ (\^|˄)}}
18+
# CHECK3: {{^ (╰─ )?error: use of undeclared identifier 'a'}}
1919

2020
# RUN: echo "int main(){return 0;}">%t.c
2121
# RUN: %clang_host %t.c -o %t.exe
2222
# RUN: echo quit | %lldb %t.exe -o "b main" -o r -o \
2323
# RUN: "expr --top-level -- template<typename T> T FOO(T x) { return x/2;}" -o \
2424
# RUN: "expression -- FOO(\"\")" 2>&1 | FileCheck %s --check-prefix=CHECK4
2525
# (lldb) expression -- FOO("")
26-
# CHECK4:{{^ \^}}
26+
# CHECK4:{{^ (\^|˄)}}
2727
# CHECK4: {{^ note: in instantiation of function template}}
2828
# CHECK4: error: <user expression
2929

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
# RUN: echo quit | %lldb -O "log enable -x" \
22
# RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK1
33
# (lldb) log enable -x
4-
# CHECK1:{{^ \^~}}
5-
# CHECK1: {{^ error: unknown or ambiguous option}}
4+
# CHECK1:{{^ (\^|˄)(~|˜)}}
5+
# CHECK1: {{^ (╰─ )?error: unknown or ambiguous option}}
66

77
# RUN: echo quit | %lldb -O " log enable -xxxxxxx" \
88
# RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK2
99
# (lldb) log enable -xxxxxxx
10-
# CHECK2:{{^ \^~~~~~~~}}
11-
# CHECK2: {{^ error: unknown or ambiguous option}}
10+
# CHECK2:{{^ (\^|˄)(~|˜)+}}
11+
# CHECK2: {{^ (╰─ )?error: unknown or ambiguous option}}
1212
# RUN: echo quit | %lldb -O "log enable dwarf all -f dwarf.log -x" \
1313
# RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK3
1414
# (lldb) log enable dwarf all -f dwarf.log -x
15-
# CHECK3:{{^ \^~}}
16-
# CHECK3: {{^ error: unknown or ambiguous option}}
15+
# CHECK3:{{^ (\^|˄)(~|˜)}}
16+
# CHECK3: {{^ (╰─ )?error: unknown or ambiguous option}}

lldb/unittests/Host/common/DiagnosticsRenderingTest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class ErrorDisplayTest : public ::testing::Test {};
1010

1111
std::string Render(std::vector<DiagnosticDetail> details) {
1212
StreamString stream;
13-
RenderDiagnosticDetails(stream, 0, true, details);
13+
RenderDiagnosticDetails(stream, 0, true, details, /*force_ascii=*/true);
1414
return stream.GetData();
1515
}
1616
} // namespace

0 commit comments

Comments
 (0)