emacs-diffs
[Top][All Lists]
Advanced

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

master db03eda636: Merge branch 'feature/long-lines-and-font-locking'


From: Gregory Heytings
Subject: master db03eda636: Merge branch 'feature/long-lines-and-font-locking'
Date: Fri, 29 Jul 2022 04:22:32 -0400 (EDT)

branch: master
commit db03eda6369a9d4af3c72a8ab6ec29e3cc58acc4
Merge: 77882158b2 cdaa3b51f1
Author: Gregory Heytings <gregory@heytings.org>
Commit: Gregory Heytings <gregory@heytings.org>

    Merge branch 'feature/long-lines-and-font-locking'
---
 doc/lispref/display.texi   |   6 ++
 doc/lispref/positions.texi |  11 +-
 etc/NEWS                   |  27 +++--
 src/bytecode.c             |   2 +-
 src/dispextern.h           |   8 +-
 src/editfns.c              |  75 +++++++++++--
 src/indent.c               |   5 +
 src/lread.c                |   2 +-
 src/process.c              |   2 +-
 src/xdisp.c                | 256 +++++++++++++++++++++++++++++++++++++++------
 10 files changed, 339 insertions(+), 55 deletions(-)

diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 86f490677d..d2e075c54e 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -3480,6 +3480,12 @@ function finishes are the ones that really matter.
 
 For efficiency, we recommend writing these functions so that they
 usually assign faces to around 400 to 600 characters at each call.
+
+When the buffer text includes very long lines, these functions are
+called with the buffer narrowed to a relatively small region around
+@var{pos}, and with narrowing locked, so the functions cannot use
+@code{widen} to gain access to the rest of the buffer.
+@xref{Narrowing}.
 @end defvar
 
 @node Basic Faces
diff --git a/doc/lispref/positions.texi b/doc/lispref/positions.texi
index ca1166caac..3a9a152f8d 100644
--- a/doc/lispref/positions.texi
+++ b/doc/lispref/positions.texi
@@ -995,13 +995,18 @@ the entire buffer regardless of any narrowing.
 types of text, consider using an alternative facility described in
 @ref{Swapping Text}.
 
-@deffn Command narrow-to-region start end
+@deffn Command narrow-to-region start end &optional lock
 This function sets the accessible portion of the current buffer to start
 at @var{start} and end at @var{end}.  Both arguments should be character
 positions.
 
 In an interactive call, @var{start} and @var{end} are set to the bounds
 of the current region (point and the mark, with the smallest first).
+
+When @var{lock} is non-@code{nil}, calls to @code{widen}, or to
+@code{narrow-to-region} with an optional argument @var{lock}
+@code{nil}, do not produce any effect until the end of the current
+body form.
 @end deffn
 
 @deffn Command narrow-to-page &optional move-count
@@ -1027,6 +1032,10 @@ It is equivalent to the following expression:
 @end example
 @end deffn
 
+However, when @code{widen} is called inside a body form in which
+@code{narrow-to-region} was called with an optional argument
+@code{lock} non-@code{nil}, it does not produce any effect.
+
 @defun buffer-narrowed-p
 This function returns non-@code{nil} if the buffer is narrowed, and
 @code{nil} otherwise.
diff --git a/etc/NEWS b/etc/NEWS
index b6d22fdf2b..43f057a407 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -357,14 +357,20 @@ option) and can be set to nil to disable Just-in-time 
Lock mode.
 ---
 ** Emacs is now capable of editing files with arbitrarily long lines.
 The display of long lines has been optimized, and Emacs no longer
-chokes when a buffer on display contains long lines.  If you still
-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 'C-u C-x x f', 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'.  The variable
+chokes when a buffer on display contains long lines.  The variable
 'long-line-threshold' controls whether and when these display
-optimizations are used.
+optimizations are in effect.
+
+If you still experience slowdowns while editing files with long lines,
+this is due to line truncation, or to one of the enabled minor modes,
+or to the current major mode.  Try turning off line truncation with
+'C-x x t', or try disabling all known slow minor modes with 'M-x
+so-long-minor-mode', or try disabling all known slow minor modes and
+the major mode with 'M-x so-long-mode', or visit the file with 'M-x
+find-file-literally' instead of the usual 'C-x C-f'.
+
+Note that the display optimizations in these cases may cause the
+buffer to be occasionally mis-fontified.
 
 +++
 ** New command to change the font size globally.
