emacs-devel
[Top][All Lists]
Advanced

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

Re: address@hidden: No doc for cl stuff even after loading cl?]


From: Stefan Monnier
Subject: Re: address@hidden: No doc for cl stuff even after loading cl?]
Date: Mon, 29 May 2006 05:09:11 -0400
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (gnu/linux)

>>>>> "Richard" == Richard Stallman <address@hidden> writes:

>     We could add ;;;###autoload cookies in cl-macs.el and friends and then
>     arrange for autoloads.el to put the autoload statements in cl.el (rather
>     than loaddefs.el) by adding file-local settings of 
> generated-autoload-file.

> Would you please do that?

OK, so I've implemented it, but here's the rub: it requires a fair bit of
changes, because of the way autoload.el works.  Basically, currently
autoload.el first looks at the loaddefs.el file to determine where (within
loaddefs.el) to put autoloads and which files are up-to-date, but if we
allow file-local settings of generated-autoload-file, then we basically have
to do it the other way around: first look at the file to see in which other
file the autoloads go, then check there to see if they're up-to-date already.

See the patch below which has been only lightly tested.  I'm fairly
satisfied with this new code, although I'd rather test it more seriously
before installing it, and maybe it should wait post-22.  The most
satisfactory part of this code is that it gets rid of most of the O(N^2)
behavior of the old code.  The only remaining O(N^2) situation is when
encountering a O(N) new files, such as when building the initial loaddefs.el
from scratch (but not from ldefs-boot.el where we should see a nice O(N)).

Once this patch can be installed, I can install the subsequent patches that
add the autload cookies to the cl-*.el files.


        Stefan


