diff options
| author | Stefan Monnier | 2013-08-04 02:48:00 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2013-08-04 02:48:00 -0400 |
| commit | 1d44e9dcad7b0e4d884287288895916718bbd663 (patch) | |
| tree | 5b2d22fd601d2aa54212ca29fe10fad3ea37d2df | |
| parent | dc8dfa8a70df6ccb9d265ea98203cc0efe5d2fff (diff) | |
| download | emacs-1d44e9dcad7b0e4d884287288895916718bbd663.tar.gz emacs-1d44e9dcad7b0e4d884287288895916718bbd663.zip | |
* lisp/emacs-lisp/nadvice.el (advice-function-mapc): Rename from advice-mapc.
(advice-mapc): New function, using it.
(advice-function-member-p): New function.
(advice--normalize): Store the cdr in advice--saved-rewrite since
that's the part that will be changed.
(advice--symbol-function): New function.
(advice-remove): Handle removal before the function is defined.
Adjust to new advice--saved-rewrite.
(advice-member-p): Use advice-function-member-p and
advice--symbol-function.
| -rw-r--r-- | lisp/ChangeLog | 13 | ||||
| -rw-r--r-- | lisp/emacs-lisp/nadvice.el | 85 |
2 files changed, 72 insertions, 26 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 848c4e85407..dc1fa09b316 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,16 @@ | |||
| 1 | 2013-08-04 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * emacs-lisp/nadvice.el (advice-function-mapc): Rename from advice-mapc. | ||
| 4 | (advice-mapc): New function, using it. | ||
| 5 | (advice-function-member-p): New function. | ||
| 6 | (advice--normalize): Store the cdr in advice--saved-rewrite since | ||
| 7 | that's the part that will be changed. | ||
| 8 | (advice--symbol-function): New function. | ||
| 9 | (advice-remove): Handle removal before the function is defined. | ||
| 10 | Adjust to new advice--saved-rewrite. | ||
| 11 | (advice-member-p): Use advice-function-member-p and | ||
| 12 | advice--symbol-function. | ||
| 13 | |||
| 1 | 2013-08-04 Juanma Barranquero <lekktu@gmail.com> | 14 | 2013-08-04 Juanma Barranquero <lekktu@gmail.com> |
| 2 | 15 | ||
| 3 | * frameset.el (frameset-p, frameset-save): Fix autoload cookies. | 16 | * frameset.el (frameset-p, frameset-save): Fix autoload cookies. |
diff --git a/lisp/emacs-lisp/nadvice.el b/lisp/emacs-lisp/nadvice.el index edcfc409085..660eb0365ae 100644 --- a/lisp/emacs-lisp/nadvice.el +++ b/lisp/emacs-lisp/nadvice.el | |||
| @@ -193,7 +193,11 @@ WHERE is a symbol to select an entry in `advice--where-alist'." | |||
| 193 | (equal function (cdr (assq 'name props)))) | 193 | (equal function (cdr (assq 'name props)))) |
| 194 | (list rest)))))) | 194 | (list rest)))))) |
| 195 | 195 | ||
| 196 | (defvar advice--buffer-local-function-sample nil) | 196 | (defvar advice--buffer-local-function-sample nil |
| 197 | "keeps an example of the special \"run the default value\" functions. | ||
| 198 | These functions play the same role as t in buffer-local hooks, and to recognize | ||
| 199 | them, we keep a sample here against which to compare. Each instance is | ||
| 200 | different, but `function-equal' will hopefully ignore those differences.") | ||
| 197 | 201 | ||
| 198 | (defun advice--set-buffer-local (var val) | 202 | (defun advice--set-buffer-local (var val) |
| 199 | (if (function-equal val advice--buffer-local-function-sample) | 203 | (if (function-equal val advice--buffer-local-function-sample) |
| @@ -206,6 +210,7 @@ WHERE is a symbol to select an entry in `advice--where-alist'." | |||
| 206 | (declare (gv-setter advice--set-buffer-local)) | 210 | (declare (gv-setter advice--set-buffer-local)) |
| 207 | (if (local-variable-p var) (symbol-value var) | 211 | (if (local-variable-p var) (symbol-value var) |
| 208 | (setq advice--buffer-local-function-sample | 212 | (setq advice--buffer-local-function-sample |
| 213 | ;; This function acts like the t special value in buffer-local hooks. | ||
| 209 | (lambda (&rest args) (apply (default-value var) args))))) | 214 | (lambda (&rest args) (apply (default-value var) args))))) |
| 210 | 215 | ||
| 211 | ;;;###autoload | 216 | ;;;###autoload |
| @@ -284,6 +289,20 @@ of the piece of advice." | |||
| 284 | (macroexp-let2 nil new `(advice--remove-function ,getter ,function) | 289 | (macroexp-let2 nil new `(advice--remove-function ,getter ,function) |
| 285 | `(unless (eq ,new ,getter) ,(funcall setter new))))) | 290 | `(unless (eq ,new ,getter) ,(funcall setter new))))) |
| 286 | 291 | ||
| 292 | (defun advice-function-mapc (f function-def) | ||
| 293 | "Apply F to every advice function in FUNCTION-DEF. | ||
| 294 | F is called with two arguments: the function that was added, and the | ||
| 295 | properties alist that was specified when it was added." | ||
| 296 | (while (advice--p function-def) | ||
| 297 | (funcall f (advice--car function-def) (advice--props function-def)) | ||
| 298 | (setq function-def (advice--cdr function-def)))) | ||
| 299 | |||
| 300 | (defun advice-function-member-p (advice function-def) | ||
| 301 | "Return non-nil if ADVICE is already in FUNCTION-DEF. | ||
| 302 | Instead of ADVICE being the actual function, it can also be the `name' | ||
| 303 | of the piece of advice." | ||
| 304 | (advice--member-p advice advice function-def)) | ||
| 305 | |||
| 287 | ;;;; Specific application of add-function to `symbol-function' for advice. | 306 | ;;;; Specific application of add-function to `symbol-function' for advice. |
| 288 | 307 | ||
| 289 | (defun advice--subst-main (old new) | 308 | (defun advice--subst-main (old new) |
| @@ -294,11 +313,11 @@ of the piece of advice." | |||
| 294 | (cond | 313 | (cond |
| 295 | ((special-form-p def) | 314 | ((special-form-p def) |
| 296 | ;; Not worth the trouble trying to handle this, I think. | 315 | ;; Not worth the trouble trying to handle this, I think. |
| 297 | (error "advice-add failure: %S is a special form" symbol)) | 316 | (error "Advice impossible: %S is a special form" symbol)) |
| 298 | ((and (symbolp def) | 317 | ((and (symbolp def) |
| 299 | (eq 'macro (car-safe (ignore-errors (indirect-function def))))) | 318 | (eq 'macro (car-safe (ignore-errors (indirect-function def))))) |
| 300 | (let ((newval (cons 'macro (cdr (indirect-function def))))) | 319 | (let ((newval (cons 'macro (cdr (indirect-function def))))) |
| 301 | (put symbol 'advice--saved-rewrite (cons def newval)) | 320 | (put symbol 'advice--saved-rewrite (cons def (cdr newval))) |
| 302 | newval)) | 321 | newval)) |
| 303 | ;; `f' might be a pure (hence read-only) cons! | 322 | ;; `f' might be a pure (hence read-only) cons! |
| 304 | ((and (eq 'macro (car-safe def)) | 323 | ((and (eq 'macro (car-safe def)) |
| @@ -309,7 +328,26 @@ of the piece of advice." | |||
| 309 | (defsubst advice--strip-macro (x) | 328 | (defsubst advice--strip-macro (x) |
| 310 | (if (eq 'macro (car-safe x)) (cdr x) x)) | 329 | (if (eq 'macro (car-safe x)) (cdr x) x)) |
| 311 | 330 | ||
| 331 | (defun advice--symbol-function (symbol) | ||
| 332 | ;; The value conceptually stored in `symbol-function' is split into two | ||
| 333 | ;; parts: | ||
| 334 | ;; - the normal function definition. | ||
| 335 | ;; - the list of advice applied to it. | ||
| 336 | ;; `advice--symbol-function' is intended to return the second part (i.e. the | ||
| 337 | ;; list of advice, which includes a hole at the end which typically holds the | ||
| 338 | ;; first part, but this function doesn't care much which value is found | ||
| 339 | ;; there). | ||
| 340 | ;; In the "normal" state both parts are combined into a single value stored | ||
| 341 | ;; in the "function slot" of the symbol. But the way they are combined is | ||
| 342 | ;; different depending on whether the definition is a function or a macro. | ||
| 343 | ;; Also if the function definition is nil (i.e. unbound) or is an autoload, | ||
| 344 | ;; the second part is stashed away temporarily in the `advice--pending' | ||
| 345 | ;; symbol property. | ||
| 346 | (or (get symbol 'advice--pending) | ||
| 347 | (advice--strip-macro (symbol-function symbol)))) | ||
| 348 | |||
| 312 | (defun advice--defalias-fset (fsetfun symbol newdef) | 349 | (defun advice--defalias-fset (fsetfun symbol newdef) |
| 350 | (unless fsetfun (setq fsetfun #'fset)) | ||
| 313 | (when (get symbol 'advice--saved-rewrite) | 351 | (when (get symbol 'advice--saved-rewrite) |
| 314 | (put symbol 'advice--saved-rewrite nil)) | 352 | (put symbol 'advice--saved-rewrite nil)) |
| 315 | (setq newdef (advice--normalize symbol newdef)) | 353 | (setq newdef (advice--normalize symbol newdef)) |
| @@ -330,11 +368,11 @@ of the piece of advice." | |||
| 330 | (let* ((snewdef (advice--strip-macro newdef)) | 368 | (let* ((snewdef (advice--strip-macro newdef)) |
| 331 | (snewadv (advice--subst-main oldadv snewdef))) | 369 | (snewadv (advice--subst-main oldadv snewdef))) |
| 332 | (put symbol 'advice--pending nil) | 370 | (put symbol 'advice--pending nil) |
| 333 | (funcall (or fsetfun #'fset) symbol | 371 | (funcall fsetfun symbol |
| 334 | (if (eq snewdef newdef) snewadv (cons 'macro snewadv)))) | 372 | (if (eq snewdef newdef) snewadv (cons 'macro snewadv)))) |
| 335 | (unless (eq oldadv (get symbol 'advice--pending)) | 373 | (unless (eq oldadv (get symbol 'advice--pending)) |
| 336 | (put symbol 'advice--pending (advice--subst-main oldadv nil))) | 374 | (put symbol 'advice--pending (advice--subst-main oldadv nil))) |
| 337 | (funcall (or fsetfun #'fset) symbol newdef)))) | 375 | (funcall fsetfun symbol newdef)))) |
| 338 | 376 | ||
| 339 | 377 | ||
| 340 | ;;;###autoload | 378 | ;;;###autoload |
| @@ -349,8 +387,7 @@ is defined as a macro, alias, command, ..." | |||
| 349 | ;; - obsolete advice.el. | 387 | ;; - obsolete advice.el. |
| 350 | (let* ((f (symbol-function symbol)) | 388 | (let* ((f (symbol-function symbol)) |
| 351 | (nf (advice--normalize symbol f))) | 389 | (nf (advice--normalize symbol f))) |
| 352 | (unless (eq f nf) ;; Most importantly, if nf == nil! | 390 | (unless (eq f nf) (fset symbol nf)) |
| 353 | (fset symbol nf)) | ||
| 354 | (add-function where (cond | 391 | (add-function where (cond |
| 355 | ((eq (car-safe nf) 'macro) (cdr nf)) | 392 | ((eq (car-safe nf) 'macro) (cdr nf)) |
| 356 | ;; Reasons to delay installation of the advice: | 393 | ;; Reasons to delay installation of the advice: |
| @@ -377,39 +414,35 @@ or an autoload and it preserves `fboundp'. | |||
| 377 | Instead of the actual function to remove, FUNCTION can also be the `name' | 414 | Instead of the actual function to remove, FUNCTION can also be the `name' |
| 378 | of the piece of advice." | 415 | of the piece of advice." |
| 379 | (let ((f (symbol-function symbol))) | 416 | (let ((f (symbol-function symbol))) |
| 380 | ;; Can't use the `if' place here, because the body is too large, | 417 | (remove-function (cond ;This is `advice--symbol-function' but as a "place". |
| 381 | ;; resulting in use of code that only works with lexical-scoping. | 418 | ((get symbol 'advice--pending) |
| 382 | (remove-function (if (eq (car-safe f) 'macro) | 419 | (get symbol 'advice--pending)) |
| 383 | (cdr f) | 420 | ((eq (car-safe f) 'macro) (cdr f)) |
| 384 | (symbol-function symbol)) | 421 | (t (symbol-function symbol))) |
| 385 | function) | 422 | function) |
| 386 | (unless (advice--p | 423 | (unless (advice--p |
| 387 | (if (eq (car-safe f) 'macro) (cdr f) (symbol-function symbol))) | 424 | (if (eq (car-safe f) 'macro) (cdr f) (symbol-function symbol))) |
| 388 | ;; Not advised any more. | 425 | ;; Not advised any more. |
| 389 | (remove-function (get symbol 'defalias-fset-function) | 426 | (remove-function (get symbol 'defalias-fset-function) |
| 390 | #'advice--defalias-fset) | 427 | #'advice--defalias-fset) |
| 391 | (if (eq (symbol-function symbol) | 428 | (let ((asr (get symbol 'advice--saved-rewrite))) |
| 392 | (cdr (get symbol 'advice--saved-rewrite))) | 429 | (and asr (eq (cdr-safe (symbol-function symbol)) |
| 393 | (fset symbol (car (get symbol 'advice--saved-rewrite)))))) | 430 | (cdr asr)) |
| 431 | (fset symbol (car (get symbol 'advice--saved-rewrite))))))) | ||
| 394 | nil) | 432 | nil) |
| 395 | 433 | ||
| 396 | (defun advice-mapc (fun def) | 434 | (defun advice-mapc (fun symbol) |
| 397 | "Apply FUN to every advice function in DEF. | 435 | "Apply FUN to every advice function in SYMBOL. |
| 398 | FUN is called with a two arguments: the function that was added, and the | 436 | FUN is called with a two arguments: the function that was added, and the |
| 399 | properties alist that was specified when it was added." | 437 | properties alist that was specified when it was added." |
| 400 | (while (advice--p def) | 438 | (advice-function-mapc fun (advice--symbol-function symbol))) |
| 401 | (funcall fun (advice--car def) (advice--props def)) | ||
| 402 | (setq def (advice--cdr def)))) | ||
| 403 | 439 | ||
| 404 | ;;;###autoload | 440 | ;;;###autoload |
| 405 | (defun advice-member-p (advice function-name) | 441 | (defun advice-member-p (advice symbol) |
| 406 | "Return non-nil if ADVICE has been added to FUNCTION-NAME. | 442 | "Return non-nil if ADVICE has been added to SYMBOL. |
| 407 | Instead of ADVICE being the actual function, it can also be the `name' | 443 | Instead of ADVICE being the actual function, it can also be the `name' |
| 408 | of the piece of advice." | 444 | of the piece of advice." |
| 409 | (advice--member-p advice advice | 445 | (advice-function-member-p advice (advice--symbol-function symbol))) |
| 410 | (or (get function-name 'advice--pending) | ||
| 411 | (advice--strip-macro | ||
| 412 | (symbol-function function-name))))) | ||
| 413 | 446 | ||
| 414 | ;; When code is advised, called-interactively-p needs to be taught to skip | 447 | ;; When code is advised, called-interactively-p needs to be taught to skip |
| 415 | ;; the advising frames. | 448 | ;; the advising frames. |