Skip to content

Commit 850e90c

Browse files
authored
[lldb] Support Unicode in the prompt (#66312)
Account for Unicode when computing the prompt column width. Previously, the string length (i.e. number of bytes) rather than the width of the Glyph was used to compute the cursor position. The result was that the cursor would be offset to the right when using a prompt containing Unicode.
1 parent 1dae4dd commit 850e90c

File tree

4 files changed

+31
-12
lines changed

4 files changed

+31
-12
lines changed

lldb/include/lldb/Host/Editline.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,8 @@ class Editline {
248248
void SetCurrentLine(int line_index);
249249

250250
/// Determines the width of the prompt in characters. The width is guaranteed
251-
/// to be the same for
252-
/// all lines of the current multi-line session.
253-
int GetPromptWidth();
251+
/// to be the same for all lines of the current multi-line session.
252+
size_t GetPromptWidth();
254253

255254
/// Returns true if the underlying EditLine session's keybindings are
256255
/// Emacs-based, or false if

lldb/packages/Python/lldbsuite/test/lldbpexpect.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def launch(
2626
dimensions=None,
2727
run_under=None,
2828
post_spawn=None,
29+
encoding=None,
2930
use_colors=False,
3031
):
3132
logfile = getattr(sys.stdout, "buffer", sys.stdout) if self.TraceOn() else None
@@ -58,6 +59,7 @@ def launch(
5859
timeout=timeout,
5960
dimensions=dimensions,
6061
env=env,
62+
encoding=encoding,
6163
)
6264
self.child.ptyproc.delayafterclose = timeout / 10
6365
self.child.ptyproc.delayafterterminate = timeout / 10

lldb/source/Host/common/Editline.cpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "lldb/Utility/Timeout.h"
2626

2727
#include "llvm/Support/FileSystem.h"
28+
#include "llvm/Support/Locale.h"
2829
#include "llvm/Support/Threading.h"
2930

3031
using namespace lldb_private;
@@ -101,6 +102,10 @@ bool IsOnlySpaces(const EditLineStringType &content) {
101102
return true;
102103
}
103104

105+
static size_t ColumnWidth(llvm::StringRef str) {
106+
return llvm::sys::locale::columnWidth(str);
107+
}
108+
104109
static int GetOperation(HistoryOperation op) {
105110
// The naming used by editline for the history operations is counter
106111
// intuitive to how it's used in LLDB's editline implementation.
@@ -328,14 +333,16 @@ std::string Editline::PromptForIndex(int line_index) {
328333
std::string continuation_prompt = prompt;
329334
if (m_set_continuation_prompt.length() > 0) {
330335
continuation_prompt = m_set_continuation_prompt;
331-
332336
// Ensure that both prompts are the same length through space padding
333-
while (continuation_prompt.length() < prompt.length()) {
334-
continuation_prompt += ' ';
335-
}
336-
while (prompt.length() < continuation_prompt.length()) {
337-
prompt += ' ';
338-
}
337+
const size_t prompt_width = ColumnWidth(prompt);
338+
const size_t cont_prompt_width = ColumnWidth(continuation_prompt);
339+
const size_t padded_prompt_width =
340+
std::max(prompt_width, cont_prompt_width);
341+
if (prompt_width < padded_prompt_width)
342+
prompt += std::string(padded_prompt_width - prompt_width, ' ');
343+
else if (cont_prompt_width < padded_prompt_width)
344+
continuation_prompt +=
345+
std::string(padded_prompt_width - cont_prompt_width, ' ');
339346
}
340347

341348
if (use_line_numbers) {
@@ -353,7 +360,7 @@ void Editline::SetCurrentLine(int line_index) {
353360
m_current_prompt = PromptForIndex(line_index);
354361
}
355362

356-
int Editline::GetPromptWidth() { return (int)PromptForIndex(0).length(); }
363+
size_t Editline::GetPromptWidth() { return ColumnWidth(PromptForIndex(0)); }
357364

358365
bool Editline::IsEmacs() {
359366
const char *editor;
@@ -441,7 +448,7 @@ void Editline::DisplayInput(int firstIndex) {
441448
int Editline::CountRowsForLine(const EditLineStringType &content) {
442449
std::string prompt =
443450
PromptForIndex(0); // Prompt width is constant during an edit session
444-
int line_length = (int)(content.length() + prompt.length());
451+
int line_length = (int)(content.length() + ColumnWidth(prompt));
445452
return (line_length / m_terminal_width) + 1;
446453
}
447454

lldb/test/API/terminal/TestEditline.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,14 @@ def test_left_right_arrow(self):
4444
)
4545

4646
self.quit()
47+
48+
@skipIfAsan
49+
@skipIfEditlineSupportMissing
50+
def test_prompt_unicode(self):
51+
"""Test that we can use Unicode in the LLDB prompt."""
52+
self.launch(use_colors=True, encoding="utf-8")
53+
self.child.send('settings set prompt "🐛 "\n')
54+
# Check that the cursor is at position 4 ([4G)
55+
# Prompt: 🐛 _
56+
# Column: 1..4
57+
self.child.expect(re.escape("🐛 \x1b[0m\x1b[4G"))

0 commit comments

Comments
 (0)