@@ -2520,6 +2526,13 @@ things to be saved.
 ** New function 'string-equal-ignore-case'.
 This compares strings ignoring case differences.
 
++++
+** New argument LOCK of 'narrow-to-region'.
+If 'narrow-to-region' is called from Lisp with the new optional
+argument LOCK non-nil, then calls to 'widen' and calls to
+'narrow-to-region' with the optional argument LOCK nil or omitted do
+not produce any effect until the end of the current body form.
+
 ** Themes
 
 ---
diff --git a/src/bytecode.c b/src/bytecode.c
index d75767bb0c..241cbaf04f 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -1481,7 +1481,7 @@ exec_byte_code (Lisp_Object fun, ptrdiff_t args_template,
        CASE (Bnarrow_to_region):
          {
            Lisp_Object v1 = POP;
-           TOP = Fnarrow_to_region (TOP, v1);
+           TOP = Fnarrow_to_region (TOP, v1, Qnil);
            NEXT;
          }
 
diff --git a/src/dispextern.h b/src/dispextern.h
index 1cdfdca74c..2772e8cda8 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2336,6 +2336,10 @@ struct it
      optimize display (see the SET_WITH_NARROWED_BEGV macro).  */
   ptrdiff_t narrowed_begv;
 
+  /* Alternate end position of the buffer that may be used to
+     optimize display.  */
+  ptrdiff_t narrowed_zv;
+
   /* C string to iterate over.  Non-null means get characters from
      this string, otherwise characters are read from current_buffer
      or it->string.  */
@@ -3400,7 +3404,9 @@ void mark_window_display_accurate (Lisp_Object, bool);
 void redisplay_preserve_echo_area (int);
 void init_iterator (struct it *, struct window *, ptrdiff_t,
                     ptrdiff_t, struct glyph_row *, enum face_id);
-ptrdiff_t get_narrowed_begv (struct window *w);
+ptrdiff_t get_narrowed_begv (struct window *);
+ptrdiff_t get_narrowed_zv (struct window *);
+ptrdiff_t get_closer_narrowed_begv (struct window *, ptrdiff_t);
 void init_iterator_to_row_start (struct it *, struct window *,
                                  struct glyph_row *);
 void start_display (struct it *, struct window *, struct text_pos);
diff --git a/src/editfns.c b/src/editfns.c
index 4587b1132b..d15d4dc68b 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -2658,9 +2658,15 @@ DEFUN ("delete-and-extract-region", 
Fdelete_and_extract_region,
 
 DEFUN ("widen", Fwiden, Swiden, 0, 0, "",
        doc: /* Remove restrictions (narrowing) from current buffer.
-This allows the buffer's full text to be seen and edited.  */)
+This allows the buffer's full text to be seen and edited.
+
+When called from Lisp inside a body form in which `narrow-to-region'
+was called with an optional argument LOCK non-nil, this function does
+not produce any effect.  */)
   (void)
 {
+  if (! NILP (Vrestrictions_locked))
+    return Qnil;
   if (BEG != BEGV || Z != ZV)
     current_buffer->clip_changed = 1;
   BEGV = BEG;
@@ -2671,7 +2677,19 @@ This allows the buffer's full text to be seen and 
edited.  */)
   return Qnil;
 }
 
-DEFUN ("narrow-to-region", Fnarrow_to_region, Snarrow_to_region, 2, 2, "r",
+static void
+unwind_locked_begv (Lisp_Object point_min)
+{
+  SET_BUF_BEGV (current_buffer, XFIXNUM (point_min));
+}
+
+static void
+unwind_locked_zv (Lisp_Object point_max)
+{
+  SET_BUF_ZV (current_buffer, XFIXNUM (point_max));
+}
+
+DEFUN ("narrow-to-region", Fnarrow_to_region, Snarrow_to_region, 2, 3, "r",
        doc: /* Restrict editing in this buffer to the current region.
 The rest of the text becomes temporarily invisible and untouchable
 but is not deleted; if you save the buffer in a file, the invisible
@@ -2680,8 +2698,13 @@ See also `save-restriction'.
 
 When calling from Lisp, pass two arguments START and END:
 positions (integers or markers) bounding the text that should
-remain visible.  */)
-  (Lisp_Object start, Lisp_Object end)
+remain visible.
+
+When called from Lisp with the optional argument LOCK non-nil,
+calls to `widen', or to `narrow-to-region' with an optional
+argument LOCK nil, do not produce any effect until the end of
+the current body form.  */)
+  (Lisp_Object start, Lisp_Object end, Lisp_Object lock)
 {
   EMACS_INT s = fix_position (start), e = fix_position (end);
 
@@ -2690,14 +2713,37 @@ remain visible.  */)
       EMACS_INT tem = s; s = e; e = tem;
     }
 
