Add arch tagline
[bpt/emacs.git] / lisp / loadhist.el
CommitLineData
2b86d62c 1;;; loadhist.el --- lisp functions for working with feature groups
b578f267 2
c90f2757 3;; Copyright (C) 1995, 1998, 2000, 2001, 2002, 2003, 2004,
d7a0267c 4;; 2005, 2006, 2007 Free Software Foundation, Inc.
2b86d62c
RS
5
6;; Author: Eric S. Raymond <esr@snark.thyrsus.com>
53c1fa0f 7;; Maintainer: FSF
2b86d62c
RS
8;; Keywords: internal
9
131a0c01
KH
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
b4aa6026 14;; the Free Software Foundation; either version 3, or (at your option)
131a0c01
KH
15;; any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
b578f267 23;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
24;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25;; Boston, MA 02110-1301, USA.
131a0c01 26
2b86d62c
RS
27;;; Commentary:
28
29;; These functions exploit the load-history system variable.
fde4581d
RS
30;; Entry points include `unload-feature', `symbol-file', and
31;; `feature-file', documented in the Emacs Lisp manual.
2b86d62c
RS
32
33;;; Code:
34
ab215e72
SM
35(eval-when-compile (require 'cl))
36
2b86d62c 37(defun feature-symbols (feature)
7dc2cc98
RS
38 "Return the file and list of definitions associated with FEATURE.
39The value is actually the element of `load-history'
40for the file that did (provide FEATURE)."
b5307e9c
JB
41 (catch 'foundit
42 (let ((element (cons 'provide feature)))
43 (dolist (x load-history nil)
44 (when (member element (cdr x))
45 (throw 'foundit x))))))
2b86d62c
RS
46
47(defun feature-file (feature)
48 "Return the file name from which a given FEATURE was loaded.
49Actually, return the load argument, if any; this is sometimes the name of a
53c1fa0f
DL
50Lisp file without an extension. If the feature came from an `eval-buffer' on
51a buffer with no associated file, or an `eval-region', return nil."
2b86d62c 52 (if (not (featurep feature))
53c1fa0f 53 (error "%S is not a currently loaded feature" feature)
2b86d62c
RS
54 (car (feature-symbols feature))))
55
27af61fe 56(defun file-loadhist-lookup (file)
1c11da91
RS
57 "Return the `load-history' element for FILE.
58FILE can be a file name, or a library name.
59A library name is equivalent to the file name that `load-library' would load."
27af61fe
RS
60 ;; First look for FILE as given.
61 (let ((symbols (assoc file load-history)))
62 ;; Try converting a library name to an absolute file name.
63 (and (null symbols)
e18ce91d
LT
64 (let ((absname
65 (locate-file file load-path (get-load-suffixes))))
1c11da91
RS
66 (and absname (not (equal absname file))
67 (setq symbols (cdr (assoc absname load-history))))))
27af61fe
RS
68 symbols))
69
2b86d62c 70(defun file-provides (file)
1c11da91
RS
71 "Return the list of features provided by FILE as it was loaded.
72FILE can be a file name, or a library name.
73A library name is equivalent to the file name that `load-library' would load."
b5307e9c
JB
74 (let (provides)
75 (dolist (x (file-loadhist-lookup file) provides)
76 (when (eq (car-safe x) 'provide)
77 (push x provides)))))
2b86d62c
RS
78
79(defun file-requires (file)
1c11da91
RS
80 "Return the list of features required by FILE as it was loaded.
81FILE can be a file name, or a library name.
82A library name is equivalent to the file name that `load-library' would load."
b5307e9c
JB
83 (let (requires)
84 (dolist (x (file-loadhist-lookup file) requires)
85 (when (eq (car-safe x) 'require)
86 (push x requires)))))
53c1fa0f
DL
87
88(defsubst file-set-intersect (p q)
89 "Return the set intersection of two lists."
b5307e9c 90 (let (ret)
53c1fa0f 91 (dolist (x p ret)
b5307e9c 92 (when (memq x q) (push x ret)))))
2b86d62c
RS
93
94(defun file-dependents (file)
e01ac82c 95 "Return the list of loaded libraries that depend on FILE.
1c11da91
RS
96This can include FILE itself.
97FILE can be a file name, or a library name.
98A library name is equivalent to the file name that `load-library' would load."
53c1fa0f
DL
99 (let ((provides (file-provides file))
100 (dependents nil))
101 (dolist (x load-history dependents)
b5307e9c
JB
102 (when (file-set-intersect provides (file-requires (car x)))
103 (push (car x) dependents)))))
2b86d62c 104
12d9b59e
KS
105(defun read-feature (prompt &optional loaded-p)
106 "Read feature name from the minibuffer, prompting with string PROMPT.
107If optional second arg LOADED-P is non-nil, the feature must be loaded
108from a file."
109 (intern
110 (completing-read prompt
111 (cons nil features)
112 (and loaded-p
113 #'(lambda (f)
114 (and f ; ignore nil
115 (feature-file f))))
116 loaded-p)))
d4708676 117
28d02da1
RS
118(defvaralias 'loadhist-hook-functions 'unload-feature-special-hooks)
119(defvar unload-feature-special-hooks
b5307e9c
JB
120 '(after-change-functions after-insert-file-functions
121 after-make-frame-functions auto-fill-function before-change-functions
122 blink-paren-function buffer-access-fontify-functions command-line-functions
b09ee19d 123 comment-indent-function compilation-finish-functions delete-frame-functions
b5307e9c
JB
124 disabled-command-function find-file-not-found-functions
125 font-lock-beginning-of-syntax-function font-lock-fontify-buffer-function
126 font-lock-fontify-region-function font-lock-mark-block-function
127 font-lock-syntactic-face-function font-lock-unfontify-buffer-function
128 font-lock-unfontify-region-function kill-buffer-query-functions
129 kill-emacs-query-functions lisp-indent-function mouse-position-function
b09ee19d
JB
130 redisplay-end-trigger-functions suspend-tty-functions
131 temp-buffer-show-function window-scroll-functions
132 window-size-change-functions write-contents-functions write-file-functions
7dc2cc98 133 write-region-annotate-functions)
3eef341a 134 "A list of special hooks from Info node `(elisp)Standard Hooks'.
fde4581d 135
8ed7fe5c
RS
136These are symbols with hooklike values whose names don't end in
137`-hook' or `-hooks', from which `unload-feature' should try to remove
fde4581d
RS
138pertinent symbols.")
139
8ed7fe5c
RS
140(defvar unload-function-defs-list nil
141 "List of defintions in the Lisp library being unloaded.
dffc4dfc 142
8ed7fe5c 143This is meant to be used by `FEATURE-unload-function'; see the
dffc4dfc 144documentation of `unload-feature' for details.")
d66d6ac0 145(define-obsolete-variable-alias 'unload-hook-features-list
8ed7fe5c 146 'unload-function-defs-list "22.2")
dffc4dfc 147
2b86d62c
RS
148;;;###autoload
149(defun unload-feature (feature &optional force)
8ed7fe5c 150 "Unload the library that provided FEATURE.
4370a375 151If the feature is required by any other loaded code, and prefix arg FORCE
8cb16ad1
EZ
152is nil, raise an error.
153
8ed7fe5c
RS
154Standard unloading activities include restoring old autoloads for
155functions defined by the library, undoing any additions that the
156library has made to hook variables or to `auto-mode-alist', undoing
157ELP profiling of functions in that library, unproviding any features
158provided by the library, and canceling timers held in variables
159defined by the library.
160
161If a function `FEATURE-unload-function' is defined, this function
162calls it with no arguments, before doing anything else. That function
163can do whatever is appropriate to undo the loading of the library. If
164`FEATURE-unload-function' returns non-nil, that suppresses the
165standard unloading of the library. Otherwise the standard unloading
166proceeds.
167
168`FEATURE-unload-function' has access to the package's list of
169definitions in the variable `unload-function-defs-list' and could
170remove symbols from it in the event that the package has done
171something strange, such as redefining an Emacs function."
12d9b59e
KS
172 (interactive
173 (list
5c34b94b
KS
174 (read-feature "Unload feature: " t)
175 current-prefix-arg))
191652f8
LK
176 (unless (featurep feature)
177 (error "%s is not a currently loaded feature" (symbol-name feature)))
178 (unless force
179 (let* ((file (feature-file feature))
180 (dependents (delete file (copy-sequence (file-dependents file)))))
181 (when dependents
182 (error "Loaded libraries %s depend on %s"
183 (prin1-to-string dependents) file))))
8ed7fe5c
RS
184 (let* ((unload-function-defs-list (feature-symbols feature))
185 (file (pop unload-function-defs-list))
531309eb
RS
186 ;; If non-nil, this is a symbol for which we should
187 ;; restore a previous autoload if possible.
188 restore-autoload
d66d6ac0
JB
189 (name (symbol-name feature))
190 (unload-hook (intern-soft (concat name "-unload-hook")))
191 (unload-func (intern-soft (concat name "-unload-function"))))
192 ;; If FEATURE-unload-function is defined and returns non-nil,
193 ;; don't try to do anything more; otherwise proceed normally.
d83fb256 194 (unless (and (fboundp unload-func)
d66d6ac0
JB
195 (funcall unload-func))
196 ;; Try to avoid losing badly when hooks installed in critical
197 ;; places go away. (Some packages install things on
198 ;; `kill-buffer-hook', `activate-menubar-hook' and the like.)
199 (if unload-hook
200 ;; First off, provide a clean way for package FOO to arrange
201 ;; this by adding hooks on the variable `FOO-unload-hook'.
202 ;; This is obsolete; FEATURE-unload-function should be used now.
203 (run-hooks unload-hook)
204 ;; Otherwise, do our best. Look through the obarray for symbols
205 ;; which seem to be hook variables or special hook functions and
206 ;; remove anything from them which matches the feature-symbols
207 ;; about to get zapped. Obviously this won't get anonymous
208 ;; functions which the package might just have installed, and
209 ;; there might be other important state, but this tactic
210 ;; normally works.
211 (mapatoms
212 (lambda (x)
213 (when (and (boundp x)
214 (or (and (consp (symbol-value x)) ; Random hooks.
215 (string-match "-hooks?\\'" (symbol-name x)))
216 (memq x unload-feature-special-hooks))) ; Known abnormal hooks etc.
8ed7fe5c 217 (dolist (y unload-function-defs-list)
d66d6ac0
JB
218 (when (and (eq (car-safe y) 'defun)
219 (not (get (cdr y) 'autoload)))
220 (remove-hook x (cdr y)))))))
221 ;; Remove any feature-symbols from auto-mode-alist as well.
8ed7fe5c 222 (dolist (y unload-function-defs-list)
d66d6ac0
JB
223 (when (and (eq (car-safe y) 'defun)
224 (not (get (cdr y) 'autoload)))
225 (setq auto-mode-alist
226 (rassq-delete-all (cdr y) auto-mode-alist)))))
227 (when (fboundp 'elp-restore-function) ; remove ELP stuff first
8ed7fe5c 228 (dolist (elt unload-function-defs-list)
d66d6ac0
JB
229 (when (symbolp elt)
230 (elp-restore-function elt))))
531309eb 231
8ed7fe5c 232 (dolist (x unload-function-defs-list)
d66d6ac0
JB
233 (if (consp x)
234 (case (car x)
235 ;; Remove any feature names that this file provided.
236 (provide
237 (setq features (delq (cdr x) features)))
238 ((defun autoload)
239 (let ((fun (cdr x)))
240 (when (fboundp fun)
241 (when (fboundp 'ad-unadvise)
242 (ad-unadvise fun))
243 (let ((aload (get fun 'autoload)))
244 (if (and aload (eq fun restore-autoload))
245 (fset fun (cons 'autoload aload))
246 (fmakunbound fun))))))
247 ;; (t . SYMBOL) comes before (defun . SYMBOL)
248 ;; and says we should restore SYMBOL's autoload
249 ;; when we undefine it.
250 ((t) (setq restore-autoload (cdr x)))
251 ((require defface) nil)
252 (t (message "Unexpected element %s in load-history" x)))
253 ;; Kill local values as much as possible.
254 (dolist (buf (buffer-list))
255 (with-current-buffer buf
256 (if (and (boundp x) (timerp (symbol-value x)))
257 (cancel-timer (symbol-value x)))
258 (kill-local-variable x)))
259 (if (and (boundp x) (timerp (symbol-value x)))
260 (cancel-timer (symbol-value x)))
261 ;; Get rid of the default binding if we can.
262 (unless (local-variable-if-set-p x)
263 (makunbound x))))
264 ;; Delete the load-history element for this file.
265 (setq load-history (delq (assoc file load-history) load-history))))
54c6a1c4
JB
266 ;; Don't return load-history, it is not useful.
267 nil)
2b86d62c
RS
268
269(provide 'loadhist)
270
ab215e72 271;; arch-tag: 70bb846a-c413-4f01-bf88-78dba4ac0798
2b86d62c 272;;; loadhist.el ends here