[Lldb-commits] [lldb] dcd4589 - [lldb][gui] use left/right in the source view to scroll

Luboš Luňák via lldb-commits lldb-commits at lists.llvm.org
Tue Aug 18 04:25:27 PDT 2020


Author: Luboš Luňák
Date: 2020-08-18T13:25:01+02:00
New Revision: dcd4589a0d68032076f6951190ab170fef9c3cf5

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

LOG: [lldb][gui] use left/right in the source view to scroll

I intentionally decided not to reset the column automatically
anywhere, because I don't know where and if at all that should happen.
There should be always an indication of being scrolled (too much)
to the right, so I'll leave this to whoever has an opinion.

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

Added: 
    

Modified: 
    lldb/source/Core/IOHandlerCursesGUI.cpp
    lldb/test/API/commands/gui/viewlarge/TestGuiViewLarge.py

Removed: 
    


################################################################################
diff  --git a/lldb/source/Core/IOHandlerCursesGUI.cpp b/lldb/source/Core/IOHandlerCursesGUI.cpp
index 6a24625fc7eb..10aff7a6c217 100644
--- a/lldb/source/Core/IOHandlerCursesGUI.cpp
+++ b/lldb/source/Core/IOHandlerCursesGUI.cpp
@@ -480,23 +480,40 @@ class Window {
 
   // Curses doesn't allow direct output of color escape sequences, but that's
   // how we get source lines from the Highligher class. Read the line and
-  // convert color escape sequences to curses color attributes.
-  void OutputColoredStringTruncated(int right_pad, StringRef string,
+  // convert color escape sequences to curses color attributes. Use
+  // first_skip_count to skip leading visible characters. Returns false if all
+  // visible characters were skipped due to first_skip_count.
+  bool OutputColoredStringTruncated(int right_pad, StringRef string,
+                                    size_t skip_first_count,
                                     bool use_blue_background) {
     attr_t saved_attr;
     short saved_pair;
+    bool result = false;
     wattr_get(m_window, &saved_attr, &saved_pair, nullptr);
     if (use_blue_background)
       ::wattron(m_window, COLOR_PAIR(WhiteOnBlue));
     while (!string.empty()) {
       size_t esc_pos = string.find('\x1b');
       if (esc_pos == StringRef::npos) {
-        PutCStringTruncated(right_pad, string.data(), string.size());
+        string = string.substr(skip_first_count);
+        if (!string.empty()) {
+          PutCStringTruncated(right_pad, string.data(), string.size());
+          result = true;
+        }
         break;
       }
       if (esc_pos > 0) {
-        PutCStringTruncated(right_pad, string.data(), esc_pos);
-        string = string.drop_front(esc_pos);
+        if (skip_first_count > 0) {
+          int skip = std::min(esc_pos, skip_first_count);
+          string = string.substr(skip);
+          skip_first_count -= skip;
+          esc_pos -= skip;
+        }
+        if (esc_pos > 0) {
+          PutCStringTruncated(right_pad, string.data(), esc_pos);
+          result = true;
+          string = string.drop_front(esc_pos);
+        }
       }
       bool consumed = string.consume_front("\x1b");
       assert(consumed);
@@ -531,6 +548,7 @@ class Window {
       }
     }
     wattr_set(m_window, saved_attr, saved_pair, nullptr);
+    return result;
   }
 
   void Touch() {
@@ -3379,7 +3397,8 @@ class SourceFileWindowDelegate : public WindowDelegate {
         m_disassembly_scope(nullptr), m_disassembly_sp(), m_disassembly_range(),
         m_title(), m_line_width(4), m_selected_line(0), m_pc_line(0),
         m_stop_id(0), m_frame_idx(UINT32_MAX), m_first_visible_line(0),
-        m_min_x(0), m_min_y(0), m_max_x(0), m_max_y(0) {}
+        m_first_visible_column(0), m_min_x(0), m_min_y(0), m_max_x(0),
+        m_max_y(0) {}
 
   ~SourceFileWindowDelegate() override = default;
 
@@ -3396,6 +3415,8 @@ class SourceFileWindowDelegate : public WindowDelegate {
         {KEY_RETURN, "Run to selected line with one shot breakpoint"},
         {KEY_UP, "Select previous source line"},
         {KEY_DOWN, "Select next source line"},
+        {KEY_LEFT, "Scroll to the left"},
+        {KEY_RIGHT, "Scroll to the right"},
         {KEY_PPAGE, "Page up"},
         {KEY_NPAGE, "Page down"},
         {'b', "Set breakpoint on selected source/disassembly line"},
@@ -3650,7 +3671,15 @@ class SourceFileWindowDelegate : public WindowDelegate {
           StringRef line = lineStream.GetString();
           if (line.endswith("\n"))
             line = line.drop_back();
-          window.OutputColoredStringTruncated(1, line, is_pc_line);
+          bool wasWritten = window.OutputColoredStringTruncated(
+              1, line, m_first_visible_column, line_is_selected);
+          if (line_is_selected && !wasWritten) {
+            // Draw an empty space to show the selected line if empty,
+            // or draw '<' if nothing is visible because of scrolling too much
+            // to the right.
+            window.PutCStringTruncated(
+                1, line.empty() && m_first_visible_column == 0 ? " " : "<");
+          }
 
           if (is_pc_line && frame_sp &&
               frame_sp->GetConcreteFrameIndex() == 0) {
@@ -3801,7 +3830,9 @@ class SourceFileWindowDelegate : public WindowDelegate {
             strm.Printf("%s", mnemonic);
 
           int right_pad = 1;
-          window.PutCStringTruncated(right_pad, strm.GetData());
+          window.PutCStringTruncated(
+              right_pad,
+              strm.GetString().substr(m_first_visible_column).data());
 
           if (is_pc_line && frame_sp &&
               frame_sp->GetConcreteFrameIndex() == 0) {
@@ -3896,6 +3927,15 @@ class SourceFileWindowDelegate : public WindowDelegate {
       }
       return eKeyHandled;
 
+    case KEY_LEFT:
+      if (m_first_visible_column > 0)
+        --m_first_visible_column;
+      return eKeyHandled;
+
+    case KEY_RIGHT:
+      ++m_first_visible_column;
+      return eKeyHandled;
+
     case '\r':
     case '\n':
     case KEY_ENTER:
@@ -4127,6 +4167,7 @@ class SourceFileWindowDelegate : public WindowDelegate {
   uint32_t m_stop_id;
   uint32_t m_frame_idx;
   int m_first_visible_line;
+  int m_first_visible_column;
   int m_min_x;
   int m_min_y;
   int m_max_x;

diff  --git a/lldb/test/API/commands/gui/viewlarge/TestGuiViewLarge.py b/lldb/test/API/commands/gui/viewlarge/TestGuiViewLarge.py
index ebb99f65047f..19f8334e5d75 100644
--- a/lldb/test/API/commands/gui/viewlarge/TestGuiViewLarge.py
+++ b/lldb/test/API/commands/gui/viewlarge/TestGuiViewLarge.py
@@ -25,6 +25,9 @@ def test_gui(self):
         self.expect("run", substrs=["stop reason ="])
 
         escape_key = chr(27).encode()
+        left_key = chr(27)+'OD' # for vt100 terminal (lldbexpect sets TERM=vt100)
+        right_key = chr(27)+'OC'
+        ctrl_l = chr(12)
 
         # Start the GUI and close the welcome window.
         self.child.sendline("gui")
@@ -45,6 +48,20 @@ def test_gui(self):
         self.child.expect_exact("(int) a_variable_with_a_very_looooooooooooooooooooooooooooooo"+chr(27))
         self.child.expect_exact("(int) shortvar = 1"+chr(27))
 
+        # Scroll the sources view twice to the right.
+        self.child.send(right_key)
+        self.child.send(right_key)
+        # Force a redraw, otherwise curses will optimize the drawing to not draw all 'o'.
+        self.child.send(ctrl_l)
+        # The source code is indented by two spaces, so there'll be just two extra 'o' on the right.
+        self.child.expect_exact("int a_variable_with_a_very_looooooooooooooooooooooooooooo"+chr(27))
+
+        # And scroll back to the left.
+        self.child.send(left_key)
+        self.child.send(left_key)
+        self.child.send(ctrl_l)
+        self.child.expect_exact("int a_variable_with_a_very_looooooooooooooooooooooooooo"+chr(27))
+
         # Press escape to quit the gui
         self.child.send(escape_key)
 


        


More information about the lldb-commits mailing list