-  if (!(BEG <= s && s <= e && e <= Z))
-    args_out_of_range (start, end);
+  if (! NILP (lock))
+    {
+      if (!(BEGV <= s && s <= e && e <= ZV))
+       args_out_of_range (start, end);
 
-  if (BEGV != s || ZV != e)
-    current_buffer->clip_changed = 1;
+      if (BEGV != s || ZV != e)
+       current_buffer->clip_changed = 1;
+
+      record_unwind_protect (unwind_locked_begv, Fpoint_min ());
+      record_unwind_protect (unwind_locked_zv, Fpoint_max ());
+
+      SET_BUF_BEGV (current_buffer, s);
+      SET_BUF_ZV (current_buffer, e);
+
+      specbind (Qrestrictions_locked, Qt);
+    }
+  else
+    {
+      if (! NILP (Vrestrictions_locked))
+       return Qnil;
+
+      if (!(BEG <= s && s <= e && e <= Z))
+       args_out_of_range (start, end);
+
+      if (BEGV != s || ZV != e)
+       current_buffer->clip_changed = 1;
+
+      SET_BUF_BEGV (current_buffer, s);
+      SET_BUF_ZV (current_buffer, e);
+    }
 
-  SET_BUF_BEGV (current_buffer, s);
-  SET_BUF_ZV (current_buffer, e);
   if (PT < s)
     SET_PT (s);
   if (e < PT)
@@ -4517,6 +4563,15 @@ This variable is experimental; email 
32252@debbugs.gnu.org if you need
 it to be non-nil.  */);
   binary_as_unsigned = false;
 
+  DEFSYM (Qrestrictions_locked, "restrictions-locked");
+  DEFVAR_LISP ("restrictions-locked", Vrestrictions_locked,
+              doc: /* If non-nil, restrictions are currently locked.
+
+This happens when `narrow-to-region', which see, is called from Lisp
+with an optional argument LOCK non-nil.  */);
+  Vrestrictions_locked = Qnil;
+  Funintern (Qrestrictions_locked, Qnil);
+
   defsubr (&Spropertize);
   defsubr (&Schar_equal);
   defsubr (&Sgoto_char);
diff --git a/src/indent.c b/src/indent.c
index d4ef075f00..e90e3fde20 100644
--- a/src/indent.c
+++ b/src/indent.c
@@ -306,6 +306,8 @@ and point (e.g., control characters will have a width of 2 
or 4, tabs
 will have a variable width).
 Ignores finite width of frame, which means that this function may return
 values greater than (frame-width).
