]> code.delx.au - gnu-emacs/blobdiff - lisp/emacs-lisp/nadvice.el
Typo fix.
[gnu-emacs] / lisp / emacs-lisp / nadvice.el
index 576e72088e9760390bc30d043e1b48b07de82e64..3dfeb04a9b3f9401591735e73c98951fa44bc602 100644 (file)
@@ -1,6 +1,6 @@
 ;;; nadvice.el --- Light-weight advice primitives for Elisp functions  -*- lexical-binding: t -*-
 
-;; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+;; Copyright (C) 2012-2014 Free Software Foundation, Inc.
 
 ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
 ;; Keywords: extensions, lisp, tools
@@ -67,8 +67,8 @@ Each element has the form (WHERE BYTECODE STACK) where:
 (defsubst advice--cdr   (f) (aref (aref f 2) 2))
 (defsubst advice--props (f) (aref (aref f 2) 3))
 
-(defun advice--make-docstring (_string function)
-  "Build the raw doc-string of SYMBOL, presumably advised."
+(defun advice--make-docstring (function)
+  "Build the raw docstring for FUNCTION, presumably advised."
   (let ((flist (indirect-function function))
         (docstring nil))
     (if (eq 'macro (car-safe flist)) (setq flist (cdr flist)))
@@ -105,13 +105,6 @@ Each element has the form (WHERE BYTECODE STACK) where:
                     (setq origdoc (cdr usage)) (car usage)))
       (help-add-fundoc-usage (concat docstring origdoc) usage))))
 
-(defvar advice--docstring
-  ;; Can't eval-when-compile nor use defconst because it then gets pure-copied,
-  ;; which drops the text-properties.
-  ;;(eval-when-compile
-  (propertize "Advised function"
-              'dynamic-docstring-function #'advice--make-docstring)) ;; )
-
 (defun advice-eval-interactive-spec (spec)
   "Evaluate the interactive spec SPEC."
   (cond
@@ -129,8 +122,6 @@ Each element has the form (WHERE BYTECODE STACK) where:
   ;; TODO: make it so that interactive spec can be a constant which
   ;; dynamically checks the advice--car/cdr to do its job.
   ;; For that, advice-eval-interactive-spec needs to be more faithful.
-  ;; FIXME: The calls to interactive-form below load autoloaded functions
-  ;; too eagerly.
   (let ((fspec (cadr (interactive-form function))))
     (when (eq 'function (car-safe fspec)) ;; Macroexpanded lambda?
       (setq fspec (nth 1 fspec)))
@@ -146,20 +137,30 @@ Each element has the form (WHERE BYTECODE STACK) where:
         (advice
          (apply #'make-byte-code 128 byte-code
                 (vector #'apply function main props) stack-depth
-                advice--docstring
-                (when (or (commandp function) (commandp main))
-                  (list (advice--make-interactive-form
-                         function main))))))
+                nil
+                (and (or (commandp function) (commandp main))
+                    (not (and (symbolp main) ;; Don't autoload too eagerly!
+                              (autoloadp (symbol-function main))))
+                     (list (advice--make-interactive-form
+                            function main))))))
     (when adv-sig (puthash advice adv-sig advertised-signature-table))
     advice))
 
 (defun advice--make (where function main props)
   "Build a function value that adds FUNCTION to MAIN at WHERE.
 WHERE is a symbol to select an entry in `advice--where-alist'."
-  (let ((desc (assq where advice--where-alist)))
-    (unless desc (error "Unknown add-function location `%S'" where))
-    (advice--make-1 (nth 1 desc) (nth 2 desc)
-                    function main props)))
+  (let ((fd (or (cdr (assq 'depth props)) 0))
+        (md (if (advice--p main)
+                (or (cdr (assq 'depth (advice--props main))) 0))))
+    (if (and md (> fd md))
+        ;; `function' should go deeper.
+        (let ((rest (advice--make where function (advice--cdr main) props)))
+          (advice--make-1 (aref main 1) (aref main 3)
+                          (advice--car main) rest (advice--props main)))
+      (let ((desc (assq where advice--where-alist)))
+        (unless desc (error "Unknown add-function location `%S'" where))
+        (advice--make-1 (nth 1 desc) (nth 2 desc)
+                        function main props)))))
 
 (defun advice--member-p (function name definition)
   (let ((found nil))
@@ -216,8 +217,6 @@ different, but `function-equal' will hopefully ignore those differences.")
 ;;;###autoload
 (defmacro add-function (where place function &optional props)
   ;; TODO:
-  ;; - provide some kind of control over ordering.  E.g. debug-on-entry, ELP
-  ;;   and tracing want to stay first.
   ;; - maybe let `where' specify some kind of predicate and use it
   ;;   to implement things like mode-local or eieio-defmethod.
   ;;   Of course, that only makes sense if the predicates of all advices can
@@ -245,6 +244,10 @@ If FUNCTION was already added, do nothing.
 PROPS is an alist of additional properties, among which the following have
 a special meaning:
 - `name': a string or symbol.  It can be used to refer to this piece of advice.
+- `depth': a number indicating a preference w.r.t ordering.
+  The default depth is 0.  By convention, a depth of 100 means that
+  the advice  should be innermost (i.e. at the end of the list),
+  whereas a depth of -100 means that the advice should be outermost.
 
 If PLACE is a simple variable, only its global value will be affected.
 Use (local 'VAR) if you want to apply FUNCTION to VAR buffer-locally.
@@ -284,7 +287,7 @@ of the piece of advice."
   (cond ((eq 'local (car-safe place))
          (setq place `(advice--buffer-local ,@(cdr place))))
         ((symbolp place)
-         (error "Use (default-value '%S) or (local '%S)" place place)))
+         (setq place `(default-value ',place))))
   (gv-letplace (getter setter) place
     (macroexp-let2 nil new `(advice--remove-function ,getter ,function)
       `(unless (eq ,new ,getter) ,(funcall setter new)))))
@@ -360,7 +363,6 @@ of the piece of advice."
       (unless (eq oldadv (get symbol 'advice--pending))
         (put symbol 'advice--pending (advice--subst-main oldadv nil)))
       (funcall fsetfun symbol newdef))))
-    
 
 ;;;###autoload
 (defun advice-add (symbol where function &optional props)
@@ -388,6 +390,7 @@ is defined as a macro, alias, command, ..."
                           (get symbol 'advice--pending))
                          (t (symbol-function symbol)))
                   function props)
+    (put symbol 'function-documentation `(advice--make-docstring ',symbol))
     (add-function :around (get symbol 'defalias-fset-function)
                   #'advice--defalias-fset))
   nil)