aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2013-07-26 03:38:18 -0400
committerStefan Monnier2013-07-26 03:38:18 -0400
commit56ea72917a7a700e29cf6c115fd1cd75ad782e9e (patch)
tree1a9220717c6333b376d45ebc044ad8ed71cfda37
parentf6b1502430653fac080f76a08edd2eb690f92146 (diff)
downloademacs-56ea72917a7a700e29cf6c115fd1cd75ad782e9e.tar.gz
emacs-56ea72917a7a700e29cf6c115fd1cd75ad782e9e.zip
Add support for lexical variables to the debugger's `e' command.
* lisp/emacs-lisp/debug.el (debug): Don't let-bind the debugger-outer-* vars, except for debugger-outer-match-data. (debugger-frame-number): Move check for "on a function call" from callers into it. Add `skip-base' argument. (debugger-frame, debugger-frame-clear): Simplify accordingly. (debugger-env-macro): Only reset the state stored in non-variables, i.e. current-buffer and match-data. (debugger-eval-expression): Rewrite using backtrace-eval. * lisp/subr.el (internal--called-interactively-p--get-frame): Remove. (called-interactively-p): * lisp/emacs-lisp/edebug.el (edebug--called-interactively-skip): Use the new `base' arg of backtrace-frame instead. * src/eval.c (set_specpdl_old_value): New function. (unbind_to): Minor simplification. (get_backtrace_frame): New function. (Fbacktrace_frame): Use it. Add `base' argument. (backtrace_eval_unrewind, Fbacktrace_eval): New functions. (syms_of_eval): Export backtrace-eval. * src/xterm.c (x_focus_changed): Simplify.
-rw-r--r--etc/NEWS4
-rw-r--r--lisp/ChangeLog16
-rw-r--r--lisp/emacs-lisp/debug.el145
-rw-r--r--lisp/emacs-lisp/edebug.el2
-rw-r--r--lisp/subr.el18
-rw-r--r--src/ChangeLog10
-rw-r--r--src/eval.c169
-rw-r--r--src/xterm.c15
8 files changed, 212 insertions, 167 deletions
diff --git a/etc/NEWS b/etc/NEWS
index feb45f43348..c9805ab55ba 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -158,6 +158,10 @@ You can pick the name of the function and the variables with `C-x 4 a'.
158 158
159* Changes in Specialized Modes and Packages in Emacs 24.4 159* Changes in Specialized Modes and Packages in Emacs 24.4
160 160
161** The debugger's `e' command evaluates the code in the context at point.
162This includes using the lexical environment at point, which means that
163`e' now lets you access lexical variables as well.
164
161** `eshell' now supports visual subcommands and options 165** `eshell' now supports visual subcommands and options
162Eshell has been able to handle "visual" commands (interactive, 166Eshell has been able to handle "visual" commands (interactive,
163non-line oriented commands such as top that require display 167non-line oriented commands such as top that require display
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 79582ea560a..84919e634be 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,19 @@
12013-07-26 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 Add support for lexical variables to the debugger's `e' command.
4 * emacs-lisp/debug.el (debug): Don't let-bind the debugger-outer-*
5 vars, except for debugger-outer-match-data.
6 (debugger-frame-number): Move check for "on a function call" from
7 callers into it. Add `skip-base' argument.
8 (debugger-frame, debugger-frame-clear): Simplify accordingly.
9 (debugger-env-macro): Only reset the state stored in non-variables,
10 i.e. current-buffer and match-data.
11 (debugger-eval-expression): Rewrite using backtrace-eval.
12 * subr.el (internal--called-interactively-p--get-frame): Remove.
13 (called-interactively-p):
14 * emacs-lisp/edebug.el (edebug--called-interactively-skip): Use the new
15 `base' arg of backtrace-frame instead.
16
12013-07-26 Glenn Morris <rgm@gnu.org> 172013-07-26 Glenn Morris <rgm@gnu.org>
2 18
3 * align.el (align-regexp): Doc fix. (Bug#14857) 19 * align.el (align-regexp): Doc fix. (Bug#14857)
diff --git a/lisp/emacs-lisp/debug.el b/lisp/emacs-lisp/debug.el
index 0728e86d072..aee48eef668 100644
--- a/lisp/emacs-lisp/debug.el
+++ b/lisp/emacs-lisp/debug.el
@@ -102,22 +102,6 @@ The value used here is passed to `quit-restore-window'."
102This is to optimize `debugger-make-xrefs'.") 102This is to optimize `debugger-make-xrefs'.")
103 103
104(defvar debugger-outer-match-data) 104(defvar debugger-outer-match-data)
105(defvar debugger-outer-load-read-function)
106(defvar debugger-outer-overriding-local-map)
107(defvar debugger-outer-overriding-terminal-local-map)
108(defvar debugger-outer-track-mouse)
109(defvar debugger-outer-last-command)
110(defvar debugger-outer-this-command)
111(defvar debugger-outer-unread-command-events)
112(defvar debugger-outer-unread-post-input-method-events)
113(defvar debugger-outer-last-input-event)
114(defvar debugger-outer-last-command-event)
115(defvar debugger-outer-last-nonmenu-event)
116(defvar debugger-outer-last-event-frame)
117(defvar debugger-outer-standard-input)
118(defvar debugger-outer-standard-output)
119(defvar debugger-outer-inhibit-redisplay)
120(defvar debugger-outer-cursor-in-echo-area)
121(defvar debugger-will-be-back nil 105(defvar debugger-will-be-back nil
122 "Non-nil if we expect to get back in the debugger soon.") 106 "Non-nil if we expect to get back in the debugger soon.")
123 107
@@ -174,24 +158,6 @@ first will be printed into the backtrace buffer."
174 ;; Save the outer values of these vars for the `e' command 158 ;; Save the outer values of these vars for the `e' command
175 ;; before we replace the values. 159 ;; before we replace the values.
176 (debugger-outer-match-data (match-data)) 160 (debugger-outer-match-data (match-data))
177 (debugger-outer-load-read-function load-read-function)
178 (debugger-outer-overriding-local-map overriding-local-map)
179 (debugger-outer-overriding-terminal-local-map
180 overriding-terminal-local-map)
181 (debugger-outer-track-mouse track-mouse)
182 (debugger-outer-last-command last-command)
183 (debugger-outer-this-command this-command)
184 (debugger-outer-unread-command-events unread-command-events)
185 (debugger-outer-unread-post-input-method-events
186 unread-post-input-method-events)
187 (debugger-outer-last-input-event last-input-event)
188 (debugger-outer-last-command-event last-command-event)
189 (debugger-outer-last-nonmenu-event last-nonmenu-event)
190 (debugger-outer-last-event-frame last-event-frame)
191 (debugger-outer-standard-input standard-input)
192 (debugger-outer-standard-output standard-output)
193 (debugger-outer-inhibit-redisplay inhibit-redisplay)
194 (debugger-outer-cursor-in-echo-area cursor-in-echo-area)
195 (debugger-with-timeout-suspend (with-timeout-suspend))) 161 (debugger-with-timeout-suspend (with-timeout-suspend)))
196 ;; Set this instead of binding it, so that `q' 162 ;; Set this instead of binding it, so that `q'
197 ;; will not restore it. 163 ;; will not restore it.
@@ -294,26 +260,6 @@ first will be printed into the backtrace buffer."
294 (funcall (nth 0 debugger-previous-state)))))) 260 (funcall (nth 0 debugger-previous-state))))))
295 (with-timeout-unsuspend debugger-with-timeout-suspend) 261 (with-timeout-unsuspend debugger-with-timeout-suspend)
296 (set-match-data debugger-outer-match-data))) 262 (set-match-data debugger-outer-match-data)))
297 ;; Put into effect the modified values of these variables
298 ;; in case the user set them with the `e' command.
299 (setq load-read-function debugger-outer-load-read-function)
300 (setq overriding-local-map debugger-outer-overriding-local-map)
301 (setq overriding-terminal-local-map
302 debugger-outer-overriding-terminal-local-map)
303 (setq track-mouse debugger-outer-track-mouse)
304 (setq last-command debugger-outer-last-command)
305 (setq this-command debugger-outer-this-command)
306 (setq unread-command-events debugger-outer-unread-command-events)
307 (setq unread-post-input-method-events
308 debugger-outer-unread-post-input-method-events)
309 (setq last-input-event debugger-outer-last-input-event)
310 (setq last-command-event debugger-outer-last-command-event)
311 (setq last-nonmenu-event debugger-outer-last-nonmenu-event)
312 (setq last-event-frame debugger-outer-last-event-frame)
313 (setq standard-input debugger-outer-standard-input)
314 (setq standard-output debugger-outer-standard-output)
315 (setq inhibit-redisplay debugger-outer-inhibit-redisplay)
316 (setq cursor-in-echo-area debugger-outer-cursor-in-echo-area)
317 (setq debug-on-next-call debugger-step-after-exit) 263 (setq debug-on-next-call debugger-step-after-exit)
318 debugger-value))) 264 debugger-value)))
319 265
@@ -518,18 +464,21 @@ removes itself from that hook."
518 (setq debugger-jumping-flag nil) 464 (setq debugger-jumping-flag nil)
519 (remove-hook 'post-command-hook 'debugger-reenable)) 465 (remove-hook 'post-command-hook 'debugger-reenable))
520 466
521(defun debugger-frame-number () 467(defun debugger-frame-number (&optional skip-base)
522 "Return number of frames in backtrace before the one point points at." 468 "Return number of frames in backtrace before the one point points at."
523 (save-excursion 469 (save-excursion
524 (beginning-of-line) 470 (beginning-of-line)
471 (if (looking-at " *;;;\\|[a-z]")
472 (error "This line is not a function call"))
525 (let ((opoint (point)) 473 (let ((opoint (point))
526 (count 0)) 474 (count 0))
527 (while (not (eq (cadr (backtrace-frame count)) 'debug)) 475 (unless skip-base
528 (setq count (1+ count))) 476 (while (not (eq (cadr (backtrace-frame count)) 'debug))
529 ;; Skip debug--implement-debug-on-entry frame. 477 (setq count (1+ count)))
530 (when (eq 'debug--implement-debug-on-entry 478 ;; Skip debug--implement-debug-on-entry frame.
531 (cadr (backtrace-frame (1+ count)))) 479 (when (eq 'debug--implement-debug-on-entry
532 (setq count (+ 2 count))) 480 (cadr (backtrace-frame (1+ count))))
481 (setq count (+ 2 count))))
533 (goto-char (point-min)) 482 (goto-char (point-min))
534 (when (looking-at "Debugger entered--\\(Lisp error\\|returning value\\):") 483 (when (looking-at "Debugger entered--\\(Lisp error\\|returning value\\):")
535 (goto-char (match-end 0)) 484 (goto-char (match-end 0))
@@ -551,12 +500,8 @@ removes itself from that hook."
551 "Request entry to debugger when this frame exits. 500 "Request entry to debugger when this frame exits.
552Applies to the frame whose line point is on in the backtrace." 501Applies to the frame whose line point is on in the backtrace."
553 (interactive) 502 (interactive)
554 (save-excursion
555 (beginning-of-line)
556 (if (looking-at " *;;;\\|[a-z]")
557 (error "This line is not a function call")))
558 (beginning-of-line)
559 (backtrace-debug (debugger-frame-number) t) 503 (backtrace-debug (debugger-frame-number) t)
504 (beginning-of-line)
560 (if (= (following-char) ? ) 505 (if (= (following-char) ? )
561 (let ((inhibit-read-only t)) 506 (let ((inhibit-read-only t))
562 (delete-char 1) 507 (delete-char 1)
@@ -567,12 +512,8 @@ Applies to the frame whose line point is on in the backtrace."
567 "Do not enter debugger when this frame exits. 512 "Do not enter debugger when this frame exits.
568Applies to the frame whose line point is on in the backtrace." 513Applies to the frame whose line point is on in the backtrace."
569 (interactive) 514 (interactive)
570 (save-excursion
571 (beginning-of-line)
572 (if (looking-at " *;;;\\|[a-z]")
573 (error "This line is not a function call")))
574 (beginning-of-line)
575 (backtrace-debug (debugger-frame-number) nil) 515 (backtrace-debug (debugger-frame-number) nil)
516 (beginning-of-line)
576 (if (= (following-char) ?*) 517 (if (= (following-char) ?*)
577 (let ((inhibit-read-only t)) 518 (let ((inhibit-read-only t))
578 (delete-char 1) 519 (delete-char 1)
@@ -583,59 +524,33 @@ Applies to the frame whose line point is on in the backtrace."
583 "Run BODY in original environment." 524 "Run BODY in original environment."
584 (declare (indent 0)) 525 (declare (indent 0))
585 `(save-excursion 526 `(save-excursion
586 (if (null (buffer-name debugger-old-buffer)) 527 (if (null (buffer-live-p debugger-old-buffer))
587 ;; old buffer deleted 528 ;; old buffer deleted
588 (setq debugger-old-buffer (current-buffer))) 529 (setq debugger-old-buffer (current-buffer)))
589 (set-buffer debugger-old-buffer) 530 (set-buffer debugger-old-buffer)
590 (let ((load-read-function debugger-outer-load-read-function) 531 (set-match-data debugger-outer-match-data)
591 (overriding-terminal-local-map 532 (prog1
592 debugger-outer-overriding-terminal-local-map) 533 (progn ,@body)
593 (overriding-local-map debugger-outer-overriding-local-map) 534 (setq debugger-outer-match-data (match-data)))))
594 (track-mouse debugger-outer-track-mouse)
595 (last-command debugger-outer-last-command)
596 (this-command debugger-outer-this-command)
597 (unread-command-events debugger-outer-unread-command-events)
598 (unread-post-input-method-events
599 debugger-outer-unread-post-input-method-events)
600 (last-input-event debugger-outer-last-input-event)
601 (last-command-event debugger-outer-last-command-event)
602 (last-nonmenu-event debugger-outer-last-nonmenu-event)
603 (last-event-frame debugger-outer-last-event-frame)
604 (standard-input debugger-outer-standard-input)
605 (standard-output debugger-outer-standard-output)
606 (inhibit-redisplay debugger-outer-inhibit-redisplay)
607 (cursor-in-echo-area debugger-outer-cursor-in-echo-area))
608 (set-match-data debugger-outer-match-data)
609 (prog1
610 (progn ,@body)
611 (setq debugger-outer-match-data (match-data))
612 (setq debugger-outer-load-read-function load-read-function)
613 (setq debugger-outer-overriding-terminal-local-map
614 overriding-terminal-local-map)
615 (setq debugger-outer-overriding-local-map overriding-local-map)
616 (setq debugger-outer-track-mouse track-mouse)
617 (setq debugger-outer-last-command last-command)
618 (setq debugger-outer-this-command this-command)
619 (setq debugger-outer-unread-command-events unread-command-events)
620 (setq debugger-outer-unread-post-input-method-events
621 unread-post-input-method-events)
622 (setq debugger-outer-last-input-event last-input-event)
623 (setq debugger-outer-last-command-event last-command-event)
624 (setq debugger-outer-last-nonmenu-event last-nonmenu-event)
625 (setq debugger-outer-last-event-frame last-event-frame)
626 (setq debugger-outer-standard-input standard-input)
627 (setq debugger-outer-standard-output standard-output)
628 (setq debugger-outer-inhibit-redisplay inhibit-redisplay)
629 (setq debugger-outer-cursor-in-echo-area cursor-in-echo-area)
630 ))))
631 535
632(defun debugger-eval-expression (exp) 536(defun debugger-eval-expression (exp)
633 "Eval an expression, in an environment like that outside the debugger." 537 "Eval an expression, in an environment like that outside the debugger.
538The environment used is the one when entering the activation frame at point."
634 (interactive 539 (interactive
635 (list (read-from-minibuffer "Eval: " 540 (list (read-from-minibuffer "Eval: "
636 nil read-expression-map t 541 nil read-expression-map t
637 'read-expression-history))) 542 'read-expression-history)))
638 (debugger-env-macro (eval-expression exp))) 543 (let ((nframe (condition-case nil (1+ (debugger-frame-number 'skip-base))
544 (error 0))) ;; If on first line.
545 (base (if (eq 'debug--implement-debug-on-entry
546 (cadr (backtrace-frame 1 'debug)))
547 'debug--implement-debug-on-entry 'debug)))
548 (debugger-env-macro
549 (let ((val (backtrace-eval exp nframe base)))
550 (prog1
551 (prin1 val t)
552 (let ((str (eval-expression-print-format val)))
553 (if str (princ str t))))))))
639 554
640(defvar debugger-mode-map 555(defvar debugger-mode-map
641 (let ((map (make-keymap)) 556 (let ((map (make-keymap))
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el
index 36c72f3a3bd..7771c3adaa4 100644
--- a/lisp/emacs-lisp/edebug.el
+++ b/lisp/emacs-lisp/edebug.el
@@ -4268,7 +4268,7 @@ With prefix argument, make it a temporary breakpoint."
4268 (eq (nth 1 (nth 1 frame1)) '()) 4268 (eq (nth 1 (nth 1 frame1)) '())
4269 (eq (nth 1 frame2) 'edebug-enter)) 4269 (eq (nth 1 frame2) 'edebug-enter))
4270 ;; `edebug-enter' calls itself on its first invocation. 4270 ;; `edebug-enter' calls itself on its first invocation.
4271 (if (eq (nth 1 (internal--called-interactively-p--get-frame i)) 4271 (if (eq (nth 1 (backtrace-frame i 'called-interactively-p))
4272 'edebug-enter) 4272 'edebug-enter)
4273 2 1))) 4273 2 1)))
4274 4274
diff --git a/lisp/subr.el b/lisp/subr.el
index 7130639dbe5..3b85a9bedb0 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -4191,22 +4191,6 @@ I is the index of the frame after FRAME2. It should return nil
4191if those frames don't seem special and otherwise, it should return 4191if those frames don't seem special and otherwise, it should return
4192the number of frames to skip (minus 1).") 4192the number of frames to skip (minus 1).")
4193 4193
4194(defmacro internal--called-interactively-p--get-frame (n)
4195 ;; `sym' will hold a global variable, which will be used kind of like C's
4196 ;; "static" variables.
4197 (let ((sym (make-symbol "base-index")))
4198 `(progn
4199 (defvar ,sym)
4200 (unless (boundp ',sym)
4201 (let ((i 1))
4202 (while (not (eq (indirect-function (nth 1 (backtrace-frame i)) t)
4203 (indirect-function 'called-interactively-p)))
4204 (setq i (1+ i)))
4205 (setq ,sym i)))
4206 ;; (unless (eq (nth 1 (backtrace-frame ,sym)) 'called-interactively-p)
4207 ;; (error "called-interactively-p: %s is out-of-sync!" ,sym))
4208 (backtrace-frame (+ ,sym ,n)))))
4209
4210(defun called-interactively-p (&optional kind) 4194(defun called-interactively-p (&optional kind)
4211 "Return t if the containing function was called by `call-interactively'. 4195 "Return t if the containing function was called by `call-interactively'.
4212If KIND is `interactive', then only return t if the call was made 4196If KIND is `interactive', then only return t if the call was made
@@ -4241,7 +4225,7 @@ command is called from a keyboard macro?"
4241 (get-next-frame 4225 (get-next-frame
4242 (lambda () 4226 (lambda ()
4243 (setq frame nextframe) 4227 (setq frame nextframe)
4244 (setq nextframe (internal--called-interactively-p--get-frame i)) 4228 (setq nextframe (backtrace-frame i 'called-interactively-p))
4245 ;; (message "Frame %d = %S" i nextframe) 4229 ;; (message "Frame %d = %S" i nextframe)
4246 (setq i (1+ i))))) 4230 (setq i (1+ i)))))
4247 (funcall get-next-frame) ;; Get the first frame. 4231 (funcall get-next-frame) ;; Get the first frame.
diff --git a/src/ChangeLog b/src/ChangeLog
index 56fe20fda98..6542703adbb 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,13 @@
12013-07-26 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * eval.c (set_specpdl_old_value): New function.
4 (unbind_to): Minor simplification.
5 (get_backtrace_frame): New function.
6 (Fbacktrace_frame): Use it. Add `base' argument.
7 (backtrace_eval_unrewind, Fbacktrace_eval): New functions.
8 (syms_of_eval): Export backtrace-eval.
9 * xterm.c (x_focus_changed): Simplify.
10
12013-07-25 Paul Eggert <eggert@cs.ucla.edu> 112013-07-25 Paul Eggert <eggert@cs.ucla.edu>
2 12
3 * fileio.c (Finsert_file_contents): Avoid double-close (Bug#14936). 13 * fileio.c (Finsert_file_contents): Avoid double-close (Bug#14936).
diff --git a/src/eval.c b/src/eval.c
index 6cb2b7a92b8..e55a3b259e0 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -138,6 +138,13 @@ specpdl_old_value (union specbinding *pdl)
138 return pdl->let.old_value; 138 return pdl->let.old_value;
139} 139}
140 140
141static void
142set_specpdl_old_value (union specbinding *pdl, Lisp_Object val)
143{
144 eassert (pdl->kind >= SPECPDL_LET);
145 pdl->let.old_value = val;
146}
147
141static Lisp_Object 148static Lisp_Object
142specpdl_where (union specbinding *pdl) 149specpdl_where (union specbinding *pdl)
143{ 150{
@@ -3301,6 +3308,8 @@ unbind_to (ptrdiff_t count, Lisp_Object value)
3301 case SPECPDL_UNWIND_VOID: 3308 case SPECPDL_UNWIND_VOID:
3302 specpdl_ptr->unwind_void.func (); 3309 specpdl_ptr->unwind_void.func ();
3303 break; 3310 break;
3311 case SPECPDL_BACKTRACE:
3312 break;
3304 case SPECPDL_LET: 3313 case SPECPDL_LET:
3305 /* If variable has a trivial value (no forwarding), we can 3314 /* If variable has a trivial value (no forwarding), we can
3306 just set it. No need to check for constant symbols here, 3315 just set it. No need to check for constant symbols here,
@@ -3315,27 +3324,20 @@ unbind_to (ptrdiff_t count, Lisp_Object value)
3315 Fset_default (specpdl_symbol (specpdl_ptr), 3324 Fset_default (specpdl_symbol (specpdl_ptr),
3316 specpdl_old_value (specpdl_ptr)); 3325 specpdl_old_value (specpdl_ptr));
3317 break; 3326 break;
3318 case SPECPDL_BACKTRACE: 3327 case SPECPDL_LET_DEFAULT:
3328 Fset_default (specpdl_symbol (specpdl_ptr),
3329 specpdl_old_value (specpdl_ptr));
3319 break; 3330 break;
3320 case SPECPDL_LET_LOCAL: 3331 case SPECPDL_LET_LOCAL:
3321 case SPECPDL_LET_DEFAULT: 3332 {
3322 { /* If the symbol is a list, it is really (SYMBOL WHERE
3323 . CURRENT-BUFFER) where WHERE is either nil, a buffer, or a
3324 frame. If WHERE is a buffer or frame, this indicates we
3325 bound a variable that had a buffer-local or frame-local
3326 binding. WHERE nil means that the variable had the default
3327 value when it was bound. CURRENT-BUFFER is the buffer that
3328 was current when the variable was bound. */
3329 Lisp_Object symbol = specpdl_symbol (specpdl_ptr); 3333 Lisp_Object symbol = specpdl_symbol (specpdl_ptr);
3330 Lisp_Object where = specpdl_where (specpdl_ptr); 3334 Lisp_Object where = specpdl_where (specpdl_ptr);
3331 Lisp_Object old_value = specpdl_old_value (specpdl_ptr); 3335 Lisp_Object old_value = specpdl_old_value (specpdl_ptr);
3332 eassert (BUFFERP (where)); 3336 eassert (BUFFERP (where));
3333 3337
3334 if (specpdl_ptr->kind == SPECPDL_LET_DEFAULT)
3335 Fset_default (symbol, old_value);
3336 /* If this was a local binding, reset the value in the appropriate 3338 /* If this was a local binding, reset the value in the appropriate
3337 buffer, but only if that buffer's binding still exists. */ 3339 buffer, but only if that buffer's binding still exists. */
3338 else if (!NILP (Flocal_variable_p (symbol, where))) 3340 if (!NILP (Flocal_variable_p (symbol, where)))
3339 set_internal (symbol, old_value, where, 1); 3341 set_internal (symbol, old_value, where, 1);
3340 } 3342 }
3341 break; 3343 break;
@@ -3422,7 +3424,30 @@ Output stream used is value of `standard-output'. */)
3422 return Qnil; 3424 return Qnil;
3423} 3425}
3424 3426
3425DEFUN ("backtrace-frame", Fbacktrace_frame, Sbacktrace_frame, 1, 1, NULL, 3427union specbinding *
3428get_backtrace_frame (Lisp_Object nframes, Lisp_Object base)
3429{
3430 union specbinding *pdl = backtrace_top ();
3431 register EMACS_INT i;
3432
3433 CHECK_NATNUM (nframes);
3434
3435 if (!NILP (base))
3436 { /* Skip up to `base'. */
3437 base = Findirect_function (base, Qt);
3438 while (backtrace_p (pdl)
3439 && !EQ (base, Findirect_function (backtrace_function (pdl), Qt)))
3440 pdl = backtrace_next (pdl);
3441 }
3442
3443 /* Find the frame requested. */
3444 for (i = XFASTINT (nframes); i > 0 && backtrace_p (pdl); i--)
3445 pdl = backtrace_next (pdl);
3446
3447 return pdl;
3448}
3449
3450DEFUN ("backtrace-frame", Fbacktrace_frame, Sbacktrace_frame, 1, 2, NULL,
3426 doc: /* Return the function and arguments NFRAMES up from current execution point. 3451 doc: /* Return the function and arguments NFRAMES up from current execution point.
3427If that frame has not evaluated the arguments yet (or is a special form), 3452If that frame has not evaluated the arguments yet (or is a special form),
3428the value is (nil FUNCTION ARG-FORMS...). 3453the value is (nil FUNCTION ARG-FORMS...).
@@ -3431,17 +3456,12 @@ the value is (t FUNCTION ARG-VALUES...).
3431A &rest arg is represented as the tail of the list ARG-VALUES. 3456A &rest arg is represented as the tail of the list ARG-VALUES.
3432FUNCTION is whatever was supplied as car of evaluated list, 3457FUNCTION is whatever was supplied as car of evaluated list,
3433or a lambda expression for macro calls. 3458or a lambda expression for macro calls.
3434If NFRAMES is more than the number of frames, the value is nil. */) 3459If NFRAMES is more than the number of frames, the value is nil.
3435 (Lisp_Object nframes) 3460If BASE is non-nil, it should be a function and NFRAMES counts from its
3461nearest activation frame. */)
3462 (Lisp_Object nframes, Lisp_Object base)
3436{ 3463{
3437 union specbinding *pdl = backtrace_top (); 3464 union specbinding *pdl = get_backtrace_frame (nframes, base);
3438 register EMACS_INT i;
3439
3440 CHECK_NATNUM (nframes);
3441
3442 /* Find the frame requested. */
3443 for (i = 0; backtrace_p (pdl) && i < XFASTINT (nframes); i++)
3444 pdl = backtrace_next (pdl);
3445 3465
3446 if (!backtrace_p (pdl)) 3466 if (!backtrace_p (pdl))
3447 return Qnil; 3467 return Qnil;
@@ -3456,6 +3476,108 @@ If NFRAMES is more than the number of frames, the value is nil. */)
3456 } 3476 }
3457} 3477}
3458 3478
3479/* For backtrace-eval, we want to temporarily unwind the last few elements of
3480 the specpdl stack, and then rewind them. We store the pre-unwind values
3481 directly in the pre-existing specpdl elements (i.e. we swap the current
3482 value and the old value stored in the specpdl), kind of like the inplace
3483 pointer-reversal trick. As it turns out, the rewind does the same as the
3484 unwind, except it starts from the other end of the spepdl stack, so we use
3485 the same function for both unwind and rewind. */
3486void
3487backtrace_eval_unrewind (int distance)
3488{
3489 union specbinding *tmp = specpdl_ptr;
3490 int step = -1;
3491 if (distance < 0)
3492 { /* It's a rewind rather than unwind. */
3493 tmp += distance - 1;
3494 step = 1;
3495 distance = -distance;
3496 }
3497
3498 for (; distance > 0; distance--)
3499 {
3500 tmp += step;
3501 /* */
3502 switch (tmp->kind)
3503 {
3504 /* FIXME: Ideally we'd like to "temporarily unwind" (some of) those
3505 unwind_protect, but the problem is that we don't know how to
3506 rewind them afterwards. */
3507 case SPECPDL_UNWIND:
3508 case SPECPDL_UNWIND_PTR:
3509 case SPECPDL_UNWIND_INT:
3510 case SPECPDL_UNWIND_VOID:
3511 case SPECPDL_BACKTRACE:
3512 break;
3513 case SPECPDL_LET:
3514 /* If variable has a trivial value (no forwarding), we can
3515 just set it. No need to check for constant symbols here,
3516 since that was already done by specbind. */
3517 if (XSYMBOL (specpdl_symbol (tmp))->redirect
3518 == SYMBOL_PLAINVAL)
3519 {
3520 struct Lisp_Symbol *sym = XSYMBOL (specpdl_symbol (tmp));
3521 Lisp_Object old_value = specpdl_old_value (tmp);
3522 set_specpdl_old_value (tmp, SYMBOL_VAL (sym));
3523 SET_SYMBOL_VAL (sym, old_value);
3524 break;
3525 }
3526 else
3527 /* FALLTHROUGH!
3528 NOTE: we only ever come here if make_local_foo was used for
3529 the first time on this var within this let. */
3530 ;
3531 case SPECPDL_LET_DEFAULT:
3532 {
3533 Lisp_Object sym = specpdl_symbol (tmp);
3534 Lisp_Object old_value = specpdl_old_value (tmp);
3535 set_specpdl_old_value (tmp, Fdefault_value (sym));
3536 Fset_default (sym, old_value);
3537 }
3538 break;
3539 case SPECPDL_LET_LOCAL:
3540 {
3541 Lisp_Object symbol = specpdl_symbol (tmp);
3542 Lisp_Object where = specpdl_where (tmp);
3543 Lisp_Object old_value = specpdl_old_value (tmp);
3544 eassert (BUFFERP (where));
3545
3546 /* If this was a local binding, reset the value in the appropriate
3547 buffer, but only if that buffer's binding still exists. */
3548 if (!NILP (Flocal_variable_p (symbol, where)))
3549 {
3550 set_specpdl_old_value
3551 (tmp, Fbuffer_local_value (symbol, where));
3552 set_internal (symbol, old_value, where, 1);
3553 }
3554 }
3555 break;
3556 }
3557 }
3558}
3559
3560DEFUN ("backtrace-eval", Fbacktrace_eval, Sbacktrace_eval, 2, 3, NULL,
3561 doc: /* Evaluate EXP in the context of some activation frame.
3562NFRAMES and BASE specify the activation frame to use, as in `backtrace-frame'. */)
3563 (Lisp_Object exp, Lisp_Object nframes, Lisp_Object base)
3564{
3565 union specbinding *pdl = get_backtrace_frame (nframes, base);
3566 ptrdiff_t count = SPECPDL_INDEX ();
3567 ptrdiff_t distance = specpdl_ptr - pdl;
3568 eassert (distance >= 0);
3569
3570 if (!backtrace_p (pdl))
3571 error ("Activation frame not found!");
3572
3573 backtrace_eval_unrewind (distance);
3574 record_unwind_protect_int (backtrace_eval_unrewind, -distance);
3575
3576 /* Use eval_sub rather than Feval since the main motivation behind
3577 backtrace-eval is to be able to get/set the value of lexical variables
3578 from the debugger. */
3579 return unbind_to (count, eval_sub (exp));
3580}
3459 3581
3460void 3582void
3461mark_specpdl (void) 3583mark_specpdl (void)
@@ -3701,6 +3823,7 @@ alist of active lexical bindings. */);
3701 defsubr (&Sbacktrace_debug); 3823 defsubr (&Sbacktrace_debug);
3702 defsubr (&Sbacktrace); 3824 defsubr (&Sbacktrace);
3703 defsubr (&Sbacktrace_frame); 3825 defsubr (&Sbacktrace_frame);
3826 defsubr (&Sbacktrace_eval);
3704 defsubr (&Sspecial_variable_p); 3827 defsubr (&Sspecial_variable_p);
3705 defsubr (&Sfunctionp); 3828 defsubr (&Sfunctionp);
3706} 3829}
diff --git a/src/xterm.c b/src/xterm.c
index 74e495e5645..b3534871da9 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -3435,17 +3435,10 @@ x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct fra
3435 /* Don't stop displaying the initial startup message 3435 /* Don't stop displaying the initial startup message
3436 for a switch-frame event we don't need. */ 3436 for a switch-frame event we don't need. */
3437 /* When run as a daemon, Vterminal_frame is always NIL. */ 3437 /* When run as a daemon, Vterminal_frame is always NIL. */
3438 if ((NILP (Vterminal_frame) || EQ (Fdaemonp(), Qt)) 3438 bufp->arg = (((NILP (Vterminal_frame) || EQ (Fdaemonp (), Qt))
3439 && CONSP (Vframe_list) 3439 && CONSP (Vframe_list)
3440 && !NILP (XCDR (Vframe_list))) 3440 && !NILP (XCDR (Vframe_list)))
3441 { 3441 ? Qt : Qnil);
3442 bufp->arg = Qt;
3443 }
3444 else
3445 {
3446 bufp->arg = Qnil;
3447 }
3448
3449 bufp->kind = FOCUS_IN_EVENT; 3442 bufp->kind = FOCUS_IN_EVENT;
3450 XSETFRAME (bufp->frame_or_window, frame); 3443 XSETFRAME (bufp->frame_or_window, frame);
3451 } 3444 }