+In a buffer with very long lines, the value can be zero, because calculating
+the exact number is very expensive.
 Whether the line is visible (if `selective-display' is t) has no effect;
 however, ^M is treated as end of line when `selective-display' is t.
 Text that has an invisible property is considered as having width 0, unless
@@ -313,6 +315,9 @@ Text that has an invisible property is considered as having 
width 0, unless
   (void)
 {
   Lisp_Object temp;
+
+  if (current_buffer->long_line_optimizations_p)
+    return make_fixnum (0);
   XSETFASTINT (temp, current_column ());
   return temp;
 }
diff --git a/src/lread.c b/src/lread.c
index 0b46a2e4ee..0720774db2 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -2261,7 +2261,7 @@ readevalloop (Lisp_Object readcharfun,
          /* Set point and ZV around stuff to be read.  */
          Fgoto_char (start);
          if (!NILP (end))
-           Fnarrow_to_region (make_fixnum (BEGV), end);
+           Fnarrow_to_region (make_fixnum (BEGV), end, Qnil);
 
          /* Just for cleanliness, convert END to a marker
             if it is an integer.  */
diff --git a/src/process.c b/src/process.c
index 1ac5a509e5..a15efa39bd 100644
--- a/src/process.c
+++ b/src/process.c
@@ -6339,7 +6339,7 @@ Otherwise it discards the output.  */)
 
       /* If the restriction isn't what it should be, set it.  */
       if (old_begv != BEGV || old_zv != ZV)
-       Fnarrow_to_region (make_fixnum (old_begv), make_fixnum (old_zv));
+       Fnarrow_to_region (make_fixnum (old_begv), make_fixnum (old_zv), Qnil);
 
       bset_read_only (current_buffer, old_read_only);
       SET_PT_BOTH (opoint, opoint_byte);
diff --git a/src/xdisp.c b/src/xdisp.c
index e998df32a6..2c889586cd 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -3426,7 +3426,10 @@ init_iterator (struct it *it, struct window *w,
     }
 
   if (current_buffer->long_line_optimizations_p)
-    it->narrowed_begv = get_narrowed_begv (w);
+    {
+      it->narrowed_begv = get_narrowed_begv (w);
+      it->narrowed_zv = get_narrowed_zv (w);
+    }
 
   /* If a buffer position was specified, set the iterator there,
      getting overlays and face properties from that position.  */
@@ -3494,23 +3497,50 @@ init_iterator (struct it *it, struct window *w,
   CHECK_IT (it);
 }
 
-/* Compute a suitable alternate value for BEGV that may be used
+/* Compute a suitable alternate value for BEGV and ZV 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)
+static int
+get_narrowed_width (struct window *w)
 {
-  int len, fact; ptrdiff_t begv;
+  int fact;
   /* In a character-only terminal, only one font size is used, so we
      can use a smaller factor.  */
   fact = EQ (Fterminal_live_p (Qnil), Qt) ? 2 : 3;
-  len = fact * (window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) *
-               window_body_height (w, WINDOW_BODY_IN_CANONICAL_CHARS));
+  return fact * window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS);
+}
+
+static int
+get_narrowed_len (struct window *w)
+{
+  return get_narrowed_width (w) *
+    window_body_height (w, WINDOW_BODY_IN_CANONICAL_CHARS);
+}
+
+ptrdiff_t
+get_narrowed_begv (struct window *w)
+{
+  int len = get_narrowed_len (w);
+  ptrdiff_t begv;
   begv = max ((window_point (w) / len - 1) * len, BEGV);
   return begv == BEGV ? 0 : begv;
 }
 
+ptrdiff_t
+get_narrowed_zv (struct window *w)
+{
+  int len = get_narrowed_len (w);
+  return min ((window_point (w) / len + 1) * len, ZV);
+}
+
+ptrdiff_t
+get_closer_narrowed_begv (struct window *w, ptrdiff_t pos)
+{
+  int len = get_narrowed_width (w);
+  return max ((pos / len - 1) * len, BEGV);
+}
+
 static void
 unwind_narrowed_begv (Lisp_Object point_min)
 {
@@ -3518,15 +3548,15 @@ unwind_narrowed_begv (Lisp_Object point_min)
 }
 
 /* Set DST to EXPR.  When IT indicates that BEGV should temporarily be
-   updated to optimize display, evaluate EXPR with an updated BEGV.  */
+   updated to optimize display, evaluate EXPR with BEGV set to BV.  */
 
-#define SET_WITH_NARROWED_BEGV(IT,DST,EXPR)                            \
+#define SET_WITH_NARROWED_BEGV(IT,DST,EXPR,BV)                         \
   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);               \
+       SET_BUF_BEGV (current_buffer, BV);                              \
        DST = EXPR;                                                     \
        unbind_to (count, Qnil);                                        \
       }                                                                        
\
@@ -4377,6 +4407,10 @@ handle_fontified_prop (struct it *it)
 
       eassert (it->end_charpos == ZV);
 
+      if (it->narrowed_begv)
+       Fnarrow_to_region (make_fixnum (it->narrowed_begv),
+                          make_fixnum (it->narrowed_zv), Qt);
+
       /* Don't allow Lisp that runs from 'fontification-functions'
         clear our face and image caches behind our back.  */
       it->f->inhibit_clear_image_cache = true;
