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.

View in manual

Probably introduced at or before Emacs version 19.20.

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))))