Function: unload-feature

unload-feature is an autoloaded, interactive and byte-compiled function defined in loadhist.el.gz.

Signature

(unload-feature FEATURE &optional FORCE)

Documentation

Unload the library that provided FEATURE.

If the feature is required by any other loaded code, and prefix arg FORCE is nil, raise an error.

Standard unloading activities include restoring old autoloads for functions defined by the library, removing such functions from hooks and auto-mode-alist, undoing their ELP profiling, unproviding any features provided by the library, and canceling timers held in variables defined by the library.

If a function FEATURE-unload-function is defined, this function calls it with no arguments, before doing anything else. That function can do whatever is appropriate to undo the loading of the library. If FEATURE-unload-function returns non-nil, that suppresses the standard unloading of the library. Otherwise the standard unloading proceeds.

FEATURE-unload-function has access to the package's list of definitions in the variable unload-function-defs-list and could remove symbols from it in the event that the package has done something strange, such as redefining an Emacs function.

View in manual

Probably introduced at or before Emacs version 20.3.

Key Bindings

Source Code

;; Defined in /usr/src/emacs/lisp/loadhist.el.gz
;;;###autoload
(defun unload-feature (feature &optional force)
  "Unload the library that provided FEATURE.
If the feature is required by any other loaded code, and prefix arg FORCE
is nil, raise an error.

Standard unloading activities include restoring old autoloads for
functions defined by the library, removing such functions from
hooks and `auto-mode-alist', undoing their ELP profiling,
unproviding any features provided by the library, and canceling
timers held in variables defined by the library.

If a function `FEATURE-unload-function' is defined, this function
calls it with no arguments, before doing anything else.  That function
can do whatever is appropriate to undo the loading of the library.  If
`FEATURE-unload-function' returns non-nil, that suppresses the
standard unloading of the library.  Otherwise the standard unloading
proceeds.

`FEATURE-unload-function' has access to the package's list of
definitions in the variable `unload-function-defs-list' and could
remove symbols from it in the event that the package has done
something strange, such as redefining an Emacs function."
  (interactive
   (list
    (read-feature "Unload feature: " t)
    current-prefix-arg))
  (unless (featurep feature)
    (error "%s is not a currently loaded feature" (symbol-name feature)))
  (unless force
    (let* ((file (feature-file feature))
	   (dependents (delete file (copy-sequence (file-dependents file)))))
      (when dependents
	(error "Loaded libraries %s depend on %s"
	       (prin1-to-string dependents) file))))
  (let* ((unload-function-defs-list (feature-symbols feature))
         (file (pop unload-function-defs-list))
         (loadhist-unload-filename file)
	 (name (symbol-name feature))
         (unload-hook (intern-soft (concat name "-unload-hook")))
	 (unload-func (intern-soft (concat name "-unload-function"))))
    ;; If FEATURE-unload-function is defined and returns non-nil,
    ;; don't try to do anything more; otherwise proceed normally.
    (unless (and (fboundp unload-func)
		 (funcall unload-func))
      ;; Try to avoid losing badly when hooks installed in critical
      ;; places go away.  (Some packages install things on
      ;; `kill-buffer-hook', `activate-menubar-hook' and the like.)
      (if unload-hook
	  ;; First off, provide a clean way for package FOO to arrange
	  ;; this by adding hooks on the variable `FOO-unload-hook'.
	  ;; This is obsolete; FEATURE-unload-function should be used now.
	  (run-hooks unload-hook)
	;; Otherwise, do our best.  Look through the obarray for symbols
	;; which seem to be hook variables or special hook functions and
	;; remove anything from them which matches the feature-symbols
	;; about to get zapped.  Obviously this won't get anonymous
	;; functions which the package might just have installed, and
	;; there might be other important state, but this tactic
	;; normally works.
        (let ((removables (cl-loop for def in unload-function-defs-list
                                   when (and (eq (car-safe def) 'defun)
                                             (not (get (cdr def) 'autoload)))
                                   collect (cdr def))))
          (mapatoms
	   (lambda (x)
	     (when (and (boundp x)
                        (or (and (consp (symbol-value x)) ; Random hooks.
                                 (string-match "-hooks?\\'" (symbol-name x)))
                            ;; Known abnormal hooks etc.
			    (memq x unload-feature-special-hooks)))
	       (dolist (func removables)
                 (remove-hook x func)))))
          (save-current-buffer
            (dolist (buffer (buffer-list))
              (pcase-dolist (`(,sym . ,val) (buffer-local-variables buffer))
                (when (or (and (consp val)
                               (string-match "-hooks?\\'" (symbol-name sym)))
                          (memq sym unload-feature-special-hooks))
                  (set-buffer buffer)
                  (dolist (func removables)
                    (remove-hook sym func t))))))
          ;; Remove any feature-symbols from auto-mode-alist as well.
          (dolist (func removables)
            (setq auto-mode-alist
                  (rassq-delete-all func auto-mode-alist)))))

      ;; Change major mode in all buffers using one defined in the feature being unloaded.
      (unload--set-major-mode)

      (mapc #'loadhist-unload-element unload-function-defs-list)
      ;; Delete the load-history element for this file.
      (setq load-history (delq (assoc file load-history) load-history))))
  ;; Don't return load-history, it is not useful.
  nil)