Commit f345395c authored by Helmut Eller's avatar Helmut Eller Committed by Stefan Monnier
Browse files

* lisp/emacs-lisp/debug.el (debugger-toggle-locals): New command.

(debugger-mode-map): Bind it.
(debugger--backtrace-base): New function.
(debugger-eval-expression): Use it.
(debugger-frame-number): Skip local vars when present.
(debugger--locals-visible-p, debugger--insert-locals)
(debugger--show-locals, debugger--hide-locals): New functions.
* src/eval.c (Fbacktrace__locals): New function.
(syms_of_eval): Defsubr it.
parent a8a15d9d
......@@ -247,6 +247,8 @@ You can pick the name of the function and the variables with `C-x 4 a'.
* Changes in Specialized Modes and Packages in Emacs 24.4
** The backtrace debugger can display local vars with `v'.
** prolog-use-smie has been removed, along with the non-SMIE indentation code.
** SMIE indentation can be customized via `smie-config'.
......
2013-12-02 Helmut Eller <eller.helmut@gmail.com>
* emacs-lisp/debug.el (debugger-toggle-locals): New command.
(debugger-mode-map): Bind it.
(debugger--backtrace-base): New function.
(debugger-eval-expression): Use it.
(debugger-frame-number): Skip local vars when present.
(debugger--locals-visible-p, debugger--insert-locals)
(debugger--show-locals, debugger--hide-locals): New functions.
2013-12-02 Michael Albinus <michael.albinus@gmx.de>
* net/tramp-sh.el (tramp-remote-process-environment): Do not set
......
......@@ -494,9 +494,13 @@ removes itself from that hook."
(forward-line 1)
(while (progn
(forward-char 2)
(if (= (following-char) ?\()
(forward-sexp 1)
(forward-sexp 2))
(cond ((debugger--locals-visible-p)
(goto-char (next-single-char-property-change
(point) 'locals-visible)))
((= (following-char) ?\()
(forward-sexp 1))
(t
(forward-sexp 2)))
(forward-line 1)
(<= (point) opoint))
(if (looking-at " *;;;")
......@@ -541,6 +545,14 @@ Applies to the frame whose line point is on in the backtrace."
(progn ,@body)
(setq debugger-outer-match-data (match-data)))))
(defun debugger--backtrace-base ()
"Return the function name that marks the top of the backtrace.
See `backtrace-frame'."
(cond ((eq 'debug--implement-debug-on-entry
(cadr (backtrace-frame 1 'debug)))
'debug--implement-debug-on-entry)
(t 'debug)))
(defun debugger-eval-expression (exp &optional nframe)
"Eval an expression, in an environment like that outside the debugger.
The environment used is the one when entering the activation frame at point."
......@@ -549,15 +561,70 @@ The environment used is the one when entering the activation frame at point."
(let ((nframe (or nframe
(condition-case nil (1+ (debugger-frame-number 'skip-base))
(error 0)))) ;; If on first line.
(base (if (eq 'debug--implement-debug-on-entry
(cadr (backtrace-frame 1 'debug)))
'debug--implement-debug-on-entry 'debug)))
(base (debugger--backtrace-base)))
(debugger-env-macro
(let ((val (backtrace-eval exp nframe base)))
(prog1
(prin1 val t)
(let ((str (eval-expression-print-format val)))
(if str (princ str t))))))))
(defun debugger--locals-visible-p ()
"Are the local variables of the current stack frame visible?"
(save-excursion
(move-to-column 2)
(get-text-property (point) 'locals-visible)))
(defun debugger--insert-locals (locals)
"Insert the local variables LOCALS at point."
(cond ((null locals)
(insert "\n [no locals]"))
(t
(let ((print-escape-newlines t))
(dolist (s+v locals)
(let ((symbol (car s+v))
(value (cdr s+v)))
(insert "\n ")
(prin1 symbol (current-buffer))
(insert " = ")
(prin1 value (current-buffer))))))))
(defun debugger--show-locals ()
"For the frame at point, insert locals and add text properties."
(let* ((nframe (1+ (debugger-frame-number 'skip-base)))
(base (debugger--backtrace-base))
(locals (backtrace--locals nframe base))
(inhibit-read-only t))
(save-excursion
(let ((start (progn
(move-to-column 2)
(point))))
(end-of-line)
(debugger--insert-locals locals)
(add-text-properties start (point) '(locals-visible t))))))
(defun debugger--hide-locals ()
"Delete local variables and remove the text property."
(let* ((col (current-column))
(end (progn
(move-to-column 2)
(next-single-char-property-change (point) 'locals-visible)))
(start (previous-single-char-property-change end 'locals-visible))
(inhibit-read-only t))
(remove-text-properties start end '(locals-visible))
(goto-char start)
(end-of-line)
(delete-region (point) end)
(move-to-column col)))
(defun debugger-toggle-locals ()
"Show or hide local variables of the current stack frame."
(interactive)
(cond ((debugger--locals-visible-p)
(debugger--hide-locals))
(t
(debugger--show-locals))))
(defvar debugger-mode-map
(let ((map (make-keymap))
......@@ -575,6 +642,7 @@ The environment used is the one when entering the activation frame at point."
(define-key map "h" 'describe-mode)
(define-key map "q" 'top-level)
(define-key map "e" 'debugger-eval-expression)
(define-key map "v" 'debugger-toggle-locals) ;"v" is for "v"ariables.
(define-key map " " 'next-line)
(define-key map "R" 'debugger-record-expression)
(define-key map "\C-m" 'debug-help-follow)
......
2013-12-02 Helmut Eller <eller.helmut@gmail.com>
* eval.c (Fbacktrace__locals): New function.
(syms_of_eval): Defsubr it.
2013-12-02 Dmitry Antipov <dmantipov@yandex.ru>
* font.h (FONT_WIDTH, FONT_HEIGHT, FONT_BASE, FONT_DESCENT):
......
......@@ -3576,6 +3576,73 @@ NFRAMES and BASE specify the activation frame to use, as in `backtrace-frame'.
from the debugger. */
return unbind_to (count, eval_sub (exp));
}
DEFUN ("backtrace--locals", Fbacktrace__locals, Sbacktrace__locals, 1, 2, NULL,
doc: /* Return names and values of local variables of a stack frame.
NFRAMES and BASE specify the activation frame to use, as in `backtrace-frame'. */)
(Lisp_Object nframes, Lisp_Object base)
{
union specbinding *frame = get_backtrace_frame (nframes, base);
union specbinding *prevframe
= get_backtrace_frame (make_number (XFASTINT (nframes) - 1), base);
ptrdiff_t distance = specpdl_ptr - frame;
Lisp_Object result = Qnil;
eassert (distance >= 0);
if (!backtrace_p (prevframe))
error ("Activation frame not found!");
if (!backtrace_p (frame))
error ("Activation frame not found!");
/* The specpdl entries normally contain the symbol being bound along with its
`old_value', so it can be restored. The new value to which it is bound is
available in one of two places: either in the current value of the
variable (if it hasn't been rebount yet) or in the `old_value' slot of the
next specpdl entry for it.
`backtrace_eval_unrewind' happens to swap the role of `old_value'
and "new value", so we abuse it here, to fetch the new value.
It's ugly (we'd rather not modify global data) and a bit inefficient,
but it does the job for now. */
backtrace_eval_unrewind (distance);
/* Grab values. */
{
union specbinding *tmp = prevframe;
for (; tmp > frame; tmp--)
{
switch (tmp->kind)
{
case SPECPDL_LET:
case SPECPDL_LET_DEFAULT:
case SPECPDL_LET_LOCAL:
{
Lisp_Object sym = specpdl_symbol (tmp);
Lisp_Object val = specpdl_old_value (tmp);
if (EQ (sym, Qinternal_interpreter_environment))
{
Lisp_Object env = val;
for (; CONSP (env); env = XCDR (env))
{
Lisp_Object binding = XCAR (env);
if (CONSP (binding))
result = Fcons (Fcons (XCAR (binding),
XCDR (binding)),
result);
}
}
else
result = Fcons (Fcons (sym, val), result);
}
}
}
}
/* Restore values from specpdl to original place. */
backtrace_eval_unrewind (-distance);
return result;
}
void
mark_specpdl (void)
......@@ -3824,6 +3891,7 @@ alist of active lexical bindings. */);
defsubr (&Sbacktrace);
defsubr (&Sbacktrace_frame);
defsubr (&Sbacktrace_eval);
defsubr (&Sbacktrace__locals);
defsubr (&Sspecial_variable_p);
defsubr (&Sfunctionp);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment