Commit de0503df authored by Stefan Monnier's avatar Stefan Monnier

* 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>
* files.texi (File Name Expansion): Make the example more
......
......@@ -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
......@@ -452,8 +452,9 @@ file using `set-file-extended-attributes'.
* 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
......
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
......@@ -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)
......
......@@ -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
......
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)
......
......@@ -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");
......
......@@ -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. */);
......
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