1 ;;; autoload.el --- maintain autoloads in loaddefs.el.
3 ;;; Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
5 ;; Author: Roland McGrath <roland@gnu.ai.mit.edu>
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
10 ;;; the Free Software Foundation; either version 2, or (at your option)
11 ;;; any later version.
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.
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
26 ;; This code helps GNU Emacs maintainers keep the loaddefs.el file up to
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.
33 (defun make-autoload (form file
)
34 "Turn FORM, a defun or defmacro, into an autoload for source file FILE.
35 Returns nil if FORM is not a defun or defmacro."
36 (let ((car (car-safe form
)))
37 (if (memq car
'(defun defmacro))
38 (let ((macrop (eq car
'defmacro
))
40 (setq form
(cdr form
))
41 (setq name
(car form
))
42 ;; Ignore the arguments.
43 (setq form
(cdr (cdr form
)))
46 (setq form
(cdr form
))
48 (list 'autoload
(list 'quote name
) file doc
49 (eq (car-safe (car form
)) 'interactive
)
50 (if macrop
(list 'quote
'macro
) nil
)))
53 (defconst generate-autoload-cookie
";;;###autoload"
54 "Magic comment indicating the following form should be autoloaded.
55 Used by \\[update-file-autoloads]. This string should be
56 meaningless to Lisp (e.g., a comment).
61 \(defun function-to-be-autoloaded () ...)
63 If this string appears alone on a line, the following form will be
64 read and an autoload made for it. If there is further text on the line,
65 that text will be copied verbatim to `generated-autoload-file'.")
67 (defconst generate-autoload-section-header
"\f\n;;;### "
68 "String inserted before the form identifying
69 the section of autoloads for a file.")
71 (defconst generate-autoload-section-trailer
"\n;;;***\n"
72 "String which indicates the end of the section of autoloads for a file.")
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.
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.
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.
92 (put 'autoload
'doc-string-elt
3)
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)
98 (defun autoload-trim-file-name (file)
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.
104 (setq file
(expand-file-name file
))
105 (file-relative-name file
106 (file-name-directory generated-autoload-file
)))
108 (defun generate-file-autoloads (file)
109 "Insert at point a loaddefs autoload section for FILE.
110 autoloads are generated for defuns and defmacros in FILE
111 marked by `generate-autoload-cookie' (which see).
112 If FILE is being visited in a buffer, the contents of the buffer
114 (interactive "fGenerate autoloads for file: ")
115 (let ((outbuf (current-buffer))
117 (load-name (let ((name (file-name-nondirectory file
)))
118 (if (string-match "\\.elc?$" name
)
119 (substring name
0 (match-beginning 0))
122 (print-readably t
) ; This does something in Lucid Emacs.
123 (float-output-format nil
)
125 (visited (get-file-buffer file
))
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
133 ;; subdirectory of the current buffer's directory, we'll make it
134 ;; relative to the current buffer's directory.
135 (setq file
(expand-file-name file
))
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
))))
144 (message "Generating autoloads for %s..." file
)
148 (set-buffer (find-file-noselect file
))
152 (goto-char (point-min))
154 (skip-chars-forward " \t\n\f")
156 ((looking-at (regexp-quote generate-autoload-cookie
))
157 (search-forward generate-autoload-cookie
)
158 (skip-chars-forward " \t")
161 ;; Read the next form and make an autoload.
162 (let* ((form (prog1 (read (current-buffer))
163 (or (bolp) (forward-line 1))))
164 (autoload (make-autoload form load-name
))
165 (doc-string-elt (get (car-safe form
)
168 (setq autoloads-done
(cons (nth 1 form
)
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
)
181 (let ((print-escape-newlines t
))
182 (mapcar (function (lambda (elt)
186 (princ "\"\\\n" outbuf
)
187 (let ((begin (save-excursion
191 (prin1-to-string (car elt
)) 1)
193 ;; Insert a backslash before each ( that
194 ;; appears at the beginning of a line in
199 (while (search-backward "\n(" begin t
)
206 (prin1-to-string (cdr elt
))
210 (let ((print-escape-newlines t
))
211 (print autoload outbuf
))))
212 ;; Copy the rest of the line to the output.
213 (let ((begin (point)))
215 (princ (buffer-substring begin
(point)) outbuf
))))
217 ;; Don't read the comment.
221 (forward-line 1)))))))
223 ;; We created this buffer, so we should kill it.
224 (kill-buffer (current-buffer)))
226 (setq output-end
(point-marker))))
229 (insert generate-autoload-section-header
)
230 (prin1 (list 'autoloads autoloads-done load-name
231 (autoload-trim-file-name file
)
232 (nth 5 (file-attributes file
)))
235 (insert ";;; Generated autoloads from "
236 (autoload-trim-file-name file
) "\n")
237 (goto-char output-end
)
238 (insert generate-autoload-section-trailer
)))
239 (message "Generating autoloads for %s...done" file
)))
241 (defconst generated-autoload-file
"loaddefs.el"
242 "*File \\[update-file-autoloads] puts autoloads into.
243 A .el file can set this in its local variables section to make its
244 autoloads go somewhere else.")
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))
256 (existing-buffer (get-file-buffer file
)))
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
))
265 (goto-char (point-min))
266 ;; Look for the section for LOAD-NAME.
267 (while (and (not found
)
268 (search-forward generate-autoload-section-header nil t
))
269 (let ((form (condition-case ()
270 (read (current-buffer))
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
)))))
286 (message "Autoload section for %s is up to date."
288 (setq found
'up-to-date
))
289 (search-forward generate-autoload-section-trailer
)
290 (delete-region begin
(point))
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))
298 (setq found
'new
)))))
299 (or (eq found
'up-to-date
)
301 ;; Check that FILE has any cookies before generating a
302 ;; new section for it.
304 (set-buffer (find-file-noselect file
))
307 (goto-char (point-min))
308 (if (search-forward (concat "\n"
309 generate-autoload-cookie
)
313 (message file
" has no autoloads"))
315 (generate-file-autoloads file
))))
316 (if (interactive-p) (save-buffer))
317 (if (and (null existing-buffer
)
318 (setq existing-buffer
(get-file-buffer file
)))
319 (kill-buffer existing-buffer
)))))
322 (defun update-autoloads-here ()
324 Update sections of the current buffer generated by \\[update-file-autoloads]."
326 (let ((generated-autoload-file (buffer-file-name)))
328 (goto-char (point-min))
329 (while (search-forward generate-autoload-section-header nil t
)
330 (let* ((form (condition-case ()
331 (read (current-buffer))
334 (if (and (stringp file
)
335 (or (get-file-buffer file
)
336 (file-exists-p file
)))
338 (setq file
(if (y-or-n-p (format "Can't find library `%s'; remove its autoloads? "
342 (read-file-name (format "Find `%s' load file: "
347 (let ((begin (match-beginning 0)))
348 (search-forward generate-autoload-section-trailer
)
349 (delete-region begin
(point))))
351 (generate-file-autoloads file
)))))))
354 (defun update-directory-autoloads (dir)
355 "Run \\[update-file-autoloads] on each .el file in DIR."
356 (interactive "DUpdate autoloads for directory: ")
357 (let ((enable-local-eval nil
))
358 (mapcar 'update-file-autoloads
359 (directory-files dir t
"^[^=].*\\.el$")))
362 (set-buffer (find-file-noselect generated-autoload-file
))
366 (defun batch-update-autoloads ()
367 "Update the autoloads for the files or directories on the command line.
368 Runs \\[update-file-autoloads] on files and \\[update-directory-autoloads]
369 on directories. Must be used only with -batch, and kills Emacs on completion.
370 Each file will be processed even if an error occurred previously.
371 For example, invoke `emacs -batch -f batch-update-autoloads *.el'."
372 (if (not noninteractive
)
373 (error "batch-update-autoloads is to be used only with -batch"))
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
380 (condition-case lossage
381 (update-file-autoloads file
)
383 (princ ">>Error processing ")
386 (if (fboundp 'display-error
)
387 (display-error lossage nil
)
392 (if (file-directory-p (expand-file-name (car args
)))
393 (let ((rest (directory-files (car args
) t
"\\.el$")))
395 (funcall frob
(car rest
))
396 (setq rest
(cdr rest
))))
397 (funcall frob
(car args
)))
398 (setq args
(cdr args
))))
399 (save-some-buffers t
)
401 (kill-emacs (if lost
1 0))))
405 ;;; autoload.el ends here