aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2013-08-04 02:48:00 -0400
committerStefan Monnier2013-08-04 02:48:00 -0400
commit1d44e9dcad7b0e4d884287288895916718bbd663 (patch)
tree5b2d22fd601d2aa54212ca29fe10fad3ea37d2df
parentdc8dfa8a70df6ccb9d265ea98203cc0efe5d2fff (diff)
downloademacs-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/ChangeLog13
-rw-r--r--lisp/emacs-lisp/nadvice.el85
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 @@
12013-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
12013-08-04 Juanma Barranquero <lekktu@gmail.com> 142013-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.
198These functions play the same role as t in buffer-local hooks, and to recognize
199them, we keep a sample here against which to compare. Each instance is
200different, 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.
294F is called with two arguments: the function that was added, and the
295properties 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.
302Instead of ADVICE being the actual function, it can also be the `name'
303of 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'.
377Instead of the actual function to remove, FUNCTION can also be the `name' 414Instead of the actual function to remove, FUNCTION can also be the `name'
378of the piece of advice." 415of 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.
398FUN is called with a two arguments: the function that was added, and the 436FUN is called with a two arguments: the function that was added, and the
399properties alist that was specified when it was added." 437properties 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.
407Instead of ADVICE being the actual function, it can also be the `name' 443Instead of ADVICE being the actual function, it can also be the `name'
408of the piece of advice." 444of 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.