emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 4f114c0d95: Speed up scrolling when lines are very long and trunc


From: Eli Zaretskii
Subject: master 4f114c0d95: Speed up scrolling when lines are very long and truncated
Date: Tue, 11 Oct 2022 06:26:49 -0400 (EDT)

branch: master
commit 4f114c0d95caa0e26de3d188cebe9e3cbcb2dee8
Author: Eli Zaretskii <eliz@gnu.org>
Commit: Eli Zaretskii <eliz@gnu.org>

    Speed up scrolling when lines are very long and truncated
    
    * src/window.c (window_scroll_for_long_lines): New function.
    (window_scroll): Call 'window_scroll_for_long_lines' when lines
    are very long and truncated on display.  Also, disable
    'fontification-functions' during scrolling in that case.
    * src/xdisp.c (redisplay_window): When recentering the window's
    display, go back to the centering position using a simplified
    method, if lines in the buffer are very long and truncated on
    display.
---
 src/window.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 src/xdisp.c  | 15 +++++++++-
 2 files changed, 106 insertions(+), 6 deletions(-)

diff --git a/src/window.c b/src/window.c
index da80fabe33..4e8b352e16 100644
--- a/src/window.c
+++ b/src/window.c
@@ -52,6 +52,7 @@ static ptrdiff_t get_leaf_windows (struct window *, struct 
window **,
                                   ptrdiff_t);
 static void window_scroll_pixel_based (Lisp_Object, int, bool, bool);
 static void window_scroll_line_based (Lisp_Object, int, bool, bool);
+static void window_scroll_for_long_lines (struct window *, int, bool);
 static void foreach_window (struct frame *,
                            bool (* fn) (struct window *, void *),
                             void *);
@@ -5536,19 +5537,40 @@ window_internal_height (struct window *w)
 static void
 window_scroll (Lisp_Object window, EMACS_INT n, bool whole, bool noerror)
 {
+  struct window *w = XWINDOW (window);
+  struct buffer *b = XBUFFER (w->contents);
+  bool long_lines_truncated =
+    b->long_line_optimizations_p && !NILP (BVAR (b, truncate_lines));
   specpdl_ref count = SPECPDL_INDEX ();
 
   n = clip_to_bounds (INT_MIN, n, INT_MAX);
 
-  wset_redisplay (XWINDOW (window));
+  wset_redisplay (w);
 
-  if (whole && fast_but_imprecise_scrolling)
+  /* Does this window's buffer have very long and truncated lines?  */
+  if (b->long_line_optimizations_p
+      && !long_lines_truncated
+      && !NILP (Vtruncate_partial_width_windows)
+      && w->total_cols < FRAME_COLS (XFRAME (WINDOW_FRAME (w))))
+    {
+      if (FIXNUMP (Vtruncate_partial_width_windows))
+       long_lines_truncated =
+         w->total_cols < XFIXNAT (Vtruncate_partial_width_windows);
+      else
+       long_lines_truncated = true;
+    }
+
+  if (whole && (fast_but_imprecise_scrolling || long_lines_truncated))
     specbind (Qfontification_functions, Qnil);
 
-  /* On GUI frames, use the pixel-based version which is much slower
-     than the line-based one but can handle varying line heights.  */
-  if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
+  if (whole && long_lines_truncated)
+    window_scroll_for_long_lines (w, n, noerror);
+  else if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
     {
+
+      /* On GUI frames, use the pixel-based version which is much
+        slower than the line-based one, but can handle varying
+        line heights.  */
       record_unwind_protect_void (unwind_display_working_on_window);
       display_working_on_window_p = true;
       window_scroll_pixel_based (window, n, whole, noerror);
@@ -5598,6 +5620,71 @@ sanitize_next_screen_context_lines (void)
   return clip_to_bounds (0, next_screen_context_lines, 1000000);
 }
 
+/* Implementation of window_scroll for very long and truncated lines.
+   This is a simplified version, it only handles WHOLE window scrolls,
+   and doesn't honor scroll-preserve-screen-position nor scroll-margin.  */
+static void
+window_scroll_for_long_lines (struct window *w, int n, bool noerror)
+{
+  ptrdiff_t startpos = marker_position (w->start);
+  ptrdiff_t startbyte = marker_byte_position (w->start);
+  int nscls = sanitize_next_screen_context_lines ();
+  register int ht = window_internal_height (w);
+
+  n *= max (1, ht - nscls);
+
+  /* If point is not visible in window, bring it inside window.  */
+  struct position pos;
+  int rtop, rbot, dummy_rowh, dummy_vpos, dummy_x, dummy_y;
+  if (!(PT >= startpos
+       && PT <= ZV
+       && startpos <= ZV
+       && pos_visible_p (w, PT, &dummy_x, &dummy_y, &rtop, &rbot, &dummy_rowh,
+                         &dummy_vpos)
+       && !rtop && !rbot))
+    {
+      pos = *vmotion (PT, PT_BYTE, - (ht / 2), w);
+      startpos = pos.bufpos;
+      startbyte = pos.bytepos;
+    }
+  SET_PT_BOTH (startpos, startbyte);
+
+  bool lose = n < 0 && PT == BEGV;
+  pos = *vmotion (PT, PT_BYTE, n, w);
+  if (lose)
+    {
+      if (noerror)
+       return;
+      else
+       xsignal0 (Qbeginning_of_buffer);
+    }
+
+  bool bolp = pos.bufpos == BEGV || FETCH_BYTE (pos.bytepos - 1) == '\n';
+  if (pos.bufpos < ZV)
+    {
+      set_marker_restricted_both (w->start, w->contents,
+                                 pos.bufpos, pos.bytepos);
+      w->start_at_line_beg = bolp;
+      wset_update_mode_line (w);
+      /* Set force_start so that redisplay_window will run
+        the window-scroll-functions.  */
+      w->force_start = true;
+      SET_PT_BOTH (pos.bufpos, pos.bytepos);
+      if (n > 0)
+       pos = *vmotion (PT, PT_BYTE, ht / 2, w);
+      else if (n < 0)
+       pos = *vmotion (PT, PT_BYTE, - (ht / 2), w);
+      SET_PT_BOTH (pos.bufpos, pos.bytepos);
+    }
+  else
+    {
+      if (noerror)
+       return;
+      else
+       xsignal0 (Qend_of_buffer);
+    }
+}
+
 /* Implementation of window_scroll that works based on pixel line
    heights.  See the comment of window_scroll for parameter
    descriptions.  */
diff --git a/src/xdisp.c b/src/xdisp.c
index 9534e27843..e390de6a33 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -20165,7 +20165,20 @@ redisplay_window (Lisp_Object window, bool 
just_this_one_p)
           from point.  */
        centering_position = window_box_height (w) / 2;
     }
-  move_it_vertically_backward (&it, centering_position);
+  if (current_buffer->long_line_optimizations_p
+      && it.line_wrap == TRUNCATE)
+    {
+      /* For very long and truncated lines, go back using a simplified
+        method, which ignored any inaccuracies due to line-height
+        differences, display properties/overlays, etc.  */
+      int nlines = centering_position / frame_line_height;
+
+      while (nlines-- && IT_CHARPOS (it) > BEGV)
+       back_to_previous_visible_line_start (&it);
+      reseat_1 (&it, it.current.pos, true);
+    }
+  else
+    move_it_vertically_backward (&it, centering_position);
 
   eassert (IT_CHARPOS (it) >= BEGV);
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]