emacs-diffs
[Top][All Lists]
Advanced

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

feature/fix-the-long-lines-display-bug e7b5912b23: Improvements to long


From: Gregory Heytings
Subject: feature/fix-the-long-lines-display-bug e7b5912b23: Improvements to long lines handling.
Date: Sat, 16 Jul 2022 15:14:56 -0400 (EDT)

branch: feature/fix-the-long-lines-display-bug
commit e7b5912b235936b304701ba6b1e808d9b197fd4f
Author: Gregory Heytings <gregory@heytings.org>
Commit: Gregory Heytings <gregory@heytings.org>

    Improvements to long lines handling.
    
    * src/buffer.h (struct buffer): New field 'long_line_optimizations_p'.
    
    * src/buffer.c (syms_of_buffer): New variable 'long-line-threshold'.
    (reset_buffer): Initialize the 'long_line_optimizations_p' field.
    (Fbuffer_swap_text): Handle it.
    
    * src/xdisp.c (redisplay_window): Set 'long_line_optimizations_p' when
    a buffer contains long lines.
    (init_iterator): Use 'long_line_optimizations_p'.
    (get_narrowed_begv): Update.
    (SET_WITH_NARROWED_BEGV): New macro.
    (unwind_narrowed_begv): New internal function used by the new macro.
    (back_to_previous_line_start, get_visually_first_element,
    move_it_vertically_backward): Use the new macro.
    
    * src/search.c (find_newline1): Make it externally visible.
    
    * src/lisp.h: Make 'find_newline1' externally visible.
    
    * src/dispextern.h (struct it): Update comment.  Remove the
    'WITH_NARROWED_BEGV' macro.
    
    * etc/NEWS: Mention the 'long-line-threshold' variable.
---
 etc/NEWS         |  4 +++-
 src/buffer.c     | 10 ++++++++
 src/buffer.h     |  4 ++++
 src/dispextern.h | 16 ++-----------
 src/lisp.h       |  2 ++
 src/search.c     |  2 +-
 src/xdisp.c      | 72 ++++++++++++++++++++++++++++++++++++++++++++------------
 7 files changed, 79 insertions(+), 31 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 223e6dd761..6050a8ae1a 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -332,7 +332,9 @@ experience slowdowns while editing files with long lines, 
this is
 either due to font locking, which you can turn off with M-x
 font-lock-mode, or to the current major mode or one of the enabled
 minor modes, in which case you should open the the file with M-x
-find-file-literally instead of C-x C-f.
+find-file-literally instead of C-x C-f.  The variable
+'long-line-threshold' controls whether and when these display
+optimizations are used.
 
 +++
 ** New command to change the font size globally.
diff --git a/src/buffer.c b/src/buffer.c
index 509ce51b55..a777668e44 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -984,6 +984,7 @@ reset_buffer (register struct buffer *b)
   /* It is more conservative to start out "changed" than "unchanged".  */
   b->clip_changed = 0;
   b->prevent_redisplay_optimizations_p = 1;
+  b->long_line_optimizations_p = 0;
   bset_backed_up (b, Qnil);
   bset_local_minor_modes (b, Qnil);
   BUF_AUTOSAVE_MODIFF (b) = 0;
@@ -2445,6 +2446,7 @@ results, see Info node `(elisp)Swapping Text'.  */)
   swapfield (bidi_paragraph_cache, struct region_cache *);
   current_buffer->prevent_redisplay_optimizations_p = 1;
   other_buffer->prevent_redisplay_optimizations_p = 1;
+  swapfield (long_line_optimizations_p, bool_bf);
   swapfield (overlays_before, struct Lisp_Overlay *);
   swapfield (overlays_after, struct Lisp_Overlay *);
   swapfield (overlay_center, ptrdiff_t);
@@ -6423,6 +6425,14 @@ Since `clone-indirect-buffer' calls 
`make-indirect-buffer', this hook
 will run for `clone-indirect-buffer' calls as well.  */);
   Vclone_indirect_buffer_hook = Qnil;
 
+  DEFVAR_LISP ("long-line-threshold", Vlong_line_threshold,
+              doc: /* Line length above which specific display optimizations 
are used.
+Display optimizations for long lines will automatically be enabled in
+buffers which contain one or more lines whose length is above that
+threshold.
+When nil, these display optimizations are disabled.  */);
+  XSETFASTINT (Vlong_line_threshold, 10000);
+
   defsubr (&Sbuffer_live_p);
   defsubr (&Sbuffer_list);
   defsubr (&Sget_buffer);