@@ -7035,7 +7069,108 @@ back_to_previous_line_start (struct it *it)
 
   dec_both (&cp, &bp);
   SET_WITH_NARROWED_BEGV (it, IT_CHARPOS (*it),
-                         find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it)));
+                         find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it)),
+                         get_closer_narrowed_begv (it->w, IT_CHARPOS (*it)));
+}
+
+/* Find in the current buffer the first display or overlay string
+   between STARTPOS and ENDPOS that includes embedded newlines.
+   Consider only overlays that apply to window W.
+   Value is non-zero if such a display/overlay string is found.  */
+static bool
+strings_with_newlines (ptrdiff_t startpos, ptrdiff_t endpos, struct window *w)
+{
+  /* Process overlays before the overlay center.  */
+  for (struct Lisp_Overlay *ov = current_buffer->overlays_before;
+       ov; ov = ov->next)
+    {
+      Lisp_Object overlay = make_lisp_ptr (ov, Lisp_Vectorlike);
+      eassert (OVERLAYP (overlay));
+
+      /* Skip this overlay if it doesn't apply to our window.  */
+      Lisp_Object window = Foverlay_get (overlay, Qwindow);
+      if (WINDOWP (window) && XWINDOW (window) != w)
+       continue;
+
+      ptrdiff_t ostart = OVERLAY_POSITION (OVERLAY_START (overlay));
+      ptrdiff_t oend = OVERLAY_POSITION (OVERLAY_END (overlay));
+
+      /* Due to the order of overlays in overlays_before, once we get
+        to an overlay whose end position is before STARTPOS, all the
+        rest also end before STARTPOS, and thus are of no concern to us.  */
+      if (oend < startpos)
+       break;
+
+      /* Skip overlays that don't overlap the range.  */
+      if (!((startpos < oend && ostart < endpos)
+           || (ostart == oend
+               && (startpos == oend || (endpos == ZV && oend == endpos)))))
+       continue;
+
+      Lisp_Object str;
+      str = Foverlay_get (overlay, Qbefore_string);
+      if (STRINGP (str) && SCHARS (str)
+         && memchr (SDATA (str), '\n', SBYTES (str)))
+       return true;
+      str = Foverlay_get (overlay, Qafter_string);
+      if (STRINGP (str) && SCHARS (str)
+         && memchr (SDATA (str), '\n', SBYTES (str)))
+       return true;
+    }
+
+  /* Process overlays after the overlay center.  */
+  for (struct Lisp_Overlay *ov = current_buffer->overlays_after;
+       ov; ov = ov->next)
+    {
+      Lisp_Object overlay = make_lisp_ptr (ov, Lisp_Vectorlike);
+      eassert (OVERLAYP (overlay));
+
+      /* Skip this overlay if it doesn't apply to our window.  */
+      Lisp_Object window = Foverlay_get (overlay, Qwindow);
+      if (WINDOWP (window) && XWINDOW (window) != w)
+       continue;
+
+      ptrdiff_t ostart = OVERLAY_POSITION (OVERLAY_START (overlay));
+      ptrdiff_t oend = OVERLAY_POSITION (OVERLAY_END (overlay));
+
+      /* Due to the order of overlays in overlays_after, once we get
+        to an overlay whose start position is after ENDPOS, all the
+        rest also start after ENDPOS, and thus are of no concern to us.  */
+      if (ostart > endpos)
+       break;
+
+      /* Skip overlays that don't overlap the range.  */
+      if (!((startpos < oend && ostart < endpos)
+           || (ostart == oend
+               && (startpos == oend || (endpos == ZV && oend == endpos)))))
+       continue;
+
+      Lisp_Object str;
+      str = Foverlay_get (overlay, Qbefore_string);
+      if (STRINGP (str) && SCHARS (str)
+         && memchr (SDATA (str), '\n', SBYTES (str)))
+       return true;
+      str = Foverlay_get (overlay, Qafter_string);
+      if (STRINGP (str) && SCHARS (str)
+         && memchr (SDATA (str), '\n', SBYTES (str)))
+       return true;
+    }
+
+  /* Check for 'display' properties whose values include strings.  */
+  Lisp_Object cpos = make_fixnum (startpos);
+  Lisp_Object limpos = make_fixnum (endpos);
+
+  while ((cpos = Fnext_single_property_change (cpos, Qdisplay, Qnil, limpos),
+         !(NILP (cpos) || XFIXNAT (cpos) >= endpos)))
+    {
+      Lisp_Object spec = Fget_char_property (cpos, Qdisplay, Qnil);
+      Lisp_Object string = string_from_display_spec (spec);
+      if (STRINGP (string)
+         && memchr (SDATA (string), '\n', SBYTES (string)))
+       return true;
+    }
+
+  return false;
 }
 
 
