diff options
| author | Stefan Monnier | 2012-11-14 15:27:42 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2012-11-14 15:27:42 -0500 |
| commit | 1668ea9062effeaf84e2fcf1e97c9b174c66a4ec (patch) | |
| tree | b07875c2d311c6e5249015fd51a902bbcad2a8f5 | |
| parent | 14f207289c224b3ad12fc8704c2183ef8fbcab28 (diff) | |
| download | emacs-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/ChangeLog | 6 | ||||
| -rw-r--r-- | lisp/emacs-lisp/nadvice.el | 66 |
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 @@ | |||
| 1 | 2012-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 | |||
| 1 | 2012-11-14 Dmitry Gutov <dgutov@yandex.ru> | 7 | 2012-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: | |||
| 197 | If FUNCTION was already added, do nothing. | 212 | If FUNCTION was already added, do nothing. |
| 198 | PROPS is an alist of additional properties, among which the following have | 213 | PROPS is an alist of additional properties, among which the following have |
| 199 | a special meaning: | 214 | a 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 | |||
| 217 | If one of FUNCTION or OLDFUN is interactive, then the resulting function | ||
| 218 | is 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) |