[Lldb-commits] [lldb] fc0e8fb - [lldb][gui] truncate long lines/names if needed

Luboš Luňák via lldb-commits lldb-commits at lists.llvm.org
Wed Aug 5 23:40:58 PDT 2020


Author: Luboš Luňák
Date: 2020-08-06T08:40:42+02:00
New Revision: fc0e8fb7874a73277b221e3f940b749cdd0a99d7

URL: https://github.com/llvm/llvm-project/commit/fc0e8fb7874a73277b221e3f940b749cdd0a99d7
DIFF: https://github.com/llvm/llvm-project/commit/fc0e8fb7874a73277b221e3f940b749cdd0a99d7.diff

LOG: [lldb][gui] truncate long lines/names if needed

Without this, sources with long lines or variable names may overwrite
panel frames, or even overrun to the following line. There's currently
no way to scroll left/right in the views, so that should be added
to handle these cases.
This commit includes fixing constness of some Window functions,
and also makes PutCStringTruncated() consistent with the added
printf-like variant to take the padding as the first argument (can't
add it after the format to the printf-like function).

Differential Revision: https://reviews.llvm.org/D85123

Added: 
    lldb/test/API/commands/gui/viewlarge/Makefile
    lldb/test/API/commands/gui/viewlarge/TestGuiViewLarge.py
    lldb/test/API/commands/gui/viewlarge/main.c

Modified: 
    lldb/source/Core/IOHandlerCursesGUI.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Core/IOHandlerCursesGUI.cpp b/lldb/source/Core/IOHandlerCursesGUI.cpp
index 37e24d4f7533..5a921ceeb84a 100644
--- a/lldb/source/Core/IOHandlerCursesGUI.cpp
+++ b/lldb/source/Core/IOHandlerCursesGUI.cpp
@@ -367,23 +367,23 @@ class Window {
   }
   void Clear() { ::wclear(m_window); }
   void Erase() { ::werase(m_window); }
