unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Refactoring of emacs-lisp/autoload.el
@ 2008-08-12 16:23 Alan Mackenzie
  2008-08-12 20:09 ` Stefan Monnier
  0 siblings, 1 reply; 10+ messages in thread
From: Alan Mackenzie @ 2008-08-12 16:23 UTC (permalink / raw)
  To: emacs-devel; +Cc: Glenn Morris, Chong Yidong, Stefan Monnier

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).




^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2008-09-01 21:55 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-12 16:23 Refactoring of emacs-lisp/autoload.el Alan Mackenzie
2008-08-12 20:09 ` 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

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).