diff --git a/src/buffer.h b/src/buffer.h
index 135eaf72d3..09daa29992 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -681,6 +681,10 @@ struct buffer
      defined, as well as by with-temp-buffer, for example.  */
   bool_bf inhibit_buffer_hooks : 1;
 
+  /* Non-zero when the buffer contains long lines and specific
+     display optimizations must be used.  */
+  bool_bf long_line_optimizations_p : 1;
+
   /* List of overlays that end at or before the current center,
      in order of end-position.  */
   struct Lisp_Overlay *overlays_before;
diff --git a/src/dispextern.h b/src/dispextern.h
index 2edf4b73f8..c579499495 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2332,8 +2332,8 @@ struct it
      with which display_string was called.  */
   ptrdiff_t end_charpos;
 
-  /* Alternate begin position of the buffer, which is used to optimize
-     display (see the WITH_NARROWED_BEGV macro below).  */
+  /* Alternate begin position of the buffer that may be used to
+     optimize display (see the WITH_NARROWED_BEGV macro below).  */
   ptrdiff_t narrowed_begv;
 
   /* C string to iterate over.  Non-null means get characters from
@@ -2817,18 +2817,6 @@ struct it
     reset_box_start_end_flags ((IT));                  \
   } while (false)
 
-/* Execute STATEMENT with a temporarily narrowed buffer.  */
-
-#define WITH_NARROWED_BEGV(STATEMENT)                              \
-  do {                                                             \
-    ptrdiff_t obegv = BEGV;                                        \
-    if (it->narrowed_begv)                                         \
-      SET_BUF_BEGV (current_buffer, it->narrowed_begv);                    \
-    STATEMENT;                                                     \
-    if (it->narrowed_begv)                                         \
-      SET_BUF_BEGV (current_buffer, obegv);                        \
-  } while (0)
-
 /* Bit-flags indicating what operation move_it_to should perform.  */
 
 enum move_operation_enum
diff --git a/src/lisp.h b/src/lisp.h
index e4a49b8ef9..5045d49e1b 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4761,6 +4761,8 @@ extern ptrdiff_t fast_c_string_match_ignore_case 
(Lisp_Object, const char *,
                                                  ptrdiff_t);
 extern ptrdiff_t fast_looking_at (Lisp_Object, ptrdiff_t, ptrdiff_t,
                                   ptrdiff_t, ptrdiff_t, Lisp_Object);
+extern ptrdiff_t find_newline1 (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
+                               ptrdiff_t, ptrdiff_t *, ptrdiff_t *, bool);
 extern ptrdiff_t find_newline (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
                               ptrdiff_t, ptrdiff_t *, ptrdiff_t *, bool);
 extern void scan_newline (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
diff --git a/src/search.c b/src/search.c
index 9d6bd074e1..b5d6a442c0 100644
--- a/src/search.c
+++ b/src/search.c
@@ -3192,7 +3192,7 @@ DEFUN ("regexp-quote", Fregexp_quote, Sregexp_quote, 1, 
1, 0,
 }
 
 /* Like find_newline, but doesn't use the cache, and only searches forward.  */
-static ptrdiff_t
+ptrdiff_t
 find_newline1 (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end,
               ptrdiff_t end_byte, ptrdiff_t count, ptrdiff_t *counted,
               ptrdiff_t *bytepos, bool allow_quit)
diff --git a/src/xdisp.c b/src/xdisp.c
index ac76917eb3..98bf15a859 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -3425,7 +3425,8 @@ init_iterator (struct it *it, struct window *w,
        }
     }
 
-  it->narrowed_begv = get_narrowed_begv (w);
+  if (current_buffer->long_line_optimizations_p)
+    it->narrowed_begv = get_narrowed_begv (w);
 
   /* If a buffer position was specified, set the iterator there,
      getting overlays and face properties from that position.  */
@@ -3493,20 +3494,43 @@ init_iterator (struct it *it, struct window *w,
   CHECK_IT (it);
 }
 
-/* Compute a suitable value for BEGV that can be used temporarily, to
-   optimize display, for the buffer in window W.  */
+/* Compute a suitable alternate value for BEGV that may be used
+   temporarily to optimize display if the buffer in window W contains
+   long lines.  */
 
 ptrdiff_t
 get_narrowed_begv (struct window *w)
 {
   int len; ptrdiff_t begv;
-  len = (1 + ((window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) *
-              window_body_height (w, WINDOW_BODY_IN_CANONICAL_CHARS)) /
-             10000)) * 10000;
-  begv = max ((PT / len - 2) * len, BEGV);
+  len = 3 * (window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) *
+            window_body_height (w, WINDOW_BODY_IN_CANONICAL_CHARS));
+  begv = max ((window_point (w) / len - 1) * len, BEGV);
   return begv == BEGV ? 0 : begv;
 }
 
