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.

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.

HOOK should be a symbol. If HOOK is void, it is first set to nil. If HOOK's value is a single function, it is changed to a list of functions.

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.

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.

HOOK should be a symbol.  If HOOK is void, it is first set to
nil.  If HOOK's value is a single function, it is changed to a
list of functions.

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