Mercurial > emacs
changeset 8445:81f7b5d9b990
New handling of automatic advice activation that
exploits modified built-in versions of `fset' and `defalias' which
take care of this functionality directly:
(ad-start-advice-on-load, ad-activate-on-definition)
(ad-definition-hooks, ad-enable-definition-hooks, ad-defined-function)
(ad-advised-definers, ad-advised-byte-compilers, byte-constant)
(byte-constant-limit, byte-constant2, byte-fset)
(ad-byte-code-fset-regexp): Variables deleted.
(ad-activate-defined-function, ad-find-fset-in-byte-code)
(ad-scan-byte-code-for-fsets, ad-advised-byte-code)
(ad-recover-byte-code, ad-enable-definition-hooks)
(ad-disable-definition-hooks): Functions deleted.
(defun, defmacro, fset, defalias, define-function)
(byte-compile-from-buffer, byte-compile-top-level): Removed `defadvice'
for these functions.
(ad-save-real-definitions): Removed saving of `byte-code'.
(ad-activate-off): New dummy function.
(ad-activate-on): New name for `ad-activate'. All calls changed.
(ad-with-auto-activation-disabled): New macro prevents automatic
advice activation.
(ad-safe-fset): New function, used instead of `ad-real-fset'.
(ad-compile-function): Disable automatic advice activation while
compiling, because `byte-compile' uses `fset'.
(ad-activate-on): Renamed from `ad-activate'. Avoid recursive calls.
(ad-activate-on-top-level): New variable.
(ad-start-advice, ad-stop-advice, ad-recover-normality): Modified to
achieve de/activation of automatic advice activation by setting the
definition of `ad-activate' to `ad-activate-on' or `ad-activate-off'.
(ad-start-advice): Is now called unconditionally when Advice is loaded.
Made compilation behavior of advised definitions customizable, since
loading the byte-compiler takes some time and is not always worth the
cost, e.g., if one only wants to make a few simple modifications:
(ad-default-compilation-action): New variable which specifies whether
to compile an advised definition in case the COMPILE argument to
`ad-activate-on' or one of its friends was supplied as nil.
(ad-preactivate-advice): Supply negative COMPILE argument to prevent
compilation.
(ad-should-compile): New function.
(ad-activate-advised-definition): Use `ad-should-compile' to determine
whether an advised definition should get compiled.
(ad-activate-on, ad-update, ad-activate-regexp, ad-update-regexp)
(ad-activate-all): Doc fixes.
(ad-update): Leave handling of COMPILE up to `ad-activate-on'.
Extracted construction of freeze-advices from `defadvice':
(ad-make-freeze-definition): New function.
(defadvice): Use `ad-make-freeze-definition' to construct frozen defs.
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Thu, 04 Aug 1994 21:40:49 +0000 |
parents | 841f2c8ae5bb |
children | 0199ece40d91 |
files | lisp/emacs-lisp/advice.el |
diffstat | 1 files changed, 285 insertions(+), 596 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/emacs-lisp/advice.el Thu Aug 04 21:08:04 1994 +0000 +++ b/lisp/emacs-lisp/advice.el Thu Aug 04 21:40:49 1994 +0000 @@ -4,7 +4,7 @@ ;; Author: Hans Chalupsky <hans@cs.buffalo.edu> ;; Created: 12 Dec 1992 -;; Version: advice.el,v 2.11 1994/02/24 22:51:43 hans Exp +;; Version: advice.el,v 2.13 1994/08/03 23:27:05 hans Exp ;; Keywords: extensions, lisp, tools ;; This file is part of GNU Emacs. @@ -26,7 +26,7 @@ ;; LCD Archive Entry: ;; advice|Hans Chalupsky|hans@cs.buffalo.edu| ;; Overloading mechanism for Emacs Lisp functions| -;; 1994/02/24 22:51:43|2.11|~/packages/advice.el.Z| +;; 1994/08/03 23:27:05|2.13|~/packages/advice.el.Z| ;;; Commentary: @@ -68,8 +68,7 @@ ;; - Advised functions can be byte-compiled either at file-compile time ;; (see preactivation) or activation time. ;; - Separation of advice definition and activation -;; - Provides generally accessible function definition (after) hooks -;; - Forward advice is possible (an application of definition hooks), that is +;; - Forward advice is possible, that is ;; as yet undefined or autoload functions can be advised without having to ;; preload the file in which they are defined. ;; - Forward redefinition is possible because around advice can be used to @@ -83,8 +82,6 @@ ;; functions depending on what pieces of advice are currently en/disabled ;; - Provides manipulation mechanisms for sets of advised functions via ;; regular expressions that match advice names -;; - Allows definition of load-hooks for arbitrary Emacs Lisp files without -;; modification of these files ;; @ How to get Advice for Emacs-18: ;; ================================= @@ -114,7 +111,9 @@ ;; @ Restrictions: ;; =============== -;; - This version of Advice only works for Emacs-19 or Lucid Emacs. +;; - This version of Advice only works for Emacs 19.26 and later. It uses +;; new versions of the built-in functions `fset/defalias' which are not +;; yet available in Lucid Emacs, hence, it won't work there. ;; - Advised functions/macros/subrs will only exhibit their advised behavior ;; when they are invoked via their function cell. This means that advice will ;; not work for the following: @@ -124,13 +123,6 @@ ;; + advised macros which were expanded during byte-compilation before ;; their advice was activated. -;; @ Known bug: -;; ============ -;; - Using automatic activation of (forward) advice will break the -;; function `interactive-p' when it is used in the body of a `catch' -;; (this problem will go away once automatic advice activation gets -;; supported by built-in functions). - ;; @ Credits: ;; ========== ;; This package is an extension and generalization of packages such as @@ -151,14 +143,11 @@ ;; Before we begin: CAUTION!! ;; Advice provides you with a lot of rope to hang yourself on very ;; easily accessible trees, so, here are a few important things you -;; should know: Once Advice has been started with `ad-start-advice' it -;; generates advised definitions of the `documentation' function, and, -;; if definition hooks are enabled (e.g., for forward advice), also of -;; `defun', `defmacro' and `fset' (if you use Jamie Zawinski's (jwz) -;; optimizing byte-compiler as standardly used in Emacs-19 and -;; Lucid Emacs-19 (Lemacs), then enabling definition hooks will also -;; redefine the `byte-code' subr). All these changes can be undone at -;; any time with `M-x ad-stop-advice'. +;; should know: Once Advice has been started with `ad-start-advice' +;; (which happens automatically when you load this file), it +;; generates an advised definition of the `documentation' function, and +;; it will enable automatic advice activation when functions get defined. +;; All of this can be undone at any time with `M-x ad-stop-advice'. ;; ;; If you experience any strange behavior/errors etc. that you attribute to ;; Advice or to some ill-advised function do one of the following: @@ -190,30 +179,17 @@ ;; @ Customization: ;; ================ -;; Part of the advice magic does not start until you call `ad-start-advice' -;; which you can either do interactively, explicitly in your .emacs, or by -;; putting -;; -;; (setq ad-start-advice-on-load t) -;; -;; into your .emacs which will automatically start advice when the file gets -;; loaded. - -;; If you want to be able to forward advise functions, that is to advise them -;; when they are not yet defined or defined as autoloads, then you should put -;; the following into your .emacs -;; -;; (setq ad-activate-on-definition t) -;; -;; which will activate all advice at the time the function gets actually -;; defined/loaded. The value of this variable will not have any effect until -;; `ad-start-advice' gets executed. ;; Look at the documentation of `ad-redefinition-action' for possible values ;; of this variable. Its default value is `warn' which will print a warning ;; message when an already defined advised function gets redefined with a ;; new original definition and de/activated. +;; Look at the documentation of `ad-default-compilation-action' for possible +;; values of this variable. Its default value is `maybe' which will compile +;; advised definitions during activation in case the byte-compiler is already +;; loaded. Otherwise, it will leave them uncompiled. + ;; @ Motivation: ;; ============= ;; Before I go on explaining how advice works, here are four simple examples @@ -575,8 +551,8 @@ ;; The advised definition will get compiled either if `ad-activate' was called ;; interactively with a prefix argument, or called explicitly with its second -;; argument as t, or, if this was a case of forward advice if the original -;; definition of the function was compiled. If the advised definition was +;; argument as t, or, if `ad-default-compilation-action' justifies it according +;; to the current system state. If the advised definition was ;; constructed during "preactivation" (see below) then that definition will ;; be already compiled because it was constructed during byte-compilation of ;; the file that contained the `defadvice' with the `preactivate' flag. @@ -691,8 +667,8 @@ ;; match for the regular expression. To enable ange-ftp again we would use ;; `ad-enable-regexp' and then activate or update again. -;; @@ Forward advice, function definition hooks: -;; ============================================= +;; @@ Forward advice, automatic advice activation: +;; =============================================== ;; Because most Emacs Lisp packages are loaded on demand via an autoload ;; mechanism it is essential to be able to "forward advise" functions. ;; Otherwise, proper advice definition and activation would make it necessary @@ -706,129 +682,20 @@ ;; Advice implements forward advice mainly via the following: 1) Separation ;; of advice definition and activation that makes it possible to accumulate ;; advice information without having the original function already defined, -;; 2) special versions of the function defining functions `defun', `defmacro' -;; and `fset' that check for advice information whenever they define a -;; function. If advice information was found and forward advice is enabled -;; then the advice will immediately get activated when the function gets -;; defined. - -;; @@@ Enabling forward advice: -;; ============================ -;; Forward advice is enabled by setting `ad-activate-on-definition' to t -;; and then calling `ad-start-advice' which can either be done interactively, -;; directly with `(ad-start-advice)' in your .emacs, or by setting -;; `ad-start-advice-on-load' to t before advice gets loaded. For example, -;; putting the following into your .emacs will enable forward advice: -;; -;; (setq ad-start-advice-on-load t) -;; (setq ad-activate-on-definition t) -;; -;; "Activation on definition" means, that whenever a function gets defined +;; 2) special versions of the built-in functions `fset/defalias' which check +;; for advice information whenever they define a function. If advice +;; information was found then the advice will immediately get activated when +;; the function gets defined. + +;; Automatic advice activation means, that whenever a function gets defined ;; with either `defun', `defmacro', `fset' or by loading a byte-compiled ;; file, and the function has some advice-info stored with it then that ;; advice will get activated right away. -;; If jwz's byte-compiler is used then `ad-use-jwz-byte-compiler' should -;; be t in order to make forward advice work with functions defined in -;; compiled files generated by that compiler. In v19s which use this -;; compiler the value of this variable will be correct automatically. -;; If you use a v18 Emacs in conjunction with jwz's compiler and you want -;; to use forward advice then you should check its value after loading -;; advice. If it is nil set it explicitly with -;; -;; (setq ad-use-jwz-byte-compiler t) -;; -;; along with `ad-activate-on-definition' before you start advice (see above). - -;; IMPORTANT: A v18 Emacs + jwz's compiler + forward advice means performance -;; tradeoffs which are described below. - -;; @@@ Forward advice with compiled files generated by jwz's byte-compiler: -;; ======================================================================== -;; The v18 byte-compiler only uses `defun/defmacro' to define compiled -;; functions, hence, providing advised versions of these functions was -;; sufficient to achieve forward advice. With the advent of Jamie Zawinski's -;; optimizing byte-compiler which is now standardly used in Emacs-19 and -;; Lemacs things became more complicated. jwz's compiler defines functions -;; in hunks of byte-code without explicit usage of `defun/defmacro'. To -;; still provide forward advice even in this scenario, advice defines an -;; advised version of the `byte-code' subr that scans its arguments for -;; function definitions during the loading of compiled files. While this is -;; no problem in a v19 Emacs, because it uses a new datatype for compiled -;; code objects and the `byte-code' subr is only rarely used at all, it -;; presents a major problem in a v18 Emacs because there calls to -;; `byte-code' are the only means of executing compiled code (every body of -;; a compiled function contains a call to `byte-code'). Because the advised -;; `byte-code' has to perform some extra checks every call to a compiled -;; function becomes more expensive. - -;; Enabling forward advice leads to performance degradation in the following -;; situations: -;; - A v18 Emacs is used and the value of `ad-use-jwz-byte-compiler' is t -;; (either because jwz's byte-compiler is used instead of the standard v18 -;; compiler, or some compiled files generated by jwz's compiler are used). -;; - A v19 Emacs is used with some old-style v18 compiled files. -;; Some performance experiments I conducted showed that function call intensive -;; code (such as the highly recursive byte-compiler itself) slows down by a -;; factor of 1.8. Function call intensive code that runs while a file gets -;; loaded can slow down by a factor of 6! For the v19 scenario this performance -;; lossage would only apply to code that was loaded from old v18 compiled -;; files. - -;; MORAL: If you use a v18 Emacs in conjunction with jwz's byte-compiler you -;; should think twice whether you really need forward advice. There are some -;; alternatives to forward advice described below that might give you what -;; you need without the loss of performance (that performance loss probably -;; outweighs by far any performance gain due to the optimizing nature of jwz's -;; compiler). - -;; @@@ Alternatives to automatic activation of forward advice: -;; =========================================================== -;; If you use a v18 Emacs in conjunction with jwz's compiler, or you simply -;; don't trust the automatic activation mechanism of forward advice, then -;; you can use some of the following alternatives to get around that: -;; - Preload the file that contains the definition of the function that you -;; want to advice. Inelegant and wasteful, but it works. -;; - If the package that contains the definition of the function you want to -;; advise has any mode hooks, and the advised function is only used once such -;; a mode has been entered, then you can activate the advice in the mode -;; hook. Just put a form like `(ad-activate 'my-advised-fn t)' into the -;; hook definition. The caching mechanism will reuse advised definitions, -;; so calling that mode hook over and over again will not construct -;; advised definitions over and over again, so you won't loose any -;; performance. -;; - If your Emacs comes with file load hooks (such as v19's -;; `after-load-alist' mechanism), then you can put the activation form -;; into that, for example, add `("myfile" (ad-activate 'my-advised-fn t))' -;; to it to activate the advice right ater "myfile" got loaded. - -;; @@@ Function definition hooks: -;; ============================== -;; Automatic activation of forward advice is implemented as an application -;; of a more general function definition hook mechanism. After a function -;; gets re/defined with `defun/defmacro/fset' or via a hunk of byte-code -;; during the loading of a byte-compiled file, and function definition hooks -;; are enabled, then all hook functions stored in `ad-definition-hooks' are -;; run with the variable `ad-defined-function' bound to the name of the -;; currently defined function. - -;; Function definition hooks can be enabled with -;; -;; (setq ad-enable-definition-hooks t) -;; -;; before advice gets started with `ad-start-advice'. Setting -;; `ad-activate-on-definition' to t automatically enables definition hooks -;; regardless of the value of `ad-enable-definition-hooks'. - -;; @@@ Wish list: -;; ============== -;; - The implementation of definition hooks for v19 compiled files would be -;; safer if jwz's byte-compiler used something like `byte-code-tl' instead -;; of `byte-code' to execute hunks of function defining byte-code at the -;; top level of compiled files. -;; - Definition hooks should be implemented directly as part of the C-code -;; that implements `fset', because then Advice wouldn't have to use all -;; these dirty hacks to achieve this functionality. +;; @@@ Enabling automatic advice activation: +;; ========================================= +;; Automatic advice activation is enabled by default. It can be disabled by +;; doint `M-x ad-stop-advice' and enabled again with `M-x ad-start-advice'. ;; @@ Caching of advised definitions: ;; ================================== @@ -1954,34 +1821,20 @@ (require 'advice-preload "advice.el") -;; @@ Variable definitions: -;; ======================== - -(defconst ad-version "2.11") - (defmacro ad-lemacs-p () ;;Expands into Non-nil constant if we run Lucid's version of Emacs-19. ;;Unselected conditional code will be optimized away during compilation. (string-match "Lucid" emacs-version)) -;;;###autoload -(defvar ad-start-advice-on-load t - "*Non-nil will start Advice magic when this file gets loaded. -Also see function `ad-start-advice'.") - -;;;###autoload -(defvar ad-activate-on-definition nil - "*Non-nil means automatic advice activation at function definition. -Set this variable to t if you want to enable forward advice (which is -automatic advice activation of a previously undefined function at the -point the function gets defined/loaded/autoloaded). The value of this -variable takes effect only during the execution of `ad-start-advice'. -If non-nil it will enable definition hooks regardless of the value -of `ad-enable-definition-hooks'.") + +;; @@ Variable definitions: +;; ======================== + +(defconst ad-version "2.13") ;;;###autoload (defvar ad-redefinition-action 'warn - "*Defines what to do with redefinitions during de/activation. + "*Defines what to do with redefinitions during Advice de/activation. Redefinition occurs if a previously activated function that already has an original definition associated with it gets redefined and then de/activated. In such a case we can either accept the current definition as the new @@ -1992,16 +1845,14 @@ interpreted as `error'.") ;;;###autoload -(defvar ad-definition-hooks nil - "*List of hooks to be run after a function definition. -The variable `ad-defined-function' will be bound to the name of -the currently defined function when the hook function is run.") - -;;;###autoload -(defvar ad-enable-definition-hooks nil - "*Non-nil will enable hooks to be run on function definition. -Setting this variable is a noop unless the value of -`ad-activate-on-definition' (which see) is nil.") +(defvar ad-default-compilation-action 'maybe + "*Defines whether to compile advised definitions during activation. +A value of `always' will result in unconditional compilation, `never' will +always avoid compilation, `maybe' will compile if the byte-compiler is already +loaded, and `like-original' will compile if the original definition of the +advised function is compiled or a built-in function. Every other value will +be interpreted as `maybe'. This variable will only be considered if the +COMPILE argument of `ad-activate' was supplied as nil.") ;; @@ Some utilities: @@ -2100,9 +1951,7 @@ ;; properties into the compiled version of this function such that the ;; proper values will be available at runtime without loading the compiler: (ad-save-real-definition fset) - (ad-save-real-definition documentation) - (ad-save-real-definition byte-code) - (put 'ad-real-byte-code 'byte-compile nil)) + (ad-save-real-definition documentation)) (ad-save-real-definitions) @@ -2263,6 +2112,55 @@ (reverse enabled-advices))) +;; @@ Dealing with automatic advice activation via `fset/defalias': +;; ================================================================ + +;; Since Emacs 19.26 the built-in versions of `fset' and `defalias' +;; take care of automatic advice activation, hence, we don't have to +;; hack it anymore by advising `fset/defun/defmacro/byte-code/etc'. + +;; The functionality of the new `fset' is as follows: +;; +;; fset(sym,newdef) +;; assign NEWDEF to SYM +;; if (get SYM 'ad-advice-info) +;; ad-activate(SYM, nil) +;; return (symbol-function SYM) +;; +;; Whether advised definitions created by automatic activations will be +;; compiled depends on the value of `ad-default-compilation-action'. + +;; Since calling `ad-activate' in the built-in definition of `fset' can +;; create major disasters we have to be a bit careful. One precaution is +;; to provide a dummy definition for `ad-activate' which can be used to +;; turn off automatic advice activation (e.g., when `ad-stop-advice' or +;; `ad-recover-normality' are called). Another is to avoid recursive calls +;; to `ad-activate-on' by using `ad-with-auto-activation-disabled' where +;; appropriate, especially in a safe version of `fset'. + +;; For now define `ad-activate' to the dummy definition: +(defun ad-activate (function &optional compile) + "Automatic advice activation is disabled. `ad-start-advice' enables it." + nil) + +;; This is just a copy of the above: +(defun ad-activate-off (function &optional compile) + "Automatic advice activation is disabled. `ad-start-advice' enables it." + nil) + +;; This will be t for top-level calls to `ad-activate-on': +(defvar ad-activate-on-top-level t) + +(defmacro ad-with-auto-activation-disabled (&rest body) + (` (let ((ad-activate-on-top-level nil)) + (,@ body)))) + +(defun ad-safe-fset (symbol definition) + ;; A safe `fset' which will never call `ad-activate' recursively. + (ad-with-auto-activation-disabled + (ad-real-fset symbol definition))) + + ;; @@ Access functions for original definitions: ;; ============================================ ;; The advice-info of an advised function contains its `origname' which is @@ -2282,7 +2180,7 @@ (symbol-function origname))))) (defmacro ad-set-orig-definition (function definition) - (` (ad-real-fset + (` (ad-safe-fset (ad-get-advice-info-field function 'origname) (, definition)))) (defmacro ad-clear-orig-definition (function) @@ -2598,7 +2496,7 @@ ;; (compiled-function-p is an obsolete function in Emacs): (if (and (not (fboundp 'byte-code-function-p)) (fboundp 'compiled-function-p)) - (ad-real-fset 'byte-code-function-p 'compiled-function-p)) + (ad-safe-fset 'byte-code-function-p 'compiled-function-p)) (defmacro ad-compiled-p (definition) ;;"non-nil if DEFINITION is a compiled byte-code object." @@ -2777,7 +2675,10 @@ "Byte-compiles FUNCTION (or macro) if it is not yet compiled." (interactive "aByte-compile function: ") (if (ad-is-compilable function) - (byte-compile function))) + ;; Need to turn off auto-activation + ;; because `byte-compile' uses `fset': + (ad-with-auto-activation-disabled + (byte-compile function)))) ;; @@ Constructing advised definitions: @@ -3469,7 +3370,7 @@ (ad-add-advice function advice class position) (ad-enable-advice function class (ad-advice-name advice)) (ad-clear-cache function) - (ad-activate function nil) + (ad-activate-on function -1) (if (and (ad-is-active function) (ad-get-cache-definition function)) (list (ad-get-cache-definition function) @@ -3477,20 +3378,129 @@ (ad-set-advice-info function old-advice-info) ;; Don't `fset' function to nil if it was previously unbound: (if function-defined-p - (ad-real-fset function old-definition) + (ad-safe-fset function old-definition) (fmakunbound function))))) + +;; @@ Freezing: +;; ============ +;; Freezing transforms a `defadvice' into a redefining `defun/defmacro' +;; for the advised function without keeping any advice information. This +;; feature was jwz's idea: It generates a dumpable function definition +;; whose documentation can be written to the DOC file, and the generated +;; code does not need any Advice runtime support. Of course, frozen advices +;; cannot be undone. + +;; Freezing only considers the advice of the particular `defadvice', other +;; already existing advices for the same function will be ignored. To ensure +;; proper interaction when an already advised function gets redefined with +;; a frozen advice, frozen advices always use the actual original definition +;; of the function, i.e., they are always at the core of the onion. E.g., if +;; an already advised function gets redefined with a frozen advice and then +;; unadvised, the frozen advice remains as the new definition of the function. + +;; While multiple freeze advices for a single function or freeze-advising +;; of an already advised function are possible, they are better avoided, +;; because definition/compile/load ordering is relevant, and it becomes +;; incomprehensible pretty quickly. + +(defun ad-make-freeze-definition (function advice class position) + (if (not (ad-has-proper-definition function)) + (error + "ad-make-freeze-definition: `%s' is not yet defined" + function)) + (let* ((name (ad-advice-name advice)) + ;; With a unique origname we can have multiple freeze advices + ;; for the same function, each overloading the previous one: + (unique-origname + (intern (format "%s-%s-%s" (ad-make-origname function) class name))) + (orig-definition + ;; If FUNCTION is already advised, we'll use its current origdef + ;; as the original definition of the frozen advice: + (or (ad-get-orig-definition function) + (symbol-function function))) + (old-advice-info + (if (ad-is-advised function) + (ad-copy-advice-info function))) + (real-docstring-fn + (symbol-function 'ad-make-advised-definition-docstring)) + (real-origname-fn + (symbol-function 'ad-make-origname)) + (frozen-definition + (unwind-protect + (progn + ;; Make sure we construct a proper docstring: + (ad-safe-fset 'ad-make-advised-definition-docstring + 'ad-make-freeze-docstring) + ;; Make sure `unique-origname' is used as the origname: + (ad-safe-fset 'ad-make-origname '(lambda (x) unique-origname)) + ;; No we reset all current advice information to nil and + ;; generate an advised definition that's solely determined + ;; by ADVICE and the current origdef of FUNCTION: + (ad-set-advice-info function nil) + (ad-add-advice function advice class position) + ;; The following will provide proper real docstrings as + ;; well as a definition that will make the compiler happy: + (ad-set-orig-definition function orig-definition) + (ad-make-advised-definition function)) + ;; Restore the old advice state: + (ad-set-advice-info function old-advice-info) + ;; Restore functions: + (ad-safe-fset + 'ad-make-advised-definition-docstring real-docstring-fn) + (ad-safe-fset 'ad-make-origname real-origname-fn)))) + (if frozen-definition + (let* ((macro-p (ad-macro-p frozen-definition)) + (body (cdr (if macro-p + (ad-lambdafy frozen-definition) + frozen-definition)))) + (` (progn + (if (not (fboundp '(, unique-origname))) + (fset '(, unique-origname) + ;; avoid infinite recursion in case the function + ;; we want to freeze is already advised: + (or (ad-get-orig-definition '(, function)) + (symbol-function '(, function))))) + ((, (if macro-p 'defmacro 'defun)) + (, function) + (,@ body)))))))) + + +;; @@ Activation and definition handling: +;; ====================================== + +(defun ad-should-compile (function compile) + ;;"Returns non-nil if the advised FUNCTION should be compiled. + ;;If COMPILE is non-nil and not a negative number then it returns t. + ;;If COMPILE is a negative number then it returns nil. + ;;If COMPILE is nil then the result depends on the value of + ;;`ad-default-compilation-action' (which see)." + (if (integerp compile) + (>= compile 0) + (if compile + compile + (cond ((eq ad-default-compilation-action 'never) + nil) + ((eq ad-default-compilation-action 'always) + t) + ((eq ad-default-compilation-action 'like-original) + (or (ad-subr-p (ad-get-orig-definition function)) + (ad-compiled-p (ad-get-orig-definition function)))) + ;; everything else means `maybe': + (t (featurep 'byte-compile)))))) + (defun ad-activate-advised-definition (function compile) ;;"Redefines FUNCTION with its advised definition from cache or scratch. - ;;If COMPILE is true the resulting FUNCTION will be compiled. The current - ;;definition and its cache-id will be put into the cache." + ;;The resulting FUNCTION will be compiled if `ad-should-compile' returns t. + ;;The current definition and its cache-id will be put into the cache." (let ((verified-cached-definition (if (ad-verify-cache-id function) (ad-get-cache-definition function)))) - (ad-real-fset function + (ad-safe-fset function (or verified-cached-definition (ad-make-advised-definition function))) - (if compile (ad-compile-function function)) + (if (ad-should-compile function compile) + (ad-compile-function function)) (if verified-cached-definition (if (not (eq verified-cached-definition (symbol-function function))) ;; we must have compiled, cache the compiled definition: @@ -3528,7 +3538,7 @@ (error "ad-handle-definition (see its doc): `%s' %s" function "illegally redefined") (if (eq ad-redefinition-action 'discard) - (ad-real-fset function original-definition) + (ad-safe-fset function original-definition) (ad-set-orig-definition function current-definition) (if (eq ad-redefinition-action 'warn) (message "ad-handle-definition: `%s' got redefined" @@ -3547,37 +3557,43 @@ ;; @@ The top-level advice interface: ;; ================================== -(defun ad-activate (function &optional compile) +(defun ad-activate-on (function &optional compile) "Activates all the advice information of an advised FUNCTION. If FUNCTION has a proper original definition then an advised definition will be generated from FUNCTION's advice info and the definition of FUNCTION will be replaced with it. If a previously -cached advised definition was available, it will be used. With an -argument (COMPILE is non-nil) the resulting function (or a compilable -cached definition) will also be compiled. Activation of an advised -function that has an advice info but no actual pieces of advice is -equivalent to a call to `ad-unadvise'. Activation of an advised -function that has actual pieces of advice but none of them are enabled -is equivalent to a call to `ad-deactivate'. The current advised +cached advised definition was available, it will be used. +The optional COMPILE argument determines whether the resulting function +or a compilable cached definition will be compiled. If it is negative +no compilation will be performed, if it is positive or otherwise non-nil +the resulting function will be compiled, if it is nil the behavior depends +on the value of `ad-default-compilation-action' (which see). +Activation of an advised function that has an advice info but no actual +pieces of advice is equivalent to a call to `ad-unadvise'. Activation of +an advised function that has actual pieces of advice but none of them are +enabled is equivalent to a call to `ad-deactivate'. The current advised definition will always be cached for later usage." (interactive (list (ad-read-advised-function "Activate advice of: ") current-prefix-arg)) - (if (not (ad-is-advised function)) - (error "ad-activate: `%s' is not advised" function) - (ad-handle-definition function) - ;; Just return for forward advised and not yet defined functions: - (if (ad-get-orig-definition function) - (if (not (ad-has-any-advice function)) - (ad-unadvise function) - ;; Otherwise activate the advice: - (cond ((ad-has-redefining-advice function) - (ad-activate-advised-definition function compile) - (ad-set-advice-info-field function 'active t) - (eval (ad-make-hook-form function 'activation)) - function) - ;; Here we are if we have all disabled advices: - (t (ad-deactivate function))))))) + (if ad-activate-on-top-level + ;; avoid recursive calls to `ad-activate-on': + (ad-with-auto-activation-disabled + (if (not (ad-is-advised function)) + (error "ad-activate: `%s' is not advised" function) + (ad-handle-definition function) + ;; Just return for forward advised and not yet defined functions: + (if (ad-get-orig-definition function) + (if (not (ad-has-any-advice function)) + (ad-unadvise function) + ;; Otherwise activate the advice: + (cond ((ad-has-redefining-advice function) + (ad-activate-advised-definition function compile) + (ad-set-advice-info-field function 'active t) + (eval (ad-make-hook-form function 'activation)) + function) + ;; Here we are if we have all disabled advices: + (t (ad-deactivate function))))))))) (defun ad-deactivate (function) "Deactivates the advice of an actively advised FUNCTION. @@ -3594,21 +3610,19 @@ (if (not (ad-get-orig-definition function)) (error "ad-deactivate: `%s' has no original definition" function) - (ad-real-fset function (ad-get-orig-definition function)) + (ad-safe-fset function (ad-get-orig-definition function)) (ad-set-advice-info-field function 'active nil) (eval (ad-make-hook-form function 'deactivation)) function))))) (defun ad-update (function &optional compile) "Update the advised definition of FUNCTION if its advice is active. -With a prefix argument or if the current definition is compiled compile the -resulting advised definition." +See `ad-activate-on' for documentation on the optional COMPILE argument." (interactive (list (ad-read-advised-function "Update advised definition of: " 'ad-is-active))) (if (ad-is-active function) - (ad-activate - function (or compile (ad-compiled-p (symbol-function function)))))) + (ad-activate-on function compile))) (defun ad-unadvise (function) "Deactivates FUNCTION and then removes all its advice information. @@ -3634,20 +3648,20 @@ (completing-read "Recover advised function: " obarray nil t)))) (cond ((ad-is-advised function) (cond ((ad-get-orig-definition function) - (ad-real-fset function (ad-get-orig-definition function)) + (ad-safe-fset function (ad-get-orig-definition function)) (ad-clear-orig-definition function))) (ad-set-advice-info function nil) (ad-pop-advised-function function)))) (defun ad-activate-regexp (regexp &optional compile) "Activates functions with an advice name containing a REGEXP match. -With prefix argument compiles resulting advised definitions." +See `ad-activate-on' for documentation on the optional COMPILE argument." (interactive (list (ad-read-regexp "Activate via advice regexp: ") current-prefix-arg)) (ad-do-advised-functions (function) (if (ad-find-some-advice function 'any regexp) - (ad-activate function compile)))) + (ad-activate-on function compile)))) (defun ad-deactivate-regexp (regexp) "Deactivates functions with an advice name containing REGEXP match." @@ -3659,7 +3673,7 @@ (defun ad-update-regexp (regexp &optional compile) "Updates functions with an advice name containing a REGEXP match. -With prefix argument compiles resulting advised definitions." +See `ad-activate-on' for documentation on the optional COMPILE argument." (interactive (list (ad-read-regexp "Update via advice regexp: ") current-prefix-arg)) @@ -3669,10 +3683,10 @@ (defun ad-activate-all (&optional compile) "Activates all currently advised functions. -With prefix argument compiles resulting advised definitions." +See `ad-activate-on' for documentation on the optional COMPILE argument." (interactive "P") (ad-do-advised-functions (function) - (ad-activate function))) + (ad-activate-on function compile))) (defun ad-deactivate-all () "Deactivates all currently advised functions." @@ -3751,7 +3765,7 @@ this if the `defadvice' gets actually compiled. `freeze': Expands the `defadvice' into a redefining `defun/defmacro' according -to the current advice state. No other advice information will be saved. +to this particular single advice. No other advice information will be saved. Frozen advices cannot be undone, they behave like a hard redefinition of the advised function. `freeze' implies `activate' and `preactivate'. The documentation of the advised function can be dumped onto the `DOC' file @@ -3791,40 +3805,12 @@ (` (advice lambda (, arglist) (,@ body))))) (preactivation (if (memq 'preactivate flags) (ad-preactivate-advice - function advice class position))) - unique-origname - (redefinition - (if (memq 'freeze flags) - (ad-with-originals (ad-make-advised-definition-docstring - ad-make-origname) - ;; Make sure we construct the actual docstring: - (fset 'ad-make-advised-definition-docstring - 'ad-make-freeze-docstring) - ;; With a unique origname we can have multiple freeze advices - ;; for the same function, each overloading the previous one: - (setq unique-origname - (intern (format "%s-%s-%s" - (ad-make-origname function) class name))) - (fset 'ad-make-origname '(lambda (x) unique-origname)) - (if (not (ad-has-proper-definition function)) - (error - "defadvice: `freeze' needs proper definition of `%s'" - function)) - (ad-preactivate-advice function advice class position))))) + function advice class position)))) ;; Now for the things to be done at evaluation time: - (if redefinition + (if (memq 'freeze flags) ;; jwz's idea: Freeze the advised definition into a dumpable ;; defun/defmacro whose docs can be written to the DOC file: - (let* ((macro-p (ad-macro-p (car redefinition))) - (body (cdr (if macro-p - (ad-lambdafy (car redefinition)) - (car redefinition))))) - (` (progn - (if (not (fboundp '(, unique-origname))) - (fset '(, unique-origname) (symbol-function '(, function)))) - ((, (if macro-p 'defmacro 'defun)) - (, function) - (,@ body))))) + (ad-make-freeze-definition function advice class position) ;; the normal case: (` (progn (ad-add-advice '(, function) '(, advice) '(, class) '(, position)) @@ -3841,8 +3827,8 @@ (, (car preactivation))))))) '(, (car (cdr preactivation)))))))) (,@ (if (memq 'activate flags) - (` ((ad-activate '(, function) - (, (if (memq 'compile flags) t))))))) + (` ((ad-activate-on '(, function) + (, (if (memq 'compile flags) t))))))) '(, function)))))) @@ -3874,7 +3860,7 @@ (function (lambda (function) (setq index (1+ index)) - (` (ad-real-fset + (` (ad-safe-fset '(, function) (or (ad-get-orig-definition '(, function)) (, (car (nth index current-bindings)))))))) @@ -3888,7 +3874,7 @@ (function (lambda (function) (setq index (1+ index)) - (` (ad-real-fset + (` (ad-safe-fset '(, function) (, (car (nth index current-bindings))))))) functions)))))))) @@ -3897,79 +3883,10 @@ (put 'ad-with-originals 'lisp-indent-hook 1)) -;; @@ Advising `defun', `defmacro', `fset' and `documentation' -;; =========================================================== -;; Use the advice mechanism to advise defun/defmacro/fset so we can forward -;; advise functions that might be defined later during load/autoload. -;; Enabling forward advice was the original motivation for doing this, it -;; has now been generalized to running definition hooks so other packages -;; can make use of this sort of functionality too. - -(defvar ad-defined-function nil) - -(defun ad-activate-defined-function (&optional function) - "Activates the advice of an advised and defined FUNCTION. -If the current definition of FUNCTION is byte-compiled then the advised -definition will be compiled too. FUNCTION defaults to the value of -`ad-defined-function'." - (if (and (null function) - ad-defined-function) - (setq function ad-defined-function)) - (if (and (ad-is-advised function) - (ad-real-definition function)) - (ad-activate function (ad-compiled-p (symbol-function function))))) - -(defvar ad-advised-definers - '(defun defmacro fset defalias define-function)) - -(defadvice defun (after ad-definition-hooks first disable preact) - "Whenever a function gets re/defined with `defun' all hook functions -in `ad-definition-hooks' will be run after the re/definition with -`ad-defined-function' bound to the name of the function." - (let ((ad-defined-function (ad-get-arg 0))) - (run-hooks 'ad-definition-hooks))) - -(defadvice defmacro (after ad-definition-hooks first disable preact) - "Whenever a macro gets re/defined with `defmacro' all hook functions -in `ad-definition-hooks' will be run after the re/definition with -`ad-defined-function' bound to the name of the function." - (let ((ad-defined-function (ad-get-arg 0))) - (run-hooks 'ad-definition-hooks))) - -(defadvice fset (after ad-definition-hooks first disable preact) - "Whenever a function gets re/defined with `fset' all hook functions -in `ad-definition-hooks' will be run after the re/definition with -`ad-defined-function' bound to the name of the function. This advice was -mainly created to handle forward-advice for byte-compiled files created -by jwz's byte-compiler used in Lemacs. -CAUTION: If you need the primitive `fset' behavior either deactivate - its advice or use `ad-real-fset' instead!" - (let ((ad-defined-function (ad-get-arg 0))) - (run-hooks 'ad-definition-hooks))) - -;; In Lemacs this is just a noop: -(defadvice defalias (after ad-definition-hooks first disable preact) - "Whenever a function gets re/defined with `defalias' all hook functions -in `ad-definition-hooks' will be run after the re/definition with -`ad-defined-function' bound to the name of the function." - (let ((ad-defined-function (ad-get-arg 0))) - ;; The new `byte-compile' uses `defalias' to set the definition which - ;; leads to infinite recursion if it gets to use the advised version - ;; (with `fset' this didn't matter because the compiled `byte-compile' - ;; called it via its byte-code). Should there be a general provision to - ;; avoid recursive application of definition hooks? - (ad-with-originals (defalias) - (run-hooks 'ad-definition-hooks)))) - -;; Needed for Emacs (seems to be an identical copy of `defalias', but -;; it is used in `simple.el' and might be used later, hence, advise it): -(defadvice define-function (after ad-definition-hooks first disable preact) - "Whenever a function gets re/defined with `define-function' all hook -functions in `ad-definition-hooks' will be run after the re/definition with -`ad-defined-function' bound to the name of the function." - (let ((ad-defined-function (ad-get-arg 0))) - (ad-with-originals (define-function) - (run-hooks 'ad-definition-hooks)))) +;; @@ Advising `documentation': +;; ============================ +;; Use the advice mechanism to advise `documentation' to make it +;; generate proper documentation strings for advised definitions: (defadvice documentation (after ad-advised-docstring first disable preact) "Builds an advised docstring if FUNCTION is advised." @@ -3988,274 +3905,46 @@ (setq ad-return-value (substitute-command-keys ad-return-value)))))))) -;; The following two advised functions are a (hopefully temporary) kludge -;; to fix a problem with the compilation of embedded (or non-top-level) -;; `defun/defmacro's when automatic activation of advice is enabled. For -;; the time of the compilation they backdefine `defun/defmacro' to their -;; original definition to make sure they are not treated as plain macros. -;; Both advices are forward advices, hence, they will only be activated if -;; automatic advice activation is enabled, but since that is the actual -;; situation where we have a problem, we can be sure that the advices will -;; be active when we need them. - -;; We only need this in Lemacs, because in Emacs it is -;; now taken care of directly by the byte-compiler: -(cond ((ad-lemacs-p) - -(defvar ad-advised-byte-compilers - '(byte-compile-from-buffer byte-compile-top-level)) - -(defadvice byte-compile-from-buffer (around ad-deactivate-defun-defmacro - first disable preact) - "Deactivates `defun/defmacro' for proper compilation when they are embedded." - (let (;; make sure no `require' starts them again by accident: - (ad-advised-definers '(fset defalias define-function))) - (ad-with-originals (defun defmacro) - ad-do-it))) - -(defadvice byte-compile-top-level (around ad-deactivate-defun-defmacro - first disable preact) - "Deactivates `defun/defmacro' for proper compilation when they are embedded." - (let (;; make sure no `require' starts them again by accident: - (ad-advised-definers '(fset defalias define-function))) - (ad-with-originals (defun defmacro) - ad-do-it))) - -)) ;; end of cond - -;; Make sure advice-infos are not allocated in pure space -;; (this might not be necessary anymore): -(ad-dolist (advised-function (cons 'documentation - (append ad-advised-definers - (if (ad-lemacs-p) - ad-advised-byte-compilers)))) - (ad-set-advice-info advised-function (ad-copy-advice-info advised-function))) - - -;; @@ Forward advice support for jwz's byte-compiler (M-x serious-HACK-mode-on) -;; ============================================================================ -;; Jamie Zawinski's optimizing byte-compiler used in v19 (and by some daring -;; folks in v18) produces compiled files that do not define functions via -;; explicit calls to `defun/defmacro', it rather uses `fset' for functions with -;; documentation strings, and hunks of byte-code for sets of functions without -;; any documentation. In Jamie's byte-compiler a series of compiled functions -;; without docstrings get hunked as -;; (progn (fset 'f1 <code1>) (fset 'f2 <code2>) ...). -;; The resulting progn will be compiled and the compiled form will be written -;; to the compiled file as `(byte-code [progn-code] [constants] [depth])'. To -;; handle forward advice we have to know when functions get defined so we can -;; activate any advice there might be. For standard v18 byte-compiled files -;; we can do this by simply advising `defun/defmacro' because these subrs are -;; evaluated explicitly when such a file is loaded. For Jamie's v19 compiler -;; our only choice is to additionally advise `fset' and change the subr -;; `byte-code' such that it analyzes its byte-code string looking for fset's -;; when we are currently loading a file. In v19 the general overhead caused -;; by the advice of `byte-code' shouldn't be too bad, because byte-compiled -;; functions do not call byte-code explicitly (as done in v18). In v18 this -;; is a problem because with the changed `byte-code' function function calls -;; become more expensive. -;; -;; Wish-List: -;; - special defining functions for use in byte-compiled files, e.g., -;; `byte-compile-fset' and `byte-code-tl' which do the same as their -;; standard brothers, but which can be advised for forward advice without -;; the problems that advising `byte-code' generates. -;; - More generally, a symbol definition hook that could be used for -;; forward advice and related purposes. -;; -;; Until then: For the analysis of the byte-code string we simply scan it for -;; an `fset' opcode (M in ascii) that is preceded by two constant references, -;; the first of which points to the function name and the second to its code. -;; A constant reference can either be a simple one-byte one, or a three-byte -;; one if the function has more than 64 constants. The scanning can pretty -;; efficiently be done with a regular expression. Here it goes: - -;; Have to hardcode these opcodes if I don't -;; want to require the byte-compiler: -(defvar byte-constant 192) -(defvar byte-constant-limit 64) -(defvar byte-constant2 129) -(defvar byte-fset 77) - -;; Matches a byte-compiled fset operation with two constant arguments: -(defvar ad-byte-code-fset-regexp - (let* ((constant-reference - (format "[%s-%s]" - (char-to-string byte-constant) - (char-to-string (+ byte-constant (1- byte-constant-limit))))) - (constant2-reference - ;; \0 makes it necessary to use concat instead of format in 18.57: - (concat (char-to-string byte-constant2) "[\0-\377][\0-\377]")) - (fset-opcode (char-to-string byte-fset))) - (concat "\\(" constant-reference "\\|" constant2-reference "\\)" - "\\(" constant-reference "\\|" constant2-reference "\\)" - fset-opcode))) - -(defun ad-find-fset-in-byte-code (code constants start) - ;;"Finds the first two-constant fset operation in CODE after START. - ;;Returns a three element list consisting of the name of the defined - ;;function, its code (both taken from the CONSTANTS vector), and an - ;;advanced start index." - (let ((start - ;; The odd case that this regexp matches something that isn't an - ;; actual fset operation is handled by additional tests and a - ;; condition handler in ad-scan-byte-code-for-fsets: - (string-match ad-byte-code-fset-regexp code start)) - name-index code-index) - (cond (start - (cond ((= (aref code start) byte-constant2) - (setq name-index - (+ (aref code (setq start (1+ start))) - (* (aref code (setq start (1+ start))) 256))) - (setq start (1+ start))) - (t (setq name-index (- (aref code start) byte-constant)) - (setq start (1+ start)))) - (cond ((= (aref code start) byte-constant2) - (setq code-index - (+ (aref code (setq start (1+ start))) - (* (aref code (setq start (1+ start))) 256))) - (setq start (1+ start))) - (t (setq code-index (- (aref code start) byte-constant)) - (setq start (1+ start)))) - (list (aref constants name-index) - (aref constants code-index) - ;; start points to fset opcode: - start)) - (t nil)))) - -(defun ad-scan-byte-code-for-fsets (ad-code ad-constants) - ;; In case anything in here goes wrong we reset `byte-code' to its real - ;; identity. In particular, the handler of the condition-case uses - ;; `byte-code', so it better be the real one if we have an error: - (ad-real-fset 'byte-code (symbol-function 'ad-real-byte-code)) - (condition-case nil - (let ((fset-args '(0 0 0))) - (while (setq fset-args (ad-find-fset-in-byte-code - ad-code ad-constants - (car (cdr (cdr fset-args))))) - (if (and (symbolp (car fset-args)) - (fboundp (car fset-args)) - (eq (symbol-function (car fset-args)) - (car (cdr fset-args)))) - ;; We've found an fset that was executed during this call - ;; to byte-code, and whose definition is still eq to the - ;; current definition of the defined function: - (let ((ad-defined-function (car fset-args))) - (run-hooks 'ad-definition-hooks)))) - ;; Everything worked fine, readvise `byte-code': - (ad-real-fset 'byte-code (symbol-function 'ad-advised-byte-code))) - (error nil))) - -;; CAUTION: Don't try this at home!! Changing `byte-code' is a -;; pretty suicidal activity. -;; To allow v19 forward advice we cannot advise `byte-code' as a subr as -;; we did for `defun' etc., because `ad-subr-args' of the advised -;; `byte-code' would shield references to `ad-subr-args' in the body of -;; v18 compiled advised subrs such as `defun', and, more importantly, the -;; changed version of `byte-code' has to be as small and efficient as -;; possible because it is used in every call to a compiled function. -;; Hence, we previously saved its original definition and redefine it as -;; the following function - yuck: - -;; The arguments will scope around the body of every byte-compiled -;; function, hence they have to be obscure enough to not be equal to any -;; global or argument variable referenced by any compiled function: -(defun ad-advised-byte-code (ad-cOdE ad-cOnStAnTs ad-dEpTh) - "Modified version of `byte-code' subr used by the Advice package. -`byte-code' has been modified to allow automatic activation of forward -advice for functions that are defined in byte-compiled files. -See `ad-real-byte-code' for original documentation." - (prog1 (ad-real-byte-code ad-cOdE ad-cOnStAnTs ad-dEpTh) - (if load-in-progress - (ad-scan-byte-code-for-fsets ad-cOdE ad-cOnStAnTs)))) - -(defun ad-recover-byte-code () - "Recovers the real `byte-code' functionality." - (interactive) - (ad-real-fset 'byte-code (symbol-function 'ad-real-byte-code))) - -(defun ad-enable-definition-hooks () - ;;"Enables definition hooks by redefining definition primitives. - ;;Activates the advice of defun/defmacro/fset and redefines `byte-code'. - ;;Redefining these primitives might lead to problems. Use - ;;`ad-disable-definition-hooks' or `ad-stop-advice' in such a case - ;;to establish a safe state." - (ad-dolist (definer ad-advised-definers) - (ad-enable-advice definer 'after 'ad-definition-hooks) - (ad-activate definer 'compile)) - (if (ad-lemacs-p) - (ad-dolist (byte-compiler ad-advised-byte-compilers) - (ad-enable-advice byte-compiler 'around 'ad-deactivate-defun-defmacro) - (ad-activate byte-compiler 'compile))) - ;; Now redefine byte-code... - (ad-real-fset 'byte-code (symbol-function 'ad-advised-byte-code))) - -(defun ad-disable-definition-hooks () - ;;"Disables definition hooks by resetting definition primitives." - (ad-recover-byte-code) - (ad-dolist (definer ad-advised-definers) - (ad-disable-advice definer 'after 'ad-definition-hooks) - (ad-update definer)) - (if (ad-lemacs-p) - (ad-dolist (byte-compiler ad-advised-byte-compilers) - (ad-disable-advice byte-compiler 'around 'ad-deactivate-defun-defmacro) - (ad-update byte-compiler 'compile)))) - ;; @@ Starting, stopping and recovering from the advice package magic: ;; =================================================================== -;;;###autoload (defun ad-start-advice () - "Redefines some primitives to start the advice magic. -If `ad-activate-on-definition' is t then advice information will -automatically get activated whenever an advised function gets defined or -redefined. This will enable goodies such as forward advice and -automatically enable function definition hooks. If its value is nil but -the value of `ad-enable-definition-hooks' is t then definition hooks -will be enabled without having automatic advice activation, otherwise -function definition hooks will be disabled too. If definition hooks are -enabled then functions stored in `ad-definition-hooks' are run whenever -a function gets defined or redefined." + "Starts the automatic advice handling magic." (interactive) + ;; Advising `ad-activate' means death!! + (ad-set-advice-info 'ad-activate nil) + (ad-safe-fset 'ad-activate 'ad-activate-on) (ad-enable-advice 'documentation 'after 'ad-advised-docstring) - (ad-activate 'documentation 'compile) - (if (or ad-activate-on-definition - ad-enable-definition-hooks) - (ad-enable-definition-hooks) - (ad-disable-definition-hooks)) - (setq ad-definition-hooks - (if ad-activate-on-definition - (if (memq 'ad-activate-defined-function ad-definition-hooks) - ad-definition-hooks - (cons 'ad-activate-defined-function ad-definition-hooks)) - (delq 'ad-activate-defined-function ad-definition-hooks)))) + (ad-activate-on 'documentation 'compile)) (defun ad-stop-advice () - "Undefines some primitives to stop the advice magic. -This can also be used to recover from advice related emergencies." + "Stops the automatic advice handling magic. +You should only need this in case of Advice-related emergencies." (interactive) - (ad-recover-byte-code) + ;; Advising `ad-activate' means death!! + (ad-set-advice-info 'ad-activate nil) (ad-disable-advice 'documentation 'after 'ad-advised-docstring) (ad-update 'documentation) - (ad-disable-definition-hooks) - (setq ad-definition-hooks - (delq 'ad-activate-defined-function ad-definition-hooks))) + (ad-safe-fset 'ad-activate 'ad-activate-off)) (defun ad-recover-normality () "Undoes all advice related redefinitions and unadvises everything. Use only in REAL emergencies." (interactive) - (ad-recover-byte-code) + ;; Advising `ad-activate' means death!! + (ad-set-advice-info 'ad-activate nil) + (ad-safe-fset 'ad-activate 'ad-activate-off) (ad-recover-all) (setq ad-advised-functions nil)) -(if (and ad-start-advice-on-load - ;; ...but only if we are compiled: - (ad-compiled-p (symbol-function 'ad-start-advice))) - (ad-start-advice)) +;; Until the Advice-related changes to `data.c' are part of Lemacs we +;; have to load the old implementation of advice activation hooks: +(if (ad-lemacs-p) + (require 'ad-hooks)) + +(ad-start-advice) (provide 'advice) ;;; advice.el ends here -