aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorStefan Monnier2012-11-20 14:30:37 -0500
committerStefan Monnier2012-11-20 14:30:37 -0500
commit8b62d7427e12bbf07ab3454cc061a6b43ded56dd (patch)
tree8d4718f70f62c2917e8f8a536ccd3cb537b8f59d /lisp
parent5d0ccd9509a21ef18e60004a4d46e60a916e4a36 (diff)
downloademacs-8b62d7427e12bbf07ab3454cc061a6b43ded56dd.tar.gz
emacs-8b62d7427e12bbf07ab3454cc061a6b43ded56dd.zip
* lisp/emacs-lisp/trace.el: Rewrite, use nadvice and lexical-binding.
(trace-buffer): Don't purecopy. (trace-entry-message, trace-exit-message): Add `context' arg. (trace--timer): New var. (trace-make-advice): Adjust for use in nadvice. Add `context' argument. Delay `display-buffer' via a timer. (trace-function-internal): Use advice-add. (trace--read-args): New function. (trace-function-foreground, trace-function-background): Use it. (trace-function): Rename to trace-function-foreground and redefine as an alias to that new name. (untrace-function, untrace-all): Adjust to the use of nadvice.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/ChangeLog13
-rw-r--r--lisp/emacs-lisp/trace.el206
2 files changed, 127 insertions, 92 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 910cc3522bd..c2d1b58b6ec 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,5 +1,18 @@
12012-11-20 Stefan Monnier <monnier@iro.umontreal.ca> 12012-11-20 Stefan Monnier <monnier@iro.umontreal.ca>
2 2
3 * emacs-lisp/trace.el: Rewrite, use nadvice and lexical-binding.
4 (trace-buffer): Don't purecopy.
5 (trace-entry-message, trace-exit-message): Add `context' arg.
6 (trace--timer): New var.
7 (trace-make-advice): Adjust for use in nadvice.
8 Add `context' argument. Delay `display-buffer' via a timer.
9 (trace-function-internal): Use advice-add.
10 (trace--read-args): New function.
11 (trace-function-foreground, trace-function-background): Use it.
12 (trace-function): Rename to trace-function-foreground and redefine as
13 an alias to that new name.
14 (untrace-function, untrace-all): Adjust to the use of nadvice.
15
3 * emacs-lisp/bytecomp.el (byte-compile): Fix handling of closures. 16 * emacs-lisp/bytecomp.el (byte-compile): Fix handling of closures.
4 17
5 * emacs-lisp/byte-run.el (defun-declarations-alist): Fix last change. 18 * emacs-lisp/byte-run.el (defun-declarations-alist): Fix last change.
diff --git a/lisp/emacs-lisp/trace.el b/lisp/emacs-lisp/trace.el
index c6fff7aa443..722e6270e95 100644
--- a/lisp/emacs-lisp/trace.el
+++ b/lisp/emacs-lisp/trace.el
@@ -1,4 +1,4 @@
1;;; trace.el --- tracing facility for Emacs Lisp functions 1;;; trace.el --- tracing facility for Emacs Lisp functions -*- lexical-binding: t -*-
2 2
3;; Copyright (C) 1993, 1998, 2000-2012 Free Software Foundation, Inc. 3;; Copyright (C) 1993, 1998, 2000-2012 Free Software Foundation, Inc.
4 4
@@ -151,18 +151,15 @@
151 151
152;;; Code: 152;;; Code:
153 153
154(require 'advice)
155
156(defgroup trace nil 154(defgroup trace nil
157 "Tracing facility for Emacs Lisp functions." 155 "Tracing facility for Emacs Lisp functions."
158 :prefix "trace-" 156 :prefix "trace-"
159 :group 'lisp) 157 :group 'lisp)
160 158
161;;;###autoload 159;;;###autoload
162(defcustom trace-buffer (purecopy "*trace-output*") 160(defcustom trace-buffer "*trace-output*"
163 "Trace output will by default go to that buffer." 161 "Trace output will by default go to that buffer."
164 :type 'string 162 :type 'string)
165 :group 'trace)
166 163
167;; Current level of traced function invocation: 164;; Current level of traced function invocation:
168(defvar trace-level 0) 165(defvar trace-level 0)
@@ -176,78 +173,109 @@
176(defvar inhibit-trace nil 173(defvar inhibit-trace nil
177 "If non-nil, all tracing is temporarily inhibited.") 174 "If non-nil, all tracing is temporarily inhibited.")
178 175
179(defun trace-entry-message (function level argument-bindings) 176(defun trace-entry-message (function level args context)
180 ;; Generates a string that describes that FUNCTION has been entered at 177 "Generate a string that describes that FUNCTION has been entered.
181 ;; trace LEVEL with ARGUMENT-BINDINGS. 178LEVEL is the trace level, ARGS is the list of arguments passed to FUNCTION,
182 (format "%s%s%d -> %s: %s\n" 179and CONTEXT is a string describing the dynamic context (e.g. values of
183 (mapconcat 'char-to-string (make-string (1- level) ?|) " ") 180some global variables)."
184 (if (> level 1) " " "") 181 (let ((print-circle t))
185 level 182 (format "%s%s%d -> %S%s\n"
186 function 183 (mapconcat 'char-to-string (make-string (1- level) ?|) " ")
187 (let ((print-circle t)) 184 (if (> level 1) " " "")
188 (mapconcat (lambda (binding) 185 level
189 (concat 186 (cons function args)
190 (symbol-name (ad-arg-binding-field binding 'name)) 187 context)))
191 "=" 188
192 ;; do this so we'll see strings: 189(defun trace-exit-message (function level value context)
193 (prin1-to-string 190 "Generate a string that describes that FUNCTION has exited.
194 (ad-arg-binding-field binding 'value)))) 191LEVEL is the trace level, VALUE value returned by FUNCTION,
195 argument-bindings 192and CONTEXT is a string describing the dynamic context (e.g. values of
196 " ")))) 193some global variables)."
197 194 (let ((print-circle t))
198(defun trace-exit-message (function level value) 195 (format "%s%s%d <- %s: %S%s\n"
199 ;; Generates a string that describes that FUNCTION has been exited at 196 (mapconcat 'char-to-string (make-string (1- level) ?|) " ")
200 ;; trace LEVEL and that it returned VALUE. 197 (if (> level 1) " " "")
201 (format "%s%s%d <- %s: %s\n" 198 level
202 (mapconcat 'char-to-string (make-string (1- level) ?|) " ") 199 function
203 (if (> level 1) " " "") 200 ;; Do this so we'll see strings:
204 level 201 value
205 function 202 context)))
206 ;; do this so we'll see strings: 203
207 (let ((print-circle t)) (prin1-to-string value)))) 204(defvar trace--timer nil)
208 205
209(defun trace-make-advice (function buffer background) 206(defun trace-make-advice (function buffer background context)
210 ;; Builds the piece of advice to be added to FUNCTION's advice info 207 "Build the piece of advice to be added to trace FUNCTION.
211 ;; so that it will generate the proper trace output in BUFFER 208FUNCTION is the name of the traced function.
212 ;; (quietly if BACKGROUND is t). 209BUFFER is the buffer where the trace should be printed.
213 (ad-make-advice 210BACKGROUND if nil means to display BUFFER.
214 trace-advice-name nil t 211CONTEXT if non-nil should be a function that returns extra info that should
215 `(advice 212be printed along with the arguments in the trace."
216 lambda () 213 (lambda (body &rest args)
217 (let ((trace-level (1+ trace-level)) 214 (let ((trace-level (1+ trace-level))
218 (trace-buffer (get-buffer-create ,buffer))) 215 (trace-buffer (get-buffer-create buffer))
219 (unless inhibit-trace 216 (ctx (funcall context)))
220 (with-current-buffer trace-buffer 217 (unless inhibit-trace
221 (set (make-local-variable 'window-point-insertion-type) t) 218 (with-current-buffer trace-buffer
222 ,(unless background '(display-buffer trace-buffer)) 219 (set (make-local-variable 'window-point-insertion-type) t)
223 (goto-char (point-max)) 220 (unless (or background trace--timer
224 ;; Insert a separator from previous trace output: 221 (get-buffer-window trace-buffer 'visible))
225 (if (= trace-level 1) (insert trace-separator)) 222 (setq trace--timer
226 (insert 223 ;; Postpone the display to some later time, in case we
227 (trace-entry-message 224 ;; can't actually do it now.
228 ',function trace-level ad-arg-bindings)))) 225 (run-with-timer 0 nil
229 ad-do-it 226 (lambda ()
230 (unless inhibit-trace 227 (setq trace--timer nil)
231 (with-current-buffer trace-buffer 228 (display-buffer trace-buffer)))))
232 ,(unless background '(display-buffer trace-buffer)) 229 (goto-char (point-max))
233 (goto-char (point-max)) 230 ;; Insert a separator from previous trace output:
234 (insert 231 (if (= trace-level 1) (insert trace-separator))
235 (trace-exit-message 232 (insert
236 ',function trace-level ad-return-value)))))))) 233 (trace-entry-message
237 234 function trace-level args ctx))))
238(defun trace-function-internal (function buffer background) 235 (let ((result))
239 ;; Adds trace advice for FUNCTION and activates it. 236 (unwind-protect
240 (ad-add-advice 237 (setq result (list (apply body args)))
241 function 238 (unless inhibit-trace
242 (trace-make-advice function (or buffer trace-buffer) background) 239 (let ((ctx (funcall context)))
243 'around 'last) 240 (with-current-buffer trace-buffer
244 (ad-activate function nil)) 241 (unless background (display-buffer trace-buffer))
242 (goto-char (point-max))
243 (insert
244 (trace-exit-message
245 function
246 trace-level
247 (if result (car result) '\!non-local\ exit\!)
248 ctx))))))
249 (car result)))))
250
251(defun trace-function-internal (function buffer background context)
252 "Add trace advice for FUNCTION."
253 (advice-add
254 function :around
255 (trace-make-advice function (or buffer trace-buffer) background
256 (or context (lambda () "")))
257 `((name . ,trace-advice-name))))
245 258
246(defun trace-is-traced (function) 259(defun trace-is-traced (function)
247 (ad-find-advice function 'around trace-advice-name)) 260 (advice-member-p trace-advice-name function))
261
262(defun trace--read-args (prompt)
263 (cons
264 (intern (completing-read prompt obarray 'fboundp t))
265 (when current-prefix-arg
266 (list
267 (read-buffer "Output to buffer: " trace-buffer)
268 (let ((exp
269 (let ((minibuffer-completing-symbol t))
270 (read-from-minibuffer "Context expression: "
271 nil read-expression-map t
272 'read-expression-history))))
273 `(lambda ()
274 (let ((print-circle t))
275 (concat " [" (prin1-to-string ,exp) "]"))))))))
248 276
249;;;###autoload 277;;;###autoload
250(defun trace-function (function &optional buffer) 278(defun trace-function-foreground (function &optional buffer context)
251 "Traces FUNCTION with trace output going to BUFFER. 279 "Traces FUNCTION with trace output going to BUFFER.
252For every call of FUNCTION Lisp-style trace messages that display argument 280For every call of FUNCTION Lisp-style trace messages that display argument
253and return values will be inserted into BUFFER. This function generates the 281and return values will be inserted into BUFFER. This function generates the
@@ -255,14 +283,11 @@ trace advice for FUNCTION and activates it together with any other advice
255there might be!! The trace BUFFER will popup whenever FUNCTION is called. 283there might be!! The trace BUFFER will popup whenever FUNCTION is called.
256Do not use this to trace functions that switch buffers or do any other 284Do not use this to trace functions that switch buffers or do any other
257display oriented stuff, use `trace-function-background' instead." 285display oriented stuff, use `trace-function-background' instead."
258 (interactive 286 (interactive (trace--read-args "Trace function: "))
259 (list 287 (trace-function-internal function buffer nil context))
260 (intern (completing-read "Trace function: " obarray 'fboundp t))
261 (read-buffer "Output to buffer: " trace-buffer)))
262 (trace-function-internal function buffer nil))
263 288
264;;;###autoload 289;;;###autoload
265(defun trace-function-background (function &optional buffer) 290(defun trace-function-background (function &optional buffer context)
266 "Traces FUNCTION with trace output going quietly to BUFFER. 291 "Traces FUNCTION with trace output going quietly to BUFFER.
267When this tracing is enabled, every call to FUNCTION writes 292When this tracing is enabled, every call to FUNCTION writes
268a Lisp-style trace message (showing the arguments and return value) 293a Lisp-style trace message (showing the arguments and return value)
@@ -272,12 +297,11 @@ The trace output goes to BUFFER quietly, without changing
272the window or buffer configuration. 297the window or buffer configuration.
273 298
274BUFFER defaults to `trace-buffer'." 299BUFFER defaults to `trace-buffer'."
275 (interactive 300 (interactive (trace--read-args "Trace function in background: "))
276 (list 301 (trace-function-internal function buffer t context))
277 (intern 302
278 (completing-read "Trace function in background: " obarray 'fboundp t)) 303;;;###autoload
279 (read-buffer "Output to buffer: " trace-buffer))) 304(defalias 'trace-function 'trace-function-foreground)
280 (trace-function-internal function buffer t))
281 305
282(defun untrace-function (function) 306(defun untrace-function (function)
283 "Untraces FUNCTION and possibly activates all remaining advice. 307 "Untraces FUNCTION and possibly activates all remaining advice.
@@ -285,16 +309,14 @@ Activation is performed with `ad-update', hence remaining advice will get
285activated only if the advice of FUNCTION is currently active. If FUNCTION 309activated only if the advice of FUNCTION is currently active. If FUNCTION
286was not traced this is a noop." 310was not traced this is a noop."
287 (interactive 311 (interactive
288 (list (ad-read-advised-function "Untrace function" 'trace-is-traced))) 312 (list (intern (completing-read "Untrace function: "
289 (when (trace-is-traced function) 313 obarray #'trace-is-traced t))))
290 (ad-remove-advice function 'around trace-advice-name) 314 (advice-remove function trace-advice-name))
291 (ad-update function)))
292 315
293(defun untrace-all () 316(defun untrace-all ()
294 "Untraces all currently traced functions." 317 "Untraces all currently traced functions."
295 (interactive) 318 (interactive)
296 (ad-do-advised-functions (function) 319 (mapatoms #'untrace-function))
297 (untrace-function function)))
298 320
299(provide 'trace) 321(provide 'trace)
300 322