Function: define-globalized-minor-mode
define-globalized-minor-mode is an autoloaded macro defined in
easy-mmode.el.gz.
Signature
(define-globalized-minor-mode GLOBAL-MODE MODE TURN-ON [KEY VALUE]... BODY...)
Documentation
Make a global mode GLOBAL-MODE corresponding to buffer-local minor MODE.
TURN-ON is a function that will be called with no args in every buffer and that should try to turn MODE on if applicable for that buffer.
Each of KEY VALUE is a pair of CL-style keyword arguments.
The :predicate key specifies in which major modes should the
globalized minor mode be switched on. The value should be t (meaning
switch on the minor mode in all major modes), nil (meaning don't
switch on in any major mode), a list of modes (meaning switch on only
in those modes and their descendants), or a list (not MODES...),
meaning switch on in any major mode except MODES. The value can also
mix all of these forms, see the Info node (elisp)Defining Minor Modes
for details. The :predicate key causes the macro to create a user option
named the same as MODE, but ending with "-modes" instead of "-mode".
That user option can then be used to customize in which modes this
globalized minor mode will be switched on.
As the minor mode defined by this function is always global, any
:global keyword is ignored.
Other keywords have the same meaning as in define-minor-mode,
which see. In particular, :group specifies the custom group.
The most useful keywords are those that are passed on to the defcustom.
It normally makes no sense to pass the :lighter or :keymap keywords
to define-globalized-minor-mode, since these are usually passed to
the buffer-local version of the minor mode.
BODY contains code to execute each time the mode is enabled or disabled. It is executed after toggling the mode, and before running GLOBAL-MODE-hook.
If MODE's set-up depends on the major mode in effect when it was enabled, then disabling and reenabling MODE should make MODE work correctly with the current major mode. This is important to prevent problems with derived modes, that is, major modes that call another major mode in their body.
When a major mode is initialized, MODE is actually turned on just after running the major mode's hook. However, MODE is not turned on if the hook has explicitly disabled it.
Probably introduced at or before Emacs version 22.1.
Aliases
easy-mmode-define-global-mode (obsolete since 30.1)
define-global-minor-mode (obsolete since 31.1)
Source Code
;; Defined in /usr/src/emacs/lisp/emacs-lisp/easy-mmode.el.gz
;;;
;;; make global minor mode
;;;
;;;###autoload
(defmacro define-globalized-minor-mode (global-mode mode turn-on &rest body)
"Make a global mode GLOBAL-MODE corresponding to buffer-local minor MODE.
TURN-ON is a function that will be called with no args in every buffer
and that should try to turn MODE on if applicable for that buffer.
Each of KEY VALUE is a pair of CL-style keyword arguments.
The :predicate key specifies in which major modes should the
globalized minor mode be switched on. The value should be t (meaning
switch on the minor mode in all major modes), nil (meaning don't
switch on in any major mode), a list of modes (meaning switch on only
in those modes and their descendants), or a list (not MODES...),
meaning switch on in any major mode except MODES. The value can also
mix all of these forms, see the Info node `(elisp)Defining Minor Modes'
for details. The :predicate key causes the macro to create a user option
named the same as MODE, but ending with \"-modes\" instead of \"-mode\".
That user option can then be used to customize in which modes this
globalized minor mode will be switched on.
As the minor mode defined by this function is always global, any
:global keyword is ignored.
Other keywords have the same meaning as in `define-minor-mode',
which see. In particular, :group specifies the custom group.
The most useful keywords are those that are passed on to the `defcustom'.
It normally makes no sense to pass the :lighter or :keymap keywords
to `define-globalized-minor-mode', since these are usually passed to
the buffer-local version of the minor mode.
BODY contains code to execute each time the mode is enabled or disabled.
It is executed after toggling the mode, and before running
GLOBAL-MODE-hook.
If MODE's set-up depends on the major mode in effect when it was
enabled, then disabling and reenabling MODE should make MODE work
correctly with the current major mode. This is important to
prevent problems with derived modes, that is, major modes that
call another major mode in their body.
When a major mode is initialized, MODE is actually turned on just
after running the major mode's hook. However, MODE is not turned
on if the hook has explicitly disabled it.
\(fn GLOBAL-MODE MODE TURN-ON [KEY VALUE]... BODY...)"
(declare (doc-string 2) (indent defun)
;; expand to the minor-mode definition on autoload gen
(autoload-macro expand))
(let* ((global-mode-name (symbol-name global-mode))
(mode-name (symbol-name mode))
(pretty-name (easy-mmode-pretty-mode-name mode))
(pretty-global-name (easy-mmode-pretty-mode-name global-mode))
(group nil)
(extra-keywords nil)
(MODE-variable mode)
(MODE-enable-in-buffer
(intern (concat global-mode-name "-enable-in-buffer")))
(minor-MODE-hook (intern (concat mode-name "-hook")))
(MODE-set-explicitly (intern (concat mode-name "--set-explicitly")))
(MODE-suppress-set-explicitly (intern (concat mode-name
"--suppress-set-explicitly")))
(MODE-predicate (intern (concat (replace-regexp-in-string
"-mode\\'" "" global-mode-name)
"-modes")))
(turn-on-function `#',turn-on)
keyw predicate)
;; Check keys.
(while (keywordp (setq keyw (car body)))
(pop body)
(pcase keyw
(:group (setq group (nconc group (list :group (pop body)))))
(:global (pop body))
(:variable (setq MODE-variable (pop body)))
(:predicate
(setq predicate (list (pop body)))
(setq turn-on-function
`(lambda ()
(require 'easy-mmode)
(when (easy-mmode--globalized-predicate-p ,MODE-predicate)
(funcall ,turn-on-function)))))
(_ (push keyw extra-keywords) (push (pop body) extra-keywords))))
(setq extra-keywords (nreverse extra-keywords))
(when (and (plist-get extra-keywords :init-value)
(null (plist-get extra-keywords :initialize)))
(setq extra-keywords `(:initialize #'custom-initialize-after-file-load
. ,extra-keywords)))
`(progn
(progn
(put ',global-mode 'globalized-minor-mode t)
:autoload-end
,@(when predicate `((defvar ,MODE-predicate))))
;; The actual global minor-mode
(define-minor-mode ,global-mode
,(concat (format "Toggle %s in many buffers.\n" pretty-name)
(internal--format-docstring-line
"Specifically, %s is enabled in all buffers where `%S' would do it."
pretty-name turn-on)
"\n\n"
(internal--format-docstring-line
(concat "With prefix ARG, enable %s if ARG is positive; "
"otherwise, disable it.")
pretty-global-name)
"\n\n"
"If called from Lisp, toggle the mode if ARG is `toggle'.
Enable the mode if ARG is nil, omitted, or is a positive number.
Disable the mode if ARG is a negative number.\n\n"
(internal--format-docstring-line
"See `%s' for more information on %s."
mode pretty-name)
(if predicate
(concat
"\n\n"
(internal--format-docstring-line
"`%s' is used to control which modes this minor mode is used in."
MODE-predicate))
""))
:global t ,@group ,@extra-keywords
;; Setup hook to handle future mode changes and new buffers.
(if ,global-mode
(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))
(with-current-buffer buf
(if ,global-mode (funcall ,turn-on-function)
(when (bound-and-true-p ,MODE-variable) (,mode -1)))))
,@body)
,(when predicate
`(defcustom ,MODE-predicate ,(car predicate)
,(format "Which major modes `%s' is switched on in.
This variable can be either t (all major modes), nil (no major modes),
or a list of modes and (not modes) to switch use this minor mode or
not. For instance
(c-mode (not message-mode mail-mode) text-mode)
means \"use this mode in all modes derived from `c-mode', don't use in
modes derived from `message-mode' or `mail-mode', but do use in other
modes derived from `text-mode'\". An element with value t means \"use\"
and nil means \"don't use\". There's an implicit nil at the end of the
list."
mode)
:type '(choice
(const :tag "Enable in all major modes" t)
(const :tag "Don't enable in any major mode" nil)
(repeat
:tag "Rules (earlier takes precedence)..."
(choice
(const :tag "Enable in all (other) modes" t)
(const :tag "Don't enable in any (other) mode" nil)
(symbol :value fundamental-mode
:tag "Enable in major mode")
(cons :tag "Don't enable in major modes"
(const :tag "Don't enable in..." not)
(repeat (symbol :value fundamental-mode
:tag "Major mode"))))))
,@group))
;; Autoloading define-globalized-minor-mode autoloads everything
;; up-to-here.
:autoload-end
;; MODE-set-explicitly is set in MODE-set-explicitly and cleared by
;; kill-all-local-variables.
(defvar-local ,MODE-set-explicitly nil)
(defvar ,MODE-suppress-set-explicitly nil)
(defun ,MODE-set-explicitly ()
(unless ,MODE-suppress-set-explicitly
(setq ,MODE-set-explicitly t)))
(put ',MODE-set-explicitly 'definition-name ',global-mode)
;; A function which checks whether MODE has been disabled in the major
;; mode hook which has just been run.
(add-hook ',minor-MODE-hook #',MODE-set-explicitly)
;; The function that calls TURN-ON in the current buffer.
(defun ,MODE-enable-in-buffer ()
(unless ,MODE-set-explicitly
(let (;; We are not part of the major mode hook so we don't
;; want to set MODE-set-explicitly to t.
;; In particular this is necessary when there are
;; multiple globalized versions of a single minor mode.
;; If one of them declines to turn the minor mode on,
;; that should not mean the others can't.
(,MODE-suppress-set-explicitly t))
(funcall ,turn-on-function))))
(put ',MODE-enable-in-buffer 'definition-name ',global-mode))))