commit 097b685aa1c781afc298062f1cc76ab058cdb1a1 (HEAD, refs/remotes/origin/master) Author: Eshel Yaron Date: Fri Nov 22 08:17:25 2024 +0100 New option 'flyspell-delay-use-timer' * lisp/textmodes/flyspell.el (flyspell-delay-use-timer): New user option. (flyspell--timer): New variable. (flyspell-check-word-p): Use them. (flyspell-post-command-hook): Disable timer. (flyspell-word): Pass non-nil SECONDS argument to 'accept-process-output' to avoid blocking when called from a timer, in which case quitting is inhibited. * etc/NEWS: Announce new option. (bug#74437) diff --git a/etc/NEWS b/etc/NEWS index 51905f49d54..0cd18ed8a39 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -498,6 +498,17 @@ the 'mutool' program after their initial conversion to PDF format. The name of the 'djvused' program can be customized by changing the user option 'doc-view-djvused-program'. +** Flyspell + +--- +*** New user option 'flyspell-delay-use-timer'. +By default, Flyspell waits after so-called "delayed" commands by calling +'sit-for'. If you customize this option to non-nil, Flyspell instead +sets up a timer to perform spell-checking after a short delay, which +allows idle timers and other code to run during this delay period. We +consider making this behavior the default in a future Emacs version, so +we invite Flyspell users to enable this new option and report issues. + ** Tramp +++ diff --git a/lisp/textmodes/flyspell.el b/lisp/textmodes/flyspell.el index 09d4e8a8d1a..9d51ed27371 100644 --- a/lisp/textmodes/flyspell.el +++ b/lisp/textmodes/flyspell.el @@ -810,6 +810,18 @@ Mostly we check word delimiters." (let ((pos (point))) (or (>= pos start) (<= pos stop) (= pos (1+ stop)))))))) +(defcustom flyspell-delay-use-timer nil + "Whether Flyspell should use a timer for waiting after a delayed command. + +If this is non-nil, Flyspell sets up a timer for checking the word at +point `flyspell-delay' seconds after you invoke a delayed command. +Otherwise, if this option is nil, Flyspell uses `sit-for' to wait for +that duration instead." + :type 'boolean + :version "31.1") + +(defvar flyspell--timer nil) + ;;*---------------------------------------------------------------------*/ ;;* flyspell-check-word-p ... */ ;;*---------------------------------------------------------------------*/ @@ -844,7 +856,15 @@ Mostly we check word delimiters." ;; The current command is not delayed, that ;; is that we must check the word now. (and (not unread-command-events) - (sit-for flyspell-delay))) + (if (not flyspell-delay-use-timer) + (sit-for flyspell-delay) + (setq flyspell--timer + (run-with-idle-timer + flyspell-delay nil + (lambda (buffer) + (when (eq (current-buffer) buffer) (flyspell-word))) + (current-buffer))) + nil))) (t t))) (t t)))) @@ -955,6 +975,7 @@ Mostly we check word delimiters." (defun flyspell-post-command-hook () "The `post-command-hook' used by flyspell to check a word on-the-fly." (interactive) + (when (timerp flyspell--timer) (cl-callf cancel-timer flyspell--timer)) (when flyspell-mode (with-local-quit (let ((command this-command) @@ -1179,7 +1200,7 @@ spell-check." (set-process-query-on-exit-flag ispell-process nil) ;; Wait until ispell has processed word. (while (progn - (accept-process-output ispell-process) + (accept-process-output ispell-process 1) (not (string= "" (car ispell-filter))))) ;; (ispell-send-string "!\n") ;; back to terse mode.