emacs-devel
[Top][All Lists]
Advanced

[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: Tue, 26 Nov 2019 02:30:12 +0000

On Mon, Nov 25, 2019 at 9:07 PM João Távora <address@hidden> wrote:

> But even in that particular case, whose frequency I presume to
> be minute in proportion to the number of opened-and-closed
> strings, it can be argued that the patch has a benefit,
> since it's normally easier to spot where you want to end the
> new string made of existing non-string text when it's fontified
> as non-string text.  The amount of CPU spent is also lower.

A correction, again.  This paragraph is an inaccurate description
of how jit-lock-antiblink-grace works when the user wants to
insert multi-line strings. In fact, I believe that scenario produce
mostly the same behaviour in both antiblink-on/antiblink-off cases.

The best way to explain it to show it in action, so I hope the
animated gifs illustrate (from Emacs -Q).

Eli, I also attach an updated patch (which I hope Gmail doesn't
mangle) with the fixes you requested earlier.

Thanks,
João

diff --git a/etc/NEWS b/etc/NEWS
index 7e86ccc71e..e66dd4a21c 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 adding strings to source code, this helps avoid
+\"blinking\", an unwanted oscillation of certain regions between
+string and non-string fontification.
+
+

 * Changes in Specialized Modes and Packages in Emacs 27.1

diff --git a/lisp/jit-lock.el b/lisp/jit-lock.el
index 48998a81fe..23afb53bf8 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
+  "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."
+  :type '(number :tag "seconds")
+  :group 'jit-lock)
+
 (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,15 @@ 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 +255,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 +695,55 @@ 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
+             ;; is per Lars' request, and it makes sense because we
+             ;; should remark 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

Attachment: antiblink-on.gif
Description: GIF image

Attachment: multi-line-strings-antiblink-on-and-off.gif
Description: GIF image

Attachment: antiblink-off.gif
Description: GIF image


reply via email to

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