emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Refactoring of emacs-lisp/autoload.el


From: Alan Mackenzie
Subject: Refactoring of emacs-lisp/autoload.el
Date: Tue, 12 Aug 2008 16:23:33 +0000
User-agent: Mutt/1.5.9i

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  <address@hidden>

        * 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))))
  
! (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)))
  
  
! (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).




reply via email to

[Prev in Thread] Current Thread [Next in Thread]