comparison lisp/utils/autoload.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children bcdc7deadc19
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 ;;; autoload.el --- maintain autoloads in loaddefs.el.
2
3 ;;; Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
4 ;;; Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
5 ;;; Copyright (C) 1996 Ben Wing.
6
7 ;; Author: Roland McGrath <roland@gnu.ai.mit.edu>
8 ;; Keywords: maint
9
10 ;;; This program is free software; you can redistribute it and/or modify
11 ;;; it under the terms of the GNU General Public License as published by
12 ;;; the Free Software Foundation; either version 2, or (at your option)
13 ;;; any later version.
14 ;;;
15 ;;; This program is distributed in the hope that it will be useful,
16 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;;; GNU General Public License for more details.
19 ;;;
20 ;;; A copy of the GNU General Public License can be obtained from this
21 ;;; program's author (send electronic mail to roland@ai.mit.edu) or from
22 ;;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
23 ;;; 02139, USA.
24 ;;;
25
26 ;;; Synched up with: FSF 19.30.
27
28 ;;; Commentary:
29
30 ;; This code helps GNU Emacs maintainers keep the loaddefs.el file up to
31 ;; date. It interprets magic cookies of the form ";;;###autoload" in
32 ;; lisp source files in various useful ways. To learn more, read the
33 ;; source; if you're going to use this, you'd better be able to.
34
35 ;;; Code:
36
37 (defun make-autoload (form file)
38 "Turn FORM, a defun or defmacro, into an autoload for source file FILE.
39 Returns nil if FORM is not a defun, define-skeleton or defmacro."
40 (let ((car (car-safe form)))
41 (if (memq car '(defun define-skeleton defmacro))
42 (let ((macrop (eq car 'defmacro))
43 name doc)
44 (setq form (cdr form)
45 name (car form)
46 ;; Ignore the arguments.
47 form (cdr (if (eq car 'define-skeleton)
48 form
49 (cdr form)))
50 doc (car form))
51 (if (stringp doc)
52 (setq form (cdr form))
53 (setq doc nil))
54 (list 'autoload (list 'quote name) file doc
55 (or (eq car 'define-skeleton)
56 (eq (car-safe (car form)) 'interactive))
57 (if macrop (list 'quote 'macro) nil)))
58 nil)))
59
60 (put 'define-skeleton 'doc-string-elt 3)
61
62 (defconst generate-autoload-cookie ";;;###autoload"
63 "Magic comment indicating the following form should be autoloaded.
64 Used by \\[update-file-autoloads]. This string should be
65 meaningless to Lisp (e.g., a comment).
66
67 This string is used:
68
69 ;;;###autoload
70 \(defun function-to-be-autoloaded () ...)
71
72 If this string appears alone on a line, the following form will be read and
73 an autoload made for it. If it is followed by the string \"immediate\",
74 then the form on the following will be copied verbatim. If there is further
75 text on the line, that text will be copied verbatim to
76 `generated-autoload-file'.")
77
78 (defconst generate-autoload-section-header "\f\n;;;### "
79 "String inserted before the form identifying
80 the section of autoloads for a file.")
81
82 (defconst generate-autoload-section-trailer "\n;;;***\n"
83 "String which indicates the end of the section of autoloads for a file.")
84
85 ;;; Forms which have doc-strings which should be printed specially.
86 ;;; A doc-string-elt property of ELT says that (nth ELT FORM) is
87 ;;; the doc-string in FORM.
88 ;;;
89 ;;; There used to be the following note here:
90 ;;; ;;; Note: defconst and defvar should NOT be marked in this way.
91 ;;; ;;; We don't want to produce defconsts and defvars that
92 ;;; ;;; make-docfile can grok, because then it would grok them twice,
93 ;;; ;;; once in foo.el (where they are given with ;;;###autoload) and
94 ;;; ;;; once in loaddefs.el.
95 ;;;
96 ;;; Counter-note: Yes, they should be marked in this way.
97 ;;; make-docfile only processes those files that are loaded into the
98 ;;; dumped Emacs, and those files should never have anything
99 ;;; autoloaded here. The above-feared problem only occurs with files
100 ;;; which have autoloaded entries *and* are processed by make-docfile;
101 ;;; there should be no such files.
102
103 (put 'autoload 'doc-string-elt 3)
104 (put 'defun 'doc-string-elt 3)
105 (put 'defvar 'doc-string-elt 3)
106 (put 'defconst 'doc-string-elt 3)
107 (put 'defmacro 'doc-string-elt 3)
108
109 (defun autoload-trim-file-name (file)
110 ;; returns a relative pathname of FILE including the last directory.
111 (setq file (expand-file-name file))
112 (file-relative-name file
113 (file-name-directory
114 (directory-file-name
115 (file-name-directory file)))))
116
117 ;;;###autoload
118 (defun generate-file-autoloads (file &optional funlist)
119 "Insert at point a loaddefs autoload section for FILE.
120 autoloads are generated for defuns and defmacros in FILE
121 marked by `generate-autoload-cookie' (which see).
122 If FILE is being visited in a buffer, the contents of the buffer
123 are used."
124 (interactive "fGenerate autoloads for file: ")
125 (let ((outbuf (current-buffer))
126 (autoloads-done '())
127 (load-name (let ((name (file-name-nondirectory file)))
128 (if (string-match "\\.elc?$" name)
129 (substring name 0 (match-beginning 0))
130 name)))
131 (dofiles (not (null funlist)))
132 (print-length nil)
133 (print-readably t) ; XEmacs
134 (float-output-format nil)
135 (done-any nil)
136 (visited (get-file-buffer file))
137 output-end)
138
139 ;; If the autoload section we create here uses an absolute
140 ;; pathname for FILE in its header, and then Emacs is installed
141 ;; under a different path on another system,
142 ;; `update-autoloads-here' won't be able to find the files to be
143 ;; autoloaded. So, if FILE is in the same directory or a
144 ;; subdirectory of the current buffer's directory, we'll make it
145 ;; relative to the current buffer's directory.
146 (setq file (expand-file-name file))
147 (let* ((source-truename (file-truename file))
148 (dir-truename (file-name-as-directory
149 (file-truename default-directory)))
150 (len (length dir-truename)))
151 (if (and (< len (length source-truename))
152 (string= dir-truename (substring source-truename 0 len)))
153 (setq file (substring source-truename len))))
154
155 (message "Generating autoloads for %s..." file)
156 (save-excursion
157 (unwind-protect
158 (progn
159 (set-buffer (find-file-noselect file))
160 (save-excursion
161 (save-restriction
162 (widen)
163 (goto-char (point-min))
164 (while (if dofiles funlist (not (eobp)))
165 (if (not dofiles)
166 (skip-chars-forward " \t\n\f")
167 (goto-char (point-min))
168 (re-search-forward
169 (concat "(def\\(un\\|var\\|const\\|macro\\) "
170 (regexp-quote (symbol-name (car funlist)))
171 "\\s "))
172 (goto-char (match-beginning 0)))
173 (cond
174 ((or dofiles
175 (looking-at (regexp-quote generate-autoload-cookie)))
176 (if dofiles
177 nil
178 (search-forward generate-autoload-cookie)
179 (skip-chars-forward " \t"))
180 (setq done-any t)
181 (if (or dofiles (eolp))
182 ;; Read the next form and make an autoload.
183 (let* ((form (prog1 (read (current-buffer))
184 (or (bolp) (forward-line 1))))
185 (autoload (make-autoload form load-name))
186 (doc-string-elt (get (car-safe form)
187 'doc-string-elt)))
188 (if autoload
189 (setq autoloads-done (cons (nth 1 form)
190 autoloads-done))
191 (setq autoload form))
192 (if (and doc-string-elt
193 (stringp (nth doc-string-elt autoload)))
194 ;; We need to hack the printing because the
195 ;; doc-string must be printed specially for
196 ;; make-docfile (sigh).
197 (let* ((p (nthcdr (1- doc-string-elt)
198 autoload))
199 (elt (cdr p)))
200 (setcdr p nil)
201 (princ "\n(" outbuf)
202 ;; XEmacs change: don't let ^^L's get into
203 ;; the file or sorting is hard.
204 (let ((print-escape-newlines t)
205 (p (save-excursion
206 (set-buffer outbuf)
207 (point)))
208 p2)
209 (mapcar (function (lambda (elt)
210 (prin1 elt outbuf)
211 (princ " " outbuf)))
212 autoload)
213 (save-excursion
214 (set-buffer outbuf)
215 (setq p2 (point-marker))
216 (goto-char p)
217 (save-match-data
218 (while (search-forward "\^L" p2 t)
219 (delete-char -1)
220 (insert "\\^L")))
221 (goto-char p2)
222 ))
223 (princ "\"\\\n" outbuf)
224 (let ((begin (save-excursion
225 (set-buffer outbuf)
226 (point))))
227 (princ (substring
228 (prin1-to-string (car elt)) 1)
229 outbuf)
230 ;; Insert a backslash before each ( that
231 ;; appears at the beginning of a line in
232 ;; the doc string.
233 (save-excursion
234 (set-buffer outbuf)
235 (save-excursion
236 (while (search-backward "\n(" begin t)
237 (forward-char 1)
238 (insert "\\"))))
239 (if (null (cdr elt))
240 (princ ")" outbuf)
241 (princ " " outbuf)
242 (princ (substring
243 (prin1-to-string (cdr elt))
244 1)
245 outbuf))
246 (terpri outbuf)))
247 ;; XEmacs change: another fucking ^L hack
248 (let ((p (save-excursion
249 (set-buffer outbuf)
250 (point)))
251 (print-escape-newlines t)
252 p2)
253 (print autoload outbuf)
254 (save-excursion
255 (set-buffer outbuf)
256 (setq p2 (point-marker))
257 (goto-char p)
258 (save-match-data
259 (while (search-forward "\^L" p2 t)
260 (delete-char -1)
261 (insert "\\^L")))
262 (goto-char p2)
263 ))
264 ))
265 ;; Copy the rest of the line to the output.
266 (let ((begin (point)))
267 (terpri outbuf)
268 (cond ((looking-at "immediate\\s *$") ; XEmacs
269 ;; This is here so that you can automatically
270 ;; have small hook functions copied to
271 ;; loaddefs.el so that it's not necessary to
272 ;; load a whole file just to get a two-line
273 ;; do-nothing find-file-hook... --Stig
274 (forward-line 1)
275 (setq begin (point))
276 (forward-sexp)
277 (forward-line 1))
278 (t
279 (forward-line 1)))
280 (princ (buffer-substring begin (point)) outbuf))))
281 ((looking-at ";")
282 ;; Don't read the comment.
283 (forward-line 1))
284 (t
285 (forward-sexp 1)
286 (forward-line 1)))
287 (if dofiles
288 (setq funlist (cdr funlist)))))))
289 (or visited
290 ;; We created this buffer, so we should kill it.
291 (kill-buffer (current-buffer)))
292 (set-buffer outbuf)
293 (setq output-end (point-marker))))
294 (if t ;; done-any
295 ;; XEmacs -- always do this so that we cache the information
296 ;; that we've processed the file already.
297 (progn
298 (insert generate-autoload-section-header)
299 (prin1 (list 'autoloads autoloads-done load-name
300 (autoload-trim-file-name file)
301 (nth 5 (file-attributes file)))
302 outbuf)
303 (terpri outbuf)
304 (insert ";;; Generated autoloads from "
305 (autoload-trim-file-name file) "\n")
306 ;; Warn if we put a line in loaddefs.el
307 ;; that is long enough to cause trouble.
308 (while (< (point) output-end)
309 (let ((beg (point)))
310 (end-of-line)
311 (if (> (- (point) beg) 900)
312 (progn
313 (message "A line is too long--over 900 characters")
314 (sleep-for 2)
315 (goto-char output-end))))
316 (forward-line 1))
317 (goto-char output-end)
318 (insert generate-autoload-section-trailer)))
319 (or noninteractive ; XEmacs: only need one line in -batch mode.
320 (message "Generating autoloads for %s...done" file))))
321
322 (defconst generated-autoload-file (expand-file-name "../lisp/prim/loaddefs.el"
323 data-directory)
324 "*File \\[update-file-autoloads] puts autoloads into.
325 A .el file can set this in its local variables section to make its
326 autoloads go somewhere else.")
327
328 (defvar generate-autoload-dynamic-but-inefficient nil
329 "If non-nil, `update-file-autoloads' will always read in its files.
330 This allows you to bind `generated-autoload-file' in your local variables
331 (do you really want to do that?) but makes it very slow in updating
332 lots of files.")
333
334 ;;;###autoload
335 (defun update-file-autoloads (file)
336 "Update the autoloads for FILE in `generated-autoload-file'
337 \(which FILE might bind in its local variables)."
338 (interactive "fUpdate autoloads for file: ")
339 ;; avoid horrid horrid problems with relative filenames.
340 (setq file (expand-file-name file default-directory))
341 (let ((load-name (let ((name (file-name-nondirectory file)))
342 (if (string-match "\\.elc?$" name)
343 (substring name 0 (match-beginning 0))
344 name)))
345 (trim-name (autoload-trim-file-name file))
346 (found nil)
347 (pass 'first)
348 (existing-buffer (get-file-buffer file)))
349 (save-excursion
350 ;; We want to get a value for generated-autoload-file from
351 ;; the local variables section if it's there.
352 (and generate-autoload-dynamic-but-inefficient
353 (set-buffer (find-file-noselect file)))
354 (set-buffer (or (get-file-buffer generated-autoload-file)
355 (find-file-noselect generated-autoload-file)))
356 (save-excursion
357 (save-restriction
358 (widen)
359 (while pass
360 ;; This is done in two passes:
361 ;; 1st pass: Look for the section for LOAD-NAME anywhere in the file.
362 ;; 2st pass: Find a place to insert it. Use alphabetical order.
363 (goto-char (point-min))
364 (while (and (not found)
365 (search-forward generate-autoload-section-header nil t))
366 (let ((form (condition-case ()
367 (read (current-buffer))
368 (end-of-file nil))))
369 (cond ((and (eq pass 'first)
370 (string= (nth 2 form) load-name))
371 ;; We found the section for this file.
372 ;; Check if it is up to date.
373 (let ((begin (match-beginning 0))
374 (last-time (nth 4 form))
375 (file-time (nth 5 (file-attributes file))))
376 (if (and (or (null existing-buffer)
377 (not (buffer-modified-p existing-buffer)))
378 (listp last-time) (= (length last-time) 2)
379 (or (> (car last-time) (car file-time))
380 (and (= (car last-time) (car file-time))
381 (>= (nth 1 last-time)
382 (nth 1 file-time)))))
383 (progn
384 (or noninteractive
385 ;; jwz: too loud in -batch mode
386 (message
387 "Autoload section for %s is up to date."
388 file))
389 (setq found 'up-to-date))
390 ;; Okay, we found it and it's not up to date...
391 (search-forward generate-autoload-section-trailer)
392 (delete-region begin (point))
393 ;; if the file has moved, then act like it hasn't
394 ;; been found and then reinsert it alphabetically.
395 (setq found (string= trim-name (nth 3 form)))
396 )))
397 ;; XEmacs change -- we organize by sub-directories
398 ;; so inserting new autoload entries is a bit tricky...
399 ((and (eq pass 'last)
400 (string< trim-name (nth 3 form)))
401 ;; We've come to a section alphabetically later than
402 ;; LOAD-NAME. We assume the file is in order and so
403 ;; there must be no section for LOAD-NAME. We will
404 ;; insert one before the section here.
405 (goto-char (match-beginning 0))
406 (setq found 'new))
407 )))
408 (cond (found
409 (setq pass nil)) ; success -- exit loop
410 ((eq pass 'first)
411 (setq pass 'last))
412 (t
413 ;; failure -- exit loop
414 (setq pass nil))))
415 (or (eq found 'up-to-date)
416 ;; XEmacs -- don't do the following. If we do, then
417 ;; every time we update autoloads we have to search
418 ;; the whole file (yuck).
419 ; (and (eq found 'new)
420 ; ;; Check that FILE has any cookies before generating a
421 ; ;; new section for it.
422 ; (save-excursion
423 ; (set-buffer (find-file-noselect file))
424 ; (save-excursion
425 ; (widen)
426 ; (goto-char (point-min))
427 ; (if (search-forward (concat "\n"
428 ; generate-autoload-cookie)
429 ; nil t)
430 ; nil
431 ; (if (interactive-p)
432 ; (message file " has no autoloads"))
433 ; t))))
434 (generate-file-autoloads file))))
435 (if (interactive-p) (save-buffer))
436 (if (and (null existing-buffer)
437 (setq existing-buffer (get-file-buffer file)))
438 (kill-buffer existing-buffer)))))
439
440 ;;;###autoload
441 (defun update-autoloads-here ()
442 "\
443 Update sections of the current buffer generated by \\[update-file-autoloads]."
444 (interactive)
445 (let ((generated-autoload-file (buffer-file-name)))
446 (save-excursion
447 (goto-char (point-min))
448 (while (search-forward generate-autoload-section-header nil t)
449 (let* ((form (condition-case ()
450 (read (current-buffer))
451 (end-of-file nil)))
452 (file (nth 3 form)))
453 ;; XEmacs change: if we can't find the file as specified, look
454 ;; around a bit more.
455 (cond ((and (stringp file)
456 (or (get-file-buffer file)
457 (file-exists-p file))))
458 ((and (stringp file)
459 (save-match-data
460 (let ((loc (locate-file (file-name-nondirectory file)
461 load-path)))
462 (if (null loc)
463 nil
464 (setq loc (expand-file-name
465 (autoload-trim-file-name loc)
466 ".."))
467 (if (or (get-file-buffer loc)
468 (file-exists-p loc))
469 (setq file loc)
470 nil))))))
471 (t
472 (setq file (if (y-or-n-p (format "Can't find library `%s'; remove its autoloads? "
473 (nth 2 form) file))
474 t
475 (condition-case ()
476 (read-file-name
477 (format "Find `%s' load file: "
478 (nth 2 form))
479 nil nil t)
480 (quit nil))))))
481 (if file
482 (let ((begin (match-beginning 0)))
483 (search-forward generate-autoload-section-trailer)
484 (delete-region begin (point))))
485 (if (stringp file)
486 (generate-file-autoloads file)))))))
487
488 ;;;###autoload
489 (defun update-directory-autoloads (dir)
490 "Run \\[update-file-autoloads] on each .el file in DIR."
491 (interactive "DUpdate autoloads for directory: ")
492 (let ((enable-local-eval nil))
493 (mapcar 'update-file-autoloads
494 (directory-files dir t "^[^=].*\\.el$")))
495 (if (interactive-p)
496 (save-excursion
497 (set-buffer (find-file-noselect generated-autoload-file))
498 (save-buffer))))
499
500 ;;;###autoload
501 (defun batch-update-autoloads ()
502 "Update the autoloads for the files or directories on the command line.
503 Runs \\[update-file-autoloads] on files and \\[update-directory-autoloads]
504 on directories. Must be used only with -batch, and kills Emacs on completion.
505 Each file will be processed even if an error occurred previously.
506 For example, invoke `emacs -batch -f batch-update-autoloads *.el'."
507 (if (not noninteractive)
508 (error "batch-update-autoloads is to be used only with -batch"))
509 (let ((lost nil)
510 (args command-line-args-left)
511 (defdir default-directory)
512 (enable-local-eval nil)) ;Don't query in batch mode.
513 (message "Updating autoloads in %s..." generated-autoload-file)
514 (let ((frob (function
515 (lambda (file)
516 (condition-case lossage
517 (let ((default-directory defdir))
518 (update-file-autoloads file))
519 (error
520 (princ ">>Error processing ")
521 (princ file)
522 (princ ": ")
523 (if (fboundp 'display-error)
524 (display-error lossage nil)
525 (prin1 lossage))
526 (princ "\n")
527 (setq lost t)))))))
528 (while args
529 (if (file-directory-p (expand-file-name (car args)))
530 (let ((rest (directory-files (car args) t "\\.el$")))
531 (if noninteractive
532 (message "Processing directory %s..." (car args)))
533 (while rest
534 (funcall frob (car rest))
535 (setq rest (cdr rest))))
536 (funcall frob (car args)))
537 (setq args (cdr args))))
538 (save-some-buffers t)
539 (message "Done")
540 (kill-emacs (if lost 1 0))))
541
542 (provide 'autoload)
543
544 ;;; autoload.el ends here