summaryrefslogtreecommitdiff
path: root/lisp
diff options
context:
space:
mode:
authorJoão Távora <joaotavora@gmail.com>2019-07-12 19:27:53 +0100
committerJoão Távora <joaotavora@gmail.com>2019-12-04 23:38:06 +0100
commit5b45c269cda09fe46e110adb6f6767040f4ade59 (patch)
tree0a6cd49204b36d878db339d145d331ab10eb8f5d /lisp
parent0e774d4f355b4f12a625da5ca9602d1ba876bcc1 (diff)
downloademacs-5b45c269cda09fe46e110adb6f6767040f4ade59.tar.gz
New jit-lock-antiblink-grace feature
* 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
Diffstat (limited to 'lisp')
-rw-r--r--lisp/jit-lock.el75
1 files changed, 74 insertions, 1 deletions
diff --git a/lisp/jit-lock.el b/lisp/jit-lock.el
index 48998a81fe7..a17224e4bd0 100644
--- a/lisp/jit-lock.el
+++ b/lisp/jit-lock.el
@@ -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).")
;;; 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