Comment change.
[bpt/emacs.git] / lisp / emacs-lisp / autoload.el
CommitLineData
c0274f38
ER
1;;; autoload.el --- maintain autoloads in loaddefs.el.
2
d55e3ff0 3;;; Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
3a801d0c 4;;;
e5167999 5;; Author: Roland McGrath <roland@gnu.ai.mit.edu>
e9571d2a 6;; Keywords: maint
e5167999 7
0231f2dc
JB
8;;; This program is free software; you can redistribute it and/or modify
9;;; it under the terms of the GNU General Public License as published by
e5167999 10;;; the Free Software Foundation; either version 2, or (at your option)
0231f2dc
JB
11;;; any later version.
12;;;
13;;; This program is distributed in the hope that it will be useful,
14;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16;;; GNU General Public License for more details.
17;;;
18;;; A copy of the GNU General Public License can be obtained from this
19;;; program's author (send electronic mail to roland@ai.mit.edu) or from
20;;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
21;;; 02139, USA.
22;;;
23
07b3798c 24;;; Commentary:
e41b2db1 25
00ee57f3 26;; This code helps GNU Emacs maintainers keep the loaddefs.el file up to
e41b2db1
ER
27;; date. It interprets magic cookies of the form ";;;###autoload" in
28;; lisp source files in various useful ways. To learn more, read the
29;; source; if you're going to use this, you'd better be able to.
30
e5167999
ER
31;;; Code:
32
0231f2dc
JB
33(defun make-autoload (form file)
34 "Turn FORM, a defun or defmacro, into an autoload for source file FILE.
35Returns nil if FORM is not a defun or defmacro."
36 (let ((car (car-safe form)))
327ab40d
RM
37 (if (memq car '(defun defmacro))
38 (let ((macrop (eq car 'defmacro))
39 name doc)
0231f2dc
JB
40 (setq form (cdr form))
41 (setq name (car form))
42 ;; Ignore the arguments.
43 (setq form (cdr (cdr form)))
44 (setq doc (car form))
45 (if (stringp doc)
46 (setq form (cdr form))
47 (setq doc nil))
48 (list 'autoload (list 'quote name) file doc
44893360
JB
49 (eq (car-safe (car form)) 'interactive)
50 (if macrop (list 'quote 'macro) nil)))
0231f2dc
JB
51 nil)))
52
53(defconst generate-autoload-cookie ";;;###autoload"
d08589bf
RM
54 "Magic comment indicating the following form should be autoloaded.
55Used by \\[update-file-autoloads]. This string should be
0231f2dc
JB
56meaningless to Lisp (e.g., a comment).
57
58This string is used:
59
60;;;###autoload
61\(defun function-to-be-autoloaded () ...)
62
63If this string appears alone on a line, the following form will be
64read and an autoload made for it. If there is further text on the line,
65that text will be copied verbatim to `generated-autoload-file'.")
66
67(defconst generate-autoload-section-header "\f\n;;;### "
68 "String inserted before the form identifying
69the section of autoloads for a file.")
70
71(defconst generate-autoload-section-trailer "\n;;;***\n"
72 "String which indicates the end of the section of autoloads for a file.")
73
daa37602
JB
74;;; Forms which have doc-strings which should be printed specially.
75;;; A doc-string-elt property of ELT says that (nth ELT FORM) is
76;;; the doc-string in FORM.
77;;;
78;;; There used to be the following note here:
79;;; ;;; Note: defconst and defvar should NOT be marked in this way.
80;;; ;;; We don't want to produce defconsts and defvars that
81;;; ;;; make-docfile can grok, because then it would grok them twice,
82;;; ;;; once in foo.el (where they are given with ;;;###autoload) and
83;;; ;;; once in loaddefs.el.
84;;;
85;;; Counter-note: Yes, they should be marked in this way.
86;;; make-docfile only processes those files that are loaded into the
87;;; dumped Emacs, and those files should never have anything
88;;; autoloaded here. The above-feared problem only occurs with files
89;;; which have autoloaded entries *and* are processed by make-docfile;
90;;; there should be no such files.
91
0231f2dc 92(put 'autoload 'doc-string-elt 3)
daa37602
JB
93(put 'defun 'doc-string-elt 3)
94(put 'defvar 'doc-string-elt 3)
95(put 'defconst 'doc-string-elt 3)
96(put 'defmacro 'doc-string-elt 3)
0231f2dc 97
72c19d97 98(defun autoload-trim-file-name (file)
1eb0a345
RS
99 ;; Returns a relative pathname of FILE
100 ;; starting from the directory that loaddefs.el is in.
101 ;; That is normally a directory in load-path,
102 ;; which means Emacs will be able to find FILE when it looks.
103 ;; Any extra directory names here would prevent finding the file.
72c19d97
RM
104 (setq file (expand-file-name file))
105 (file-relative-name file
1eb0a345 106 (file-name-directory generated-autoload-file)))
72c19d97 107
0231f2dc
JB
108(defun generate-file-autoloads (file)
109 "Insert at point a loaddefs autoload section for FILE.
110autoloads are generated for defuns and defmacros in FILE
da8826b4 111marked by `generate-autoload-cookie' (which see).
0231f2dc
JB
112If FILE is being visited in a buffer, the contents of the buffer
113are used."
114 (interactive "fGenerate autoloads for file: ")
115 (let ((outbuf (current-buffer))
0231f2dc
JB
116 (autoloads-done '())
117 (load-name (let ((name (file-name-nondirectory file)))
118 (if (string-match "\\.elc?$" name)
119 (substring name 0 (match-beginning 0))
120 name)))
121 (print-length nil)
72c19d97 122 (print-readably t) ; This does something in Lucid Emacs.
aa7ea8bd 123 (float-output-format nil)
0231f2dc 124 (done-any nil)
7e4263eb 125 (visited (get-file-buffer file))
0231f2dc 126 output-end)
daa37602
JB
127
128 ;; If the autoload section we create here uses an absolute
129 ;; pathname for FILE in its header, and then Emacs is installed
130 ;; under a different path on another system,
131 ;; `update-autoloads-here' won't be able to find the files to be
132 ;; autoloaded. So, if FILE is in the same directory or a
e5d77022 133 ;; subdirectory of the current buffer's directory, we'll make it
daa37602
JB
134 ;; relative to the current buffer's directory.
135 (setq file (expand-file-name file))
1265394f
RM
136 (let* ((source-truename (file-truename file))
137 (dir-truename (file-name-as-directory
138 (file-truename default-directory)))
139 (len (length dir-truename)))
140 (if (and (< len (length source-truename))
141 (string= dir-truename (substring source-truename 0 len)))
142 (setq file (substring source-truename len))))
daa37602 143
0231f2dc 144 (message "Generating autoloads for %s..." file)
6798a385
JB
145 (save-excursion
146 (unwind-protect
147 (progn
148 (set-buffer (find-file-noselect file))
149 (save-excursion
150 (save-restriction
151 (widen)
152 (goto-char (point-min))
153 (while (not (eobp))
154 (skip-chars-forward " \t\n\f")
155 (cond
156 ((looking-at (regexp-quote generate-autoload-cookie))
157 (search-forward generate-autoload-cookie)
158 (skip-chars-forward " \t")
159 (setq done-any t)
9ed4d64f
RM
160 (if (eolp)
161 ;; Read the next form and make an autoload.
162 (let* ((form (prog1 (read (current-buffer))
ad9c7f2b 163 (or (bolp) (forward-line 1))))
9ed4d64f
RM
164 (autoload (make-autoload form load-name))
165 (doc-string-elt (get (car-safe form)
166 'doc-string-elt)))
167 (if autoload
168 (setq autoloads-done (cons (nth 1 form)
169 autoloads-done))
170 (setq autoload form))
171 (if (and doc-string-elt
172 (stringp (nth doc-string-elt autoload)))
173 ;; We need to hack the printing because the
174 ;; doc-string must be printed specially for
175 ;; make-docfile (sigh).
176 (let* ((p (nthcdr (1- doc-string-elt)
177 autoload))
178 (elt (cdr p)))
179 (setcdr p nil)
180 (princ "\n(" outbuf)
181 (let ((print-escape-newlines t))
182 (mapcar (function (lambda (elt)
183 (prin1 elt outbuf)
184 (princ " " outbuf)))
185 autoload))
186 (princ "\"\\\n" outbuf)
187 (let ((begin (save-excursion
188 (set-buffer outbuf)
189 (point))))
6798a385 190 (princ (substring
72c19d97
RM
191 (prin1-to-string (car elt)) 1)
192 outbuf)
193 ;; Insert a backslash before each ( that
194 ;; appears at the beginning of a line in
195 ;; the doc string.
196 (save-excursion
197 (set-buffer outbuf)
198 (save-excursion
199 (while (search-backward "\n(" begin t)
200 (forward-char 1)
201 (insert "\\"))))
202 (if (null (cdr elt))
203 (princ ")" outbuf)
204 (princ " " outbuf)
205 (princ (substring
206 (prin1-to-string (cdr elt))
207 1)
208 outbuf))
9ed4d64f
RM
209 (terpri outbuf)))
210 (let ((print-escape-newlines t))
52859db8 211 (print autoload outbuf))))
9ed4d64f
RM
212 ;; Copy the rest of the line to the output.
213 (let ((begin (point)))
214 (forward-line 1)
52859db8 215 (princ (buffer-substring begin (point)) outbuf))))
72c19d97
RM
216 ((looking-at ";")
217 ;; Don't read the comment.
218 (forward-line 1))
219 (t
220 (forward-sexp 1)
221 (forward-line 1)))))))
6798a385
JB
222 (or visited
223 ;; We created this buffer, so we should kill it.
224 (kill-buffer (current-buffer)))
225 (set-buffer outbuf)
226 (setq output-end (point-marker))))
0231f2dc
JB
227 (if done-any
228 (progn
229 (insert generate-autoload-section-header)
72c19d97
RM
230 (prin1 (list 'autoloads autoloads-done load-name
231 (autoload-trim-file-name file)
0231f2dc
JB
232 (nth 5 (file-attributes file)))
233 outbuf)
234 (terpri outbuf)
72c19d97
RM
235 (insert ";;; Generated autoloads from "
236 (autoload-trim-file-name file) "\n")
0231f2dc
JB
237 (goto-char output-end)
238 (insert generate-autoload-section-trailer)))
239 (message "Generating autoloads for %s...done" file)))
e2b6138f 240\f
0231f2dc
JB
241(defconst generated-autoload-file "loaddefs.el"
242 "*File \\[update-file-autoloads] puts autoloads into.
243A .el file can set this in its local variables section to make its
244autoloads go somewhere else.")
245
246;;;###autoload
247(defun update-file-autoloads (file)
248 "Update the autoloads for FILE in `generated-autoload-file'
249\(which FILE might bind in its local variables)."
250 (interactive "fUpdate autoloads for file: ")
251 (let ((load-name (let ((name (file-name-nondirectory file)))
252 (if (string-match "\\.elc?$" name)
253 (substring name 0 (match-beginning 0))
254 name)))
d55e3ff0 255 (found nil)
0231f2dc
JB
256 (existing-buffer (get-file-buffer file)))
257 (save-excursion
258 ;; We want to get a value for generated-autoload-file from
259 ;; the local variables section if it's there.
260 (set-buffer (find-file-noselect file))
261 (set-buffer (find-file-noselect generated-autoload-file))
262 (save-excursion
263 (save-restriction
264 (widen)
265 (goto-char (point-min))
d55e3ff0
RM
266 ;; Look for the section for LOAD-NAME.
267 (while (and (not found)
268 (search-forward generate-autoload-section-header nil t))
0231f2dc
JB
269 (let ((form (condition-case ()
270 (read (current-buffer))
271 (end-of-file nil))))
d55e3ff0
RM
272 (cond ((string= (nth 2 form) load-name)
273 ;; We found the section for this file.
274 ;; Check if it is up to date.
275 (let ((begin (match-beginning 0))
276 (last-time (nth 4 form))
277 (file-time (nth 5 (file-attributes file))))
278 (if (and (or (null existing-buffer)
279 (not (buffer-modified-p existing-buffer)))
280 (listp last-time) (= (length last-time) 2)
281 (or (> (car last-time) (car file-time))
282 (and (= (car last-time) (car file-time))
283 (>= (nth 1 last-time)
284 (nth 1 file-time)))))
285 (progn
286 (message "Autoload section for %s is up to date."
287 file)
288 (setq found 'up-to-date))
289 (search-forward generate-autoload-section-trailer)
290 (delete-region begin (point))
291 (setq found t))))
292 ((string< load-name (nth 2 form))
293 ;; We've come to a section alphabetically later than
294 ;; LOAD-NAME. We assume the file is in order and so
295 ;; there must be no section for LOAD-NAME. We will
296 ;; insert one before the section here.
297 (goto-char (match-beginning 0))
72c19d97
RM
298 (setq found 'new)))))
299 (or (eq found 'up-to-date)
300 (and (eq found 'new)
301 ;; Check that FILE has any cookies before generating a
302 ;; new section for it.
303 (save-excursion
304 (set-buffer (find-file-noselect file))
305 (save-excursion
306 (widen)
307 (goto-char (point-min))
308 (if (search-forward (concat "\n"
309 generate-autoload-cookie)
310 nil t)
311 nil
312 (if (interactive-p)
313 (message file " has no autoloads"))
314 t))))
57cf354d 315 (generate-file-autoloads file))))
e2b6138f 316 (if (interactive-p) (save-buffer))
0231f2dc
JB
317 (if (and (null existing-buffer)
318 (setq existing-buffer (get-file-buffer file)))
319 (kill-buffer existing-buffer)))))
320
321;;;###autoload
322(defun update-autoloads-here ()
d08589bf
RM
323 "\
324Update sections of the current buffer generated by \\[update-file-autoloads]."
0231f2dc
JB
325 (interactive)
326 (let ((generated-autoload-file (buffer-file-name)))
327 (save-excursion
328 (goto-char (point-min))
329 (while (search-forward generate-autoload-section-header nil t)
330 (let* ((form (condition-case ()
331 (read (current-buffer))
332 (end-of-file nil)))
333 (file (nth 3 form)))
334 (if (and (stringp file)
335 (or (get-file-buffer file)
336 (file-exists-p file)))
337 ()
1eb0a345
RS
338 (setq file (if (y-or-n-p (format "Can't find library `%s'; remove its autoloads? "
339 (nth 2 form) file))
0231f2dc
JB
340 t
341 (condition-case ()
1eb0a345 342 (read-file-name (format "Find `%s' load file: "
0231f2dc
JB
343 (nth 2 form))
344 nil nil t)
345 (quit nil)))))
346 (if file
347 (let ((begin (match-beginning 0)))
348 (search-forward generate-autoload-section-trailer)
349 (delete-region begin (point))))
350 (if (stringp file)
351 (generate-file-autoloads file)))))))
352
353;;;###autoload
354(defun update-directory-autoloads (dir)
355 "Run \\[update-file-autoloads] on each .el file in DIR."
356 (interactive "DUpdate autoloads for directory: ")
9f4b7963
RS
357 (let ((enable-local-eval nil))
358 (mapcar 'update-file-autoloads
359 (directory-files dir t "^[^=].*\\.el$")))
e2b6138f
RM
360 (if (interactive-p)
361 (save-excursion
362 (set-buffer (find-file-noselect generated-autoload-file))
363 (save-buffer))))
0231f2dc
JB
364
365;;;###autoload
366(defun batch-update-autoloads ()
367 "Update the autoloads for the files or directories on the command line.
368Runs \\[update-file-autoloads] on files and \\[update-directory-autoloads]
369on directories. Must be used only with -batch, and kills Emacs on completion.
370Each file will be processed even if an error occurred previously.
1eb0a345 371For example, invoke `emacs -batch -f batch-update-autoloads *.el'."
0231f2dc 372 (if (not noninteractive)
23de5766 373 (error "batch-update-autoloads is to be used only with -batch"))
0231f2dc 374 (let ((lost nil)
72c19d97
RM
375 (args command-line-args-left)
376 (enable-local-eval nil)) ;Don't query in batch mode.
377 (message "Updating autoloads in %s..." generated-autoload-file)
378 (let ((frob (function
379 (lambda (file)
380 (condition-case lossage
381 (update-file-autoloads file)
382 (error
383 (princ ">>Error processing ")
384 (princ file)
385 (princ ": ")
386 (if (fboundp 'display-error)
387 (display-error lossage nil)
388 (prin1 lossage))
389 (princ "\n")
390 (setq lost t)))))))
391 (while args
392 (if (file-directory-p (expand-file-name (car args)))
393 (let ((rest (directory-files (car args) t "\\.el$")))
394 (while rest
395 (funcall frob (car rest))
396 (setq rest (cdr rest))))
397 (funcall frob (car args)))
e15068c4 398 (setq args (cdr args))))
0231f2dc
JB
399 (save-some-buffers t)
400 (message "Done")
401 (kill-emacs (if lost 1 0))))
402
403(provide 'autoload)
ffd56f97 404
c0274f38 405;;; autoload.el ends here