-  Rect GetBounds() {
+  Rect GetBounds() const {
     return Rect(GetParentOrigin(), GetSize());
   } // Get the rectangle in our parent window
   int GetChar() { return ::wgetch(m_window); }
-  int GetCursorX() { return getcurx(m_window); }
-  int GetCursorY() { return getcury(m_window); }
-  Rect GetFrame() {
+  int GetCursorX() const { return getcurx(m_window); }
+  int GetCursorY() const { return getcury(m_window); }
+  Rect GetFrame() const {
     return Rect(Point(), GetSize());
   } // Get our rectangle in our own coordinate system
-  Point GetParentOrigin() { return Point(GetParentX(), GetParentY()); }
-  Size GetSize() { return Size(GetWidth(), GetHeight()); }
-  int GetParentX() { return getparx(m_window); }
-  int GetParentY() { return getpary(m_window); }
-  int GetMaxX() { return getmaxx(m_window); }
-  int GetMaxY() { return getmaxy(m_window); }
-  int GetWidth() { return GetMaxX(); }
-  int GetHeight() { return GetMaxY(); }
+  Point GetParentOrigin() const { return Point(GetParentX(), GetParentY()); }
+  Size GetSize() const { return Size(GetWidth(), GetHeight()); }
+  int GetParentX() const { return getparx(m_window); }
+  int GetParentY() const { return getpary(m_window); }
+  int GetMaxX() const { return getmaxx(m_window); }
+  int GetMaxY() const { return getmaxy(m_window); }
+  int GetWidth() const { return GetMaxX(); }
+  int GetHeight() const { return GetMaxY(); }
   void MoveCursor(int x, int y) { ::wmove(m_window, y, x); }
   void MoveWindow(int x, int y) { MoveWindow(Point(x, y)); }
   void Resize(int w, int h) { ::wresize(m_window, h, w); }
@@ -396,7 +396,7 @@ class Window {
     ::wbkgd(m_window, COLOR_PAIR(color_pair_idx));
   }
 
-  void PutCStringTruncated(const char *s, int right_pad) {
+  void PutCStringTruncated(int right_pad, const char *s) {
     int bytes_left = GetWidth() - GetCursorX();
     if (bytes_left > right_pad) {
       bytes_left -= right_pad;
@@ -438,6 +438,20 @@ class Window {
     va_end(args);
   }
 
+  void PrintfTruncated(int right_pad, const char *format, ...)
+      __attribute__((format(printf, 3, 4))) {
+    va_list args;
+    va_start(args, format);
+    StreamString strm;
+    strm.PrintfVarArg(format, args);
+    va_end(args);
+    PutCStringTruncated(right_pad, strm.GetData());
+  }
+
+  size_t LimitLengthToRestOfLine(size_t length) const {
+    return std::min<size_t>(length, std::max(0, GetWidth() - GetCursorX() - 1));
+  }
+
   void Touch() {
     ::touchwin(m_window);
     if (m_parent)
@@ -553,7 +567,7 @@ class Window {
       } else {
         MoveCursor(1, GetHeight() - 1);
         PutChar('[');
-        PutCStringTruncated(bottom_message, 1);
+        PutCStringTruncated(1, bottom_message);
       }
     }
     if (attr)
@@ -1911,7 +1925,7 @@ class FrameTreeDelegate : public TreeDelegate {
         if (FormatEntity::Format(m_format, strm, &sc, &exe_ctx, nullptr,
                                  nullptr, false, false)) {
           int right_pad = 1;
-          window.PutCStringTruncated(strm.GetString().str().c_str(), right_pad);
+          window.PutCStringTruncated(right_pad, strm.GetString().str().c_str());
         }
       }
     }
@@ -1970,7 +1984,7 @@ class ThreadTreeDelegate : public TreeDelegate {
       if (FormatEntity::Format(m_format, strm, nullptr, &exe_ctx, nullptr,
                                nullptr, false, false)) {
         int right_pad = 1;
-        window.PutCStringTruncated(strm.GetString().str().c_str(), right_pad);
+        window.PutCStringTruncated(right_pad, strm.GetString().str().c_str());
       }
     }
   }
@@ -2060,7 +2074,7 @@ class ThreadsTreeDelegate : public TreeDelegate {
       if (FormatEntity::Format(m_format, strm, nullptr, &exe_ctx, nullptr,
                                nullptr, false, false)) {
         int right_pad = 1;
-        window.PutCStringTruncated(strm.GetString().str().c_str(), right_pad);
+        window.PutCStringTruncated(right_pad, strm.GetString().str().c_str());
       }
     }
   }
@@ -2363,29 +2377,29 @@ class ValueObjectListDelegate : public WindowDelegate {
       window.AttributeOn(A_REVERSE);
 
     if (type_name && type_name[0])
-      window.Printf("(%s) ", type_name);
+      window.PrintfTruncated(1, "(%s) ", type_name);
 
     if (name && name[0])
-      window.PutCString(name);
+      window.PutCStringTruncated(1, name);
 
     attr_t changd_attr = 0;
     if (valobj->GetValueDidChange())
       changd_attr = COLOR_PAIR(5) | A_BOLD;
 
     if (value && value[0]) {
-      window.PutCString(" = ");
+      window.PutCStringTruncated(1, " = ");
       if (changd_attr)
         window.AttributeOn(changd_attr);
-      window.PutCString(value);
+      window.PutCStringTruncated(1, value);
       if (changd_attr)
         window.AttributeOff(changd_attr);
     }
 
     if (summary && summary[0]) {
-      window.PutChar(' ');
+      window.PutCStringTruncated(1, " ");
       if (changd_attr)
         window.AttributeOn(changd_attr);
-      window.PutCString(summary);
+      window.PutCStringTruncated(1, summary);
       if (changd_attr)
         window.AttributeOff(changd_attr);
     }
@@ -2823,7 +2837,7 @@ bool HelpDialogDelegate::WindowDelegateDraw(Window &window, bool force) {
   while (y <= max_y) {
     window.MoveCursor(x, y);
     window.PutCStringTruncated(
-        m_text.GetStringAtIndex(m_first_visible_line + y - min_y), 1);
+        1, m_text.GetStringAtIndex(m_first_visible_line + y - min_y));
     ++y;
   }
   return true;
@@ -3251,7 +3265,7 @@ class StatusBarWindowDelegate : public WindowDelegate {
         if (thread && FormatEntity::Format(m_format, strm, nullptr, &exe_ctx,
                                            nullptr, nullptr, false, false)) {
           window.MoveCursor(40, 0);
-          window.PutCStringTruncated(strm.GetString().str().c_str(), 1);
+          window.PutCStringTruncated(1, strm.GetString().str().c_str());
         }
 
         window.MoveCursor(60, 0);
@@ -3477,7 +3491,7 @@ class SourceFileWindowDelegate : public WindowDelegate {
       window.AttributeOn(A_REVERSE);
       window.MoveCursor(1, 1);
       window.PutChar(' ');
-      window.PutCStringTruncated(m_title.GetString().str().c_str(), 1);
+      window.PutCStringTruncated(1, m_title.GetString().str().c_str());
       int x = window.GetCursorX();
       if (x < window_width - 1) {
         window.Printf("%*s", window_width - x - 1, "");
@@ -3549,8 +3563,8 @@ class SourceFileWindowDelegate : public WindowDelegate {
 
           if (highlight_attr)
             window.AttributeOn(highlight_attr);
-          const uint32_t line_len =
-              m_file_sp->GetLineLength(curr_line + 1, false);
+          const uint32_t line_len = window.LimitLengthToRestOfLine(
+              m_file_sp->GetLineLength(curr_line + 1, false));
           if (line_len > 0)
             window.PutCString(m_file_sp->PeekLineData(curr_line + 1), line_len);
 
@@ -3564,11 +3578,12 @@ class SourceFileWindowDelegate : public WindowDelegate {
               if (stop_description && stop_description[0]) {
                 size_t stop_description_len = strlen(stop_description);
                 int desc_x = window_width - stop_description_len - 16;
-                window.Printf("%*s", desc_x - window.GetCursorX(), "");
-                // window.MoveCursor(window_width - stop_description_len - 15,
-                // line_y);
-                window.Printf("<<< Thread %u: %s ", thread->GetIndexID(),
-                              stop_description);
+                if (desc_x - window.GetCursorX() > 0)
+                  window.Printf("%*s", desc_x - window.GetCursorX(), "");
+                window.MoveCursor(window_width - stop_description_len - 15,
+                                  line_y);
+                window.PrintfTruncated(1, "<<< Thread %u: %s ",
+                                       thread->GetIndexID(), stop_description);
               }
             } else {
               window.Printf("%*s", window_width - window.GetCursorX() - 1, "");
@@ -3699,7 +3714,7 @@ class SourceFileWindowDelegate : public WindowDelegate {
             strm.Printf("%s", mnemonic);
 
           int right_pad = 1;
-          window.PutCStringTruncated(strm.GetData(), right_pad);
+          window.PutCStringTruncated(right_pad, strm.GetData());
 
           if (is_pc_line && frame_sp &&
               frame_sp->GetConcreteFrameIndex() == 0) {
@@ -3711,11 +3726,12 @@ class SourceFileWindowDelegate : public WindowDelegate {
               if (stop_description && stop_description[0]) {
                 size_t stop_description_len = strlen(stop_description);
                 int desc_x = window_width - stop_description_len - 16;
-                window.Printf("%*s", desc_x - window.GetCursorX(), "");
-                // window.MoveCursor(window_width - stop_description_len - 15,
-                // line_y);
-                window.Printf("<<< Thread %u: %s ", thread->GetIndexID(),
-                              stop_description);
+                if (desc_x - window.GetCursorX() > 0)
+                  window.Printf("%*s", desc_x - window.GetCursorX(), "");
+                window.MoveCursor(window_width - stop_description_len - 15,
+                                  line_y);
+                window.PrintfTruncated(1, "<<< Thread %u: %s ",
+                                       thread->GetIndexID(), stop_description);
               }
             } else {
               window.Printf("%*s", window_width - window.GetCursorX() - 1, "");

diff  --git a/lldb/test/API/commands/gui/viewlarge/Makefile b/lldb/test/API/commands/gui/viewlarge/Makefile
new file mode 100644
index 000000000000..c9319d6e6888
--- /dev/null
+++ b/lldb/test/API/commands/gui/viewlarge/Makefile
@@ -0,0 +1,2 @@
+C_SOURCES := main.c
+include Makefile.rules

diff  --git a/lldb/test/API/commands/gui/viewlarge/TestGuiViewLarge.py b/lldb/test/API/commands/gui/viewlarge/TestGuiViewLarge.py
new file mode 100644
index 000000000000..ebb99f65047f
--- /dev/null
+++ b/lldb/test/API/commands/gui/viewlarge/TestGuiViewLarge.py
@@ -0,0 +1,52 @@
+"""
+Test that the 'gui' displays long lines/names correctly without overruns.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.lldbpexpect import PExpectTest
+
+class GuiViewLargeCommandTest(PExpectTest):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    # PExpect uses many timeouts internally and doesn't play well
+    # under ASAN on a loaded machine..
+    @skipIfAsan
+    @skipIfCursesSupportMissing
+    @skipIfRemote # "run" command will not work correctly for remote debug
+    def test_gui(self):
+        self.build()
+
+        # Limit columns to 80, so that long lines will not be displayed completely.
+        self.launch(executable=self.getBuildArtifact("a.out"), dimensions=(100,80))
+        self.expect('br set -f main.c -p "// Break here"', substrs=["Breakpoint 1", "address ="])
+        self.expect("run", substrs=["stop reason ="])
+
+        escape_key = chr(27).encode()
+
+        # Start the GUI and close the welcome window.
+        self.child.sendline("gui")
+        self.child.send(escape_key)
+
+        # Check the sources window.
+        self.child.expect_exact("Sources")
+        # The string is copy&pasted from a 80-columns terminal. It will be followed by some
+        # kind of an escape sequence (color, frame, etc.).
+        self.child.expect_exact("int a_variable_with_a_very_looooooooooooooooooooooooooo"+chr(27))
+        # The escape here checks that there's no content drawn by the previous line.
+        self.child.expect_exact("int shortvar = 1;"+chr(27))
+        # Check the triggered breakpoint marker on a long line.
+        self.child.expect_exact("<<< Thread 1: breakpoint 1.1"+chr(27))
+
+        # Check the variable window.
+        self.child.expect_exact("Variables")
+        self.child.expect_exact("(int) a_variable_with_a_very_looooooooooooooooooooooooooooooo"+chr(27))
+        self.child.expect_exact("(int) shortvar = 1"+chr(27))
+
+        # Press escape to quit the gui
+        self.child.send(escape_key)
+
+        self.expect_prompt()
+        self.quit()

diff  --git a/lldb/test/API/commands/gui/viewlarge/main.c b/lldb/test/API/commands/gui/viewlarge/main.c
new file mode 100644
index 000000000000..2416a3565549
--- /dev/null
+++ b/lldb/test/API/commands/gui/viewlarge/main.c
@@ -0,0 +1,7 @@
+int main(int argc, char **argv) {
+  // This is to be viewed in a 80-column terminal, so make the line below more
+  // than 120 characters wide, to span at least two lines.
+  int a_variable_with_a_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_name = 22;
+  int shortvar = 1;
+  return a_variable_with_a_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_name; // Break here
+}


        


More information about the lldb-commits mailing list