Function: add-hook
add-hook is a byte-compiled function defined in subr.el.gz.
Signature
(add-hook HOOK FUNCTION &optional DEPTH LOCAL)
Documentation
Add to the value of HOOK the function FUNCTION.
FUNCTION is not added if already present.
HOOK should be a symbol. If HOOK is void, or if HOOK's value is a single function, it is changed to a list of functions.
The place where the function is added depends on the DEPTH parameter. DEPTH defaults to 0. By convention, it should be a number between -100 and 100 where 100 means that the function should be at the very end of the list, whereas -100 means that the function should always come first. Since nothing is "always" true, don't use 100 nor -100. When two functions have the same depth, the new one gets added after the old one if depth is strictly positive and before otherwise.
For backward compatibility reasons, a symbol other than nil is interpreted as a DEPTH of 90.
The optional fourth argument, LOCAL, if non-nil, says to modify the hook's buffer-local value rather than its global value. This makes the hook buffer-local, and it makes t a member of the buffer-local value. That acts as a flag to run the hook functions of the global value as well as in the local value.
FUNCTION may be any valid function, but it's recommended to use a
function symbol and not a lambda form. Using a symbol will
ensure that the function is not re-added if the function is
edited, and using lambda forms may also have a negative
performance impact when running add-hook and remove-hook.
Probably introduced at or before Emacs version 19.1.
Aliases
org-add-hook (obsolete since 9.0)
Source Code
;; Defined in /usr/src/emacs/lisp/subr.el.gz
;;;; Hook manipulation functions.
(defun add-hook (hook function &optional depth local)
;; Note: the -100..100 depth range is arbitrary and was chosen to match the
;; range used in add-function.
"Add to the value of HOOK the function FUNCTION.
FUNCTION is not added if already present.
HOOK should be a symbol. If HOOK is void, or if HOOK's value is a
single function, it is changed to a list of functions.
The place where the function is added depends on the DEPTH
parameter. DEPTH defaults to 0. By convention, it should be
a number between -100 and 100 where 100 means that the function
should be at the very end of the list, whereas -100 means that
the function should always come first.
Since nothing is \"always\" true, don't use 100 nor -100.
When two functions have the same depth, the new one gets added after the
old one if depth is strictly positive and before otherwise.
For backward compatibility reasons, a symbol other than nil is
interpreted as a DEPTH of 90.
The optional fourth argument, LOCAL, if non-nil, says to modify
the hook's buffer-local value rather than its global value.
This makes the hook buffer-local, and it makes t a member of the
buffer-local value. That acts as a flag to run the hook
functions of the global value as well as in the local value.
FUNCTION may be any valid function, but it's recommended to use a
function symbol and not a lambda form. Using a symbol will
ensure that the function is not re-added if the function is
edited, and using lambda forms may also have a negative
performance impact when running `add-hook' and `remove-hook'."
(or (boundp hook) (set hook nil))
(or (default-boundp hook) (set-default hook nil))
(unless (numberp depth) (setq depth (if depth 90 0)))
(if local (unless (local-variable-if-set-p hook)
(set (make-local-variable hook) (list t)))
;; Detect the case where make-local-variable was used on a hook
;; and do what we used to do.
(when (and (local-variable-if-set-p hook)
(not (and (consp (symbol-value hook))
(memq t (symbol-value hook)))))
(setq local t)))
(let ((hook-value (if local (symbol-value hook) (default-value hook))))
;; If the hook value is a single function, turn it into a list.
(when (or (not (listp hook-value)) (functionp hook-value))
(setq hook-value (list hook-value)))
;; Do the actual addition if necessary
(unless (member function hook-value)
(let ((depth-sym (get hook 'hook--depth-alist)))
;; While the `member' test above has to use `equal' for historical
;; reasons, `equal' is a performance problem on large/cyclic functions,
;; so we index `hook--depth-alist' with `eql'. (bug#46326)
(unless (zerop depth)
(unless depth-sym
(setq depth-sym (make-symbol "depth-alist"))
(set depth-sym nil)
(setf (get hook 'hook--depth-alist) depth-sym))
(if local (make-local-variable depth-sym))
(setf (alist-get function
(if local (symbol-value depth-sym)
(default-value depth-sym))
0)
depth))
(setq hook-value
(if (< 0 depth)
(append hook-value (list function))
(cons function hook-value)))
(when depth-sym
(let ((depth-alist (if local (symbol-value depth-sym)
(default-value depth-sym))))
(when depth-alist
(setq hook-value
(sort (if (< 0 depth) hook-value (copy-sequence hook-value))
(lambda (f1 f2)
(< (alist-get f1 depth-alist 0 nil #'eq)
(alist-get f2 depth-alist 0 nil #'eq))))))))))
;; Set the actual variable
(if local
(progn
;; If HOOK isn't a permanent local,
;; but FUNCTION wants to survive a change of modes,
;; mark HOOK as partially permanent.
(and (symbolp function)
(get function 'permanent-local-hook)
(not (get hook 'permanent-local))
(put hook 'permanent-local 'permanent-local-hook))
(set hook hook-value))
(set-default hook hook-value))))