(define-globalized-minor-mode): Require the use of run-mode-hooks

When `define-globalized-minor-mode` was introduced (Emacs-22),
`run-mode-hooks` was brand new, so we could not expect all major
modes to use it and we had to rely on brittle workarounds to try
and approximate `after-change-major-mode-hook`.

These workarounds have undesirable side effects, and (we hope)
they're not needed any more now that virtually all major modes
have been changed to use `run-mode-hooks` (or
`define-derived-mode`).

* lisp/emacs-lisp/easy-mmode.el (define-globalized-minor-mode):
Rely only on `after-change-major-mode-hook`, remove the "cmhh"
[typo for the intended "cmmh", BTW] workaround.

* doc/lispref/modes.texi (Mode Hooks): Clarify the importance of
`after-change-major-mode-hook` w.r.t `define-globalized-minor-mode`.
(Defining Minor Modes): Rewrite the explanation of which buffers
are affected, including adjusting it to the fact that
`fundamental-mode` has used run `run-mode-hooks` for last 10 years.
This commit is contained in:
Stefan Monnier 2024-04-13 10:31:28 -04:00
parent 3f7e26e2be
commit 17e26cf57e
3 changed files with 20 additions and 63 deletions

View file

@ -495,11 +495,6 @@ on if the hook has explicitly disabled it.
(MODE-buffers (intern (concat global-mode-name "-buffers")))
(MODE-enable-in-buffer
(intern (concat global-mode-name "-enable-in-buffer")))
(MODE-enable-in-buffers
(intern (concat global-mode-name "-enable-in-buffers")))
(MODE-check-buffers
(intern (concat global-mode-name "-check-buffers")))
(MODE-cmhh (intern (concat global-mode-name "-cmhh")))
(minor-MODE-hook (intern (concat mode-name "-hook")))
(MODE-set-explicitly (intern (concat mode-name "-set-explicitly")))
(MODE-major-mode (intern (concat (symbol-name mode) "-major-mode")))
@ -559,14 +554,9 @@ Disable the mode if ARG is a negative number.\n\n"
;; Setup hook to handle future mode changes and new buffers.
(if ,global-mode
(progn
(add-hook 'after-change-major-mode-hook
#',MODE-enable-in-buffer)
(add-hook 'find-file-hook #',MODE-check-buffers)
(add-hook 'change-major-mode-hook #',MODE-cmhh))
(remove-hook 'after-change-major-mode-hook #',MODE-enable-in-buffer)
(remove-hook 'find-file-hook #',MODE-check-buffers)
(remove-hook 'change-major-mode-hook #',MODE-cmhh))
(add-hook 'after-change-major-mode-hook
#',MODE-enable-in-buffer)
(remove-hook 'after-change-major-mode-hook #',MODE-enable-in-buffer))
;; Go through existing buffers.
(dolist (buf (buffer-list))
@ -623,51 +613,7 @@ list."
(funcall ,turn-on-function))
(funcall ,turn-on-function))))
(setq ,MODE-major-mode major-mode))
(put ',MODE-enable-in-buffer 'definition-name ',global-mode)
;; In the normal case, major modes run `after-change-major-mode-hook'
;; which will have called `MODE-enable-in-buffer' for us. But some
;; major modes don't use `run-mode-hooks' (customarily used via
;; `define-derived-mode') and thus fail to run
;; `after-change-major-mode-hook'.
;; The functions below try to handle those major modes, with
;; a combination of ugly hacks to try and catch those corner
;; cases by listening to `change-major-mode-hook' to discover
;; potential candidates and then checking in `post-command-hook'
;; and `find-file-hook' if some of those still haven't run
;; `after-change-major-mode-hook'. FIXME: We should try and get
;; rid of this ugly hack and rely purely on
;; `after-change-major-mode-hook' because they can (and do) end
;; up running `MODE-enable-in-buffer' too early (when the major
;; isn't yet fully setup) in some cases (see bug#58888).
;; The function that calls TURN-ON in each buffer.
(defun ,MODE-enable-in-buffers ()
(let ((buffers ,MODE-buffers))
;; Clear MODE-buffers to avoid scanning the same list of
;; buffers in recursive calls to MODE-enable-in-buffers.
;; Otherwise it could lead to infinite recursion.
(setq ,MODE-buffers nil)
(dolist (buf buffers)
(when (buffer-live-p buf)
(with-current-buffer buf
(,MODE-enable-in-buffer))))))
(put ',MODE-enable-in-buffers 'definition-name ',global-mode)
(defun ,MODE-check-buffers ()
(,MODE-enable-in-buffers)
(remove-hook 'post-command-hook #',MODE-check-buffers))
(put ',MODE-check-buffers 'definition-name ',global-mode)
;; The function that catches kill-all-local-variables.
(defun ,MODE-cmhh ()
;; If `delay-mode-hooks' is set, it indicates that the current
;; buffer's mode will run `run-mode-hooks' afterwards anyway,
;; so we don't need to keep this buffer in MODE-buffers.
(unless delay-mode-hooks
(add-to-list ',MODE-buffers (current-buffer))
(add-hook 'post-command-hook #',MODE-check-buffers)))
(put ',MODE-cmhh 'definition-name ',global-mode))))
(put ',MODE-enable-in-buffer 'definition-name ',global-mode))))
(defun easy-mmode--globalized-predicate-p (predicate)
(cond