]> git.eshelyaron.com Git - emacs.git/commitdiff
New jit-lock-antiblink-grace feature
authorJoão Távora <joaotavora@gmail.com>
Fri, 12 Jul 2019 18:27:53 +0000 (19:27 +0100)
committerJoão Távora <joaotavora@gmail.com>
Wed, 4 Dec 2019 22:38:06 +0000 (23:38 +0100)
* lisp/jit-lock.el (jit-lock-antiblink-grace): New defcustom.
(jit-lock--antiblink-line-beginning-position)
(jit-lock--antiblink-string-or-comment): New variables
(jit-lock--antiblink-post-command): New helper.
(jit-lock-mode): Tweak post-command-hook and
jit-lock-context-timer.

* etc/NEWS: Mention jit-lock-antiblink-grace

etc/NEWS
lisp/jit-lock.el

index 8a72c31bf9bb7145d4f1b19ca40608f1d4858017..3d17b8f979ce26e02a4db12850d585303e86df42 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -626,6 +626,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 get back the old behavior.
+
 \f
 * Changes in Specialized Modes and Packages in Emacs 27.1
 
index 48998a81fe79b774ea0e435013db8eb11542da01..a17224e4bd08c079321ec5453562d7507d0fe74f 100644 (file)
@@ -123,6 +123,20 @@ The value of this variable is used when JIT Lock mode is turned on."
   :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 @@ If nil, contextual fontification is disabled.")
   "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).")
 \f
 ;;; JIT lock mode
 
@@ -232,7 +253,10 @@ If you need to debug code run from jit-lock, see `jit-lock-debug-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,55 @@ will take place when text is fontified stealthily."
               ;; 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 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 (and release the marker)
+    (set-marker jit-lock--antiblink-line-beginning-position nil)
+    (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