Skip to content

Commit 894592c

Browse files
committed
[lldb] Use the terminal height for paging editline completions (llvm#119914)
Currently, we arbitrarily paginate editline completions to 40 elements. On large terminals, that leaves some real-estate unused. On small terminals, it's pretty annoying to not see the first completions. We can address both issues by using the terminal height for pagination. This builds on the improvements of llvm#116456. (cherry picked from commit 3dfc1d9)
1 parent 1274e90 commit 894592c

File tree

11 files changed

+138
-25
lines changed

11 files changed

+138
-25
lines changed

lldb/include/lldb/API/SBDebugger.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,10 @@ class LLDB_API SBDebugger {
382382

383383
void SetTerminalWidth(uint32_t term_width);
384384

385+
uint32_t GetTerminalHeight() const;
386+
387+
void SetTerminalHeight(uint32_t term_height);
388+
385389
lldb::user_id_t GetID();
386390

387391
const char *GetPrompt() const;

lldb/include/lldb/Core/Debugger.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,10 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
284284

285285
bool SetTerminalWidth(uint64_t term_width);
286286

287+
uint64_t GetTerminalHeight() const;
288+
289+
bool SetTerminalHeight(uint64_t term_height);
290+
287291
llvm::StringRef GetPrompt() const;
288292

289293
llvm::StringRef GetPromptAnsiPrefix() const;

lldb/include/lldb/Host/Editline.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ class Editline {
240240

241241
size_t GetTerminalWidth() { return m_terminal_width; }
242242

243+
size_t GetTerminalHeight() { return m_terminal_height; }
244+
243245
private:
244246
/// Sets the lowest line number for multi-line editing sessions. A value of
245247
/// zero suppresses line number printing in the prompt.
@@ -373,6 +375,7 @@ class Editline {
373375
std::vector<EditLineStringType> m_input_lines;
374376
EditorStatus m_editor_status;
375377
int m_terminal_width = 0;
378+
int m_terminal_height = 0;
376379
int m_base_line_number = 0;
377380
unsigned m_current_line_index = 0;
378381
int m_current_line_rows = -1;

lldb/source/API/SBDebugger.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,6 +1407,19 @@ void SBDebugger::SetTerminalWidth(uint32_t term_width) {
14071407
m_opaque_sp->SetTerminalWidth(term_width);
14081408
}
14091409

1410+
uint32_t SBDebugger::GetTerminalHeight() const {
1411+
LLDB_INSTRUMENT_VA(this);
1412+
1413+
return (m_opaque_sp ? m_opaque_sp->GetTerminalWidth() : 0);
1414+
}
1415+
1416+
void SBDebugger::SetTerminalHeight(uint32_t term_height) {
1417+
LLDB_INSTRUMENT_VA(this, term_height);
1418+
1419+
if (m_opaque_sp)
1420+
m_opaque_sp->SetTerminalHeight(term_height);
1421+
}
1422+
14101423
const char *SBDebugger::GetPrompt() const {
14111424
LLDB_INSTRUMENT_VA(this);
14121425

lldb/source/Core/CoreProperties.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,10 @@ let Definition = "debugger" in {
181181
Global,
182182
DefaultUnsignedValue<80>,
183183
Desc<"The maximum number of columns to use for displaying text.">;
184+
def TerminalHeight: Property<"term-height", "UInt64">,
185+
Global,
186+
DefaultUnsignedValue<24>,
187+
Desc<"The number of rows used for displaying text.">;
184188
def ThreadFormat: Property<"thread-format", "FormatEntity">,
185189
Global,
186190
DefaultStringValue<"thread #${thread.index}: tid = ${thread.id%tid}{, ${frame.pc}}{ ${module.file.basename}{`${function.name-with-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}{, name = ${ansi.fg.green}'${thread.name}'${ansi.normal}}{, queue = ${ansi.fg.green}'${thread.queue}'${ansi.normal}}{, activity = ${ansi.fg.green}'${thread.info.activity.name}'${ansi.normal}}{, ${thread.info.trace_messages} messages}{, stop reason = ${ansi.fg.red}${thread.stop-reason}${ansi.normal}}{\\\\nReturn value: ${thread.return-value}}{\\\\nCompleted expression: ${thread.completed-expression}}\\\\n">,

lldb/source/Core/Debugger.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -371,11 +371,29 @@ uint64_t Debugger::GetTerminalWidth() const {
371371
}
372372

373373
bool Debugger::SetTerminalWidth(uint64_t term_width) {
374+
const uint32_t idx = ePropertyTerminalWidth;
375+
const bool success = SetPropertyAtIndex(idx, term_width);
376+
374377
if (auto handler_sp = m_io_handler_stack.Top())
375378
handler_sp->TerminalSizeChanged();
376379

377-
const uint32_t idx = ePropertyTerminalWidth;
378-
return SetPropertyAtIndex(idx, term_width);
380+
return success;
381+
}
382+
383+
uint64_t Debugger::GetTerminalHeight() const {
384+
const uint32_t idx = ePropertyTerminalHeight;
385+
return GetPropertyAtIndexAs<uint64_t>(
386+
idx, g_debugger_properties[idx].default_uint_value);
387+
}
388+
389+
bool Debugger::SetTerminalHeight(uint64_t term_height) {
390+
const uint32_t idx = ePropertyTerminalHeight;
391+
const bool success = SetPropertyAtIndex(idx, term_height);
392+
393+
if (auto handler_sp = m_io_handler_stack.Top())
394+
handler_sp->TerminalSizeChanged();
395+
396+
return success;
379397
}
380398

381399
bool Debugger::GetUseExternalEditor() const {
@@ -919,7 +937,11 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton)
919937
m_collection_sp->GetPropertyAtIndexAsOptionValueUInt64(
920938
ePropertyTerminalWidth);
921939
term_width->SetMinimumValue(10);
922-
term_width->SetMaximumValue(1024);
940+
941+
OptionValueUInt64 *term_height =
942+
m_collection_sp->GetPropertyAtIndexAsOptionValueUInt64(
943+
ePropertyTerminalHeight);
944+
term_height->SetMinimumValue(10);
923945

924946
// Turn off use-color if this is a dumb terminal.
925947
const char *term = getenv("TERM");

lldb/source/Host/common/Editline.cpp

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -924,18 +924,26 @@ unsigned char Editline::BufferEndCommand(int ch) {
924924

925925
/// Prints completions and their descriptions to the given file. Only the
926926
/// completions in the interval [start, end) are printed.
927-
static void
927+
static size_t
928928
PrintCompletion(FILE *output_file,
929929
llvm::ArrayRef<CompletionResult::Completion> results,
930-
size_t max_completion_length, size_t max_length) {
930+
size_t max_completion_length, size_t max_length,
931+
std::optional<size_t> max_height = std::nullopt) {
931932
constexpr size_t ellipsis_length = 3;
932933
constexpr size_t padding_length = 8;
933934
constexpr size_t separator_length = 4;
934935

935936
const size_t description_col =
936937
std::min(max_completion_length + padding_length, max_length);
937938

939+
size_t lines_printed = 0;
940+
size_t results_printed = 0;
938941
for (const CompletionResult::Completion &c : results) {
942+
if (max_height && lines_printed >= *max_height)
943+
break;
944+
945+
results_printed++;
946+
939947
if (c.GetCompletion().empty())
940948
continue;
941949

@@ -956,6 +964,7 @@ PrintCompletion(FILE *output_file,
956964
fprintf(output_file, "%.*s...\n",
957965
static_cast<int>(max_length - padding_length - ellipsis_length),
958966
c.GetCompletion().c_str());
967+
lines_printed++;
959968
continue;
960969
}
961970

@@ -964,6 +973,7 @@ PrintCompletion(FILE *output_file,
964973
if (c.GetDescription().empty() ||
965974
description_col + separator_length + ellipsis_length >= max_length) {
966975
fprintf(output_file, "\n");
976+
lines_printed++;
967977
continue;
968978
}
969979

@@ -990,6 +1000,8 @@ PrintCompletion(FILE *output_file,
9901000
for (llvm::StringRef line : llvm::split(c.GetDescription(), '\n')) {
9911001
if (line.empty())
9921002
break;
1003+
if (max_height && lines_printed >= *max_height)
1004+
break;
9931005
if (!first)
9941006
fprintf(output_file, "%*s",
9951007
static_cast<int>(description_col + separator_length), "");
@@ -1000,14 +1012,17 @@ PrintCompletion(FILE *output_file,
10001012
if (position + description_length < max_length) {
10011013
fprintf(output_file, "%.*s\n", static_cast<int>(description_length),
10021014
line.data());
1015+
lines_printed++;
10031016
} else {
10041017
fprintf(output_file, "%.*s...\n",
10051018
static_cast<int>(max_length - position - ellipsis_length),
10061019
line.data());
1020+
lines_printed++;
10071021
continue;
10081022
}
10091023
}
10101024
}
1025+
return results_printed;
10111026
}
10121027

10131028
void Editline::DisplayCompletions(
@@ -1016,7 +1031,11 @@ void Editline::DisplayCompletions(
10161031

10171032
fprintf(editline.m_output_file,
10181033
"\n" ANSI_CLEAR_BELOW "Available completions:\n");
1019-
const size_t page_size = 40;
1034+
1035+
/// Account for the current line, the line showing "Available completions"
1036+
/// before and the line saying "More" after.
1037+
const size_t page_size = editline.GetTerminalHeight() - 3;
1038+
10201039
bool all = false;
10211040

10221041
auto longest =
@@ -1026,21 +1045,12 @@ void Editline::DisplayCompletions(
10261045

10271046
const size_t max_len = longest->GetCompletion().size();
10281047

1029-
if (results.size() < page_size) {
1030-
PrintCompletion(editline.m_output_file, results, max_len,
1031-
editline.GetTerminalWidth());
1032-
return;
1033-
}
1034-
10351048
size_t cur_pos = 0;
10361049
while (cur_pos < results.size()) {
1037-
size_t remaining = results.size() - cur_pos;
1038-
size_t next_size = all ? remaining : std::min(page_size, remaining);
1039-
1040-
PrintCompletion(editline.m_output_file, results.slice(cur_pos, next_size),
1041-
max_len, editline.GetTerminalWidth());
1042-
1043-
cur_pos += next_size;
1050+
cur_pos +=
1051+
PrintCompletion(editline.m_output_file, results.slice(cur_pos), max_len,
1052+
editline.GetTerminalWidth(),
1053+
all ? std::nullopt : std::optional<size_t>(page_size));
10441054

10451055
if (cur_pos >= results.size())
10461056
break;
@@ -1525,6 +1535,13 @@ void Editline::ApplyTerminalSizeChange() {
15251535
m_terminal_width = INT_MAX;
15261536
m_current_line_rows = 1;
15271537
}
1538+
1539+
int rows;
1540+
if (el_get(m_editline, EL_GETTC, "li", &rows, nullptr) == 0) {
1541+
m_terminal_height = rows;
1542+
} else {
1543+
m_terminal_height = INT_MAX;
1544+
}
15281545
}
15291546

15301547
const char *Editline::GetPrompt() { return m_set_prompt.c_str(); }

lldb/test/API/functionalities/completion/TestCompletion.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -335,13 +335,22 @@ def test_settings_replace_target_ru(self):
335335
)
336336

337337
def test_settings_show_term(self):
338-
self.complete_from_to("settings show term-", "settings show term-width")
338+
self.complete_from_to("settings show term-w", "settings show term-width")
339339

340340
def test_settings_list_term(self):
341-
self.complete_from_to("settings list term-", "settings list term-width")
341+
self.complete_from_to("settings list term-w", "settings list term-width")
342+
343+
def test_settings_show_term(self):
344+
self.complete_from_to("settings show term-h", "settings show term-height")
345+
346+
def test_settings_list_term(self):
347+
self.complete_from_to("settings list term-h", "settings list term-height")
348+
349+
def test_settings_remove_term(self):
350+
self.complete_from_to("settings remove term-w", "settings remove term-width")
342351

343352
def test_settings_remove_term(self):
344-
self.complete_from_to("settings remove term-", "settings remove term-width")
353+
self.complete_from_to("settings remove term-h", "settings remove term-height")
345354

346355
def test_settings_s(self):
347356
"""Test that 'settings s' completes to ['set', 'show']."""

lldb/test/API/terminal/TestEditlineCompletions.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,37 @@ def test_multiline_description(self):
6262
" kdp-remote is an abbreviation for 'process conn..."
6363
)
6464
self.child.expect(" kill -- Terminate the current target process.")
65+
66+
@skipIfAsan
67+
@skipIfEditlineSupportMissing
68+
def test_completion_pagination(self):
69+
"""Test that we use the terminal height for pagination."""
70+
self.launch(dimensions=(10, 30))
71+
self.child.send("_regexp-\t")
72+
self.child.expect("Available completions:")
73+
self.child.expect(" _regexp-attach")
74+
self.child.expect(" _regexp-break")
75+
self.child.expect(" _regexp-bt")
76+
self.child.expect(" _regexp-display")
77+
self.child.expect(" _regexp-down")
78+
self.child.expect(" _regexp-env")
79+
self.child.expect(" _regexp-jump")
80+
self.child.expect("More")
81+
82+
@skipIfAsan
83+
@skipIfEditlineSupportMissing
84+
def test_completion_multiline_pagination(self):
85+
"""Test that we use the terminal height for pagination and account for multi-line descriptions."""
86+
self.launch(dimensions=(6, 72))
87+
self.child.send("k\t")
88+
self.child.expect("Available completions:")
89+
self.child.expect(
90+
" kdp-remote -- Connect to a process via remote KDP server."
91+
)
92+
self.child.expect(
93+
" If no UDP port is specified, port 41139 is assu..."
94+
)
95+
self.child.expect(
96+
" kdp-remote is an abbreviation for 'process conn..."
97+
)
98+
self.child.expect("More")

lldb/tools/driver/Driver.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,8 @@ int Driver::MainLoop() {
459459
::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
460460
if (window_size.ws_col > 0)
461461
m_debugger.SetTerminalWidth(window_size.ws_col);
462+
if (window_size.ws_row > 0)
463+
m_debugger.SetTerminalHeight(window_size.ws_row);
462464
}
463465

464466
SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
@@ -635,16 +637,17 @@ int Driver::MainLoop() {
635637
return sb_interpreter.GetQuitStatus();
636638
}
637639

638-
void Driver::ResizeWindow(unsigned short col) {
640+
void Driver::ResizeWindow(unsigned short col, unsigned short row) {
639641
GetDebugger().SetTerminalWidth(col);
642+
GetDebugger().SetTerminalHeight(row);
640643
}
641644

642645
void sigwinch_handler(int signo) {
643646
struct winsize window_size;
644647
if ((isatty(STDIN_FILENO) != 0) &&
645648
::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
646649
if ((window_size.ws_col > 0) && g_driver != nullptr) {
647-
g_driver->ResizeWindow(window_size.ws_col);
650+
g_driver->ResizeWindow(window_size.ws_col, window_size.ws_row);
648651
}
649652
}
650653
}

0 commit comments

Comments
 (0)