--- autoload.el 28 mai 2006 22:48:22 -0400      1.115
+++ autoload.el 29 mai 2006 04:55:46 -0400      
@@ -41,6 +41,7 @@
 A `.el' file can set this in its local variables section to make its
 autoloads go somewhere else.  The autoload file is assumed to contain a
 trailer starting with a FormFeed character.")
+(put 'generated-autoload-file 'safe-local-variable 'stringp)
 
 (defconst generate-autoload-cookie ";;;###autoload"
   "Magic comment indicating the following form should be autoloaded.
@@ -153,16 +154,11 @@
 ;; the doc-string in FORM.
 ;; Those properties are now set in lisp-mode.el.
 
+(defun autoload-generated-file ()
+  (expand-file-name generated-autoload-file
+                    (if (not (local-variable-p 'generated-autoload-file))
+                        (expand-file-name "lisp" source-directory))))
 
-(defun autoload-trim-file-name (file)
-  ;; Returns a relative file path for FILE
-  ;; starting from the directory that loaddefs.el is in.
-  ;; That is normally a directory in load-path,
-  ;; which means Emacs will be able to find FILE when it looks.
-  ;; Any extra directory names here would prevent finding the file.
-  (setq file (expand-file-name file))
-  (file-relative-name file
-                     (file-name-directory generated-autoload-file)))
 
 (defun autoload-read-section-header ()
   "Read a section header form.
@@ -257,9 +253,7 @@
   "Insert the section-header line,
 which lists the file name and which functions are in it, etc."
   (insert generate-autoload-section-header)
-  (prin1 (list 'autoloads autoloads load-name
-              (if (stringp file) (autoload-trim-file-name file) file)
-              time)
+  (prin1 (list 'autoloads autoloads load-name file time)
         outbuf)
   (terpri outbuf)
   ;; Break that line at spaces, to avoid very long lines.
@@ -276,16 +270,20 @@
 (defun autoload-find-file (file)
   "Fetch file and put it in a temp buffer.  Return the buffer."
   ;; It is faster to avoid visiting the file.
+  (let ((dir default-directory))
   (with-current-buffer (get-buffer-create " *autoload-file*")
     (kill-all-local-variables)
     (erase-buffer)
     (setq buffer-undo-list t
           buffer-read-only nil)
     (emacs-lisp-mode)
+      (setq default-directory dir)
     (insert-file-contents file nil)
+      (if (file-name-directory file)
+          (setq default-directory (expand-file-name (file-name-directory 
file))))
     (let ((enable-local-variables :safe))
       (hack-local-variables))
-    (current-buffer)))
+      (current-buffer))))
 
 (defvar no-update-autoloads nil
   "File local variable to prevent scanning this file for autoload cookies.")
@@ -298,8 +296,27 @@
 are used.
 Return non-nil in the case where no autoloads were added at point."
   (interactive "fGenerate autoloads for file: ")
-  (let ((outbuf (current-buffer))
-       (autoloads-done '())
+  (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'.  --Stef
+(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 will be inserted.
+OUTFILE is the file name of OUTBUF.
+If OUTFILE is non-nil and FILE specifies an `generated-autoload-file'
+different from OUTFILE, then OUTBUF is ignored.
+If OUTBUF is nil, it will be determined by `autoload-generated-file'.
+Return non-nil in the case where no autoloads were added at point.
+Can throw `up-to-date'."
+  (let ((autoloads-done '())
        (load-name (let ((name (file-name-nondirectory file)))
                     (if (string-match "\\.elc?\\(\\.\\|$\\)" name)
                         (substring name 0 (match-beginning 0))
@@ -307,33 +324,16 @@
        (print-length nil)
        (print-readably t)              ; This does something in Lucid Emacs.
        (float-output-format nil)
-       (done-any nil)
-       (visited (get-file-buffer file))
-        output-start)
-
-    ;; If the autoload section we create here uses an absolute
-    ;; file name for FILE in its header, and then Emacs is installed
-    ;; under a different path on another system,
-    ;; `update-autoloads-here' won't be able to find the files to be
-    ;; autoloaded.  So, if FILE is in the same directory or a
-    ;; subdirectory of the current buffer's directory, we'll make it
-    ;; relative to the current buffer's directory.
-    (setq file (expand-file-name file))
-    (let* ((source-truename (file-truename file))
-          (dir-truename (file-name-as-directory
-                         (file-truename default-directory)))
-          (len (length dir-truename)))
-      (if (and (< len (length source-truename))
-              (string= dir-truename (substring source-truename 0 len)))
-         (setq file (substring source-truename len))))
+        (otherbuf nil)
+        (absfile (expand-file-name file))
+        relfile output-start)
 
-    (with-current-buffer (or visited
+    (with-current-buffer (or (get-file-buffer file)
                              ;; 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)
-        (setq output-start (with-current-buffer outbuf (point)))
         (save-excursion
           (save-restriction
             (widen)
@@ -342,9 +342,22 @@
               (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))))
+                    (setq outbuf nil)
+                    (setq otherbuf t))
+                  (unless outbuf
+                    (setq outbuf (autoload-find-destination absfile)))
+                  (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")
-                (setq done-any t)
                 (if (eolp)
                     ;; Read the next form and make an autoload.
                     (let* ((form (prog1 (read (current-buffer))
@@ -374,23 +387,27 @@
                 (forward-sexp 1)
                 (forward-line 1))))))
 
-        (when done-any
+        (when output-start
           (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 file
-               (nth 5 (file-attributes file)))
-              (insert ";;; Generated autoloads from "
-                      (autoload-trim-file-name file) "\n"))
+               outbuf autoloads-done load-name relfile
+               (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
+      (or buffer-file-name              ;This is not our own temp buffer.
           ;; We created this buffer, so we should kill it.
           (kill-buffer (current-buffer))))
-    (not done-any)))
+    (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)
@@ -401,35 +418,41 @@
 
 Return FILE if there was no autoload cookie in it, else nil."
   (interactive "fUpdate autoloads for file: \np")
+  (let ((no-autoloads nil))
+    (if (catch 'up-to-date
+          (progn (setq no-autoloads (autoload-generate-file-autoloads file))
+                 nil))
+        (if (interactive-p)
+            (message "Autoload section for %s is up to date." file))
+      (if save-after (autoload-save-buffers)))
+    (if no-autoloads file)))
+
+(defvar autoload-modified-buffers nil)
+
+(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."
+  ;; (message "autoload-find-destination %S" file)
   (let ((load-name (let ((name (file-name-nondirectory file)))
-                    (if (string-match "\\.elc?\\(\\.\\|$\\)" name)
+                    (if (string-match "\\.elc?\\(\\.\\|\\'\\)" name)
                         (substring name 0 (match-beginning 0))
                       name)))
-       (found nil)
-       (existing-buffer (get-file-buffer file))
-       (no-autoloads nil))
-    (save-excursion
-      ;; We want to get a value for generated-autoload-file from
-      ;; the local variables section if it's there.
-      (if existing-buffer
-         (set-buffer existing-buffer))
+        (existing-buffer (if buffer-file-name (current-buffer)))
+       (found nil))
+    (with-current-buffer
       ;; We must read/write the file without any code conversion,
       ;; but still decode EOLs.
       (let ((coding-system-for-read 'raw-text))
-       (set-buffer (find-file-noselect
-                    (autoload-ensure-default-file
-                     (expand-file-name generated-autoload-file
-                                       (expand-file-name "lisp"
-                                                         source-directory)))))
+          (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.
-       (setq buffer-file-coding-system 'raw-text-unix))
+      (setq buffer-file-coding-system 'raw-text-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))
-      (save-excursion
-       (save-restriction
          (widen)
          (goto-char (point-min))
          ;; Look for the section for LOAD-NAME.
@@ -439,42 +462,28 @@
              (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)))
-                               (listp last-time) (= (length last-time) 2)
-                               (not (time-less-p last-time file-time)))
-                          (progn
-                            (if (interactive-p)
-                                (message "\
-Autoload section for %s is up to date."
-                                         file))
-                            (setq found 'up-to-date))
-                        (search-forward generate-autoload-section-trailer)
-                        (delete-region begin (point))
-                        (setq found t))))
+                          (not (time-less-p (nth 4 form)
+                                            (nth 5 (file-attributes file)))))
+                     (throw 'up-to-date t)
+                   (autoload-remove-section (match-beginning 0))
+                   (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 'new)))))
+                 (setq found t)))))
          (or found
              (progn
-               (setq found 'new)
                ;; No later sections in the file.  Put before the last page.
                (goto-char (point-max))
                (search-backward "\f" nil t)))
-         (or (eq found 'up-to-date)
-             (setq no-autoloads (generate-file-autoloads file)))))
-      (and save-after
-          (buffer-modified-p)
-          (save-buffer))
-
-      (if no-autoloads file))))
+      (unless (memq (current-buffer) autoload-modified-buffers)
+        (push (current-buffer) autoload-modified-buffers))
+      (current-buffer))))
 
 (defun autoload-remove-section (begin)
   (goto-char begin)
@@ -504,18 +513,15 @@
                               dirs)))
         (this-time (current-time))
         (no-autoloads nil)             ;files with no autoload cookies.
-        (autoloads-file
-         (expand-file-name generated-autoload-file
-                           (expand-file-name "lisp" source-directory)))
-        (top-dir (file-name-directory autoloads-file)))
+        (autoloads-file (autoload-generated-file)))
 
     (with-current-buffer
        (find-file-noselect (autoload-ensure-default-file autoloads-file))
       (save-excursion
 
        ;; Canonicalize file names and remove the autoload file itself.
-       (setq files (delete (autoload-trim-file-name buffer-file-name)
-                           (mapcar 'autoload-trim-file-name files)))
+       (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)
@@ -535,19 +541,27 @@
                           (push file no-autoloads)
                           (setq files (delete file files)))))))
                  ((not (stringp file)))
-                 ((not (file-exists-p (expand-file-name file top-dir)))
+                 ((not (file-exists-p file))
                   ;; Remove the obsolete section.
                   (autoload-remove-section (match-beginning 0)))
-                 ((equal (nth 4 form) (nth 5 (file-attributes file)))
+                 ((not (time-less-p (nth 4 form)
+                                     (nth 5 (file-attributes file))))
                   ;; File hasn't changed.
                   nil)
                  (t
-                  (update-file-autoloads file)))
+                   (autoload-remove-section (match-beginning 0))
+                   (if (catch 'up-to-date
+                         (autoload-generate-file-autoloads
+                          file (current-buffer) (autoload-generated-file)))
+                       (push file no-autoloads))))
            (setq files (delete file files)))))
       ;; Elements remaining in FILES have no existing autoload sections yet.
-      (setq no-autoloads
-           (append no-autoloads
-                   (delq nil (mapcar 'update-file-autoloads files))))
+      (dolist (file files)
+        (if (catch 'up-to-date
+              (autoload-generate-file-autoloads
+               file nil (autoload-generated-file)))
+            (push file no-autoloads)))
+
       (when no-autoloads
        ;; Sort them for better readability.
        (setq no-autoloads (sort no-autoloads 'string<))
@@ -558,7 +572,8 @@
         (current-buffer) nil nil no-autoloads this-time)
        (insert generate-autoload-section-trailer))
 
-      (save-buffer))))
+      (save-buffer)
+      (autoload-save-buffers))))
 
 (define-obsolete-function-alias 'update-autoloads-from-directories
     'update-directory-autoloads "22.1")




reply via email to

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