Skip to content

Commit d954644

Browse files
committed
[lldb] Support Unicode in the prompt (llvm#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. (cherry picked from commit 850e90c)
1 parent 9a9d449 commit d954644

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
@@ -250,9 +250,8 @@ class Editline {
250250
void SetCurrentLine(int line_index);
251251

252252
/// Determines the width of the prompt in characters. The width is guaranteed
253-
/// to be the same for
254-
/// all lines of the current multi-line session.
255-
int GetPromptWidth();
253+
/// to be the same for all lines of the current multi-line session.
254+
size_t GetPromptWidth();
256255

257256
/// Returns true if the underlying EditLine session's keybindings are
258257
/// 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
@@ -28,6 +28,7 @@ def launch(
2828
dimensions=None,
2929
run_under=None,
3030
post_spawn=None,
31+
encoding=None,
3132
use_colors=False,
3233
):
3334
logfile = getattr(sys.stdout, "buffer", sys.stdout) if self.TraceOn() else None
@@ -60,6 +61,7 @@ def launch(
6061
timeout=timeout,
6162
dimensions=dimensions,
6263
env=env,
64+
encoding=encoding,
6365
)
6466
self.child.ptyproc.delayafterclose = timeout / 10
6567
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)