]> code.delx.au - gnu-emacs/commitdiff
* lisp/subr.el (with-eval-after-load): New macro.
authorStefan Monnier <monnier@iro.umontreal.ca>
Thu, 13 Jun 2013 22:24:52 +0000 (18:24 -0400)
committerStefan Monnier <monnier@iro.umontreal.ca>
Thu, 13 Jun 2013 22:24:52 +0000 (18:24 -0400)
(eval-after-load): Allow form to be a function.
take advantage of lexical-binding.
(do-after-load-evaluation): Use dolist and adjust to new format.
* lisp/simple.el (bad-packages-alist): Use dolist and with-eval-after-load.
* doc/lispref/loading.texi (Hooks for Loading): Document with-eval-after-load
instead of eval-after-load.  Don't document after-load-alist.
* src/lread.c (syms_of_lread):
* src/fns.c (Fprovide): Adjust to new format of after-load-alist.

doc/lispref/ChangeLog
doc/lispref/loading.texi
etc/NEWS
lisp/ChangeLog
lisp/simple.el
lisp/subr.el
src/ChangeLog
src/fns.c
src/lread.c

index 259bf9a78a645f6d9ec80b6f10101d967a5bc593..e14f754344366117574d1ea142bd2e269d64e334 100644 (file)
@@ -1,3 +1,8 @@
+2013-06-13  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * loading.texi (Hooks for Loading): Don't document after-load-alist.
+       Document with-eval-after-load instead of eval-after-load.
+
 2013-06-11  Xue Fuqiao  <xfq.free@gmail.com>
 
        * files.texi (File Name Expansion): Make the example more
index 5c92307f7d586ab5575e2cedc6db4ed41c5746d1..4c0f0d73e412ff4119fb801f0bf4c8e4de440c31 100644 (file)
@@ -990,19 +990,18 @@ file that was just loaded.
 @end defvar
 
 If you want code to be executed when a @emph{particular} library is
-loaded, use the function @code{eval-after-load}:
+loaded, use the macro @code{with-eval-after-load}:
 
-@defun eval-after-load library form
-This function arranges to evaluate @var{form} at the end of loading
+@defmac with-eval-after-load library body@dots{}
+This macro arranges to evaluate @var{body} at the end of loading
 the file @var{library}, each time @var{library} is loaded.  If
-@var{library} is already loaded, it evaluates @var{form} right away.
-Don't forget to quote @var{form}!
+@var{library} is already loaded, it evaluates @var{body} right away.
 
 You don't need to give a directory or extension in the file name
 @var{library}.  Normally, you just give a bare file name, like this:
 
 @example
-(eval-after-load "edebug" '(def-edebug-spec c-point t))
+(with-eval-after-load "edebug" (def-edebug-spec c-point t))
 @end example
 
 To restrict which files can trigger the evaluation, include a
@@ -1014,16 +1013,16 @@ example, @file{my_inst.elc} or @file{my_inst.elc.gz} in some directory
 @file{my_inst.el}:
 
 @example
-(eval-after-load "foo/bar/my_inst.elc" @dots{})
+(with-eval-after-load "foo/bar/my_inst.elc" @dots{})
 @end example
 
 @var{library} can also be a feature (i.e., a symbol), in which case
-@var{form} is evaluated at the end of any file where
+@var{body} is evaluated at the end of any file where
 @code{(provide @var{library})} is called.
 
-An error in @var{form} does not undo the load, but does prevent
-execution of the rest of @var{form}.
-@end defun
+An error in @var{body} does not undo the load, but does prevent
+execution of the rest of @var{body}.
+@end defmac
 
 Normally, well-designed Lisp programs should not use
 @code{eval-after-load}.  If you need to examine and set the variables
@@ -1031,18 +1030,3 @@ defined in another library (those meant for outside use), you can do
 it immediately---there is no need to wait until the library is loaded.
 If you need to call functions defined by that library, you should load
 the library, preferably with @code{require} (@pxref{Named Features}).
-
-@defvar after-load-alist
-This variable stores an alist built by @code{eval-after-load},
-containing the expressions to evaluate when certain libraries are
-loaded.  Each element looks like this:
-
-@example
-(@var{regexp-or-feature} @var{forms}@dots{})
-@end example
-
-The key @var{regexp-or-feature} is either a regular expression or a
-symbol, and the value is a list of forms.  The forms are evaluated
-when the key matches the absolute true name or feature name of the
-library being loaded.
-@end defvar
index 44e4ada50cfb87376ddfe1348f6da80455cce364..0501b4e97e229cfd24c9e7f2cc108e82d819722d 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -452,8 +452,9 @@ file using `set-file-extended-attributes'.
 \f
 * Lisp Changes in Emacs 24.4
 
-FIXME - someone who knows what they are talking about, please improve
-this - see http://debbugs.gnu.org/14596
++++
+** New macro with-eval-after-load.  Like eval-after-load, but better behaved.
+
 ** The default file coding for Emacs Lisp files is now utf-8.
 (See file-coding-system-alist.)  In most cases, this change is
 totally transparent.  Files that contain unusual characters but do
index 98e0382853d39463e42e72e6b21619ede62814cc..88f218d15f3699d80c23ebc2e320904ca341ee57 100644 (file)
@@ -1,3 +1,11 @@
+2013-06-13  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * subr.el (with-eval-after-load): New macro.
+       (eval-after-load): Allow form to be a function.
+       take advantage of lexical-binding.
+       (do-after-load-evaluation): Use dolist and adjust to new format.
+       * simple.el (bad-packages-alist): Use dolist and with-eval-after-load.
+
 2013-06-13  Juri Linkov  <juri@jurta.org>
 
        * replace.el (perform-replace): Display "symbol " and other search
index 15bf8779f56185fd78bfe3d9e5f70d25bbf3662e..3fd94e96d333280a1405873a7be9f538c8d1b142 100644 (file)
@@ -7295,8 +7295,7 @@ version and use the one distributed with Emacs."))
   "Alist of packages known to cause problems in this version of Emacs.
 Each element has the form (PACKAGE SYMBOL REGEXP STRING).
 PACKAGE is either a regular expression to match file names, or a
-symbol (a feature name); see the documentation of
-`after-load-alist', to which this variable adds functions.
+symbol (a feature name), like for `with-eval-after-load'.
 SYMBOL is either the name of a string variable, or `t'.  Upon
 loading PACKAGE, if SYMBOL is t or matches REGEXP, display a
 warning using STRING as the message.")
@@ -7314,10 +7313,10 @@ warning using STRING as the message.")
              (display-warning package (nth 3 list) :warning)))
     (error nil)))
 