@@ -7090,7 +7225,8 @@ forward_to_next_line_start (struct it *it, bool 
*skipped_p,
   it->selective = 0;
 
   /* Scan for a newline within MAX_NEWLINE_DISTANCE display elements
-     from buffer text.  */
+     from buffer text, or till the end of the string if iterating a
+     string.  */
   for (n = 0;
        !newline_found_p && n < MAX_NEWLINE_DISTANCE;
        n += !STRINGP (it->string))
@@ -7110,27 +7246,55 @@ forward_to_next_line_start (struct it *it, bool 
*skipped_p,
       ptrdiff_t bytepos, start = IT_CHARPOS (*it);
       ptrdiff_t limit = find_newline_no_quit (start, IT_BYTEPOS (*it),
                                              1, &bytepos);
-      Lisp_Object pos;
-
       eassert (!STRINGP (it->string));
 
-      /* If there isn't any `display' property in sight, and no
-        overlays, we can just use the position of the newline in
-        buffer text.  */
-      if (it->stop_charpos >= limit
-         || ((pos = Fnext_single_property_change (make_fixnum (start),
-                                                  Qdisplay, Qnil,
-                                                  make_fixnum (limit)),
-              NILP (pos))
-             && next_overlay_change (start) == ZV))
+      /* it->stop_charpos >= limit means we already know there's no
+        stop position up until the newline at LIMIT, so there's no
+        need for any further checks.  */
+      bool no_strings_with_newlines = it->stop_charpos >= limit;
+
+      if (!no_strings_with_newlines)
        {
-         if (!it->bidi_p)
+         if (!(current_buffer->long_line_optimizations_p
+               && it->line_wrap == TRUNCATE))
+           {
+             /* Quick-and-dirty check: if there isn't any `display'
+                property in sight, and no overlays, we're done.  */
+             Lisp_Object pos =
+               Fnext_single_property_change (make_fixnum (start),
+                                             Qdisplay, Qnil,
+                                             make_fixnum (limit));
+             no_strings_with_newlines =
+               (NILP (pos) || XFIXNAT (pos) == limit) /* no 'display' props */
+               && next_overlay_change (start) == ZV;  /* no overlays */
+           }
+         else
+           {
+             /* For buffers with very long and truncated lines we try
+                harder, because it's worth our while to spend some
+                time looking into the overlays and 'display' properties
+                if we can then avoid iterating through all of them.  */
+             no_strings_with_newlines =
+               !strings_with_newlines (start, limit, it->w);
+           }
+       }
+
+      /* If there's no display or overlay strings with embedded
+        newlines until the position of the newline in buffer text, we
+        can just use that position.  */
+      if (no_strings_with_newlines)
+       {
+         if (!it->bidi_p || !bidi_it_prev)
            {
+             /* The optimal case: just jump there.  */
              IT_CHARPOS (*it) = limit;
              IT_BYTEPOS (*it) = bytepos;
            }
          else
            {
+             /* The less optimal case: need to bidi-walk there, but
+                this is still cheaper that the full iteration using
+                get_next_display_element and set_iterator_to_next.  */
              struct bidi_it bprev;
 
              /* Help bidi.c avoid expensive searches for display
@@ -7154,6 +7318,7 @@ forward_to_next_line_start (struct it *it, bool 
*skipped_p,
        }
       else
        {
+         /* The slow case.  */
          while (!newline_found_p)
            {
              if (!get_next_display_element (it))
@@ -7287,7 +7452,8 @@ reseat_at_next_visible_line_start (struct it *it, bool 
on_newline_p)
   bool skipped_p = false;
   struct bidi_it bidi_it_prev;
   bool newline_found_p
-    = forward_to_next_line_start (it, &skipped_p, &bidi_it_prev);
+    = forward_to_next_line_start (it, &skipped_p,
+                                 on_newline_p ? &bidi_it_prev : NULL);
 
   /* Skip over lines that are invisible because they are indented
      more than the value of IT->selective.  */
@@ -7299,7 +7465,8 @@ reseat_at_next_visible_line_start (struct it *it, bool 
on_newline_p)
        eassert (IT_BYTEPOS (*it) == BEGV
                 || FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
        newline_found_p =
-         forward_to_next_line_start (it, &skipped_p, &bidi_it_prev);
+         forward_to_next_line_start (it, &skipped_p,
+                                     on_newline_p ? &bidi_it_prev : NULL);
       }
 
   /* Position on the newline if that's what's requested.  */
@@ -8672,7 +8839,8 @@ get_visually_first_element (struct it *it)
 
   SET_WITH_NARROWED_BEGV (it, bob,
                          string_p ? 0 :
-                         IT_BYTEPOS (*it) < BEGV ? obegv : BEGV);
+                         IT_BYTEPOS (*it) < BEGV ? obegv : BEGV,
+                         it->narrowed_begv);
 
   if (STRINGP (it->string))
     {
@@ -8715,7 +8883,8 @@ get_visually_first_element (struct it *it)
        SET_WITH_NARROWED_BEGV (it, it->bidi_it.charpos,
                                find_newline_no_quit (IT_CHARPOS (*it),
                                                      IT_BYTEPOS (*it), -1,
-                                                     &it->bidi_it.bytepos));
+                                                     &it->bidi_it.bytepos),
+                               it->narrowed_begv);
       bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, true);
       do
        {
@@ -10634,7 +10803,8 @@ move_it_vertically_backward (struct it *it, int dy)
 
          dec_both (&cp, &bp);
          SET_WITH_NARROWED_BEGV (it, cp,
-                                 find_newline_no_quit (cp, bp, -1, NULL));
+                                 find_newline_no_quit (cp, bp, -1, NULL),
+                                 it->narrowed_begv);
          move_it_to (it, cp, -1, -1, -1, MOVE_TO_POS);
        }
       bidi_unshelve_cache (it3data, true);
@@ -12964,7 +13134,8 @@ mode_line_update_needed (struct window *w)
 {
   return (w->column_number_displayed != -1
          && !(PT == w->last_point && !window_outdated (w))
-         && (w->column_number_displayed != current_column ()));
+         && (!current_buffer->long_line_optimizations_p
+             && w->column_number_displayed != current_column ()));
 }
 
 /* True if window start of W is frozen and may not be changed during
@@ -18936,8 +19107,9 @@ set_vertical_scroll_bar (struct window *w)
       end = BUF_Z (buf) - w->window_end_pos - BUF_BEGV (buf);
 
       /* If w->window_end_pos cannot be trusted, recompute it "the
-        hard way".  */
-      if (!MINI_WINDOW_P (w))
+        hard way".  But don't bother to be too accurate when
+        long-line shortcuts are in effect.  */
+      if (!w->window_end_valid && !buf->long_line_optimizations_p)
        {
          struct it it;
          struct text_pos start_pos;
@@ -20086,6 +20258,7 @@ redisplay_window (Lisp_Object window, bool 
just_this_one_p)
        || w->base_line_pos > 0
        /* Column number is displayed and different from the one displayed.  */
        || (w->column_number_displayed != -1
+          && !current_buffer->long_line_optimizations_p
           && (w->column_number_displayed != current_column ())))
       /* This means that the window has a mode line.  */
       && (window_wants_mode_line (w)
@@ -27587,6 +27760,17 @@ decode_mode_spec (struct window *w, register int c, 
int field_width,
          even crash emacs.)  */
       if (mode_line_target == MODE_LINE_TITLE)
        return "";
+      else if (b->long_line_optimizations_p)
+       {
+         char *p = decode_mode_spec_buf;
+         int pad = width - 2;
+         while (pad-- > 0)
+           *p++ = ' ';
+         *p++ = '?';
+         *p++ = '?';
+         *p = '\0';
+         return decode_mode_spec_buf;
+       }
       else
        {
          ptrdiff_t col = current_column ();
@@ -36473,7 +36657,13 @@ The tool bar style must also show labels for this to 
have any effect, see
     doc: /* List of functions to call to fontify regions of text.
 Each function is called with one argument POS.  Functions must
 fontify a region starting at POS in the current buffer, and give
-fontified regions the property `fontified'.  */);
+fontified regions the property `fontified' with a non-nil value.
+
+Note that, when the buffer contains one or more lines whose length is
+above `long-line-threshold', these functions only have access to a
+small portion of the buffer around POS, and cannot use `widen' to gain
+access to other portions of buffer text because the narrowing of the
+buffer is locked (see `narrow-to-region').  */);
   Vfontification_functions = Qnil;
   Fmake_variable_buffer_local (Qfontification_functions);
 



reply via email to

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