Be lazy when starting Flymake checks

Don't start the check immediately if the buffer is not being
displayed.  Wait until it is, using window-configuration-change-hook.

This enables the user to batch-enable flymake-mode on many buffers and
not have that operation exhaust system resources for checking each
one.  Likewise, an editing or save operation in a currently
non-displayed buffer does not immediately start a check.

* lisp/progmodes/flymake.el (flymake-start-on-flymake-mode):
Rename from flymake-start-syntax-check-on-find-file.
(flymake-start-syntax-check-on-find-file): Obsolete alias for
flymake-start-on-flymake-mode.
(flymake-start): Redesign.  Affect the global post-command-hook
and local window-configuraiton-change-hook.
(flymake--schedule-timer-maybe)
(flymake-after-change-function, flymake-after-save-hook): Pass
t to flymake-start.

* test/lisp/progmodes/flymake-tests.el (flymake-tests--call-with-fixture)
(dummy-backends, recurrent-backend): Start flymake check
explicitly and immediately.
This commit is contained in:
João Távora 2017-10-09 11:12:57 +01:00
parent 36ed9a9ede
commit 11b37b4a9f
2 changed files with 68 additions and 33 deletions

View file

@ -123,10 +123,14 @@ If nil, never start checking buffer automatically like this."
(make-obsolete-variable 'flymake-gui-warnings-enabled (make-obsolete-variable 'flymake-gui-warnings-enabled
"it no longer has any effect." "26.1") "it no longer has any effect." "26.1")
(defcustom flymake-start-syntax-check-on-find-file t (defcustom flymake-start-on-flymake-mode t
"Start syntax check on find file." "Start syntax check when `pflymake-mode'is enabled.
Specifically, start it when the buffer is actually displayed."
:type 'boolean) :type 'boolean)
(define-obsolete-variable-alias 'flymake-start-syntax-check-on-find-file
'flymake-start-on-flymake-mode "26.1")
(defcustom flymake-log-level -1 (defcustom flymake-log-level -1
"Obsolete and ignored variable." "Obsolete and ignored variable."
:type 'integer) :type 'integer)
@ -670,33 +674,59 @@ If it is running also stop it."
(flymake--disable-backend backend err))))) (flymake--disable-backend backend err)))))
(defun flymake-start (&optional deferred force) (defun flymake-start (&optional deferred force)
"Start a syntax check. "Start a syntax check for the current buffer.
Start it immediately, or after current command if DEFERRED is DEFERRED is a list of symbols designating conditions to wait for
non-nil. With optional FORCE run even disabled backends. before actually starting the check. If it is nil (the list is
empty), start it immediately, else defer the check to when those
conditions are met. Currently recognized conditions are
`post-command', for waiting until the current command is over,
`on-display', for waiting until the buffer is actually displayed
in a window. If DEFERRED is t, wait for all known conditions.
With optional FORCE run even disabled backends.
Interactively, with a prefix arg, FORCE is t." Interactively, with a prefix arg, FORCE is t."
(interactive (list nil current-prefix-arg)) (interactive (list nil current-prefix-arg))
(cl-labels (let ((deferred (if (eq t deferred)
((start '(post-command on-display)
() deferred))
(remove-hook 'post-command-hook #'start 'local) (buffer (current-buffer)))
(setq flymake-check-start-time (float-time)) (cl-labels
(run-hook-wrapped ((start-post-command
'flymake-diagnostic-functions ()
(lambda (backend) (remove-hook 'post-command-hook #'start-post-command
(cond nil)
((and (not force) (with-current-buffer buffer
(flymake--with-backend-state backend state (flymake-start (remove 'post-command deferred) force)))
(flymake--backend-state-disabled state))) (start-on-display
(flymake-log :debug "Backend %s is disabled, not starting" ()
backend)) (remove-hook 'window-configuration-change-hook #'start-on-display
'local)
(flymake-start (remove 'on-display deferred) force)))
(cond ((and (memq 'post-command deferred)
this-command)
(add-hook 'post-command-hook
#'start-post-command
'append nil))
((and (memq 'on-display deferred)
(not (get-buffer-window (current-buffer))))
(add-hook 'window-configuration-change-hook
#'start-on-display
'append 'local))
(t (t
(flymake--run-backend backend))) (setq flymake-check-start-time (float-time))
nil)))) (run-hook-wrapped
(if (and deferred 'flymake-diagnostic-functions
this-command) (lambda (backend)
(add-hook 'post-command-hook #'start 'append 'local) (cond
(start)))) ((and (not force)
(flymake--with-backend-state backend state
(flymake--backend-state-disabled state)))
(flymake-log :debug "Backend %s is disabled, not starting"
backend))
(t
(flymake--run-backend backend)))
nil)))))))
(defvar flymake-mode-map (defvar flymake-mode-map
(let ((map (make-sparse-keymap))) map) (let ((map (make-sparse-keymap))) map)
@ -714,8 +744,7 @@ Interactively, with a prefix arg, FORCE is t."
(setq flymake--backend-state (make-hash-table)) (setq flymake--backend-state (make-hash-table))
(when flymake-start-syntax-check-on-find-file (when flymake-start-on-flymake-mode (flymake-start t)))
(flymake-start)))
;; Turning the mode OFF. ;; Turning the mode OFF.
(t (t
@ -748,7 +777,7 @@ Do it only if `flymake-no-changes-timeout' is non-nil."
(flymake-log (flymake-log
:debug "starting syntax check after idle for %s seconds" :debug "starting syntax check after idle for %s seconds"
flymake-no-changes-timeout) flymake-no-changes-timeout)
(flymake-start)) (flymake-start t))
(setq flymake-timer nil)))) (setq flymake-timer nil))))
(current-buffer))))) (current-buffer)))))
@ -770,13 +799,13 @@ Do it only if `flymake-no-changes-timeout' is non-nil."
(let((new-text (buffer-substring start stop))) (let((new-text (buffer-substring start stop)))
(when (and flymake-start-syntax-check-on-newline (equal new-text "\n")) (when (and flymake-start-syntax-check-on-newline (equal new-text "\n"))
(flymake-log :debug "starting syntax check as new-line has been seen") (flymake-log :debug "starting syntax check as new-line has been seen")
(flymake-start 'deferred)) (flymake-start t))
(flymake--schedule-timer-maybe))) (flymake--schedule-timer-maybe)))
(defun flymake-after-save-hook () (defun flymake-after-save-hook ()
(when flymake-mode (when flymake-mode
(flymake-log :debug "starting syntax check as buffer was saved") (flymake-log :debug "starting syntax check as buffer was saved")
(flymake-start))) (flymake-start t)))
(defun flymake-kill-buffer-hook () (defun flymake-kill-buffer-hook ()
(when flymake-timer (when flymake-timer

View file

@ -73,7 +73,9 @@ SEVERITY-PREDICATE is used to setup
(when sev-pred-supplied-p (when sev-pred-supplied-p
(setq-local flymake-proc-diagnostic-type-pred severity-predicate)) (setq-local flymake-proc-diagnostic-type-pred severity-predicate))
(goto-char (point-min)) (goto-char (point-min))
(unless flymake-mode (flymake-mode 1)) (let ((flymake-start-on-flymake-mode nil))
(unless flymake-mode (flymake-mode 1)))
(flymake-start)
(flymake-tests--wait-for-backends) (flymake-tests--wait-for-backends)
(funcall fn))) (funcall fn)))
(and buffer (and buffer
@ -230,7 +232,9 @@ SEVERITY-PREDICATE is used to setup
'crashing-backend 'crashing-backend
)) ))
(flymake-wrap-around nil)) (flymake-wrap-around nil))
(flymake-mode) (let ((flymake-start-on-flymake-mode nil))
(flymake-mode))
(flymake-start)
(flymake-tests--assert-set (flymake-running-backends) (flymake-tests--assert-set (flymake-running-backends)
(error-backend warning-backend panicking-backend) (error-backend warning-backend panicking-backend)
@ -299,7 +303,9 @@ SEVERITY-PREDICATE is used to setup
(let ((flymake-diagnostic-functions (let ((flymake-diagnostic-functions
(list 'eager-backend)) (list 'eager-backend))
(flymake-wrap-around nil)) (flymake-wrap-around nil))
(flymake-mode) (let ((flymake-start-on-flymake-mode nil))
(flymake-mode))
(flymake-start)
(flymake-tests--assert-set (flymake-running-backends) (flymake-tests--assert-set (flymake-running-backends)
(eager-backend) ()) (eager-backend) ())
(cl-loop until tick repeat 4 do (sleep-for 0.2)) (cl-loop until tick repeat 4 do (sleep-for 0.2))