forked from Github/emacs
Compare commits
13 commits
master
...
scratch/bu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5397d684d8 | ||
|
|
faf43bcab1 | ||
|
|
69e105bc48 | ||
|
|
b1c896225c | ||
|
|
38c6820245 | ||
|
|
32d26d7411 | ||
|
|
3c90fa62ae | ||
|
|
7de3e1b855 | ||
|
|
d596474af0 | ||
|
|
9ec96fdc04 | ||
|
|
c063ca0794 | ||
|
|
1e80ca7211 | ||
|
|
904a03af5b |
5 changed files with 727 additions and 60 deletions
|
|
@ -20,14 +20,10 @@ alter its internal state.
|
|||
You can use Edebug, a source-level debugger for Emacs Lisp.
|
||||
|
||||
@item
|
||||
@cindex tracing Lisp programs
|
||||
You can trace the execution of functions involved in the problem using
|
||||
the tracing facilities provided by the @file{trace.el} package. This
|
||||
package provides the functions @code{trace-function-foreground} and
|
||||
@code{trace-function-background} for tracing function calls, and
|
||||
@code{trace-values} for adding values of select variables to the
|
||||
trace. For the details, see the documentation of these facilities in
|
||||
@file{trace.el}.
|
||||
You can trace the execution of functions involved in the problem
|
||||
(logging function calls, their arguments and return values, and other
|
||||
context values) using the tracing facilities provided by the
|
||||
@file{trace.el} package.
|
||||
|
||||
@item
|
||||
If a syntactic problem is preventing Lisp from even reading the
|
||||
|
|
@ -59,6 +55,7 @@ function (@pxref{Terminal Output}).
|
|||
* Syntax Errors:: How to find syntax errors.
|
||||
* Test Coverage:: Ensuring you have tested all branches in your code.
|
||||
* Profiling:: Measuring the resources that your code uses.
|
||||
* Tracing:: Log function calls, arguments, and return values.
|
||||
@end menu
|
||||
|
||||
@node Debugger
|
||||
|
|
@ -1072,3 +1069,327 @@ the @command{gprof} utility. This feature is mainly useful for
|
|||
debugging Emacs. It actually stops the Lisp-level @kbd{M-x
|
||||
profiler-@dots{}} commands described above from working.
|
||||
@end ifnottex
|
||||
|
||||
|
||||
@node Tracing
|
||||
@section Tracing
|
||||
@cindex tracing
|
||||
@cindex trace
|
||||
@cindex trace functions
|
||||
@cindex tracing Lisp programs
|
||||
|
||||
You can trace the execution of functions using the tracing facilities
|
||||
provided by the @file{trace.el} library. Many functions can be traced
|
||||
at the same time. The commands @code{trace-function-foreground} and
|
||||
@code{trace-function-background} add a new trace to a single specified
|
||||
function. The commands @code{trace-package}, @code{trace-regexp}, and
|
||||
@code{trace-library} enable traces to be added to functions en masse.
|
||||
Traces can also be added to autoloaded functions -- the associated
|
||||
function will be traced if and when it is defined.
|
||||
|
||||
@vindex trace-buffer
|
||||
Calls to traced functions, including the values of their arguments and
|
||||
their return values, are logged to the @file{*trace-output*} buffer
|
||||
(or another buffer as specified -- either by the @code{trace-buffer}
|
||||
user option, or as the @var{buffer} argument to a tracing command).
|
||||
|
||||
@anchor{trace context}
|
||||
@cindex @code{context} in trace functions
|
||||
Optional @var{context} expressions are also evaluated, both when the
|
||||
associated function is called and again when it returns, with the
|
||||
value logged within square brackets alongside the call-time arguments
|
||||
or return value respectively. This could be used to track the current
|
||||
buffer or position of point, for instance. If @var{context} is a
|
||||
function, it will be called (with no arguments) to obtain the value to
|
||||
be inserted into the trace output buffer.
|
||||
|
||||
Finally, you may add explicit calls to @code{trace-values} to your
|
||||
code, to log arbitrary values to the trace buffer at any time.
|
||||
|
||||
@anchor{background and foreground tracing}
|
||||
@cindex foreground tracing
|
||||
@cindex background tracing
|
||||
When using ``foreground'' tracing, the output buffer will be displayed
|
||||
whenever a traced function is called. When using ``background''
|
||||
tracing the output buffer is not forcibly displayed. Because
|
||||
foreground tracing affects the window configuration, it should not be
|
||||
used to trace functions that switch buffers, or have other
|
||||
display-oriented behaviour. To avoid such problems, all bulk tracing
|
||||
commands use background tracing -- @code{trace-function-foreground} is
|
||||
the only command providing foreground tracing.
|
||||
|
||||
@menu
|
||||
* Commands for Tracing:: Commands and variables.
|
||||
* Restrictions on Tracing:: Limitations on what can be traced.
|
||||
* Examples of Tracing:: Usage examples.
|
||||
@end menu
|
||||
|
||||
@node Commands for Tracing
|
||||
@subsection Commands and variables for tracing functions
|
||||
|
||||
@defopt trace-buffer
|
||||
This variable defines the buffer where trace output will be logged to
|
||||
by default. Trace commands can be passed a @var{buffer} argument to
|
||||
specify a non-default output buffer.
|
||||
@end defopt
|
||||
|
||||
@defvar inhibit-trace
|
||||
If this variable is non-@code{nil}, all tracing is temporarily
|
||||
inhibited (including any calls to @code{trace-values}).
|
||||
@end defvar
|
||||
|
||||
@deffn Command trace-function-background function &optional buffer context
|
||||
This function adds a background trace (@pxref{background and
|
||||
foreground tracing}) to @var{function}. When called interactively, it
|
||||
prompts for @var{function} in the minibuffer. With a prefix argument,
|
||||
it also prompts for the trace output @var{buffer} (defaulting to the
|
||||
value of @code{trace-buffer}), and a Lisp expression @var{context}
|
||||
(@pxref{trace context}).
|
||||
|
||||
If @var{function} is an autoload, the associated function will be
|
||||
traced if and when it is defined.
|
||||
|
||||
Calling @code{trace-function-background} for an already-traced
|
||||
@var{function} will update the optional argument behaviours to respect
|
||||
the new values (and change to background tracing, if foreground
|
||||
tracing was previously used).
|
||||
@end deffn
|
||||
|
||||
@deffn Command trace-function-foreground function &optional buffer context
|
||||
This function adds a foreground trace (@pxref{background and
|
||||
foreground tracing}) to @var{function}. When called interactively, it
|
||||
prompts for @var{function} in the minibuffer. With a prefix argument,
|
||||
it also prompts for the trace output @var{buffer} (defaulting to the
|
||||
value of @code{trace-buffer}), and a Lisp expression @var{context}
|
||||
(@pxref{trace context}).
|
||||
|
||||
If @var{function} is an autoload, the associated function will be
|
||||
traced if and when it is defined.
|
||||
|
||||
Calling @code{trace-function-foreground} for an already-traced
|
||||
@var{function} will update the optional argument behaviours to respect
|
||||
the new values (and change to foreground tracing, if background
|
||||
tracing was previously used).
|
||||
@end deffn
|
||||
|
||||
@deffn Command trace-package prefix &optional buffer context after-load
|
||||
This function calls @code{trace-function-background} for all functions
|
||||
with names starting with @var{prefix}.
|
||||
|
||||
For any autoload declarations matching @var{prefix}, the associated
|
||||
function will be traced if and when it is defined.
|
||||
|
||||
With a prefix argument, also prompt for the trace output @var{buffer}
|
||||
(defaulting to the value of @code{trace-buffer}); a Lisp expression
|
||||
@var{context} (@pxref{trace context}); and boolean query
|
||||
@var{after-load}. If @var{after-load} is non-@code{nil} then
|
||||
re-process @var{prefix} after loading any file.
|
||||
|
||||
Calling @code{trace-package} again for the same @var{prefix} will
|
||||
update the optional argument behaviours to respect the new values.
|
||||
@end deffn
|
||||
|
||||
@deffn Command trace-regexp regexp &optional buffer context after-load
|
||||
This function calls @code{trace-function-background} for all functions
|
||||
matching in @var{regexp}.
|
||||
|
||||
Background tracing is used. Switch to the trace output buffer to view
|
||||
the results. For any autoload declarations matching @var{regexp}, the
|
||||
associated function will be traced if and when it is defined.
|
||||
|
||||
With a prefix argument, also prompt for the trace output @var{buffer}
|
||||
(defaulting to the value of @code{trace-buffer}); a Lisp expression
|
||||
@var{context} (@pxref{trace context}); and boolean query
|
||||
@var{after-load}. If @var{after-load} is non-@code{nil} then
|
||||
re-process @var{regexp} after loading any file.
|
||||
|
||||
Calling @code{trace-regexp} again for the same @var{regexp} will
|
||||
update the optional argument behaviours to respect the new values.
|
||||
|
||||
@strong{Warning:} Do not attempt to trace all functions. Tracing too
|
||||
many functions at one time will render Emacs unusable.
|
||||
@end deffn
|
||||
|
||||
@deffn Command trace-library library &optional buffer context after-load
|
||||
This function calls @code{trace-function-background} for all functions
|
||||
currently defined in @var{library} according to @var{load-history}.
|
||||
|
||||
For any autoload declarations with a file name matching @var{library},
|
||||
the associated function will be traced if and when it is defined.
|
||||
(Autoload file names will not match if @var{library} specifies a
|
||||
longer, more specific path.)
|
||||
|
||||
With a prefix argument, also prompt for the trace output @var{buffer}
|
||||
(defaulting to the value of @code{trace-buffer}); a Lisp expression
|
||||
@var{context} (@pxref{trace context}); and boolean query
|
||||
@var{after-load}. If @var{after-load} is non-@code{nil} then
|
||||
re-process @var{library} after loading it, (ensuring that all of its
|
||||
functions will be traced).
|
||||
|
||||
Calling @code{trace-library} again for the same @var{library} will
|
||||
update the optional argument behaviours to respect the new values.
|
||||
@end deffn
|
||||
|
||||
@deffn Command trace-currently-traced &optional display-message
|
||||
This function returns the list of currently traced function symbols.
|
||||
When called interactively, or if @var{display-message} is
|
||||
non-@code{nil}, it displays the list as a message.
|
||||
@end deffn
|
||||
|
||||
@deffn Command untrace-function function
|
||||
This function removes the trace on @var{function}. This has no effect
|
||||
if @var{function} was not being traced. When called interactively, it
|
||||
prompts for @var{function} in the minibuffer.
|
||||
@end deffn
|
||||
|
||||
@deffn Command untrace-package prefix
|
||||
This function calls @code{untrace-function} for all functions with
|
||||
names starting with @var{prefix}. When called interactively, it
|
||||
prompts for @var{prefix} in the minibuffer.
|
||||
@end deffn
|
||||
|
||||
@deffn Command untrace-regexp regexp
|
||||
This function calls @code{untrace-function} for all functions matching
|
||||
@var{regexp}. When called interactively, it prompts for @var{regexp}
|
||||
in the minibuffer.
|
||||
@end deffn
|
||||
|
||||
@deffn Command untrace-library library
|
||||
This function calls @code{untrace-function} for all functions defined
|
||||
in @var{library}. When called interactively, it prompts for
|
||||
@var{library} in the minibuffer.
|
||||
@end deffn
|
||||
|
||||
@deffn Command untrace-all
|
||||
This function calls @code{untrace-function} for all functions.
|
||||
@end deffn
|
||||
|
||||
@deffn Function trace-values &rest values
|
||||
This function inserts a message showing @var{values} into the trace
|
||||
buffer. You can add explicit calls to @code{trace-values} into your
|
||||
functions in order to provide additional tracing information.
|
||||
@end deffn
|
||||
|
||||
|
||||
@node Restrictions on Tracing
|
||||
@subsection Limitations on what can be traced
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Only functions/macros/subrs that are called via their function cell
|
||||
will generate trace output; hence, you won't get trace output for:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Macros that were expanded during compilation.
|
||||
|
||||
@item
|
||||
Subrs called directly from other subrs/C-code.
|
||||
|
||||
@item
|
||||
Byte-compiled calls to subrs that have special byte-codes associated
|
||||
with them:
|
||||
|
||||
@example
|
||||
(sort (cl-loop for sym being the symbols
|
||||
if (and (subrp (symbol-function sym))
|
||||
(plist-get (symbol-plist sym)
|
||||
'byte-opcode))
|
||||
collect sym)
|
||||
(lambda (s1 s2)
|
||||
(string< (symbol-name s1) (symbol-name s2))))
|
||||
@end example
|
||||
@end itemize
|
||||
|
||||
@item
|
||||
Tracing too many functions at one time will render Emacs unusable. Do
|
||||
not attempt to trace all functions, and take care with the arguments
|
||||
passed to the bulk tracing commands @code{trace-package} and
|
||||
@code{trace-regexp}.
|
||||
|
||||
@item
|
||||
Foreground tracing should not be used to trace functions that switch
|
||||
buffers, or have other display-oriented behaviour.
|
||||
|
||||
@item
|
||||
Each function can only be subject to a single trace. When a function
|
||||
which is already being traced is targeted by any tracing command, the
|
||||
new trace criteria (including optional argument values) will replace
|
||||
the previous trace criteria for that function.
|
||||
|
||||
Note that this also means there is no need to un-trace a function in
|
||||
order to re-trace it with different arguments.
|
||||
|
||||
@item
|
||||
All the restrictions that apply to @file{nadvice.el} also apply to
|
||||
tracing (as tracing is implemented using advice). @xref{Advising
|
||||
Functions}.
|
||||
@end itemize
|
||||
|
||||
@node Examples of Tracing
|
||||
@subsection Usage examples for function tracing
|
||||
|
||||
The following is example trace output, including a context list
|
||||
expression, for a function which also makes a call to
|
||||
@code{trace-values}. The left hand column indicates the evaluation
|
||||
depth of the function call.
|
||||
|
||||
@example
|
||||
@group
|
||||
1 -> (funcname arg1 arg2) [(context1 context2)]
|
||||
1 -> (trace-values value1 value2)
|
||||
1 <- funcname: return [(context1 context2)]
|
||||
@end group
|
||||
@end example
|
||||
|
||||
The trace output display of recursion/nesting levels can be
|
||||
demonstrated by tracing a recursive function, such as a simplistic
|
||||
factorial implementation:
|
||||
|
||||
@example
|
||||
@group
|
||||
(defun fact (n)
|
||||
"Calculate factorial of N."
|
||||
(if (eql n 0) 1
|
||||
(* n (fact (1- n)))))
|
||||
@result{} fact
|
||||
|
||||
(trace-function 'fact)
|
||||
@result{} fact
|
||||
|
||||
Now, evaluating this...
|
||||
|
||||
(fact 4)
|
||||
@result{} 24
|
||||
|
||||
...will generate the following in *trace-buffer*:
|
||||
|
||||
1 -> fact: n=4
|
||||
| 2 -> fact: n=3
|
||||
| | 3 -> fact: n=2
|
||||
| | | 4 -> fact: n=1
|
||||
| | | | 5 -> fact: n=0
|
||||
| | | | 5 <- fact: 1
|
||||
| | | 4 <- fact: 1
|
||||
| | 3 <- fact: 2
|
||||
| 2 <- fact: 6
|
||||
1 <- fact: 24
|
||||
@end group
|
||||
|
||||
Try the following for some more interesting trace output:
|
||||
|
||||
@group
|
||||
(defun ack (x y z)
|
||||
(if (= x 0)
|
||||
(+ y z)
|
||||
(if (and (<= x 2) (= z 0))
|
||||
(1- x)
|
||||
(if (and (> x 2) (= z 0))
|
||||
y
|
||||
(ack (1- x) y (ack x y (1- z)))))))
|
||||
|
||||
(trace-function 'ack)
|
||||
|
||||
(ack 3 3 1)
|
||||
@end group
|
||||
@end example
|
||||
|
|
|
|||
|
|
@ -669,6 +669,7 @@ Debugging Lisp Programs
|
|||
* Syntax Errors:: How to find syntax errors.
|
||||
* Test Coverage:: Ensuring you have tested all branches in your code.
|
||||
* Profiling:: Measuring the resources that your code uses.
|
||||
* Tracing:: Log function calls, arguments, and return values.
|
||||
|
||||
The Lisp Debugger
|
||||
|
||||
|
|
|
|||
|
|
@ -2507,15 +2507,13 @@ Dashes sufficient to fill the remainder of the mode line.
|
|||
@item %%
|
||||
The character @samp{%}---this is how to include a literal @samp{%} in a
|
||||
string in which @code{%}-constructs are allowed.
|
||||
@end table
|
||||
|
||||
The following @code{%}-construct is still supported, but it is
|
||||
obsolete, since you can get the same result using the variable
|
||||
@code{mode-name}.
|
||||
|
||||
@table @code
|
||||
@item %m
|
||||
The value of @code{mode-name}.
|
||||
Obsolete; use the @code{mode-name} variable instead. The @code{%m}
|
||||
construct is still supported, but it is inadequate, as it produces an
|
||||
empty string if the value of the @code{mode-name} variable is a
|
||||
non-string mode-line construct (for example, in
|
||||
@code{emacs-lisp-mode}).
|
||||
@end table
|
||||
|
||||
@node Properties in Mode
|
||||
|
|
|
|||
10
etc/NEWS
10
etc/NEWS
|
|
@ -1918,6 +1918,16 @@ The newly created buffer will be displayed via 'display-buffer', which
|
|||
can be customized through the usual mechanism of 'display-buffer-alist'
|
||||
and friends.
|
||||
|
||||
** Trace
|
||||
|
||||
+++
|
||||
*** New commands 'trace-package', 'trace-regexp', and 'trace-library'
|
||||
(and their counterparts 'untrace-package', 'untrace-regexp', and
|
||||
'untrace-library') allow for the bulk tracing of calls to functions
|
||||
with names matching a specified prefix or regexp, or functions defined
|
||||
by a specified file. New command 'trace-currently-traced' lists the
|
||||
traced function symbols.
|
||||
|
||||
** Tramp
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@
|
|||
|
||||
;; Restrictions:
|
||||
;; =============
|
||||
;; - Traced subrs when called interactively will always show nil as the
|
||||
;; value of their arguments.
|
||||
;; - Only functions/macros/subrs that are called via their function cell will
|
||||
;; generate trace output, hence, you won't get trace output for:
|
||||
;; + Subrs called directly from other subrs/C-code
|
||||
|
|
@ -52,14 +50,28 @@
|
|||
|
||||
;; Usage:
|
||||
;; ======
|
||||
;; - To trace a function say `M-x trace-function', which will ask you for the
|
||||
;; - To trace a function use `M-x trace-function', which will ask you for the
|
||||
;; name of the function/subr/macro to trace.
|
||||
;; - If you want to trace a function that switches buffers or does other
|
||||
;; display oriented stuff use `M-x trace-function-background', which will
|
||||
;; generate the trace output silently in the background without popping
|
||||
;; up windows and doing other irritating stuff.
|
||||
;; - To untrace a function say `M-x untrace-function'.
|
||||
;; - To untrace all currently traced functions say `M-x untrace-all'.
|
||||
;; - `M-x trace-package' will ask you for a function name prefix, and trace
|
||||
;; (in the background) all matching functions.
|
||||
;; - `M-x trace-regexp' will ask you for a function name pattern (regexp),
|
||||
;; and trace (in the background) all matching functions.
|
||||
;; - `M-x trace-library' will ask you for a library name, and trace (in the
|
||||
;; background) all functions defined by that file.
|
||||
;; - Interactively in all cases, a prefix argument can be used to prompt
|
||||
;; for the output buffer and context arguments and, for bulk tracing
|
||||
;; commands, whether or not the traces should be automatically updated
|
||||
;; after loading lisp files.
|
||||
;; - To untrace a function use `M-x untrace-function'.
|
||||
;; - To untrace multiple functions by prefix use `M-x untrace-package'.
|
||||
;; - To untrace multiple functions by regexp use `M-x untrace-regexp'.
|
||||
;; - To untrace multiple functions by file use `M-x untrace-library'.
|
||||
;; - To untrace all currently traced functions use `M-x untrace-all'.
|
||||
;; - To list all currently traced functions use `M-x trace-currently-traced'.
|
||||
|
||||
;; Examples:
|
||||
;; =========
|
||||
|
|
@ -120,6 +132,23 @@
|
|||
|
||||
;;; Change Log:
|
||||
|
||||
;; 2017-06-17 Phil Sainty
|
||||
;; * New commands `trace-package', `untrace-package', `trace-regexp',
|
||||
;; `untrace-regexp', `trace-library', `untrace-library'.
|
||||
;; * Documentation added to the elisp reference manual.
|
||||
;;
|
||||
;; 2012-2014 Stefan Monnier, Glenn Morris
|
||||
;; * Adapted for nadvice.el
|
||||
;; * New `context' argument and display in trace buffer
|
||||
;; * `trace-function' renamed to (and now an alias of)
|
||||
;; `trace-function-foreground'
|
||||
;;
|
||||
;; 2005-02-27 Stefan Monnier
|
||||
;; * New `inhibit-trace' variable
|
||||
;;
|
||||
;; 1998-04-05 Stephen Eglen
|
||||
;; * New customize group `trace'
|
||||
;;
|
||||
;; Revision 2.0 1993/05/18 00:41:16 hans
|
||||
;; * Adapted for advice.el 2.0; it now also works
|
||||
;; for GNU Emacs-19 and Lemacs
|
||||
|
|
@ -134,6 +163,8 @@
|
|||
|
||||
;;; Code:
|
||||
|
||||
(eval-when-compile (require 'cl-macs))
|
||||
|
||||
(defgroup trace nil
|
||||
"Tracing facility for Emacs Lisp functions."
|
||||
:prefix "trace-"
|
||||
|
|
@ -181,7 +212,7 @@ some global variables)."
|
|||
;; FIXME: Make it so we can click the function name to jump to its
|
||||
;; definition and/or untrace it.
|
||||
(cons function args)
|
||||
context)))
|
||||
(if context (format " [%s]" context) ""))))
|
||||
|
||||
(defun trace-exit-message (function level value context)
|
||||
"Generate a string that describes that FUNCTION has exited.
|
||||
|
|
@ -197,7 +228,7 @@ some global variables)."
|
|||
function
|
||||
;; Do this so we'll see strings:
|
||||
value
|
||||
context)))
|
||||
(if context (format " [%s]" context) ""))))
|
||||
|
||||
(defvar trace--timer nil)
|
||||
|
||||
|
|
@ -218,8 +249,14 @@ some global variables)."
|
|||
FUNCTION is the name of the traced function.
|
||||
BUFFER is the buffer where the trace should be printed.
|
||||
BACKGROUND if nil means to display BUFFER.
|
||||
CONTEXT if non-nil should be a function that returns extra info that should
|
||||
be printed along with the arguments in the trace."
|
||||
CONTEXT, if non-nil, should be either a function or an expression
|
||||
that returns extra info, which will be printed after the
|
||||
arguments or return value in the trace."
|
||||
(setq context (if context
|
||||
(if (functionp context)
|
||||
context
|
||||
(trace-make-context context))
|
||||
(lambda () "")))
|
||||
(lambda (body &rest args)
|
||||
(let ((trace-level (1+ trace-level))
|
||||
(trace-buffer (get-buffer-create buffer))
|
||||
|
|
@ -227,6 +264,7 @@ be printed along with the arguments in the trace."
|
|||
(ctx (funcall context)))
|
||||
(unless inhibit-trace
|
||||
(with-current-buffer trace-buffer
|
||||
(setq-local page-delimiter (format "^%s" (regexp-quote trace-separator)))
|
||||
(setq-local window-point-insertion-type t)
|
||||
(unless background (trace--display-buffer trace-buffer))
|
||||
(goto-char (point-max))
|
||||
|
|
@ -255,41 +293,70 @@ be printed along with the arguments in the trace."
|
|||
"Add trace advice for FUNCTION."
|
||||
(advice-add
|
||||
function :around
|
||||
(trace-make-advice function (or buffer trace-buffer) background
|
||||
(or context (lambda () "")))
|
||||
(trace-make-advice function (or buffer trace-buffer) background context)
|
||||
`((name . ,trace-advice-name) (depth . -100))))
|
||||
|
||||
(defun trace-is-traced (function)
|
||||
(defun trace-is-traceable-p (sym)
|
||||
"Whether the given symbol is a traceable function.
|
||||
Autoloaded functions are traceable."
|
||||
(or (functionp sym) (macrop sym)))
|
||||
|
||||
(defun trace-is-traced-p (function)
|
||||
"Whether FUNCTION is currently traced."
|
||||
(advice-member-p trace-advice-name function))
|
||||
|
||||
(defun trace--read-args (prompt)
|
||||
"Read a function name, prompting with string PROMPT.
|
||||
If `current-prefix-arg' is non-nil, also read a buffer and a \"context\"
|
||||
\(Lisp expression). Return (FUNCTION BUFFER FUNCTION-CONTEXT)."
|
||||
(cons
|
||||
(let ((default (function-called-at-point)))
|
||||
(intern (completing-read (format-prompt prompt default)
|
||||
obarray 'fboundp t nil nil
|
||||
(if default (symbol-name default)))))
|
||||
(when current-prefix-arg
|
||||
(list
|
||||
(read-buffer "Output to buffer" trace-buffer)
|
||||
(let ((exp
|
||||
(read-from-minibuffer "Context expression: "
|
||||
nil read-expression-map t
|
||||
'read-expression-history)))
|
||||
(lambda ()
|
||||
(let ((print-circle t)
|
||||
(print-escape-newlines t))
|
||||
(concat " [" (prin1-to-string (eval exp t)) "]"))))))))
|
||||
(define-obsolete-function-alias 'trace-is-traced 'trace-is-traced-p "29.1")
|
||||
|
||||
(defun trace-currently-traced (&optional display-message)
|
||||
"Return the list of currently traced function symbols.
|
||||
Interactively, display the list as a message."
|
||||
(interactive "p")
|
||||
(let ((tracelist (cl-loop for sym being the symbols
|
||||
if (trace-is-traced-p sym)
|
||||
collect sym)))
|
||||
(when display-message
|
||||
(message "%S" tracelist))
|
||||
tracelist))
|
||||
|
||||
(defun trace--read-function (prompt)
|
||||
"Read a function name, prompting with string PROMPT."
|
||||
(let ((default (function-called-at-point)))
|
||||
(intern (completing-read (format-prompt prompt default)
|
||||
obarray 'trace-is-traceable-p t nil nil
|
||||
(if default (symbol-name default))))))
|
||||
|
||||
(defun trace--read-library (&optional prompt)
|
||||
"Read a library name, prompting with string PROMPT."
|
||||
(completing-read
|
||||
(or prompt "Library: ")
|
||||
(apply-partially 'locate-file-completion-table
|
||||
load-path (get-load-suffixes))))
|
||||
|
||||
(defun trace--read-extra-args ()
|
||||
"Read a buffer and a \"context\" (Lisp expression).
|
||||
Return (BUFFER CONTEXT)."
|
||||
(list
|
||||
(read-buffer "Output to buffer" trace-buffer)
|
||||
(when-let ((exp (read-from-minibuffer
|
||||
"Context expression: "
|
||||
nil read-expression-map t
|
||||
'read-expression-history "nil")))
|
||||
(trace-make-context exp))))
|
||||
|
||||
(defun trace-make-context (exp)
|
||||
"Return a context function for expression EXP."
|
||||
(lambda ()
|
||||
(let ((print-circle t)
|
||||
(print-escape-newlines t))
|
||||
(prin1-to-string (eval exp t)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun trace-function-foreground (function &optional buffer context)
|
||||
"Trace calls to function FUNCTION.
|
||||
With a prefix argument, also prompt for the trace buffer (default
|
||||
`trace-buffer'), and a Lisp expression CONTEXT. When called from
|
||||
Lisp, CONTEXT should be a function of no arguments which returns
|
||||
a value to insert into BUFFER during the trace.
|
||||
With a prefix argument, also prompt for the trace output BUFFER
|
||||
\(default `trace-buffer'), and a Lisp expression CONTEXT.
|
||||
When called from Lisp, CONTEXT should be a function of no arguments
|
||||
which returns a value to insert into BUFFER during the trace.
|
||||
|
||||
Tracing a function causes every call to that function to insert
|
||||
into BUFFER Lisp-style trace messages that display the function's
|
||||
|
|
@ -302,8 +369,14 @@ popup whenever FUNCTION is called. Do not use this function to trace
|
|||
functions that switch buffers, or do any other display-oriented
|
||||
stuff - use `trace-function-background' instead.
|
||||
|
||||
Calling `trace-function-foreground' again for the same FUNCTION
|
||||
will update the optional argument behaviours to respect the new
|
||||
values.
|
||||
|
||||
To stop tracing a function, use `untrace-function' or `untrace-all'."
|
||||
(interactive (trace--read-args "Trace function"))
|
||||
(interactive
|
||||
(cons (trace--read-function "Trace function")
|
||||
(and current-prefix-arg (trace--read-extra-args))))
|
||||
(trace-function-internal function buffer nil context))
|
||||
|
||||
;;;###autoload
|
||||
|
|
@ -311,26 +384,290 @@ To stop tracing a function, use `untrace-function' or `untrace-all'."
|
|||
"Trace calls to function FUNCTION, quietly.
|
||||
This is like `trace-function-foreground', but without popping up
|
||||
the output buffer or changing the window configuration."
|
||||
(interactive (trace--read-args "Trace function in background"))
|
||||
(interactive
|
||||
(cons (trace--read-function "Trace function in background")
|
||||
(and current-prefix-arg (trace--read-extra-args))))
|
||||
(trace-function-internal function buffer t context))
|
||||
|
||||
;;;###autoload
|
||||
(defalias 'trace-function 'trace-function-foreground)
|
||||
|
||||
(defun untrace-function (function)
|
||||
"Untraces FUNCTION and possibly activates all remaining advice.
|
||||
Activation is performed with `ad-update', hence remaining advice will get
|
||||
activated only if the advice of FUNCTION is currently active. If FUNCTION
|
||||
was not traced this is a noop."
|
||||
"Remove trace from FUNCTION. If FUNCTION was not traced this is a noop."
|
||||
(interactive
|
||||
(list (intern (completing-read "Untrace function: "
|
||||
obarray #'trace-is-traced t))))
|
||||
obarray #'trace-is-traced-p t))))
|
||||
(advice-remove function trace-advice-name))
|
||||
|
||||
;;;###autoload
|
||||
(defun trace-package (prefix &optional buffer context after-load)
|
||||
"Trace all functions with names starting with PREFIX.
|
||||
For example, to trace all diff functions, do the following:
|
||||
|
||||
\\[trace-package] RET diff- RET
|
||||
|
||||
Background tracing is used. Switch to the trace output buffer to
|
||||
view the results. For any autoload declarations matching PREFIX,
|
||||
the associated function will be traced if and when it is defined.
|
||||
|
||||
With a prefix argument, also prompt for the optional arguments.
|
||||
If AFTER-LOAD is non-nil then re-process PREFIX after loading any
|
||||
file. See `trace-function-foreground' for details of BUFFER and
|
||||
CONTEXT, and of foreground vs background tracing.
|
||||
|
||||
Calling `trace-package' again for the same PREFIX will update the
|
||||
optional argument behaviours to respect the new values.
|
||||
|
||||
See also `untrace-package'."
|
||||
;; Derived in part from `elp-instrument-package'.
|
||||
(interactive
|
||||
(cons (completing-read "Prefix of package to trace: "
|
||||
obarray #'trace-is-traceable-p)
|
||||
(and current-prefix-arg
|
||||
(nconc (trace--read-extra-args)
|
||||
(list (y-or-n-p "Update traces after loading files?"))))))
|
||||
(when (zerop (length prefix))
|
||||
(error "Tracing all Emacs functions would render Emacs unusable"))
|
||||
(mapc (lambda (name)
|
||||
(trace-function-background (intern name) buffer context))
|
||||
(all-completions prefix obarray #'trace-is-traceable-p))
|
||||
(message
|
||||
"Tracing to %s. Use %s to untrace a package, or %s to remove all traces."
|
||||
(or buffer trace-buffer)
|
||||
(substitute-command-keys "\\[untrace-package]")
|
||||
(substitute-command-keys "\\[untrace-all]"))
|
||||
;; Handle `after-load' argument.
|
||||
(when after-load
|
||||
(trace--after-load 'prefix prefix buffer context)))
|
||||
|
||||
(defun untrace-package (prefix)
|
||||
"Remove all traces from functions with names starting with PREFIX.
|
||||
|
||||
See also `trace-package'."
|
||||
(interactive
|
||||
(list (completing-read "Prefix of package to untrace: "
|
||||
obarray #'trace-is-traced-p)))
|
||||
(if (and (zerop (length prefix))
|
||||
(y-or-n-p "Remove all function traces?"))
|
||||
(untrace-all)
|
||||
(mapc (lambda (name)
|
||||
(untrace-function (intern name)))
|
||||
(all-completions prefix obarray #'trace-is-traced-p)))
|
||||
;; Remove any `after-load' behaviour.
|
||||
(trace--remove-after-load 'prefix prefix))
|
||||
|
||||
;;;###autoload
|
||||
(defun trace-regexp (regexp &optional buffer context after-load)
|
||||
"Trace all functions with names matching REGEXP.
|
||||
For example, to trace indentation-related functions, you could try:
|
||||
|
||||
\\[trace-regexp] RET indent\\|offset RET
|
||||
|
||||
Warning: Do not attempt to trace all functions. Tracing too many
|
||||
functions at one time will render Emacs unusable.
|
||||
|
||||
Background tracing is used. Switch to the trace output buffer to
|
||||
view the results. For any autoload declarations matching REGEXP,
|
||||
the associated function will be traced if and when it is defined.
|
||||
|
||||
With a prefix argument, also prompt for the optional arguments.
|
||||
If AFTER-LOAD is non-nil then re-process REGEXP after loading any
|
||||
file. See `trace-function-foreground' for details of BUFFER and
|
||||
CONTEXT, and of foreground vs background tracing.
|
||||
|
||||
Calling `trace-regexp' again for the same REGEXP will update the
|
||||
optional argument behaviours to respect the new values.
|
||||
|
||||
See also `untrace-regexp'."
|
||||
(interactive
|
||||
(cons (read-regexp "Regexp matching functions to trace: ")
|
||||
(and current-prefix-arg
|
||||
(nconc (trace--read-extra-args)
|
||||
(list (y-or-n-p "Update traces after loading files?"))))))
|
||||
(when (member regexp '("" "." ".+" ".*"))
|
||||
;; Not comprehensive, but it catches the most likely attempts.
|
||||
(error "Tracing all Emacs functions would render Emacs unusable"))
|
||||
(mapatoms
|
||||
(lambda (sym)
|
||||
(and (trace-is-traceable-p sym)
|
||||
(string-match-p regexp (symbol-name sym))
|
||||
(trace-function-background sym buffer context))))
|
||||
(message
|
||||
"Tracing to %s. Use %s to untrace by regexp, or %s to remove all traces."
|
||||
(or buffer trace-buffer)
|
||||
(substitute-command-keys "\\[untrace-regexp]")
|
||||
(substitute-command-keys "\\[untrace-all]"))
|
||||
;; Handle `after-load' argument.
|
||||
(when after-load
|
||||
(trace--after-load 'regexp regexp buffer context)))
|
||||
|
||||
(defun untrace-regexp (regexp)
|
||||
"Remove all traces from functions with names matching REGEXP.
|
||||
|
||||
See also `trace-regexp'."
|
||||
(interactive
|
||||
(list (read-regexp "Regexp matching functions to untrace: ")))
|
||||
(if (and (zerop (length regexp))
|
||||
(y-or-n-p "Remove all function traces?"))
|
||||
(untrace-all)
|
||||
(mapatoms
|
||||
(lambda (sym)
|
||||
(and (trace-is-traced-p sym)
|
||||
(string-match-p regexp (symbol-name sym))
|
||||
(untrace-function sym)))))
|
||||
;; Remove any `after-load' behaviour.
|
||||
(trace--remove-after-load 'regexp regexp))
|
||||
|
||||
;;;###autoload
|
||||
(defun trace-library (library &optional buffer context after-load)
|
||||
"Trace functions defined by LIBRARY.
|
||||
For example, to trace tramp.el functions, you could use:
|
||||
|
||||
\\[trace-library] RET tramp RET
|
||||
|
||||
Background tracing is used. Switch to the trace output buffer to
|
||||
view the results. For any autoload declarations with a file name
|
||||
matching LIBRARY, the associated function will be traced if and
|
||||
when it is defined. (Autoload file names will not match if LIBRARY
|
||||
specifies a longer, more specific path.)
|
||||
|
||||
With a prefix argument, also prompt for the optional arguments.
|
||||
If AFTER-LOAD is non-nil then re-process LIBRARY after loading it
|
||||
\(ensuring that all of its functions will be traced). See
|
||||
`trace-function-foreground' for details of BUFFER and CONTEXT,
|
||||
and of foreground vs background tracing.
|
||||
|
||||
Calling `trace-library' again for the same LIBRARY will update the
|
||||
optional argument behaviours to respect the new values.
|
||||
|
||||
See also `untrace-library'."
|
||||
(interactive
|
||||
(cons (trace--read-library)
|
||||
(and current-prefix-arg
|
||||
(nconc (trace--read-extra-args)
|
||||
(list (y-or-n-p "Update traces after loading this library?"))))))
|
||||
;; Build list of library functions and autoloads.
|
||||
(let ((defs (nconc (trace--library-defuns library)
|
||||
(trace--library-autoloads library))))
|
||||
;; Trace each of those definitions.
|
||||
(mapc (lambda (func)
|
||||
(trace-function-background func buffer context))
|
||||
defs))
|
||||
;; Handle `after-load' argument.
|
||||
(when after-load
|
||||
(trace--after-load 'library library buffer context)))
|
||||
|
||||
(defun trace--library-defuns (library)
|
||||
"Returns a list of loaded function definitions associated with LIBRARY."
|
||||
(delq nil (mapcar (lambda (x)
|
||||
(and (consp x)
|
||||
(eq (car x) 'defun)
|
||||
(cdr x)))
|
||||
(cdr (load-history-filename-element
|
||||
(load-history-regexp library))))))
|
||||
|
||||
(defun trace--library-autoloads (library)
|
||||
"Returns a list of all current autoloads associated with LIBRARY.
|
||||
|
||||
Autoload file names will not match if LIBRARY specifies a longer,
|
||||
more specific path than that of the autoload declaration itself."
|
||||
(let* ((functions nil)
|
||||
(filepattern (load-history-regexp library))
|
||||
(predicate (apply-partially 'trace--library-provides-autoload-p
|
||||
filepattern)))
|
||||
(mapatoms (lambda (sym)
|
||||
(when (funcall predicate sym)
|
||||
(push sym functions))))
|
||||
functions))
|
||||
|
||||
(defun trace--library-provides-autoload-p (filepattern sym)
|
||||
"Whether symbol SYM is an autoload associated with FILEPATTERN.
|
||||
|
||||
FILEPATTERN should be the result of calling `load-history-regexp'."
|
||||
(when (fboundp sym)
|
||||
(let ((f (symbol-function sym)))
|
||||
(and (autoloadp f)
|
||||
(string-match filepattern (cadr f))))))
|
||||
|
||||
(defun untrace-library (library)
|
||||
"Remove all traces from functions defined by LIBRARY.
|
||||
|
||||
See also `trace-library'."
|
||||
(interactive (list (trace--read-library)))
|
||||
;; Remove traces from known LIBRARY defuns.
|
||||
;; (Also process autoloads, in case LIBRARY is unloaded.)
|
||||
(let ((defs (nconc (trace--library-defuns library)
|
||||
(trace--library-autoloads library))))
|
||||
(mapc (lambda (func)
|
||||
(when (trace-is-traced-p func)
|
||||
(untrace-function func)))
|
||||
defs))
|
||||
;; Remove any `after-load' behaviour.
|
||||
(trace--remove-after-load 'library library))
|
||||
|
||||
(defvar trace--after-load-alist nil
|
||||
"List of trace types to update after loading.
|
||||
|
||||
Each list item has the form ((TYPE . VALUE) BUFFER CONTEXT),
|
||||
where TYPE is one of the symbols `prefix', `regexp', or `library';
|
||||
and VALUE is the respective first argument to `trace-package',
|
||||
`trace-regexp', or `trace-library'; with BUFFER and CONTEXT being
|
||||
the values of those arguments as they were passed to the same
|
||||
function.")
|
||||
|
||||
(defun trace--after-load (type value &optional buffer context)
|
||||
"Arrange to update traces after libraries are loaded.
|
||||
|
||||
TYPE is one of the symbols `prefix', `regexp', or `library';
|
||||
VALUE is the respective first argument to `trace-package',
|
||||
`trace-regexp', or `trace-library'; and BUFFER and CONTEXT are
|
||||
the values of those arguments as they were passed to the same
|
||||
function.
|
||||
|
||||
Adds `trace--after-load-function' to `after-load-functions'."
|
||||
;; Remove any existing spec for this (TYPE VALUE) key.
|
||||
(trace--remove-after-load type value)
|
||||
;; Add the new spec.
|
||||
(push (list (cons type value) buffer context)
|
||||
trace--after-load-alist)
|
||||
;; Arrange to call `trace--after-load-function'.
|
||||
(add-hook 'after-load-functions #'trace--after-load-function))
|
||||
|
||||
(defun trace--after-load-function (file)
|
||||
"React to FILE being loaded. Callback for `after-load-functions'.
|
||||
|
||||
See also `trace--after-load'."
|
||||
(dolist (spec trace--after-load-alist)
|
||||
(cl-destructuring-bind ((type . value) buffer context)
|
||||
spec
|
||||
(cl-case type
|
||||
(prefix (trace-package value nil buffer context))
|
||||
(regexp (trace-regexp value nil buffer context))
|
||||
(library (when (string-match (load-history-regexp value) file)
|
||||
(trace-library value nil buffer context)))))))
|
||||
|
||||
(defun trace--remove-after-load (type value)
|
||||
"Remove any (TYPE . VALUE) entry from `trace--after-load-alist'.
|
||||
|
||||
Remove `trace--after-load-function' from `after-load-functions'
|
||||
if it is no longer needed."
|
||||
(setq trace--after-load-alist
|
||||
(cl-delete (cons type value) trace--after-load-alist
|
||||
:key #'car :test #'equal))
|
||||
(unless trace--after-load-alist
|
||||
(remove-hook 'after-load-functions #'trace--after-load-function)))
|
||||
|
||||
(defun trace--remove-after-load-all ()
|
||||
"Reset `trace--after-load-alist'.
|
||||
Remove `trace--after-load-function' from `after-load-functions'"
|
||||
(setq trace--after-load-alist nil)
|
||||
(remove-hook 'after-load-functions #'trace--after-load-function))
|
||||
|
||||
(defun untrace-all ()
|
||||
"Untraces all currently traced functions."
|
||||
"Remove traces from all currently traced functions."
|
||||
(interactive)
|
||||
(mapatoms #'untrace-function))
|
||||
(mapatoms #'untrace-function)
|
||||
(trace--remove-after-load-all))
|
||||
|
||||
(provide 'trace)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue