Function: add-to-list

add-to-list is a byte-compiled function defined in subr.el.gz.

Signature

(add-to-list LIST-VAR ELEMENT &optional APPEND COMPARE-FN)

Documentation

Add ELEMENT to the value of LIST-VAR if it isn't there yet.

The test for presence of ELEMENT is done with equal, or with COMPARE-FN if that's non-nil. If ELEMENT is added, it is added at the beginning of the list, unless the optional argument APPEND is non-nil, in which case ELEMENT is added at the end. LIST-VAR should not refer to a lexical variable.

The return value is the new value of LIST-VAR.

This is meant to be used for adding elements to configuration variables, such as adding a directory to a path variable like load-path, but please do not abuse it to construct arbitrary lists in Elisp code, where using push or cl-pushnew will get you more efficient code.

If you want to use add-to-list on a variable that is not defined until a certain package is loaded, you should put the call to add-to-list into a hook function that will be run only after loading the package. eval-after-load provides one way to do this. In some cases other hooks, such as major mode hooks, can do the job.

View in manual

Probably introduced at or before Emacs version 19.29.

Source Code

;; Defined in /usr/src/emacs/lisp/subr.el.gz
(defun add-to-list (list-var element &optional append compare-fn)
  "Add ELEMENT to the value of LIST-VAR if it isn't there yet.
The test for presence of ELEMENT is done with `equal', or with
COMPARE-FN if that's non-nil.
If ELEMENT is added, it is added at the beginning of the list,
unless the optional argument APPEND is non-nil, in which case
ELEMENT is added at the end.
LIST-VAR should not refer to a lexical variable.

The return value is the new value of LIST-VAR.

This is meant to be used for adding elements to configuration
variables, such as adding a directory to a path variable
like `load-path', but please do not abuse it to construct
arbitrary lists in Elisp code, where using `push' or `cl-pushnew'
will get you more efficient code.

If you want to use `add-to-list' on a variable that is not
defined until a certain package is loaded, you should put the
call to `add-to-list' into a hook function that will be run only
after loading the package.  `eval-after-load' provides one way to
do this.  In some cases other hooks, such as major mode hooks,
can do the job."
  (declare
   (compiler-macro
    (lambda (exp)
      ;; FIXME: Something like this could be used for `set' as well.
      (if (or (not (eq 'quote (car-safe list-var)))
              (special-variable-p (cadr list-var))
              (not (macroexp-const-p append)))
          exp
        (let* ((sym (cadr list-var))
               (append (eval append lexical-binding))
               (msg (format-message
                     "`add-to-list' can't use lexical var `%s'; use `push' or `cl-pushnew'"
                     sym))
               ;; Big ugly hack, so we output a warning only during
               ;; byte-compilation, and so we can use
               ;; byte-compile-not-lexical-var-p to silence the warning
               ;; when a defvar has been seen but not yet executed.
               (warnfun (lambda ()
                          ;; FIXME: We should also emit a warning for let-bound
                          ;; variables with dynamic binding.
                          (when (assq sym byte-compile--lexical-environment)
                            (byte-compile-report-error msg :fill))))
               (code
                (macroexp-let2 macroexp-copyable-p x element
                  `(if ,(if compare-fn
                            (progn
                              (require 'cl-lib)
                              `(cl-member ,x ,sym :test ,compare-fn))
                          ;; For bootstrapping reasons, don't rely on
                          ;; cl--compiler-macro-member for the base case.
                          `(member ,x ,sym))
                       ,sym
                     ,(if append
                          `(setq ,sym (append ,sym (list ,x)))
                        `(push ,x ,sym))))))
          (if (not (macroexp-compiling-p))
              code
            `(progn
               (macroexp--funcall-if-compiled ',warnfun)
               ,code)))))))
  (if (cond
       ((null compare-fn)
	(member element (symbol-value list-var)))
       ((eq compare-fn #'eq)
	(memq element (symbol-value list-var)))
       ((eq compare-fn #'eql)
	(memql element (symbol-value list-var)))
       (t
	(let ((lst (symbol-value list-var)))
	  (while (and lst
		      (not (funcall compare-fn element (car lst))))
	    (setq lst (cdr lst)))
          lst)))
      (symbol-value list-var)
    (set list-var
	 (if append
	     (append (symbol-value list-var) (list element))
	   (cons element (symbol-value list-var))))))