Skip to content

Commit 8cb7da6

Browse files
authored
Merge pull request #1217 from fredriss/super-resize-me
[lldb/Driver] Support terminal resizing
2 parents 9d6a470 + 7d80113 commit 8cb7da6

File tree

6 files changed

+86
-31
lines changed

6 files changed

+86
-31
lines changed

lldb/include/lldb/Core/IOHandler.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ class IOHandler {
9595

9696
virtual void Deactivate() { m_active = false; }
9797

98+
virtual void TerminalSizeChanged() {}
99+
98100
virtual const char *GetPrompt() {
99101
// Prompt support isn't mandatory
100102
return nullptr;
@@ -369,6 +371,8 @@ class IOHandlerEditline : public IOHandler {
369371

370372
void Deactivate() override;
371373

374+
void TerminalSizeChanged() override;
375+
372376
ConstString GetControlSequence(char ch) override {
373377
return m_delegate.IOHandlerGetControlSequence(ch);
374378
}

lldb/include/lldb/Host/Editline.h

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,10 @@
1919
// good amount of the text will
2020
// disappear. It's still in the buffer, just invisible.
2121
// b) The prompt printing logic for dealing with ANSI formatting characters is
22-
// broken, which is why we're
23-
// working around it here.
24-
// c) When resizing the terminal window, if the cursor moves between rows
25-
// libedit will get confused. d) The incremental search uses escape to cancel
26-
// input, so it's confused by
22+
// broken, which is why we're working around it here.
23+
// c) The incremental search uses escape to cancel input, so it's confused by
2724
// ANSI sequences starting with escape.
28-
// e) Emoji support is fairly terrible, presumably it doesn't understand
25+
// d) Emoji support is fairly terrible, presumably it doesn't understand
2926
// composed characters?
3027

3128
#ifndef liblldb_Editline_h_
@@ -50,6 +47,7 @@
5047
#include <histedit.h>
5148
#endif
5249

50+
#include <csignal>
5351
#include <mutex>
5452
#include <string>
5553
#include <vector>
@@ -171,9 +169,7 @@ class Editline {
171169
/// editing scenarios.
172170
void SetContinuationPrompt(const char *continuation_prompt);
173171

174-
/// Required to update the width of the terminal registered for I/O. It is
175-
/// critical that this
176-
/// be correct at all times.
172+
/// Call when the terminal size changes
177173
void TerminalSizeChanged();
178174

179175
/// Returns the prompt established by SetPrompt()
@@ -328,6 +324,8 @@ class Editline {
328324

329325
bool CompleteCharacter(char ch, EditLineGetCharType &out);
330326

327+
void ApplyTerminalSizeChange();
328+
331329
private:
332330
#if LLDB_EDITLINE_USE_WCHAR
333331
std::wstring_convert<std::codecvt_utf8<wchar_t>> m_utf8conv;
@@ -350,6 +348,7 @@ class Editline {
350348
std::string m_set_continuation_prompt;
351349
std::string m_current_prompt;
352350
bool m_needs_prompt_repaint = false;
351+
volatile std::sig_atomic_t m_terminal_size_has_changed = 0;
353352
std::string m_editor_name;
354353
FILE *m_input_file;
355354
FILE *m_output_file;

lldb/source/Core/Debugger.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,9 @@ uint32_t Debugger::GetTerminalWidth() const {
388388
}
389389

390390
bool Debugger::SetTerminalWidth(uint32_t term_width) {
391+
if (auto handler_sp = m_io_handler_stack.Top())
392+
handler_sp->TerminalSizeChanged();
393+
391394
const uint32_t idx = ePropertyTerminalWidth;
392395
return m_collection_sp->SetPropertyAtIndexAsSInt64(nullptr, idx, term_width);
393396
}

lldb/source/Core/IOHandler.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,12 @@ void IOHandlerEditline::Deactivate() {
287287
m_delegate.IOHandlerDeactivated(*this);
288288
}
289289

290+
void IOHandlerEditline::TerminalSizeChanged() {
291+
#if LLDB_ENABLE_LIBEDIT
292+
m_editline_up->TerminalSizeChanged();
293+
#endif
294+
}
295+
290296
// Split out a line from the buffer, if there is a full one to get.
291297
static Optional<std::string> SplitLine(std::string &line_buffer) {
292298
size_t pos = line_buffer.find('\n');

lldb/source/Host/common/Editline.cpp

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,9 @@ int Editline::GetCharacter(EditLineGetCharType *c) {
563563
lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess;
564564
char ch = 0;
565565

566+
if (m_terminal_size_has_changed)
567+
ApplyTerminalSizeChange();
568+
566569
// This mutex is locked by our caller (GetLine). Unlock it while we read a
567570
// character (blocking operation), so we do not hold the mutex
568571
// indefinitely. This gives a chance for someone to interrupt us. After
@@ -1055,7 +1058,7 @@ void Editline::ConfigureEditor(bool multiline) {
10551058

10561059
m_editline =
10571060
el_init(m_editor_name.c_str(), m_input_file, m_output_file, m_error_file);
1058-
TerminalSizeChanged();
1061+
ApplyTerminalSizeChange();
10591062

10601063
if (m_history_sp && m_history_sp->IsValid()) {
10611064
if (!m_history_sp->Load()) {
@@ -1308,28 +1311,32 @@ void Editline::SetContinuationPrompt(const char *continuation_prompt) {
13081311
continuation_prompt == nullptr ? "" : continuation_prompt;
13091312
}
13101313

1311-
void Editline::TerminalSizeChanged() {
1312-
if (m_editline != nullptr) {
1313-
el_resize(m_editline);
1314-
int columns;
1315-
// This function is documenting as taking (const char *, void *) for the
1316-
// vararg part, but in reality in was consuming arguments until the first
1317-
// null pointer. This was fixed in libedit in April 2019
1318-
// <http://mail-index.netbsd.org/source-changes/2019/04/26/msg105454.html>,
1319-
// but we're keeping the workaround until a version with that fix is more
1320-
// widely available.
1321-
if (el_get(m_editline, EL_GETTC, "co", &columns, nullptr) == 0) {
1322-
m_terminal_width = columns;
1323-
if (m_current_line_rows != -1) {
1324-
const LineInfoW *info = el_wline(m_editline);
1325-
int lineLength =
1326-
(int)((info->lastchar - info->buffer) + GetPromptWidth());
1327-
m_current_line_rows = (lineLength / columns) + 1;
1328-
}
1329-
} else {
1330-
m_terminal_width = INT_MAX;
1331-
m_current_line_rows = 1;
1314+
void Editline::TerminalSizeChanged() { m_terminal_size_has_changed = 1; }
1315+
1316+
void Editline::ApplyTerminalSizeChange() {
1317+
if (!m_editline)
1318+
return;
1319+
1320+
m_terminal_size_has_changed = 0;
1321+
el_resize(m_editline);
1322+
int columns;
1323+
// This function is documenting as taking (const char *, void *) for the
1324+
// vararg part, but in reality in was consuming arguments until the first
1325+
// null pointer. This was fixed in libedit in April 2019
1326+
// <http://mail-index.netbsd.org/source-changes/2019/04/26/msg105454.html>,
1327+
// but we're keeping the workaround until a version with that fix is more
1328+
// widely available.
1329+
if (el_get(m_editline, EL_GETTC, "co", &columns, nullptr) == 0) {
1330+
m_terminal_width = columns;
1331+
if (m_current_line_rows != -1) {
1332+
const LineInfoW *info = el_wline(m_editline);
1333+
int lineLength =
1334+
(int)((info->lastchar - info->buffer) + GetPromptWidth());
1335+
m_current_line_rows = (lineLength / columns) + 1;
13321336
}
1337+
} else {
1338+
m_terminal_width = INT_MAX;
1339+
m_current_line_rows = 1;
13331340
}
13341341
}
13351342

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""
2+
Test resizing in our IOHandlers.
3+
"""
4+
5+
import os
6+
7+
import lldb
8+
from lldbsuite.test.decorators import *
9+
from lldbsuite.test.lldbtest import *
10+
from lldbsuite.test.lldbpexpect import PExpectTest
11+
12+
class IOHandlerCompletionTest(PExpectTest):
13+
14+
mydir = TestBase.compute_mydir(__file__)
15+
16+
# PExpect uses many timeouts internally and doesn't play well
17+
# under ASAN on a loaded machine..
18+
@skipIfAsan
19+
@skipIfEditlineSupportMissing
20+
def test_resize(self):
21+
22+
# Start with a small window
23+
self.launch(dimensions=(10,10))
24+
25+
self.child.send("his is a long sentence missing its first letter.")
26+
27+
# Now resize to something bigger
28+
self.child.setwinsize(100,500)
29+
30+
# Hit "left" 60 times (to go to the beginning of the line) and insert
31+
# a character.
32+
self.child.send(60 * "\033[D")
33+
self.child.send("T")
34+
35+
self.child.expect_exact("(lldb) This is a long sentence missing its first letter.")
36+
self.quit()

0 commit comments

Comments
 (0)