[Lldb-commits] [lldb] [lldb] Take a sledgehammer approach to resizing the statusline (PR #146578)

Jonas Devlieghere via lldb-commits lldb-commits at lists.llvm.org
Thu Jul 3 09:39:04 PDT 2025


https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/146578

>From a0ebe1e710c56ddc8108758ee461c1a934021337 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Tue, 1 Jul 2025 10:38:22 -0700
Subject: [PATCH 1/3] [lldb] Take a sledgehammer approach to resizing the
 statusline
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Terminal resizing continues to be a source of statusline bugs, so much
so that some users have started disabling it altogether. Different
operating systems and terminal emulators exhibit subtly different
behaviors, making it nearly impossible to handle resizing reliably
across the board.

This patch sidesteps those issues by clearing the entire screen when the
terminal is resized. This avoids having to account for the previous,
potentially wrapped statusline, the underlying cause of many of the
aforementioned bugs.

The obvious downside is that this clears the on-screen history, but I
believe that’s a reasonable trade-off. Note that this only happens when
resizing the terminal; when launching LLDB, the statusline is drawn
without clearing the screen.
---
 lldb/include/lldb/Core/Statusline.h           |  4 +-
 lldb/source/Core/Statusline.cpp               | 46 ++++++++++---------
 .../statusline/TestStatusline.py              |  8 ++--
 3 files changed, 30 insertions(+), 28 deletions(-)

diff --git a/lldb/include/lldb/Core/Statusline.h b/lldb/include/lldb/Core/Statusline.h
index 521b9f2526f6b..6bda153f822d2 100644
--- a/lldb/include/lldb/Core/Statusline.h
+++ b/lldb/include/lldb/Core/Statusline.h
@@ -36,12 +36,10 @@ class Statusline {
   /// Draw the statusline with the given text.
   void Draw(std::string msg);
 
-  /// Update terminal dimensions.
-  void UpdateTerminalProperties();
-
   enum ScrollWindowMode {
     EnableStatusline,
     DisableStatusline,
+    ResizeStatusline,
   };
 
   /// Set the scroll window for the given mode.
diff --git a/lldb/source/Core/Statusline.cpp b/lldb/source/Core/Statusline.cpp
index 8ec57c9fa5bac..32f69db5a48f3 100644
--- a/lldb/source/Core/Statusline.cpp
+++ b/lldb/source/Core/Statusline.cpp
@@ -24,6 +24,7 @@
 #define ANSI_SAVE_CURSOR ESCAPE "7"
 #define ANSI_RESTORE_CURSOR ESCAPE "8"
 #define ANSI_CLEAR_BELOW ESCAPE "[J"
+#define ANSI_CLEAR_SCREEN ESCAPE "[2J"
 #define ANSI_SET_SCROLL_ROWS ESCAPE "[1;%ur"
 #define ANSI_TO_START_OF_ROW ESCAPE "[%u;1f"
 #define ANSI_REVERSE_VIDEO ESCAPE "[7m"
@@ -41,10 +42,12 @@ Statusline::Statusline(Debugger &debugger)
 Statusline::~Statusline() { Disable(); }
 
 void Statusline::TerminalSizeChanged() {
-  UpdateTerminalProperties();
+  m_terminal_width = m_debugger.GetTerminalWidth();
+  m_terminal_height = m_debugger.GetTerminalHeight();
 
-  // This definitely isn't signal safe, but the best we can do, until we
-  // have proper signal-catching thread.
+  UpdateScrollWindow(ResizeStatusline);
+
+  // Draw the old statusline.
   Redraw(/*update=*/false);
 }
 
@@ -85,13 +88,6 @@ void Statusline::Draw(std::string str) {
   locked_stream << ANSI_RESTORE_CURSOR;
 }
 
-void Statusline::UpdateTerminalProperties() {
-  UpdateScrollWindow(DisableStatusline);
-  m_terminal_width = m_debugger.GetTerminalWidth();
-  m_terminal_height = m_debugger.GetTerminalHeight();
-  UpdateScrollWindow(EnableStatusline);
-}
-
 void Statusline::UpdateScrollWindow(ScrollWindowMode mode) {
   assert(m_terminal_width != 0 && m_terminal_height != 0);
 
@@ -99,24 +95,32 @@ void Statusline::UpdateScrollWindow(ScrollWindowMode mode) {
   if (!stream_sp)
     return;
 
-  const unsigned scroll_height =
-      (mode == DisableStatusline) ? m_terminal_height : m_terminal_height - 1;
-
+  const unsigned reduced_scroll_window = m_terminal_height - 1;
   LockedStreamFile locked_stream = stream_sp->Lock();
 
-  if (mode == EnableStatusline) {
+  switch (mode) {
+  case EnableStatusline:
     // Move everything on the screen up.
     locked_stream << '\n';
     locked_stream.Printf(ANSI_UP_ROWS, 1);
-  }
-
-  locked_stream << ANSI_SAVE_CURSOR;
-  locked_stream.Printf(ANSI_SET_SCROLL_ROWS, scroll_height);
-  locked_stream << ANSI_RESTORE_CURSOR;
-
-  if (mode == DisableStatusline) {
+    // Reduce the scroll window.
+    locked_stream << ANSI_SAVE_CURSOR;
+    locked_stream.Printf(ANSI_SET_SCROLL_ROWS, reduced_scroll_window);
+    locked_stream << ANSI_RESTORE_CURSOR;
+    break;
+  case DisableStatusline:
+    // Reset the scroll window.
+    locked_stream << ANSI_SAVE_CURSOR;
+    locked_stream.Printf(ANSI_SET_SCROLL_ROWS, 0);
+    locked_stream << ANSI_RESTORE_CURSOR;
     // Clear the screen below to hide the old statusline.
     locked_stream << ANSI_CLEAR_BELOW;
+    break;
+  case ResizeStatusline:
+    // Clear the screen and update the scroll window.
+    locked_stream << ANSI_CLEAR_SCREEN;
+    locked_stream.Printf(ANSI_SET_SCROLL_ROWS, reduced_scroll_window);
+    break;
   }
 
   m_debugger.RefreshIOHandler();
diff --git a/lldb/test/API/functionalities/statusline/TestStatusline.py b/lldb/test/API/functionalities/statusline/TestStatusline.py
index ca2f10820d56d..5a966ca09a08c 100644
--- a/lldb/test/API/functionalities/statusline/TestStatusline.py
+++ b/lldb/test/API/functionalities/statusline/TestStatusline.py
@@ -68,7 +68,7 @@ def test(self):
 
         # Hide the statusline and check or the control character.
         self.expect(
-            "set set show-statusline false", ["\x1b[1;{}r".format(self.TERMINAL_HEIGHT)]
+            "set set show-statusline false", ["\x1b[1;0r"]
         )
 
     def test_no_color(self):
@@ -114,6 +114,6 @@ def test_resize(self):
         self.resize()
         self.expect("set set show-statusline true", ["no target"])
         self.resize(20, 60)
-        # Check for the escape code to resize the scroll window, followed by
-        # the prompt.
-        self.child.expect(re.escape("\x1b[1;19r\x1b8(lldb)"))
+        # Check for the escape code to resize the scroll window.
+        self.child.expect(re.escape("\x1b[1;19r"))
+        self.child.expect("(lldb)")

>From 46fe0578c76f67ebd6f7ba88c3d5e199b4bbc377 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Tue, 1 Jul 2025 14:36:40 -0700
Subject: [PATCH 2/3] Formatting

---
 lldb/test/API/functionalities/statusline/TestStatusline.py | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/lldb/test/API/functionalities/statusline/TestStatusline.py b/lldb/test/API/functionalities/statusline/TestStatusline.py
index 5a966ca09a08c..087e62b387d77 100644
--- a/lldb/test/API/functionalities/statusline/TestStatusline.py
+++ b/lldb/test/API/functionalities/statusline/TestStatusline.py
@@ -67,9 +67,7 @@ def test(self):
         self.expect('set set separator "| "')
 
         # Hide the statusline and check or the control character.
-        self.expect(
-            "set set show-statusline false", ["\x1b[1;0r"]
-        )
+        self.expect("set set show-statusline false", ["\x1b[1;0r"])
 
     def test_no_color(self):
         """Basic test for the statusline with colors disabled."""

>From 448dc22feab7762a814a0c001733c512eb32924b Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Thu, 3 Jul 2025 09:38:49 -0700
Subject: [PATCH 3/3] Add FIXME

---
 lldb/source/Core/Statusline.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lldb/source/Core/Statusline.cpp b/lldb/source/Core/Statusline.cpp
index 32f69db5a48f3..393d427241021 100644
--- a/lldb/source/Core/Statusline.cpp
+++ b/lldb/source/Core/Statusline.cpp
@@ -118,6 +118,7 @@ void Statusline::UpdateScrollWindow(ScrollWindowMode mode) {
     break;
   case ResizeStatusline:
     // Clear the screen and update the scroll window.
+    // FIXME: Find a better solution (#146919).
     locked_stream << ANSI_CLEAR_SCREEN;
     locked_stream.Printf(ANSI_SET_SCROLL_ROWS, reduced_scroll_window);
     break;



More information about the lldb-commits mailing list