Commit de0503df authored by Stefan Monnier's avatar Stefan Monnier
Browse files

* lisp/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.
* 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.
parent bc5c8c5a
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> 2013-06-11 Xue Fuqiao <xfq.free@gmail.com>
* files.texi (File Name Expansion): Make the example more * files.texi (File Name Expansion): Make the example more
......
...@@ -990,19 +990,18 @@ file that was just loaded. ...@@ -990,19 +990,18 @@ file that was just loaded.
@end defvar @end defvar
If you want code to be executed when a @emph{particular} library is 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 @defmac with-eval-after-load library body@dots{}
This function arranges to evaluate @var{form} at the end of loading This macro arranges to evaluate @var{body} at the end of loading
the file @var{library}, each time @var{library} is loaded. If the file @var{library}, each time @var{library} is loaded. If
@var{library} is already loaded, it evaluates @var{form} right away. @var{library} is already loaded, it evaluates @var{body} right away.
Don't forget to quote @var{form}!
You don't need to give a directory or extension in the file name 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: @var{library}. Normally, you just give a bare file name, like this:
@example @example
(eval-after-load "edebug" '(def-edebug-spec c-point t)) (with-eval-after-load "edebug" (def-edebug-spec c-point t))
@end example @end example
To restrict which files can trigger the evaluation, include a 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 ...@@ -1014,16 +1013,16 @@ example, @file{my_inst.elc} or @file{my_inst.elc.gz} in some directory
@file{my_inst.el}: @file{my_inst.el}:
@example @example
(eval-after-load "foo/bar/my_inst.elc" @dots{}) (with-eval-after-load "foo/bar/my_inst.elc" @dots{})
@end example @end example
@var{library} can also be a feature (i.e., a symbol), in which case @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. @code{(provide @var{library})} is called.
An error in @var{form} does not undo the load, but does prevent An error in @var{body} does not undo the load, but does prevent
execution of the rest of @var{form}. execution of the rest of @var{body}.
@end defun @end defmac
Normally, well-designed Lisp programs should not use Normally, well-designed Lisp programs should not use
@code{eval-after-load}. If you need to examine and set the variables @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 ...@@ -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. 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 If you need to call functions defined by that library, you should load
the library, preferably with @code{require} (@pxref{Named Features}). 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
...@@ -452,8 +452,9 @@ file using `set-file-extended-attributes'. ...@@ -452,8 +452,9 @@ file using `set-file-extended-attributes'.
* Lisp Changes in Emacs 24.4 * 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. ** The default file coding for Emacs Lisp files is now utf-8.
(See file-coding-system-alist.) In most cases, this change is (See file-coding-system-alist.) In most cases, this change is
totally transparent. Files that contain unusual characters but do totally transparent. Files that contain unusual characters but do
......
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> 2013-06-13 Juri Linkov <juri@jurta.org>
   
* replace.el (perform-replace): Display "symbol " and other search * replace.el (perform-replace): Display "symbol " and other search
...@@ -7295,8 +7295,7 @@ version and use the one distributed with Emacs.")) ...@@ -7295,8 +7295,7 @@ version and use the one distributed with Emacs."))
"Alist of packages known to cause problems in this version of Emacs. "Alist of packages known to cause problems in this version of Emacs.
Each element has the form (PACKAGE SYMBOL REGEXP STRING). Each element has the form (PACKAGE SYMBOL REGEXP STRING).
PACKAGE is either a regular expression to match file names, or a PACKAGE is either a regular expression to match file names, or a
symbol (a feature name); see the documentation of symbol (a feature name), like for `with-eval-after-load'.
`after-load-alist', to which this variable adds functions.
SYMBOL is either the name of a string variable, or `t'. Upon SYMBOL is either the name of a string variable, or `t'. Upon
loading PACKAGE, if SYMBOL is t or matches REGEXP, display a loading PACKAGE, if SYMBOL is t or matches REGEXP, display a
warning using STRING as the message.") warning using STRING as the message.")
...@@ -7314,10 +7313,10 @@ warning using STRING as the message.") ...@@ -7314,10 +7313,10 @@ warning using STRING as the message.")
(display-warning package (nth 3 list) :warning))) (display-warning package (nth 3 list) :warning)))
(error nil))) (error nil)))
(mapc (lambda (elem) (dolist (elem bad-packages-alist)
(eval-after-load (car elem) `(bad-package-check ',(car elem)))) (let ((pkg (car elem)))
bad-packages-alist) (with-eval-after-load pkg
(bad-package-check pkg))))
(provide 'simple) (provide 'simple)
......
...@@ -3729,6 +3729,8 @@ Return nil if there isn't one." ...@@ -3729,6 +3729,8 @@ Return nil if there isn't one."
(defun eval-after-load (file form) (defun eval-after-load (file form)
"Arrange that if FILE is loaded, FORM will be run immediately afterwards. "Arrange that if FILE is loaded, FORM will be run immediately afterwards.
If FILE is already loaded, evaluate FORM right now. 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. 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 ...@@ -3756,43 +3758,58 @@ Usually FILE is just a library name like \"font-lock\" or a feature name
like 'font-lock. like 'font-lock.
This function makes or adds to an entry on `after-load-alist'." 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 ;; Add this FORM into after-load-alist (regardless of whether we'll be
;; evaluating it now). ;; evaluating it now).
(let* ((regexp-or-feature (let* ((regexp-or-feature
(if (stringp file) (if (stringp file)
(setq file (purecopy (load-history-regexp file))) (setq file (purecopy (load-history-regexp file)))
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 (unless elt
(setq elt (list regexp-or-feature)) (setq elt (list regexp-or-feature))
(push elt after-load-alist)) (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) ;; Is there an already loaded file whose name (or `provide' name)
;; matches FILE? ;; matches FILE?
(prog1 (if (if (stringp file) (prog1 (if (if (stringp file)
(load-history-filename-element regexp-or-feature) (load-history-filename-element regexp-or-feature)
(featurep file)) (featurep file))
(eval form)) (funcall func))
(when (symbolp regexp-or-feature) (let ((delayed-func
;; For features, the after-load-alist elements get run when `provide' is (if (not (symbolp regexp-or-feature)) func
;; called rather than at the end of the file. So add an indirection to ;; For features, the after-load-alist elements get run when
;; make sure that `form' is really run "after-load" in case the provide ;; `provide' is called rather than at the end of the file.
;; call happens early. ;; So add an indirection to make sure that `func' is really run
(setq form ;; "after-load" in case the provide call happens early.
`(if load-file-name (lambda ()
(let ((fun (make-symbol "eval-after-load-helper"))) (if (not load-file-name)
(fset fun `(lambda (file) ;; Not being provided from a file, run func right now.
(if (not (equal file ',load-file-name)) (funcall func)
nil (let ((lfn load-file-name))
(remove-hook 'after-load-functions ',fun) (letrec ((fun (lambda (file)
,',form))) (when (equal file lfn)
(add-hook 'after-load-functions fun)) (remove-hook 'after-load-functions fun)
;; Not being provided from a file, run form right now. (funcall func)))))
,form))) (add-hook 'after-load-functions fun))))))))
;; Add FORM to the element unless it's already there. ;; Add FORM to the element unless it's already there.
(unless (member form (cdr elt)) (unless (member delayed-func (cdr elt))
(nconc elt (list form)))))) (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 (defvar after-load-functions nil
"Special hook run after loading a file. "Special hook run after loading a file.
...@@ -3804,12 +3821,11 @@ name of the file just loaded.") ...@@ -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. ABS-FILE, a string, should be the absolute true name of a file just loaded.
This function is called directly from the C code." This function is called directly from the C code."
;; Run the relevant eval-after-load forms. ;; Run the relevant eval-after-load forms.
(mapc #'(lambda (a-l-element) (dolist (a-l-element after-load-alist)
(when (and (stringp (car a-l-element)) (when (and (stringp (car a-l-element))
(string-match-p (car a-l-element) abs-file)) (string-match-p (car a-l-element) abs-file))
;; discard the file name regexp ;; discard the file name regexp
(mapc #'eval (cdr a-l-element)))) (mapc #'funcall (cdr a-l-element))))
after-load-alist)
;; Complain when the user uses obsolete files. ;; Complain when the user uses obsolete files.
(when (string-match-p "/obsolete/[^/]*\\'" abs-file) (when (string-match-p "/obsolete/[^/]*\\'" abs-file)
(run-with-timer 0 nil (run-with-timer 0 nil
......
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) 2013-06-13 Kelly Dean <kellydeanch@yahoo.com> (tiny change)
   
* fileio.c (Fdo_auto_save): Trap errors in auto-save-hook. (Bug#14479) * fileio.c (Fdo_auto_save): Trap errors in auto-save-hook. (Bug#14479)
......
...@@ -2545,6 +2545,8 @@ SUBFEATURE can be used to check a specific subfeature of FEATURE. */) ...@@ -2545,6 +2545,8 @@ SUBFEATURE can be used to check a specific subfeature of FEATURE. */)
return (NILP (tem)) ? Qnil : Qt; return (NILP (tem)) ? Qnil : Qt;
} }
static Lisp_Object Qfuncall;
DEFUN ("provide", Fprovide, Sprovide, 1, 2, 0, DEFUN ("provide", Fprovide, Sprovide, 1, 2, 0,
doc: /* Announce that FEATURE is a feature of the current Emacs. doc: /* Announce that FEATURE is a feature of the current Emacs.
The optional argument SUBFEATURES should be a list of symbols listing The optional argument SUBFEATURES should be a list of symbols listing
...@@ -2567,7 +2569,7 @@ particular subfeatures supported in this version of FEATURE. */) ...@@ -2567,7 +2569,7 @@ particular subfeatures supported in this version of FEATURE. */)
/* Run any load-hooks for this file. */ /* Run any load-hooks for this file. */
tem = Fassq (feature, Vafter_load_alist); tem = Fassq (feature, Vafter_load_alist);
if (CONSP (tem)) if (CONSP (tem))
Fprogn (XCDR (tem)); Fmapc (Qfuncall, XCDR (tem));
return feature; return feature;
} }
...@@ -4866,6 +4868,7 @@ syms_of_fns (void) ...@@ -4866,6 +4868,7 @@ syms_of_fns (void)
Used by `featurep' and `require', and altered by `provide'. */); Used by `featurep' and `require', and altered by `provide'. */);
Vfeatures = Fcons (intern_c_string ("emacs"), Qnil); Vfeatures = Fcons (intern_c_string ("emacs"), Qnil);
DEFSYM (Qsubfeatures, "subfeatures"); DEFSYM (Qsubfeatures, "subfeatures");
DEFSYM (Qfuncall, "funcall");
#ifdef HAVE_LANGINFO_CODESET #ifdef HAVE_LANGINFO_CODESET
DEFSYM (Qcodeset, "codeset"); DEFSYM (Qcodeset, "codeset");
......
...@@ -4485,15 +4485,15 @@ customize `jka-compr-load-suffixes' rather than the present variable. */); ...@@ -4485,15 +4485,15 @@ customize `jka-compr-load-suffixes' rather than the present variable. */);
DEFSYM (Qload_in_progress, "load-in-progress"); DEFSYM (Qload_in_progress, "load-in-progress");
DEFVAR_LISP ("after-load-alist", Vafter_load_alist, DEFVAR_LISP ("after-load-alist", Vafter_load_alist,
doc: /* An alist of expressions to be evalled when particular files are loaded. doc: /* An alist of functions to be evalled when particular files are loaded.
Each element looks like (REGEXP-OR-FEATURE FORMS...). Each element looks like (REGEXP-OR-FEATURE FUNCS...).
REGEXP-OR-FEATURE is either a regular expression to match file names, or REGEXP-OR-FEATURE is either a regular expression to match file names, or
a symbol \(a feature name). a symbol \(a feature name).
When `load' is run and the file-name argument matches an element's 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, 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 An error in FORMS does not undo the load, but does prevent execution of
the rest of the FORMS. */); the rest of the FORMS. */);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment