Skip to content

[lldb] Take a sledgehammer approach to resizing the statusline #146578

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

JDevlieghere
Copy link
Member

@JDevlieghere JDevlieghere commented Jul 1, 2025

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.

rdar://154778410

@llvmbot
Copy link
Member

llvmbot commented Jul 1, 2025

@llvm/pr-subscribers-lldb

Author: Jonas Devlieghere (JDevlieghere)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/146578.diff

3 Files Affected:

  • (modified) lldb/include/lldb/Core/Statusline.h (+1-3)
  • (modified) lldb/source/Core/Statusline.cpp (+25-21)
  • (modified) lldb/source/Host/common/Editline.cpp (+2-2)
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/source/Host/common/Editline.cpp b/lldb/source/Host/common/Editline.cpp
index 4720d3b4c29ac..a5bbdcd60ec26 100644
--- a/lldb/source/Host/common/Editline.cpp
+++ b/lldb/source/Host/common/Editline.cpp
@@ -1710,10 +1710,10 @@ void Editline::PrintAsync(lldb::LockableStreamFileSP stream_sp, const char *s,
 }
 
 void Editline::Refresh() {
-  if (!m_editline || !m_output_stream_sp)
+  if (!m_editline)
     return;
   LockedStreamFile locked_stream = m_output_stream_sp->Lock();
-  MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingCursor);
+  el_set(m_editline, EL_REFRESH);
 }
 
 bool Editline::CompleteCharacter(char ch, EditLineGetCharType &out) {

@JDevlieghere JDevlieghere force-pushed the statuslin-resizing-sledgehammer branch 2 times, most recently from a57532d to a689f4c Compare July 1, 2025 18:09
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.
@JDevlieghere JDevlieghere force-pushed the statuslin-resizing-sledgehammer branch from a689f4c to a0ebe1e Compare July 1, 2025 21:13
Copy link

github-actions bot commented Jul 1, 2025

✅ With the latest revision this PR passed the Python code formatter.

@JDevlieghere
Copy link
Member Author

@labath let me know what you think of this approach. I'd like to take this on the Swift 6.2 release branch as it addresses several issues folks have reported.

Copy link
Collaborator

@labath labath left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I was out yesterday.

I think this is an okay, though not really satisfying solution (it could be you resized the window to see more of your history). To see if we can handle this uniformly, I guess we'd need to start by cataloguing the behavior of different terminal emulators.

@JDevlieghere
Copy link
Member Author

JDevlieghere commented Jul 3, 2025

Sorry, I was out yesterday.

No worries and I'm sorry for rushing you.

I think this is an okay, though not really satisfying solution (it could be you resized the window to see more of your history). To see if we can handle this uniformly, I guess we'd need to start by cataloguing the behavior of different terminal emulators.

Agreed. I'll file a new issue and leave a comment/FIXME to track improving that.

EDIT: Filed #146919

@JDevlieghere JDevlieghere merged commit 2f75f65 into llvm:main Jul 3, 2025
9 checks passed
@JDevlieghere JDevlieghere deleted the statuslin-resizing-sledgehammer branch July 3, 2025 17:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants