[Top][All Lists]

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

Re: jit-lock-antiblink-grace

From: João Távora
Subject: Re: jit-lock-antiblink-grace
Date: Sat, 30 Nov 2019 19:11:57 +0000
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux)

Eli Zaretskii <address@hidden> writes:

>> +---
>> +** New customizable variable 'jit-lock-antiblink-grace'.
>> +When adding strings to source code, this helps avoid
>> +\"blinking\", an unwanted oscillation of certain regions between
>> +string and non-string fontification.
> Escaping quotes in NEWS is not needed/expected.


> And this entry doesn't say what is the default value, and doesn't tell
> how to get back old behavior.


I didn't mention because I found examples in NEWS that don't.  But
mostly because we haven't come to a decision yet.  I generally agree
with Stefan and I propose the latest patch with the default value of 2
seconds for jit-lock-antiblink-grace.

However, I have detected a case where jit-lock-antiblink-grace kicks in
and, while not exactly causing a regression in useful behaviour, also
doesn't add any useful behaviour.  Here is the case:

a.  You want to make a string region in a non-string buffer of 10 lines
    between line 3 and 7.
b.  You go to line 7 and type a quote
c.  You go to line 3 and type a quote

Previously, after step b) you would get lines 8, 9, and 10 (and 7
partially) string-fontified "immediately".

Now, after step b), and _if stay on the same line_, it takes 2 seconds
for lines 7-10 to be string-fontified.  If you leave line 7 in your
journey to line 3 before those 2 seconds are up, 7-10 are immediately
string-fontified (and the old and new version become identical in

It may be argued by users that create strings like this that the
antiblink grace timer wasn't useful at all, or that it mis-fired: these
users were already counting on (temporarily) invalidly fontified lines
7-10, so they were suprised that it didn't happen immediately (or rather
that it didn't happen after a short jit-lock-context-time delay).

I think most users will do step c) before step b), and this doesn't
present any problem.

>> +(defcustom jit-lock-antiblink-grace 2
>> +  "Idle time after which to refontify due to unterminated strings.
>> +If the user creates a temporarily unterminated string up to the
>> +end of the current line, that part of the line is fontified after
>> +`jit-lock-context-time', but an extended idle \"grace\" period of
>> +this many seconds is granted before deciding it is a multi-line
>> +string and fontifying the remainder of the buffer accordingly.
>> +When adding strings to source code, this helps avoid
>> +\"blinking\", an unwanted oscillation of certain regions between
>> +string and non-string fontification.  If nil, there is no grace
>> +period."
> This is too wordy.  If you think this description is necessary, we
> probably need to move most of it into the user manual.

Fixed.  Tho you'll see it was about as wordy as the other jit-lock
defcustoms preceding it.  Hope it's better now.

>> +  :type '(number :tag "seconds")
>> +  :group 'jit-lock)
> Missing :version.


>> +           (when jit-lock--antiblink-grace-timer
>> +             ;; Do refontify immediately, adding a small delay.  This
>> +             ;; is per Lars' request, and it makes sense because we
>                       ^^^^^^^^^^^^^^^^^
> Let's leave personae out of the code, okay?

I really meant the person.  But okay.


diff --git a/etc/NEWS b/etc/NEWS
index 7e86ccc71e..2f2acd52ac 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -604,6 +604,13 @@ If the region is active, the command joins all the lines 
in the
 region.  When there's no active region, the command works on the
 current and the previous or the next line, as before.
+** New customizable variable 'jit-lock-antiblink-grace'.
+When typing strings, this helps avoid "blinking", an oscillation
+between string and non-string fontification.  The variable holds a
+number of seconds (default is 2) before a potentially unwanted
+fontification starts.  Set to nil to deactivate.

 * Changes in Specialized Modes and Packages in Emacs 27.1
diff --git a/lisp/jit-lock.el b/lisp/jit-lock.el
index 48998a81fe..c896c9d5ea 100644
--- a/lisp/jit-lock.el
+++ b/lisp/jit-lock.el
@@ -123,6 +123,20 @@ jit-lock-context-time
   :type '(number :tag "seconds")
   :group 'jit-lock)
+(defcustom jit-lock-antiblink-grace 2
+  "Grace period after which to refontify due to unterminated strings.
+If nil, no grace period is given.  Otherwise, a newly created
+unterminated string is fontified only to the end of the current
+line, after which the system waits this many seconds of idle time
+before deciding the string is multi-line and fontifying the
+remaining lines.  When typing strings, this helps avoid
+\"blinking\", an unwanted oscillation between string and
+non-string fontification."
+  :type '(choice (const :tag "never" nil)
+                (number :tag "seconds"))
+  :group 'jit-lock
+  :version "27.1")
 (defcustom jit-lock-defer-time nil ;; 0.25
   "Idle time after which deferred fontification should take place.
 If nil, fontification is not deferred.
@@ -157,6 +171,13 @@ jit-lock-defer-buffers
   "List of buffers with pending deferred fontification.")
 (defvar jit-lock-stealth-buffers nil
   "List of buffers that are being fontified stealthily.")
+(defvar jit-lock--antiblink-grace-timer nil
+  "Idle timer for fontifying unterminated string or comment, or nil.")
+(defvar jit-lock--antiblink-line-beginning-position (make-marker)
+  "Last line beginning position after last command (a marker).")
+(defvar jit-lock--antiblink-string-or-comment nil
+  "Non-nil if in string or comment after last command (a boolean).")

 ;;; JIT lock mode
@@ -232,7 +253,10 @@ jit-lock-mode
       (unless jit-lock-context-timer
         (setq jit-lock-context-timer
               (run-with-idle-timer jit-lock-context-time t
-                                   'jit-lock-context-fontify)))
+                                   (lambda ()
+                                     (unless jit-lock--antiblink-grace-timer
+                                       (jit-lock-context-fontify))))))
+      (add-hook 'post-command-hook 'jit-lock--antiblink-post-command nil t)
       (setq jit-lock-context-unfontify-pos
             (or jit-lock-context-unfontify-pos (point-max))))
@@ -669,6 +693,54 @@ jit-lock-after-change
               ;; buffer, only jit-lock-context-* will re-fontify it.
               (min jit-lock-context-unfontify-pos jit-lock-start))))))
+(defun jit-lock--antiblink-post-command ()
+  (let* ((new-l-b-p (copy-marker (line-beginning-position)))
+         (l-b-p-2 (line-beginning-position 2))
+         (same-line
+          (and jit-lock-antiblink-grace
+               (not (= new-l-b-p l-b-p-2))
+               (eq (marker-buffer jit-lock--antiblink-line-beginning-position)
+                   (current-buffer))
+               (= new-l-b-p jit-lock--antiblink-line-beginning-position)))
+         (new-s-o-c
+          (and same-line
+               (nth 8 (save-excursion (syntax-ppss l-b-p-2))))))
+    (cond (;; opened a new multiline string...
+           (and same-line
+                (null jit-lock--antiblink-string-or-comment) new-s-o-c)
+           (setq jit-lock--antiblink-grace-timer
+                 (run-with-idle-timer jit-lock-antiblink-grace nil
+                                      (lambda ()
+                                        (jit-lock-context-fontify)
+                                        (setq jit-lock--antiblink-grace-timer
+                                              nil)))))
+          (;; closed an unterminated multiline string.
+           (and same-line
+                (null new-s-o-c) jit-lock--antiblink-string-or-comment)
+           ;; Kill the grace timer, might already have run and died.
+           ;; Don't refontify immediately: it adds an unreasonable
+           ;; delay to a well-behaved operation.  Leave it for the
+           ;; `jit-lock-context-timer' as usual.
+           (when jit-lock--antiblink-grace-timer
+             (cancel-timer jit-lock--antiblink-grace-timer)
+             (setq jit-lock--antiblink-grace-timer nil)))
+          (same-line
+           ;; in same line, but no state change, leave everything as it was
+           )
+          (t
+           ;; left the line somehow or customized feature away, etc
+           ;; kill timer if running, resume normal operation.
+           (when jit-lock--antiblink-grace-timer
+             ;; Do refontify immediately, adding a small delay.  This
+             ;; makes sense because it remarks somehow that we are
+             ;; leaving the unstable state.
+             (jit-lock-context-fontify)
+             (cancel-timer jit-lock--antiblink-grace-timer)
+             (setq jit-lock--antiblink-grace-timer nil))))
+    ;; update variables
+    (setq jit-lock--antiblink-line-beginning-position new-l-b-p
+          jit-lock--antiblink-string-or-comment new-s-o-c)))
 (provide 'jit-lock)
 ;;; jit-lock.el ends here

reply via email to

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