Subject: Re: bug#45898: 27.1; wedged in redisplay again

From: Stefan Monnier <[email-masked]>
Date: Wed, 29 Jun 2022 12:18:47 -0400

Eli Zaretskii [2022-06-24 10:57:30] wrote:
>> Yes, that's exactly what I'm proposing in the paragraph you quoted.
>> I think it makes sense to bound the growth of the region due to
>> `font-lock-extend-region-functions`.  We could bound it where we handle
>> `font-lock-extend-region-functions`, or we could bound it just inside
>> `font-lock-extend-region-wholelines`.
>
> I hope this will be done soon.

How 'bout the patch below?

It doesn't seem to make much difference on the `medium_line.json`
example from Phil, tho :-(

        Stefan

diff --git a/lisp/font-lock.el b/lisp/font-lock.el
index df0a26f4d0f..c6bd93eb2c8 100644
--- a/lisp/font-lock.el
+++ b/lisp/font-lock.el
@@ -1258,19 +1258,31 @@ font-lock-extend-region-multiline
           (setq font-lock-end new-end))))
     changed))
 
+(defvar font-lock-wholeline-max 10000
+  "Maximum line length for `font-lock-extend-region-wholelines'.
+If lines are longer than that, `font-lock-extend-region-wholelines' will
+not always round up to whole lines, and misfontification may occur.
+This is a tradeoff between correctly applying the fontification rules,
+and avoiding major slowdown on pathologically long lines.")
+
 (defun font-lock-extend-region-wholelines ()
   "Move fontification boundaries to beginning of lines."
   (let ((changed nil))
     (goto-char font-lock-beg)
     (unless (bolp)
-      (setq changed t font-lock-beg
-            (let ((inhibit-field-text-motion t))
-              (line-beginning-position))))
+      (let ((new (max (- font-lock-beg font-lock-wholeline-max)
+                      (let ((inhibit-field-text-motion t))
+                        (line-beginning-position)))))
+        (unless (eql new font-lock-beg)
+          (setq changed t)
+          (setq font-lock-beg new))))
     (goto-char font-lock-end)
     (unless (bolp)
-      (unless (eq font-lock-end
-                  (setq font-lock-end (line-beginning-position 2)))
-        (setq changed t)))
+      (let ((new (min (+ font-lock-end font-lock-wholeline-max)
+                      (line-beginning-position 2))))
+        (unless (eql new font-lock-end)
+          (setq changed t)
+          (setq font-lock-end new))))
     changed))
 
 (defun font-lock-default-fontify-region (beg end loudly)