llunak created this revision.
llunak added a reviewer: clayborg.
llunak requested review of this revision.

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.


Repository:
  rLLDB LLDB

https://reviews.llvm.org/D85290

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

Index: lldb/test/API/commands/gui/viewlarge/TestGuiViewLarge.py
===================================================================
--- lldb/test/API/commands/gui/viewlarge/TestGuiViewLarge.py
+++ lldb/test/API/commands/gui/viewlarge/TestGuiViewLarge.py
@@ -25,6 +25,9 @@
         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.
         self.child.sendline("gui")
@@ -44,6 +47,20 @@
         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)
 
Index: lldb/source/Core/IOHandlerCursesGUI.cpp
===================================================================
--- lldb/source/Core/IOHandlerCursesGUI.cpp
+++ lldb/source/Core/IOHandlerCursesGUI.cpp
@@ -480,24 +480,41 @@
 
   // 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;
     int saved_opts;
+    bool result = false;
     ::wattr_get(m_window, &saved_attr, &saved_pair, &saved_opts);
     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);
@@ -532,6 +549,7 @@
       }
     }
     ::wattr_set(m_window, saved_attr, saved_pair, &saved_opts);
+    return result;
   }
 
   void Touch() {
@@ -3380,7 +3398,8 @@
         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;
 
@@ -3397,6 +3416,8 @@
         {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"},
@@ -3646,12 +3667,16 @@
           StringRef line = lineStream.GetString();
           if (line.endswith("\n"))
             line = line.drop_back();
-          window.OutputColoredStringTruncated(1, line, line_is_selected);
-          if (line_is_selected && line.empty()) {
-            // Draw an empty space to show the selected 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.
             const attr_t selected_attr = COLOR_PAIR(WhiteOnBlue);
             window.AttributeOn(selected_attr);
-            window.PutCStringTruncated(1, " ");
+            window.PutCStringTruncated(
+                1, line.empty() && m_first_visible_column == 0 ? " " : "<");
             window.AttributeOff(selected_attr);
           }
 
@@ -3809,7 +3834,9 @@
             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) {
@@ -3904,6 +3931,15 @@
       }
       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:
@@ -4135,6 +4171,7 @@
   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;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to