aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2012-11-14 15:27:42 -0500
committerStefan Monnier2012-11-14 15:27:42 -0500
commit1668ea9062effeaf84e2fcf1e97c9b174c66a4ec (patch)
treeb07875c2d311c6e5249015fd51a902bbcad2a8f5
parent14f207289c224b3ad12fc8704c2183ef8fbcab28 (diff)
downloademacs-1668ea9062effeaf84e2fcf1e97c9b174c66a4ec.tar.gz
emacs-1668ea9062effeaf84e2fcf1e97c9b174c66a4ec.zip
* lisp/emacs-lisp/nadvice.el: Add around advice for interactive specs.
(advice-eval-interactive-spec): New function. (advice--make-interactive-form): Support around advice. Fixes: debbugs:12844
-rw-r--r--lisp/ChangeLog6
-rw-r--r--lisp/emacs-lisp/nadvice.el66
2 files changed, 47 insertions, 25 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 99bfabb8115..01b7532e56d 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,9 @@
12012-11-14 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * emacs-lisp/nadvice.el: Add around advice for interactive specs.
4 (advice-eval-interactive-spec): New function.
5 (advice--make-interactive-form): Support around advice (bug#12844).
6
12012-11-14 Dmitry Gutov <dgutov@yandex.ru> 72012-11-14 Dmitry Gutov <dgutov@yandex.ru>
2 8
3 * progmodes/ruby-mode.el (ruby-expr-beg): Make heredoc detection 9 * progmodes/ruby-mode.el (ruby-expr-beg): Make heredoc detection
diff --git a/lisp/emacs-lisp/nadvice.el b/lisp/emacs-lisp/nadvice.el
index ff30d9e7fa4..873a1695867 100644
--- a/lisp/emacs-lisp/nadvice.el
+++ b/lisp/emacs-lisp/nadvice.el
@@ -109,18 +109,33 @@ Each element has the form (WHERE BYTECODE STACK) where:
109 (propertize "Advised function" 109 (propertize "Advised function"
110 'dynamic-docstring-function #'advice--make-docstring)) ;; ) 110 'dynamic-docstring-function #'advice--make-docstring)) ;; )
111 111
112(defun advice-eval-interactive-spec (spec)
113 "Evaluate the interactive spec SPEC."
114 (cond
115 ((stringp spec)
116 ;; There's no direct access to the C code (in call-interactively) that
117 ;; processes those specs, but that shouldn't stop us, should it?
118 ;; FIXME: Despite appearances, this is not faithful: SPEC and
119 ;; (advice-eval-interactive-spec SPEC) will behave subtly differently w.r.t
120 ;; command-history (and maybe a few other details).
121 (call-interactively `(lambda (&rest args) (interactive ,spec) args)))
122 ;; ((functionp spec) (funcall spec))
123 (t (eval spec))))
124
112(defun advice--make-interactive-form (function main) 125(defun advice--make-interactive-form (function main)
113 ;; TODO: Make it possible to do around-like advising on the
114 ;; interactive forms (bug#12844).
115 ;; TODO: make it so that interactive spec can be a constant which 126 ;; TODO: make it so that interactive spec can be a constant which
116 ;; dynamically checks the advice--car/cdr to do its job. 127 ;; dynamically checks the advice--car/cdr to do its job.
117 ;; TODO: Implement interactive-read-args: 128 ;; For that, advice-eval-interactive-spec needs to be more faithful.
118 ;;(when (or (commandp function) (commandp main)) 129 ;; FIXME: The calls to interactive-form below load autoloaded functions
119 ;; `(interactive-read-args 130 ;; too eagerly.
120 ;; (cadr (or (interactive-form function) (interactive-form main))))) 131 (let ((fspec (cadr (interactive-form function))))
121 ;; FIXME: This loads autoloaded functions too eagerly. 132 (when (eq 'function (car fspec)) ;; Macroexpanded lambda?
133 (setq fspec (nth 1 fspec)))
134 (if (functionp fspec)
135 `(funcall ',fspec
136 ',(cadr (interactive-form main)))
122 (cadr (or (interactive-form function) 137 (cadr (or (interactive-form function)
123 (interactive-form main)))) 138 (interactive-form main))))))
124 139
125(defsubst advice--make-1 (byte-code stack-depth function main props) 140(defsubst advice--make-1 (byte-code stack-depth function main props)
126 "Build a function value that adds FUNCTION to MAIN." 141 "Build a function value that adds FUNCTION to MAIN."
@@ -197,7 +212,15 @@ call OLDFUN here:
197If FUNCTION was already added, do nothing. 212If FUNCTION was already added, do nothing.
198PROPS is an alist of additional properties, among which the following have 213PROPS is an alist of additional properties, among which the following have
199a special meaning: 214a special meaning:
200- `name': a string or symbol. It can be used to refer to this piece of advice." 215- `name': a string or symbol. It can be used to refer to this piece of advice.
216
217If one of FUNCTION or OLDFUN is interactive, then the resulting function
218is also interactive. There are 3 cases:
219- FUNCTION is not interactive: the interactive spec of OLDFUN is used.
220- The interactive spec of FUNCTION is itself a function: it should take one
221 argument (the interactive spec of OLDFUN, which it can pass to
222 `advice-eval-interactive-spec') and return the list of arguments to use.
223- Else, use the interactive spec of FUNCTION and ignore the one of OLDFUN."
201 (declare (debug t)) ;;(indent 2) 224 (declare (debug t)) ;;(indent 2)
202 `(advice--add-function ,where (gv-ref ,place) ,function ,props)) 225 `(advice--add-function ,where (gv-ref ,place) ,function ,props))
203 226
@@ -285,28 +308,21 @@ is defined as a macro, alias, command, ..."
285 ;; - change all defadvice in lisp/**/*.el. 308 ;; - change all defadvice in lisp/**/*.el.
286 ;; - rewrite advice.el on top of this. 309 ;; - rewrite advice.el on top of this.
287 ;; - obsolete advice.el. 310 ;; - obsolete advice.el.
288 ;; To make advice.el and nadvice.el interoperate properly I see 2 different
289 ;; ways:
290 ;; - keep them separate: complete the defalias-fset-function setter with
291 ;; a matching accessor which both nadvice.el and advice.el will have to use
292 ;; in place of symbol-function. This can probably be made to work, but
293 ;; they have to agree on a "protocol".
294 ;; - layer advice.el on top of nadvice.el. I prefer this approach. the
295 ;; simplest way is to make advice.el build one ad-Advice-foo function for
296 ;; each advised function which is advice-added/removed whenever ad-activate
297 ;; ad-deactivate is called.
298 (let* ((f (and (fboundp symbol) (symbol-function symbol))) 311 (let* ((f (and (fboundp symbol) (symbol-function symbol)))
299 (nf (advice--normalize symbol f))) 312 (nf (advice--normalize symbol f)))
300 (unless (eq f nf) ;; Most importantly, if nf == nil! 313 (unless (eq f nf) ;; Most importantly, if nf == nil!
301 (fset symbol nf)) 314 (fset symbol nf))
302 (add-function where (cond 315 (add-function where (cond
303 ((eq (car-safe nf) 'macro) (cdr nf)) 316 ((eq (car-safe nf) 'macro) (cdr nf))
304 ;; If the function is not yet defined, we can't yet 317 ;; Reasons to delay installation of the advice:
305 ;; install the advice. 318 ;; - If the function is not yet defined, installing
306 ;; FIXME: If it's an autoloaded command, we also 319 ;; the advice would affect `fboundp'ness.
307 ;; have a problem because we need to load the 320 ;; - If it's an autoloaded command,
308 ;; command to build the interactive-form. 321 ;; advice--make-interactive-form would end up
309 ((or (not nf) (and (autoloadp nf))) ;; (commandp nf) 322 ;; loading the command eagerly.
323 ;; - `autoload' does nothing if the function is
324 ;; not an autoload or undefined.
325 ((or (not nf) (autoloadp nf))
310 (get symbol 'advice--pending)) 326 (get symbol 'advice--pending))
311 (t (symbol-function symbol))) 327 (t (symbol-function symbol)))
312 function props) 328 function props)