-(mapc (lambda (elem)
-        (eval-after-load (car elem) `(bad-package-check ',(car elem))))
-      bad-packages-alist)
-
+(dolist (elem bad-packages-alist)
+  (let ((pkg (car elem)))
+    (with-eval-after-load pkg
+      (bad-package-check pkg))))
 
 (provide 'simple)
 
index 380b2ba66eeeec23fb42ee23f889ddb386ddd47c..05f9167c699f58b69933b5b1fdcd46725b7bbd2a 100644 (file)
@@ -3729,6 +3729,8 @@ Return nil if there isn't one."
 (defun eval-after-load (file form)
   "Arrange that if FILE is loaded, FORM will be run immediately afterwards.
 If FILE is already loaded, evaluate FORM right now.
+FORM can be an Elisp expression (in which case it's passed to `eval'),
+or a function (in which case it's passed to `funcall' with no argument).
 
 If a matching file is loaded again, FORM will be evaluated again.
 
@@ -3756,43 +3758,58 @@ Usually FILE is just a library name like \"font-lock\" or a feature name
 like 'font-lock.
 
 This function makes or adds to an entry on `after-load-alist'."
+  (declare (compiler-macro
+            (lambda (whole)
+              (if (eq 'quote (car-safe form))
+                  ;; Quote with lambda so the compiler can look inside.
+                  `(eval-after-load ,file (lambda () ,(nth 1 form)))
+                whole))))
   ;; Add this FORM into after-load-alist (regardless of whether we'll be
   ;; evaluating it now).
   (let* ((regexp-or-feature
          (if (stringp file)
               (setq file (purecopy (load-history-regexp file)))
             file))
-        (elt (assoc regexp-or-feature after-load-alist)))
+        (elt (assoc regexp-or-feature after-load-alist))
+         (func
+          (if (functionp form) form
+            ;; Try to use the "current" lexical/dynamic mode for `form'.
+            (eval `(lambda () ,form) lexical-binding))))
     (unless elt
       (setq elt (list regexp-or-feature))
       (push elt after-load-alist))
-    ;; Make sure `form' is evalled in the current lexical/dynamic code.
-    (setq form `(funcall ',(eval `(lambda () ,form) lexical-binding)))
     ;; Is there an already loaded file whose name (or `provide' name)
     ;; matches FILE?
     (prog1 (if (if (stringp file)
                   (load-history-filename-element regexp-or-feature)
                 (featurep file))
-              (eval form))
-      (when (symbolp regexp-or-feature)
-       ;; For features, the after-load-alist elements get run when `provide' is
-       ;; called rather than at the end of the file.  So add an indirection to
-       ;; make sure that `form' is really run "after-load" in case the provide
-       ;; call happens early.
-       (setq form
-             `(if load-file-name
-                  (let ((fun (make-symbol "eval-after-load-helper")))
-                    (fset fun `(lambda (file)
-                                 (if (not (equal file ',load-file-name))
-                                     nil
-                                   (remove-hook 'after-load-functions ',fun)
-                                   ,',form)))
-                    (add-hook 'after-load-functions fun))
-                ;; Not being provided from a file, run form right now.
-                ,form)))
-      ;; Add FORM to the element unless it's already there.
-      (unless (member form (cdr elt))
-       (nconc elt (list form))))))
+              (funcall func))
+      (let ((delayed-func
+             (if (not (symbolp regexp-or-feature)) func
+               ;; For features, the after-load-alist elements get run when
+               ;; `provide' is called rather than at the end of the file.
+               ;; So add an indirection to make sure that `func' is really run
+               ;; "after-load" in case the provide call happens early.
+               (lambda ()
+                 (if (not load-file-name)
+                     ;; Not being provided from a file, run func right now.
+                     (funcall func)
+                   (let ((lfn load-file-name))
+                     (letrec ((fun (lambda (file)
+                                     (when (equal file lfn)
+                                       (remove-hook 'after-load-functions fun)
+                                       (funcall func)))))
+                       (add-hook 'after-load-functions fun))))))))
+        ;; Add FORM to the element unless it's already there.
+        (unless (member delayed-func (cdr elt))
+          (nconc elt (list delayed-func)))))))
+
+(defmacro with-eval-after-load (file &rest body)
+  "Execute BODY after FILE is loaded.
+FILE is normally a feature name, but it can also be a file name,
+in case that file does not provide any feature."
+  (declare (indent 1) (debug t))
+  `(eval-after-load ,file (lambda () ,@body)))
 
 (defvar after-load-functions nil
   "Special hook run after loading a file.
@@ -3804,12 +3821,11 @@ name of the file just loaded.")
 ABS-FILE, a string, should be the absolute true name of a file just loaded.
 This function is called directly from the C code."
   ;; Run the relevant eval-after-load forms.
-  (mapc #'(lambda (a-l-element)
-           (when (and (stringp (car a-l-element))
-                      (string-match-p (car a-l-element) abs-file))
-             ;; discard the file name regexp
-             (mapc #'eval (cdr a-l-element))))
-       after-load-alist)
+  (dolist (a-l-element after-load-alist)
+    (when (and (stringp (car a-l-element))
+               (string-match-p (car a-l-element) abs-file))
+      ;; discard the file name regexp
+      (mapc #'funcall (cdr a-l-element))))
   ;; Complain when the user uses obsolete files.
   (when (string-match-p "/obsolete/[^/]*\\'" abs-file)
     (run-with-timer 0 nil
index 4d6e669612fbc34ba8b8b3f92fc078caffa5e5a6..827092e7f8addb637af3c6d3f021d44985999f9d 100644 (file)
@@ -1,3 +1,8 @@
+2013-06-13  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * lread.c (syms_of_lread):
+       * fns.c (Fprovide): Adjust to new format of after-load-alist.
+
 2013-06-13  Kelly Dean  <kellydeanch@yahoo.com>  (tiny change)
 
        * fileio.c (Fdo_auto_save): Trap errors in auto-save-hook.  (Bug#14479)
index 08c6f055f38746d862e28e497f49193733583bf1..06d4e358f10e5a04434f251d877002460bf688e8 100644 (file)
--- a/src/fns.c
+++ b/src/fns.c
@@ -2545,6 +2545,8 @@ SUBFEATURE can be used to check a specific subfeature of FEATURE.  */)
   return (NILP (tem)) ? Qnil : Qt;
 }
 
+static Lisp_Object Qfuncall;
+
 DEFUN ("provide", Fprovide, Sprovide, 1, 2, 0,
        doc: /* Announce that FEATURE is a feature of the current Emacs.
 The optional argument SUBFEATURES should be a list of symbols listing
@@ -2567,7 +2569,7 @@ particular subfeatures supported in this version of FEATURE.  */)
   /* Run any load-hooks for this file.  */
   tem = Fassq (feature, Vafter_load_alist);
   if (CONSP (tem))
-    Fprogn (XCDR (tem));
+    Fmapc (Qfuncall, XCDR (tem));
 
   return feature;
 }
@@ -4866,6 +4868,7 @@ syms_of_fns (void)
 Used by `featurep' and `require', and altered by `provide'.  */);
   Vfeatures = Fcons (intern_c_string ("emacs"), Qnil);
   DEFSYM (Qsubfeatures, "subfeatures");
+  DEFSYM (Qfuncall, "funcall");
 
 #ifdef HAVE_LANGINFO_CODESET
   DEFSYM (Qcodeset, "codeset");
index 3ca644bb45b4bdc9848dbbae776847a36ed2fa31..b57665e365ce302a1cf62920c41362204c326e76 100644 (file)
@@ -4485,15 +4485,15 @@ customize `jka-compr-load-suffixes' rather than the present variable.  */);
   DEFSYM (Qload_in_progress, "load-in-progress");
 
   DEFVAR_LISP ("after-load-alist", Vafter_load_alist,
-              doc: /* An alist of expressions to be evalled when particular files are loaded.
-Each element looks like (REGEXP-OR-FEATURE FORMS...).
+              doc: /* An alist of functions to be evalled when particular files are loaded.
+Each element looks like (REGEXP-OR-FEATURE FUNCS...).
 
 REGEXP-OR-FEATURE is either a regular expression to match file names, or
 a symbol \(a feature name).
 
 When `load' is run and the file-name argument matches an element's
 REGEXP-OR-FEATURE, or when `provide' is run and provides the symbol
-REGEXP-OR-FEATURE, the FORMS in the element are executed.
+REGEXP-OR-FEATURE, the FUNCS in the element are called.
 
 An error in FORMS does not undo the load, but does prevent execution of
 the rest of the FORMS.  */);