From: Martin Rudalics Date: Sat, 8 Sep 2012 13:28:11 +0000 (+0200) Subject: Fix handling of debugger window. (Bug#8789) X-Git-Tag: emacs-24.2.90~365 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=fa2bcf435d9774c0e8542ba36b11ef4722f9675c;p=emacs.git Fix handling of debugger window. (Bug#8789) * window.el (display-buffer-in-previous-window): New buffer display action function. * emacs-lisp/debug.el (debugger-bury-or-kill): New option. (debugger-previous-window): New variable. (debug): Rewrite using display-buffer-in-previous-window, quit-restore-window and debugger-bury-or-kill. (Bug#8789) --- diff --git a/etc/NEWS b/etc/NEWS index 55b8388ca27..7a9c9a21c97 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -645,6 +645,8 @@ The interpretation of the DECLS is determined by `defun-declarations-alist'. ** New error type and new function `user-error'. Doesn't trigger the debugger. +** New option `debugger-bury-or-kill'. + +++ ** New utility function `buffer-narrowed-p'. @@ -653,20 +655,25 @@ The interpretation of the DECLS is determined by `defun-declarations-alist'. *** The functions get-lru-window, get-mru-window and get-largest-window now accept a third argument to avoid choosing the selected window. -*** New macro with-temp-buffer-window. +*** New macro `with-temp-buffer-window'. + +*** New option `temp-buffer-resize-frames'. -*** New option temp-buffer-resize-frames. +*** New function `fit-frame-to-buffer' and new option + `fit-frame-to-buffer-bottom-margin'. -*** New function fit-frame-to-buffer and new option - fit-frame-to-buffer-bottom-margin. +*** New display action functions `display-buffer-below-selected' and +`display-buffer-in-previous-window'. -*** New display action function display-buffer-below-selected. +*** New display action alist entry `inhibit-switch-frame', if non-nil, +tells display action functions to avoid changing which frame is +selected. -*** New display action alist `inhibit-switch-frame', if non-nil, tells -display action functions to avoid changing which frame is selected. +*** New display action alist entry `pop-up-frame-parameters', if +non-nil, specifies frame parameters to give any newly-created frame. -*** New display action alist `pop-up-frame-parameters', if non-nil, -specifies frame parameters to give any newly-created frame. +*** New display action alist entry `previous-window', if non-nil, +specifies window to reuse in `display-buffer-in-previous-window'. *** The following variables are obsolete, as they can be replaced by appropriate entries in the `display-buffer-alist' function introduced diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 052b85ef757..e10fe9166e7 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,13 @@ +2012-09-08 Martin Rudalics + + * window.el (display-buffer-in-previous-window): New buffer + display action function. + + * emacs-lisp/debug.el (debugger-bury-or-kill): New option. + (debugger-previous-window): New variable. + (debug): Rewrite using display-buffer-in-previous-window, + quit-restore-window and debugger-bury-or-kill. (Bug#8789) + 2012-09-07 Stefan Monnier * emacs-lisp/byte-run.el (defun): Tweak message. Simplify code. diff --git a/lisp/emacs-lisp/debug.el b/lisp/emacs-lisp/debug.el index 7bc93a19d1a..188c0800eb8 100644 --- a/lisp/emacs-lisp/debug.el +++ b/lisp/emacs-lisp/debug.el @@ -48,6 +48,39 @@ the middle is discarded, and just the beginning and end are displayed." :group 'debugger :version "21.1") +(defcustom debugger-bury-or-kill 'bury + "How to proceed with the debugger buffer when exiting `debug'. +The value used here affects the behavior of operations on any +window previously showing the debugger buffer. + +`nil' means that if its window is not deleted when exiting the + debugger, invoking `switch-to-prev-buffer' will usually show + the debugger buffer again. + +`append' means that if the window is not deleted, the debugger + buffer moves to the end of the window's previous buffers so + it's less likely that a future invocation of + `switch-to-prev-buffer' will switch to it. Also, it moves the + buffer to the end of the frame's buffer list. + +`bury' means that if the window is not deleted, its buffer is + removed from the window's list of previous buffers. Also, it + moves the buffer to the end of the frame's buffer list. This + value provides the most reliable remedy to not have + `switch-to-prev-buffer' switch to the debugger buffer again + without killing the buffer. + +`kill' means to kill the debugger buffer. + +The value used here is passed to `quit-restore-window'." + :type '(choice + (const :tag "Keep alive" nil) + (const :tag "Append" 'append) + (const :tag "Bury" 'bury) + (const :tag "Kill" 'kill)) + :group 'debugger + :version "24.2") + (defvar debug-function-list nil "List of functions currently set for debug on entry.") @@ -60,6 +93,9 @@ the middle is discarded, and just the beginning and end are displayed." (defvar debugger-old-buffer nil "This is the buffer that was current when the debugger was entered.") +(defvar debugger-previous-window nil + "This is the window last showing the debugger buffer.") + (defvar debugger-previous-backtrace nil "The contents of the previous backtrace (including text properties). This is to optimize `debugger-make-xrefs'.") @@ -133,7 +169,7 @@ first will be printed into the backtrace buffer." (with-current-buffer (get-buffer "*Backtrace*") (list major-mode (buffer-string))))) (debugger-buffer (get-buffer-create "*Backtrace*")) - (debugger-old-buffer (current-buffer)) + (debugger-window nil) (debugger-step-after-exit nil) (debugger-will-be-back nil) ;; Don't keep reading from an executing kbd macro! @@ -184,78 +220,63 @@ first will be printed into the backtrace buffer." (cursor-in-echo-area nil)) (unwind-protect (save-excursion - (save-window-excursion - (with-no-warnings - (setq unread-command-char -1)) - (when (eq (car debugger-args) 'debug) - ;; Skip the frames for backtrace-debug, byte-code, - ;; and implement-debug-on-entry. - (backtrace-debug 4 t) - ;; Place an extra debug-on-exit for macro's. - (when (eq 'lambda (car-safe (cadr (backtrace-frame 4)))) - (backtrace-debug 5 t))) - (pop-to-buffer debugger-buffer) - (debugger-mode) - (debugger-setup-buffer debugger-args) - (when noninteractive - ;; If the backtrace is long, save the beginning - ;; and the end, but discard the middle. - (when (> (count-lines (point-min) (point-max)) - debugger-batch-max-lines) - (goto-char (point-min)) - (forward-line (/ 2 debugger-batch-max-lines)) - (let ((middlestart (point))) - (goto-char (point-max)) - (forward-line (- (/ 2 debugger-batch-max-lines) - debugger-batch-max-lines)) - (delete-region middlestart (point))) - (insert "...\n")) + (with-no-warnings + (setq unread-command-char -1)) + (when (eq (car debugger-args) 'debug) + ;; Skip the frames for backtrace-debug, byte-code, + ;; and implement-debug-on-entry. + (backtrace-debug 4 t) + ;; Place an extra debug-on-exit for macro's. + (when (eq 'lambda (car-safe (cadr (backtrace-frame 4)))) + (backtrace-debug 5 t))) + (pop-to-buffer + debugger-buffer + `((display-buffer-reuse-window + display-buffer-in-previous-window) + . (,(when debugger-previous-window + `(previous-window . ,debugger-previous-window))))) + (setq debugger-window (selected-window)) + (setq debugger-previous-window debugger-window) + (debugger-mode) + (debugger-setup-buffer debugger-args) + (when noninteractive + ;; If the backtrace is long, save the beginning + ;; and the end, but discard the middle. + (when (> (count-lines (point-min) (point-max)) + debugger-batch-max-lines) (goto-char (point-min)) - (message "%s" (buffer-string)) - (kill-emacs -1)) + (forward-line (/ 2 debugger-batch-max-lines)) + (let ((middlestart (point))) + (goto-char (point-max)) + (forward-line (- (/ 2 debugger-batch-max-lines) + debugger-batch-max-lines)) + (delete-region middlestart (point))) + (insert "...\n")) + (goto-char (point-min)) + (message "%s" (buffer-string)) + (kill-emacs -1)) + (message "") + (let ((standard-output nil) + (buffer-read-only t)) (message "") - (let ((standard-output nil) - (buffer-read-only t)) - (message "") - ;; Make sure we unbind buffer-read-only in the right buffer. - (save-excursion - (recursive-edit))))) - ;; Kill or at least neuter the backtrace buffer, so that users - ;; don't try to execute debugger commands in an invalid context. - (if (get-buffer-window debugger-buffer 0) - ;; Still visible despite the save-window-excursion? Maybe it - ;; it's in a pop-up frame. It would be annoying to delete and - ;; recreate it every time the debugger stops, so instead we'll - ;; erase it (and maybe hide it) but keep it alive. - (with-current-buffer debugger-buffer - (with-selected-window (get-buffer-window debugger-buffer 0) - (when (and (window-dedicated-p (selected-window)) - (not debugger-will-be-back)) - ;; If the window is not dedicated, burying the buffer - ;; will mean that the frame created for it is left - ;; around showing some random buffer, and next time we - ;; pop to the debugger buffer we'll create yet - ;; another frame. - ;; If debugger-will-be-back is non-nil, the frame - ;; would need to be de-iconified anyway immediately - ;; after when we re-enter the debugger, so iconifying it - ;; here would cause flashing. - ;; Drew Adams is not happy with this: he wants to frame - ;; to be left at the top-level, still working on how - ;; best to do that. - (bury-buffer)))) - (unless debugger-previous-state - (kill-buffer debugger-buffer))) - ;; Restore the previous state of the debugger-buffer, in case we were - ;; in a recursive invocation of the debugger. - (when (buffer-live-p debugger-buffer) - (with-current-buffer debugger-buffer - (let ((inhibit-read-only t)) - (erase-buffer) - (if (null debugger-previous-state) - (fundamental-mode) - (insert (nth 1 debugger-previous-state)) - (funcall (nth 0 debugger-previous-state)))))) + ;; Make sure we unbind buffer-read-only in the right buffer. + (save-excursion + (recursive-edit)))) + (when (and (window-live-p debugger-window) + (eq (window-buffer debugger-window) debugger-buffer)) + ;; Unshow debugger-buffer. + (quit-restore-window debugger-window debugger-bury-or-kill)) + ;; Restore previous state of debugger-buffer in case we were + ;; in a recursive invocation of the debugger, otherwise just + ;; erase the buffer and put it into fundamental mode. + (when (buffer-live-p debugger-buffer) + (with-current-buffer debugger-buffer + (let ((inhibit-read-only t)) + (erase-buffer) + (if (null debugger-previous-state) + (fundamental-mode) + (insert (nth 1 debugger-previous-state)) + (funcall (nth 0 debugger-previous-state)))))) (with-timeout-unsuspend debugger-with-timeout-suspend) (set-match-data debugger-outer-match-data))) ;; Put into effect the modified values of these variables diff --git a/lisp/window.el b/lisp/window.el index 0e03268029c..b071a8e9c50 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -5521,6 +5521,62 @@ the selected one." (window--display-buffer buffer window 'reuse display-buffer-mark-dedicated))))) +(defun display-buffer-in-previous-window (buffer alist) + "Display BUFFER in a window previously showing it. +If ALIST has a non-nil `inhibit-same-window' entry, the selected +window is not eligible for reuse. + +If ALIST contains a `reusable-frames' entry, its value determines +which frames to search for a reusable window: + nil -- the selected frame (actually the last non-minibuffer frame) + A frame -- just that frame + `visible' -- all visible frames + 0 -- all frames on the current terminal + t -- all frames. + +If ALIST contains no `reusable-frames' entry, search just the +selected frame if `display-buffer-reuse-frames' and +`pop-up-frames' are both nil; search all frames on the current +terminal if either of those variables is non-nil. + +If ALIST has a `previous-window' entry, the window specified by +that entry will override any other window found by the methods +above, even if that window never showed BUFFER before." + (let* ((alist-entry (assq 'reusable-frames alist)) + (inhibit-same-window + (cdr (assq 'inhibit-same-window alist))) + (frames (cond + (alist-entry (cdr alist-entry)) + ((if (eq pop-up-frames 'graphic-only) + (display-graphic-p) + pop-up-frames) + 0) + (display-buffer-reuse-frames 0) + (t (last-nonminibuffer-frame)))) + entry best-window second-best-window window) + ;; Scan windows whether they have shown the buffer recently. + (catch 'best + (dolist (window (window-list-1 (frame-first-window) 'nomini frames)) + (when (and (assq buffer (window-prev-buffers window)) + (not (window-dedicated-p window))) + (if (eq window (selected-window)) + (unless inhibit-same-window + (setq second-best-window window)) + (setq best-window window) + (throw 'best t))))) + ;; When ALIST has a `previous-window' entry, that entry may override + ;; anything we found so far. + (when (and (setq window (cdr (assq 'previous-window alist))) + (window-live-p window) + (not (window-dedicated-p window))) + (if (eq window (selected-window)) + (unless inhibit-same-window + (setq second-best-window window)) + (setq best-window window))) + ;; Return best or second best window found. + (when (setq window (or best-window second-best-window)) + (window--display-buffer buffer window 'reuse)))) + (defun display-buffer-use-some-window (buffer alist) "Display BUFFER in an existing window. Search for a usable window, set that window to the buffer, and