+static void
+unwind_narrowed_begv (Lisp_Object point_min)
+{
+  SET_BUF_BEGV (current_buffer, XFIXNUM (point_min));
+}
+
+/* Set DST to EXPR.  When IT indicates that BEGV should temporarily be
+   updated to optimize display, evaluate EXPR with an updated BEGV.  */
+
+#define SET_WITH_NARROWED_BEGV(IT,DST,EXPR)                            \
+  do {                                                                 \
+    if (IT->narrowed_begv)                                             \
+      {                                                                        
\
+       specpdl_ref count = SPECPDL_INDEX ();                           \
+       record_unwind_protect (unwind_narrowed_begv, Fpoint_min ());    \
+       SET_BUF_BEGV (current_buffer, IT->narrowed_begv);               \
+       DST = EXPR;                                                     \
+       unbind_to (count, Qnil);                                        \
+      }                                                                        
\
+    else                                                               \
+      DST = EXPR;                                                      \
+  } while (0)
+
 /* Initialize IT for the display of window W with window start POS.  */
 
 void
@@ -7007,8 +7031,8 @@ back_to_previous_line_start (struct it *it)
   ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it);
 
   dec_both (&cp, &bp);
-  WITH_NARROWED_BEGV (IT_CHARPOS (*it) =
-                     find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it)));
+  SET_WITH_NARROWED_BEGV (it, IT_CHARPOS (*it),
+                         find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it)));
 }
 
 
@@ -8642,7 +8666,7 @@ get_visually_first_element (struct it *it)
   ptrdiff_t eob = (string_p ? it->bidi_it.string.schars : ZV);
   ptrdiff_t bob;
 
-  WITH_NARROWED_BEGV (bob = (string_p ? 0 : BEGV));
+  SET_WITH_NARROWED_BEGV (it, bob, string_p ? 0 : BEGV);
 
   if (STRINGP (it->string))
     {
@@ -8682,10 +8706,10 @@ get_visually_first_element (struct it *it)
       if (string_p)
        it->bidi_it.charpos = it->bidi_it.bytepos = 0;
       else
-       WITH_NARROWED_BEGV (it->bidi_it.charpos =
-                           find_newline_no_quit (IT_CHARPOS (*it),
-                                                 IT_BYTEPOS (*it), -1,
-                                                 &it->bidi_it.bytepos));
+       SET_WITH_NARROWED_BEGV (it, it->bidi_it.charpos,
+                               find_newline_no_quit (IT_CHARPOS (*it),
+                                                     IT_BYTEPOS (*it), -1,
+                                                     &it->bidi_it.bytepos));
       bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, true);
       do
        {
@@ -10603,7 +10627,8 @@ move_it_vertically_backward (struct it *it, int dy)
          ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it);
 
          dec_both (&cp, &bp);
-         WITH_NARROWED_BEGV (cp = find_newline_no_quit (cp, bp, -1, NULL));
+         SET_WITH_NARROWED_BEGV (it, cp,
+                                 find_newline_no_quit (cp, bp, -1, NULL));
          move_it_to (it, cp, -1, -1, -1, MOVE_TO_POS);
        }
       bidi_unshelve_cache (it3data, true);
@@ -19245,6 +19270,23 @@ redisplay_window (Lisp_Object window, bool 
just_this_one_p)
         }
     }
 
+  /* Check whether the buffer to be displayed contains long lines.  */
+  if (!NILP (Vlong_line_threshold)
+      && !current_buffer->long_line_optimizations_p
+      && MODIFF != UNCHANGED_MODIFIED)
+    {
+      ptrdiff_t cur, next, found, max = 0;
+      for (cur = 1; cur < Z; cur = next)
+       {
+         next = find_newline1 (cur, CHAR_TO_BYTE (cur), 0, -1, 1,
+                               &found, NULL, true);
+         if (next - cur > max) max = next - cur;
+         if (!found || max > XFIXNUM (Vlong_line_threshold)) break;
+       }
+      if (max > XFIXNUM (Vlong_line_threshold))
+       current_buffer->long_line_optimizations_p = true;
+    }
+
   /* If window-start is screwed up, choose a new one.  */
   if (XMARKER (w->start)->buffer != current_buffer)
     goto recenter;



reply via email to

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