From: Alan Mackenzie <acm@muc.de>
To: emacs-devel@gnu.org
Cc: Glenn Morris <rgm@gnu.org>, Chong Yidong <cyd@stupidchicken.com>,
Stefan Monnier <monnier@iro.umontreal.ca>
Subject: Refactoring of emacs-lisp/autoload.el
Date: Tue, 12 Aug 2008 16:23:33 +0000 [thread overview]
Message-ID: <20080812162333.GA7999@muc.de> (raw)
Hi, Glenn, Stefan, Yidong and Emacs,
in my battle to be able to build Emacs (solved when I fixed my files.el,
which was fouling up file local variables), I refactored autoload.el, to
make it easier to understand and debug.
Although there were no bugs, as such, in that source file, I would like
my refactored version to supersede the existing version anyway, for the
following reasons:
#########################################################################
(i) It is better structured:
o - the functions are coherently single purpose to a greater extent than
before;
o - the output file handling has been separated from source file
considerations;
o - two `catch' constructs (~120 and ~80 lines) have been eliminated.
(ii) It produces more consistent result in the comment sections of loaddefs.el
etc. In particular:
o - The lines that identify the source file now always (rather than just
sometimes) give a file name relative to the "starting directory" (usually
.../lisp). E.g.:
*** calc/calc-loaddefs.el.old 2008-08-12 13:17:32.983291472 +0000
--- calc/calc-loaddefs.el.new 2008-08-12 15:00:26.468779024 +0000
***************
*** 9,16 ****
;;;;;; math-read-preprocess-string calcDigit-edit calcDigit-algebraic
;;;;;; calc-alg-digit-entry calc-do-alg-entry calc-alg-entry calc-algebraic-entry
;;;;;; calc-auto-algebraic-entry calc-do-calc-eval calc-do-quick-calc)
! ;;;;;; "calc-aent" "calc-aent.el" "397561d73c948bd9256db97c177e84f6")
! ;;; Generated autoloads from calc-aent.el
(autoload 'calc-do-quick-calc "calc-aent" "\
Not documented
--- 9,16 ----
;;;;;; math-read-preprocess-string calcDigit-edit calcDigit-algebraic
;;;;;; calc-alg-digit-entry calc-do-alg-entry calc-alg-entry calc-algebraic-entry
;;;;;; calc-auto-algebraic-entry calc-do-calc-eval calc-do-quick-calc)
! ;;;;;; "calc-aent" "calc/calc-aent.el" "397561d73c948bd9256db97c177e84f6")
! ;;; Generated autoloads from calc/calc-aent.el
o - The final section (which records files which had no autoload symbols) no
longer includes any files for which there is a normal section higher up.
For example, in lisp/loaddefs.el at the moment, "calc/calc-aent.el"
violates this rule. I have assumed that this is a bug.
(iii) The new autoload.el runs quite a lot faster than the old one. :-) Here
are some comparitive timings, done under fair conditions on my 1.2 GHz
Athlon box:
OLD: NEW:
real 1m11.502s real 0m40.729s
user 0m55.141s user 0m24.519s
sys 0m15.981s sys 0m15.998s
This is a speedup of ~75%.
#########################################################################
Here is the patch:
2008-08-12 Alan Mackenzie <acm@muc.de>
* emacs-lisp/autoload.el Refactor this source file.
(autoload-ensure-unix-eols, autoload-entry-up-to-date-p)
(autoload-extract-cookie)
(autoload-locate-section-in-existing-buffer)
(autoload-parse-source-buffer, autoload-setup-output-buffer): New
functions which supersede autoload-ensure-default-file,
autoload-file-load-name, autoload-find-destination,
autoload-generate-file-autoloads, autoload-generated-file,
autoload-save-buffers, generate-file-autoloads.
(autoload-print-form-outbuf): Removed.
Index: autoload.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/emacs-lisp/autoload.el,v
retrieving revision 1.142
diff -c -r1.142 autoload.el
*** autoload.el 10 Jun 2008 09:02:38 -0000 1.142
--- autoload.el 12 Aug 2008 15:52:29 -0000
***************
*** 153,172 ****
;; the doc-string in FORM.
;; Those properties are now set in lisp-mode.el.
- (defun autoload-generated-file ()
- (expand-file-name generated-autoload-file
- ;; File-local settings of generated-autoload-file should
- ;; be interpreted relative to the file's location,
- ;; of course.
- (if (not (local-variable-p 'generated-autoload-file))
- (expand-file-name "lisp" source-directory))))
-
-
(defun autoload-read-section-header ()
"Read a section header form.
! Since continuation lines have been marked as comments,
! we must copy the text of the form and remove those comment
! markers before we call `read'."
(save-match-data
(let ((beginning (point))
string)
--- 153,164 ----
;; the doc-string in FORM.
;; Those properties are now set in lisp-mode.el.
(defun autoload-read-section-header ()
"Read a section header form.
! Point should be at the \"(\" following the \";;;### \"."
! ;; Since continuation lines have been marked as comments,
! ;; we must copy the text of the form and remove those comment
! ;; markers before we call `read'."
(save-match-data
(let ((beginning (point))
string)
***************
*** 183,203 ****
(goto-char (point-min))
(read (current-buffer))))))
! (defvar autoload-print-form-outbuf nil
! "Buffer which gets the output of `autoload-print-form'.")
!
! (defun autoload-print-form (form)
"Print FORM such that `make-docfile' will find the docstrings.
! The variable `autoload-print-form-outbuf' specifies the buffer to
! put the output in."
(cond
;; If the form is a sequence, recurse.
! ((eq (car form) 'progn) (mapcar 'autoload-print-form (cdr form)))
;; Symbols at the toplevel are meaningless.
((symbolp form) nil)
(t
! (let ((doc-string-elt (get (car-safe form) 'doc-string-elt))
! (outbuf autoload-print-form-outbuf))
(if (and doc-string-elt (stringp (nth doc-string-elt form)))
;; We need to hack the printing because the
;; doc-string must be printed specially for
--- 175,191 ----
(goto-char (point-min))
(read (current-buffer))))))
! (defun autoload-print-form (form outbuf)
"Print FORM such that `make-docfile' will find the docstrings.
! OUTBUF specifies the buffer to put the output in."
(cond
;; If the form is a sequence, recurse.
! ((eq (car form) 'progn)
! (mapcar (lambda (f) (autoload-print-form f outbuf)) (cdr form)))
;; Symbols at the toplevel are meaningless.
((symbolp form) nil)
(t
! (let ((doc-string-elt (get (car-safe form) 'doc-string-elt)))
(if (and doc-string-elt (stringp (nth doc-string-elt form)))
;; We need to hack the printing because the
;; doc-string must be printed specially for
***************
*** 255,266 ****
";;; " basename
" ends here\n")))
- (defun autoload-ensure-default-file (file)
- "Make sure that the autoload file FILE exists and if not create it."
- (unless (file-exists-p file)
- (write-region (autoload-rubric file) nil file))
- file)
-
(defun autoload-insert-section-header (outbuf autoloads load-name file time)
"Insert the section-header line,
which lists the file name and which functions are in it, etc."
--- 243,248 ----
***************
*** 304,466 ****
(substring name 0 (match-beginning 0))
name)))
- (defun generate-file-autoloads (file)
- "Insert at point a loaddefs autoload section for FILE.
- Autoloads are generated for defuns and defmacros in FILE
- marked by `generate-autoload-cookie' (which see).
- If FILE is being visited in a buffer, the contents of the buffer
- are used.
- Return non-nil in the case where no autoloads were added at point."
- (interactive "fGenerate autoloads for file: ")
- (autoload-generate-file-autoloads file (current-buffer)))
-
- ;; When called from `generate-file-autoloads' we should ignore
- ;; `generated-autoload-file' altogether. When called from
- ;; `update-file-autoloads' we don't know `outbuf'. And when called from
- ;; `update-directory-autoloads' it's in between: we know the default
- ;; `outbuf' but we should obey any file-local setting of
- ;; `generated-autoload-file'.
- (defun autoload-generate-file-autoloads (file &optional outbuf outfile)
- "Insert an autoload section for FILE in the appropriate buffer.
- Autoloads are generated for defuns and defmacros in FILE
- marked by `generate-autoload-cookie' (which see).
- If FILE is being visited in a buffer, the contents of the buffer are used.
- OUTBUF is the buffer in which the autoload statements should be inserted.
- If OUTBUF is nil, it will be determined by `autoload-generated-file'.
-
- If provided, OUTFILE is expected to be the file name of OUTBUF.
- If OUTFILE is non-nil and FILE specifies a `generated-autoload-file'
- different from OUTFILE, then OUTBUF is ignored.
-
- Return non-nil if and only if FILE adds no autoloads to OUTFILE
- \(or OUTBUF if OUTFILE is nil)."
- (catch 'done
- (let ((autoloads-done '())
- (load-name (autoload-file-load-name file))
- (print-length nil)
- (print-level nil)
- (print-readably t) ; This does something in Lucid Emacs.
- (float-output-format nil)
- (visited (get-file-buffer file))
- (otherbuf nil)
- (absfile (expand-file-name file))
- relfile
- ;; nil until we found a cookie.
- output-start)
-
- (with-current-buffer (or visited
- ;; It is faster to avoid visiting the file.
- (autoload-find-file file))
- ;; Obey the no-update-autoloads file local variable.
- (unless no-update-autoloads
- (message "Generating autoloads for %s..." file)
- (save-excursion
- (save-restriction
- (widen)
- (goto-char (point-min))
- (while (not (eobp))
- (skip-chars-forward " \t\n\f")
- (cond
- ((looking-at (regexp-quote generate-autoload-cookie))
- ;; If not done yet, figure out where to insert this text.
- (unless output-start
- (when (and outfile
- (not (equal outfile (autoload-generated-file))))
- ;; A file-local setting of autoload-generated-file says
- ;; we should ignore OUTBUF.
- (setq outbuf nil)
- (setq otherbuf t))
- (unless outbuf
- (setq outbuf (autoload-find-destination absfile))
- (unless outbuf
- ;; The file has autoload cookies, but they're
- ;; already up-to-date. If OUTFILE is nil, the
- ;; entries are in the expected OUTBUF, otherwise
- ;; they're elsewhere.
- (throw 'done outfile)))
- (with-current-buffer outbuf
- (setq relfile (file-relative-name absfile))
- (setq output-start (point)))
- ;; (message "file=%S, relfile=%S, dest=%S"
- ;; file relfile (autoload-generated-file))
- )
- (search-forward generate-autoload-cookie)
- (skip-chars-forward " \t")
- (if (eolp)
- (condition-case err
- ;; Read the next form and make an autoload.
- (let* ((form (prog1 (read (current-buffer))
- (or (bolp) (forward-line 1))))
- (autoload (make-autoload form load-name)))
- (if autoload
- (push (nth 1 form) autoloads-done)
- (setq autoload form))
- (let ((autoload-print-form-outbuf outbuf))
- (autoload-print-form autoload)))
- (error
- (message "Error in %s: %S" file err)))
-
- ;; Copy the rest of the line to the output.
- (princ (buffer-substring
- (progn
- ;; Back up over whitespace, to preserve it.
- (skip-chars-backward " \f\t")
- (if (= (char-after (1+ (point))) ? )
- ;; Eat one space.
- (forward-char 1))
- (point))
- (progn (forward-line 1) (point)))
- outbuf)))
- ((looking-at ";")
- ;; Don't read the comment.
- (forward-line 1))
- (t
- (forward-sexp 1)
- (forward-line 1))))))
-
- (when output-start
- (let ((secondary-autoloads-file-buf
- (if (local-variable-p 'generated-autoload-file)
- (current-buffer))))
- (with-current-buffer outbuf
- (save-excursion
- ;; Insert the section-header line which lists the file name
- ;; and which functions are in it, etc.
- (goto-char output-start)
- (autoload-insert-section-header
- outbuf autoloads-done load-name relfile
- (if secondary-autoloads-file-buf
- ;; MD5 checksums are much better because they do not
- ;; change unless the file changes (so they'll be
- ;; equal on two different systems and will change
- ;; less often than time-stamps, thus leading to fewer
- ;; unneeded changes causing spurious conflicts), but
- ;; using time-stamps is a very useful optimization,
- ;; so we use time-stamps for the main autoloads file
- ;; (loaddefs.el) where we have special ways to
- ;; circumvent the "random change problem", and MD5
- ;; checksum in secondary autoload files where we do
- ;; not need the time-stamp optimization because it is
- ;; already provided by the primary autoloads file.
- (md5 secondary-autoloads-file-buf
- ;; We'd really want to just use
- ;; `emacs-internal' instead.
- nil nil 'emacs-mule-unix)
- (nth 5 (file-attributes relfile))))
- (insert ";;; Generated autoloads from " relfile "\n"))
- (insert generate-autoload-section-trailer))))
- (message "Generating autoloads for %s...done" file))
- (or visited
- ;; We created this buffer, so we should kill it.
- (kill-buffer (current-buffer))))
- ;; If the entries were added to some other buffer, then the file
- ;; doesn't add entries to OUTFILE.
- (or (not output-start) otherbuf))))
\f
! (defun autoload-save-buffers ()
! (while autoload-modified-buffers
! (with-current-buffer (pop autoload-modified-buffers)
! (save-buffer))))
;;;###autoload
(defun update-file-autoloads (file &optional save-after)
--- 286,538 ----
(substring name 0 (match-beginning 0))
name)))
\f
! (defun autoload-remove-section (begin)
! (goto-char begin)
! (search-forward generate-autoload-section-trailer)
! (delete-region begin (point)))
!
! (defun autoload-locate-section-in-existing-buffer (file out-file)
! "Locate the position in OUT-FILE's buffer for the entry for FILE.
! FILE is the full path name of a source lisp file.
! OUT-FILE is file name of the output file \(e.g. \"loaddefs.el\").
!
! There needn't be an existing entry for FILE at this position.
!
! If necessary, this function loads (the already existing) OUT-FILE
! into a new buffer.
!
! Return a buffer for OUT-FILE with point at the ^L at the start of
! the entry. If neither OUT-FILE nor a buffer for it exists,
! return nil."
! (let ((outbuf
! (or (get-file-buffer out-file)
! (and (file-exists-p out-file)
! (find-file-noselect out-file))))
! (load-name (autoload-file-load-name file))
! section-name)
! (and outbuf
! (> (buffer-size outbuf) 0)
! (with-current-buffer outbuf
! (widen)
! ;; Optimise for the new entry being near current pos in out-file.
! (while (and (search-backward generate-autoload-section-header nil 'BOB)
! (save-excursion
! (goto-char (match-end 0))
! (setq section-name (nth 2 (autoload-read-section-header)))
! (or (null section-name) ; list of autoloadless files at EOF.
! (string< load-name section-name)))))
! (unless (and (looking-at generate-autoload-section-header)
! (string= load-name section-name))
! (or (search-forward "\f" nil t) ; Ensure (match-beginning 0) will work.
! (error "Autoload file %s is malformed." out-file))
! (backward-char)
! (while (and (search-forward generate-autoload-section-header nil 'EOB)
! (setq section-name (nth 2 (autoload-read-section-header)))
! section-name (string< section-name load-name)))
! (if (eobp)
! (search-backward "\f")
! (goto-char (match-beginning 0))))
! outbuf))))
!
! (defun autoload-entry-up-to-date-p (file out-file)
! "Is there an existing up to date section for FILE in OUT-FILE?
! FILE is the full path name of a source lisp file, and its
! contents are the current buffer.
!
! OUT-FILE is the file name of the output file \(e.g. \"loaddefs.el\").
! This file might not yet exist, a buffer for it may or may not exist.
!
! If necessary, this function loads OUT-FILE into a new buffer."
! (let* ((outbuf (autoload-locate-section-in-existing-buffer file out-file))
! (section-header
! (and outbuf
! (with-current-buffer outbuf
! (and (search-forward generate-autoload-section-header nil t)
! (autoload-read-section-header)))))
! (load-name (autoload-file-load-name file))
! date-or-sum)
!
! (and section-header
! (string= load-name (nth 2 section-header))
! (setq date-or-sum (nth 4 section-header))
! (cond
! ((and (listp date-or-sum) (= (length date-or-sum) 2)) ; timestamp
! (not (time-less-p date-or-sum
! (nth 5 (file-attributes file)))))
! ((stringp date-or-sum) ; MD5 checksum.
! (equal date-or-sum
! (md5 (current-buffer) nil nil 'emacs-mule)))))))
!
! (defun autoload-ensure-unix-eols ()
! "Set the buffer file coding system to use unix EOLs, if needed."
! (unless (let ((eol-type (coding-system-eol-type buffer-file-coding-system)))
! (cond ((and (numberp eol-type) (zerop eol-type)))
! ((vectorp eol-type)
! (set-buffer-file-coding-system (aref eol-type 0)))
! (t (set-buffer-file-coding-system 'unix))))))
!
! (defun autoload-setup-output-buffer (file out-file)
! "Prepare a buffer \(e.g. loaddefs.el) for outputting autoload cookies.
! OUT-FILE is the file name of this buffer.
! FILE is the name of the source lisp file.
!
! The return value is the buffer.
!
! \"Prepare\" means:
! 1. If the buffer doesn't yet exist, create it and initialize it
! with boilerplate;
! 2. move to the right place in the buffer to insert new stuff;
! this is just before a ^L;
! 3. delete any existing entry for FILE;
! 4. Make sure the buffer's coding system is set for UNIX eols.
!
! Note that we don't insert the section header for FILE here, since
! we haven't yet calculated its contents.
!
! Point in this buffer is left at the place to insert the first cookie."
! (let ((outbuf (autoload-locate-section-in-existing-buffer file out-file))
! (load-name (autoload-file-load-name file))
! section-header)
!
! (if outbuf
! ;; Existing file or buffer; Delete any existing entry for FILE.
! (with-current-buffer outbuf
! (autoload-ensure-unix-eols)
! (if (save-excursion
! (and (search-forward generate-autoload-section-header nil t)
! (setq section-header (autoload-read-section-header))
! (string= (nth 2 section-header) load-name)))
! (autoload-remove-section (point))))
!
! ;; Create a new output buffer.
! (setq outbuf (find-file-noselect out-file))
! (with-current-buffer outbuf
! (or (file-writable-p out-file)
! (error "Autoloads file %s is not writable" out-file))
! (autoload-ensure-unix-eols)
! (insert (autoload-rubric out-file))
! (search-backward "\f")))
! outbuf))
!
! (defun autoload-extract-cookie (outbuf file)
! "Extract the autoload cookie at point, write it into OUTBUF.
! Point is just after the autoload cookie \(usually \";;;###autoload\")
! on entry, and is left just after the autoload form on exit.
!
! OUTBUF is the buffer (typically, loaddefs.el) into which we
! insert the new cookie at the buffer's current position.
!
! FILE is the absolute name of the elisp source file containing the
! cookie.
!
! Return the name defined (a symbol), or nil if there wasn't one."
! (let ((load-name (autoload-file-load-name file))
! cookie-name)
! (skip-chars-forward " \t")
! (if (eolp)
! (condition-case err
! ;; Read the next form and make an autoload.
! (let* ((form (prog1 (read (current-buffer))
! (or (bolp) (forward-line 1))))
! (autoload (make-autoload form load-name)))
! (if autoload
! (setq cookie-name (nth 1 form))
! (setq autoload form))
! (autoload-print-form autoload outbuf))
! (error
! (message "Error in %s: %S" file err)))
!
! ;; Copy the rest of the line to the output.
! (princ (buffer-substring
! (progn
! ;; Back up over whitespace, to preserve it.
! (skip-chars-backward " \f\t")
! (if (= (char-after (1+ (point))) ? )
! ;; Eat one space.
! (forward-char 1))
! (point))
! (progn (forward-line 1) (point)))
! outbuf))
! cookie-name))
!
! (defun autoload-parse-source-buffer (inbuf file)
! "Extract the autoload specs, if any, from the buffer INBUF,
! writing them to the buffer whose file name is in the the variable
! `generated-autoload-file' \(which may have a file-local binding in
! INBUF). The buffer isn't saved in this function.
!
! FILE is the absolute name of the elisp source file loaded in the
! current buffer.
!
! The current directory is the \"starting directory\" for the
! autoload generation, typically .../emacs/lisp/.
!
! If the buffer for `generated-autoload-file' is actually written
! to, return this buffer. Otherwise, return nil."
! (let (autoloads-done ; list of autoload SYMBOLS written to output buffer.
! (load-name (autoload-file-load-name file))
! (relfile (file-relative-name file))
! cookie
! (cookie-regexp (concat "^" (regexp-quote generate-autoload-cookie)))
! outbuf
! output-started ; Position in outbuf of first cookie generated from
! ; current input file, or nil.
! (print-length nil) ; don't truncate a list when printing.
! (print-level nil) ; don't limit nesting of lists when printing.
! ;; (print-readably t) ; This does something in XEmacs. Removed 2008-08.
! (float-output-format nil)) ; Use a default format for printing floats.
!
! (message "Generating autoloads for %s..." relfile)
! (with-current-buffer inbuf
! (unless no-update-autoloads ; file local variable which stops autoload stuff.
! (save-excursion
! (save-restriction
! (widen)
! ;; If we already have a valid up to date entry for FILE, don't do
! ;; anything.
! (unless (autoload-entry-up-to-date-p file generated-autoload-file)
! (goto-char (point-min))
! (while (search-forward-regexp cookie-regexp nil t)
! ;; Get the output buffer only when the first cookie has been found.
! (unless outbuf
! (setq outbuf (autoload-setup-output-buffer
! file generated-autoload-file)
! output-started (with-current-buffer outbuf (point))))
! (if (setq cookie (autoload-extract-cookie outbuf file))
! (push cookie autoloads-done)))
!
! ;; Write the section header for FILE. This contains a summary list
! ;; of functions at the beginning of the section in the output file.
! (when outbuf
! (let ((date-or-checksum
! (if (local-variable-p 'generated-autoload-file)
! ;; MD5 checksums are much better because they do not
! ;; change unless the file changes (so they'll be equal
! ;; on two different systems and will change less often
! ;; than time-stamps, thus leading to fewer unneeded
! ;; changes causing spurious conflicts), but using
! ;; time-stamps is a very useful optimization, so we
! ;; use time-stamps for the main autoloads file
! ;; (loaddefs.el) where we have special ways to
! ;; circumvent the "random change problem", and MD5
! ;; checksum in secondary autoload files where we do
! ;; not need the time-stamp optimization because it is
! ;; already provided by the primary autoloads file.
! (md5 (current-buffer) nil nil 'emacs-mule-unix)
! (nth 5 (file-attributes file))))) ; timestamp.
! (with-current-buffer outbuf
! (save-excursion
! ;; Insert the section-header line which lists the file name
! ;; and which functions are in it, etc.
! (goto-char output-started)
! (autoload-insert-section-header
! outbuf autoloads-done load-name relfile
! date-or-checksum)
! (insert ";;; Generated autoloads from " relfile "\n"))
! (insert generate-autoload-section-trailer)))))))
! (message "Generating autoloads for %s...done" relfile)
! outbuf))))
;;;###autoload
(defun update-file-autoloads (file &optional save-after)
***************
*** 471,561 ****
Return FILE if there was no autoload cookie in it, else nil."
(interactive "fUpdate autoloads for file: \np")
! (let* ((autoload-modified-buffers nil)
! (no-autoloads (autoload-generate-file-autoloads file)))
! (if autoload-modified-buffers
! (if save-after (autoload-save-buffers))
(if (interactive-p)
! (message "Autoload section for %s is up to date." file)))
! (if no-autoloads file)))
!
! (defun autoload-find-destination (file)
! "Find the destination point of the current buffer's autoloads.
! FILE is the file name of the current buffer.
! Returns a buffer whose point is placed at the requested location.
! Returns nil if the file's autoloads are uptodate, otherwise
! removes any prior now out-of-date autoload entries."
! (catch 'up-to-date
! (let* ((load-name (autoload-file-load-name file))
! (buf (current-buffer))
! (existing-buffer (if buffer-file-name buf))
! (found nil))
! (with-current-buffer
! ;; We used to use `raw-text' to read this file, but this causes
! ;; problems when the file contains non-ASCII characters.
! (find-file-noselect
! (autoload-ensure-default-file (autoload-generated-file)))
! ;; This is to make generated-autoload-file have Unix EOLs, so
! ;; that it is portable to all platforms.
! (unless (zerop (coding-system-eol-type buffer-file-coding-system))
! (set-buffer-file-coding-system 'unix))
! (or (> (buffer-size) 0)
! (error "Autoloads file %s does not exist" buffer-file-name))
! (or (file-writable-p buffer-file-name)
! (error "Autoloads file %s is not writable" buffer-file-name))
! (widen)
! (goto-char (point-min))
! ;; Look for the section for LOAD-NAME.
! (while (and (not found)
! (search-forward generate-autoload-section-header nil t))
! (let ((form (autoload-read-section-header)))
! (cond ((string= (nth 2 form) load-name)
! ;; We found the section for this file.
! ;; Check if it is up to date.
! (let ((begin (match-beginning 0))
! (last-time (nth 4 form))
! (file-time (nth 5 (file-attributes file))))
! (if (and (or (null existing-buffer)
! (not (buffer-modified-p existing-buffer)))
! (or
! ;; last-time is the time-stamp (specifying
! ;; the last time we looked at the file) and
! ;; the file hasn't been changed since.
! (and (listp last-time) (= (length last-time) 2)
! (not (time-less-p last-time file-time)))
! ;; last-time is an MD5 checksum instead.
! (and (stringp last-time)
! (equal last-time
! (md5 buf nil nil 'emacs-mule)))))
! (throw 'up-to-date nil)
! (autoload-remove-section begin)
! (setq found t))))
! ((string< load-name (nth 2 form))
! ;; We've come to a section alphabetically later than
! ;; LOAD-NAME. We assume the file is in order and so
! ;; there must be no section for LOAD-NAME. We will
! ;; insert one before the section here.
! (goto-char (match-beginning 0))
! (setq found t)))))
! (or found
! (progn
! ;; No later sections in the file. Put before the last page.
! (goto-char (point-max))
! (search-backward "\f" nil t)))
! (unless (memq (current-buffer) autoload-modified-buffers)
! (push (current-buffer) autoload-modified-buffers))
! (current-buffer)))))
!
! (defun autoload-remove-section (begin)
! (goto-char begin)
! (search-forward generate-autoload-section-trailer)
! (delete-region begin (point)))
;;;###autoload
(defun update-directory-autoloads (&rest dirs)
"\
Update loaddefs.el with all the current autoloads from DIRS, and no old ones.
- This uses `update-file-autoloads' (which see) to do its work.
In an interactive call, you must give one argument, the name
of a single directory. In a call from Lisp, you can supply multiple
directories as separate arguments, but this usage is discouraged.
--- 543,570 ----
Return FILE if there was no autoload cookie in it, else nil."
(interactive "fUpdate autoloads for file: \np")
! (let* ((generated-autoload-file (expand-file-name generated-autoload-file))
! ;; The above is needed to "anchor" g-a-f to the current directory;
! ;; otherwise it might be expanded relative to FILE's directory.
! (ffile (expand-file-name file))
! (visited (get-file-buffer ffile)) ; Is the file already loaded?
! autoload-modified-buffer)
!
! (setq autoload-modified-buffer
! (autoload-parse-source-buffer
! (or visited (autoload-find-file ffile)) ffile))
!
! (if autoload-modified-buffer
! (if save-after
! (with-current-buffer autoload-modified-buffer (save-buffer)))
(if (interactive-p)
! (message "Autoload section for %s is up to date." file))
! file)))
;;;###autoload
(defun update-directory-autoloads (&rest dirs)
"\
Update loaddefs.el with all the current autoloads from DIRS, and no old ones.
In an interactive call, you must give one argument, the name
of a single directory. In a call from Lisp, you can supply multiple
directories as separate arguments, but this usage is discouraged.
***************
*** 563,569 ****
The function does NOT recursively descend into subdirectories of the
directory or directories specified."
(interactive "DUpdate autoloads from directory: ")
! (let* ((files-re (let ((tmp nil))
(dolist (suf (get-load-suffixes)
(concat "^[^=.].*" (regexp-opt tmp t) "\\'"))
(unless (string-match "\\.elc" suf) (push suf tmp)))))
--- 572,581 ----
The function does NOT recursively descend into subdirectories of the
directory or directories specified."
(interactive "DUpdate autoloads from directory: ")
! (let* ((generated-autoload-file (expand-file-name generated-autoload-file))
! ;; The above is needed to "anchor" g-a-f to the current directory;
! ;; otherwise it might be expanded relative to a file's directory.
! (files-re (let ((tmp nil))
(dolist (suf (get-load-suffixes)
(concat "^[^=.].*" (regexp-opt tmp t) "\\'"))
(unless (string-match "\\.elc" suf) (push suf tmp)))))
***************
*** 571,646 ****
(mapcar (lambda (dir)
(directory-files (expand-file-name dir)
t files-re))
dirs)))
! (done ())
(this-time (current-time))
;; Files with no autoload cookies or whose autoloads go to other
;; files because of file-local autoload-generated-file settings.
! (no-autoloads nil)
! (autoload-modified-buffers nil))
! (with-current-buffer
! (find-file-noselect
! (autoload-ensure-default-file (autoload-generated-file)))
! (save-excursion
!
! ;; Canonicalize file names and remove the autoload file itself.
! (setq files (delete (file-relative-name buffer-file-name)
! (mapcar 'file-relative-name files)))
!
! (goto-char (point-min))
! (while (search-forward generate-autoload-section-header nil t)
! (let* ((form (autoload-read-section-header))
! (file (nth 3 form)))
! (cond ((and (consp file) (stringp (car file)))
! ;; This is a list of files that have no autoload cookies.
! ;; There shouldn't be more than one such entry.
! ;; Remove the obsolete section.
! (autoload-remove-section (match-beginning 0))
! (let ((last-time (nth 4 form)))
! (dolist (file file)
! (let ((file-time (nth 5 (file-attributes file))))
! (when (and file-time
! (not (time-less-p last-time file-time)))
! ;; file unchanged
! (push file no-autoloads)
! (setq files (delete file files)))))))
! ((not (stringp file)))
! ((or (not (file-exists-p file))
! ;; Remove duplicates as well, just in case.
! (member file done))
! ;; Remove the obsolete section.
! (autoload-remove-section (match-beginning 0)))
! ((not (time-less-p (nth 4 form)
! (nth 5 (file-attributes file))))
! ;; File hasn't changed.
! nil)
! (t
! (autoload-remove-section (match-beginning 0))
! (if (autoload-generate-file-autoloads
! file (current-buffer) buffer-file-name)
! (push file no-autoloads))))
! (push file done)
! (setq files (delete file files)))))
! ;; Elements remaining in FILES have no existing autoload sections yet.
! (dolist (file files)
! (if (autoload-generate-file-autoloads file nil buffer-file-name)
! (push file no-autoloads)))
! (when no-autoloads
;; Sort them for better readability.
(setq no-autoloads (sort no-autoloads 'string<))
! ;; Add the `no-autoloads' section.
! (goto-char (point-max))
! (search-backward "\f" nil t)
! (autoload-insert-section-header
! (current-buffer) nil nil no-autoloads this-time)
! (insert generate-autoload-section-trailer))
!
! (save-buffer)
! ;; In case autoload entries were added to other files because of
! ;; file-local autoload-generated-file settings.
! (autoload-save-buffers))))
(define-obsolete-function-alias 'update-autoloads-from-directories
'update-directory-autoloads "22.1")
--- 583,629 ----
(mapcar (lambda (dir)
(directory-files (expand-file-name dir)
t files-re))
+ ;; "loaddefs.el", etc. aren't a problem here.
+ ;; They have `no-update-autoloads' set.
dirs)))
! (default-autoload-dir (file-name-directory generated-autoload-file))
! file visited
! autoload-modified-buffers
(this-time (current-time))
;; Files with no autoload cookies or whose autoloads go to other
;; files because of file-local autoload-generated-file settings.
! no-autoloads)
! (while files
! (setq file (car files) files (cdr files))
! (setq visited (get-file-buffer file)) ; Is the file already loaded?
!
! ;; This buffer might locally bind `generated-autoload-file'.
! (let* ((inbuf (or visited (autoload-find-file file)))
! (autoload-buffer (autoload-parse-source-buffer inbuf file)))
! (if autoload-buffer
! (or (memq autoload-buffer autoload-modified-buffers)
! (push autoload-buffer autoload-modified-buffers))
! (push (file-relative-name file default-autoload-dir) no-autoloads))
! (unless visited (kill-buffer inbuf))))
! ;; Write the list of autoloadless files.
! (when no-autoloads
;; Sort them for better readability.
(setq no-autoloads (sort no-autoloads 'string<))
! ;; Add the `no-autoloads' section. Surely, we'll have opened
! ;; `generated-autoload-file' by now?
! (if (setq visited (get-file-buffer generated-autoload-file))
! (with-current-buffer visited
! (goto-char (point-max))
! (search-backward "\f" nil t)
! (autoload-insert-section-header
! (current-buffer) nil nil no-autoloads this-time)
! (insert generate-autoload-section-trailer))))
!
! (while autoload-modified-buffers
! (with-current-buffer (pop autoload-modified-buffers)
! (save-buffer)))))
(define-obsolete-function-alias 'update-autoloads-from-directories
'update-directory-autoloads "22.1")
--
Alan Mackenzie (Nuremberg, Germany).
next reply other threads:[~2008-08-12 16:23 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-08-12 16:23 Alan Mackenzie [this message]
2008-08-12 20:09 ` Refactoring of emacs-lisp/autoload.el Stefan Monnier
2008-08-12 20:58 ` Glenn Morris
2008-08-13 14:13 ` Alan Mackenzie
2008-08-13 16:11 ` Glenn Morris
2008-08-13 14:11 ` Alan Mackenzie
2008-08-13 20:31 ` Stefan Monnier
2008-08-14 13:17 ` Alan Mackenzie
2008-08-14 17:52 ` Stefan Monnier
2008-09-01 21:55 ` Alan Mackenzie
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20080812162333.GA7999@muc.de \
--to=acm@muc.de \
--cc=cyd@stupidchicken.com \
--cc=emacs-devel@gnu.org \
--cc=monnier@iro.umontreal.ca \
--cc=rgm@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.