From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: martin rudalics Newsgroups: gmane.emacs.bugs Subject: bug#32825: 27.0.50; Deterministic window management Date: Tue, 13 Nov 2018 10:12:23 +0100 Message-ID: <5BEA9577.1080204@gmx.at> References: <874leeaiah.fsf@mail.linkov.net> <5BDC0E38.5020901@gmx.at> <87d0rl7kl1.fsf@mail.linkov.net> <5BDEB6BA.5000307@gmx.at> <87y3a8jz6v.fsf@mail.linkov.net> <5BE00EB1.6090107@gmx.at> <87sh0fxkih.fsf@mail.linkov.net> <5BE154F5.4050902@gmx.at> <87r2fxsvl5.fsf@mail.linkov.net> <5BE2AF02.40909@gmx.at> <87sh0cva5h.fsf@mail.linkov.net> <5BE3F981.8000002@gmx.at> <8736sbmdtv.fsf@mail.linkov.net> <5BE54FBE.306@gmx.at> <874lcqmu6u.fsf@web.de> <5BE582D4.8010201@gmx.at> <874lcok62x.fsf@mail.linkov.net> <5BE7EE09.3020003@gmx.at> <87pnvbpejc.fsf@mail.linkov.net> <5BE93DB5.8070804@gmx.at> <87wophvpag.fsf@mail.linkov.net> <87efbprc1h.fsf@mail.linkov.net> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: quoted-printable X-Trace: blaine.gmane.org 1542100272 2992 195.159.176.226 (13 Nov 2018 09:11:12 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Tue, 13 Nov 2018 09:11:12 +0000 (UTC) Cc: Michael Heerdegen , 32825@debbugs.gnu.org To: Juri Linkov Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Tue Nov 13 10:11:07 2018 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1gMUiu-0000az-G4 for geb-bug-gnu-emacs@m.gmane.org; Tue, 13 Nov 2018 10:11:04 +0100 Original-Received: from localhost ([::1]:52787 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gMUl0-0005x4-Un for geb-bug-gnu-emacs@m.gmane.org; Tue, 13 Nov 2018 04:13:14 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:52822) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gMUks-0005wu-42 for bug-gnu-emacs@gnu.org; Tue, 13 Nov 2018 04:13:07 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gMUko-0000J2-3i for bug-gnu-emacs@gnu.org; Tue, 13 Nov 2018 04:13:06 -0500 Original-Received: from debbugs.gnu.org ([208.118.235.43]:44338) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1gMUkn-0000Iv-Sm for bug-gnu-emacs@gnu.org; Tue, 13 Nov 2018 04:13:01 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1gMUkn-0002m4-M1 for bug-gnu-emacs@gnu.org; Tue, 13 Nov 2018 04:13:01 -0500 X-Loop: help-debbugs@gnu.org Resent-From: martin rudalics Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 13 Nov 2018 09:13:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 32825 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: Original-Received: via spool by 32825-submit@debbugs.gnu.org id=B32825.154210036210636 (code B ref 32825); Tue, 13 Nov 2018 09:13:01 +0000 Original-Received: (at 32825) by debbugs.gnu.org; 13 Nov 2018 09:12:42 +0000 Original-Received: from localhost ([127.0.0.1]:48596 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1gMUkT-0002lT-PU for submit@debbugs.gnu.org; Tue, 13 Nov 2018 04:12:42 -0500 Original-Received: from mout.gmx.net ([212.227.15.19]:39151) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1gMUkR-0002lF-9h for 32825@debbugs.gnu.org; Tue, 13 Nov 2018 04:12:39 -0500 Original-Received: from [192.168.1.101] ([213.162.73.32]) by mail.gmx.com (mrgmx003 [212.227.17.190]) with ESMTPSA (Nemesis) id 0LlV71-1fnywL25dH-00bKbp; Tue, 13 Nov 2018 10:12:30 +0100 In-Reply-To: <87efbprc1h.fsf@mail.linkov.net> X-Provags-ID: V03:K1:iVfrB5DOiO2PENnTK6XZzt3eVaWTNBMlCZtBPXOUhuQMmUT1zXx 2f+dMtkHR99ESixVYf+NV5bb60eMxFHeyHaqr9sbKKNfyKNj3MVy4IqZWQ9NUTSZS21GLNc u9+4scSBJl62NYcRtLXUVWRbQDqFsOMKHYqoTS0MiM8a9oPYiQwDTB7YuO0cU2xkkeSfbF6 +rerLCjhpb+2kQtIyTI/w== X-UI-Out-Filterresults: notjunk:1;V01:K0:zbuG3kPMgQg=:H2ni6i0VG4p8gSSSos6Tiu lVnw3x7cXOp/1oYc1Tf6w4Svj8xROlAN3/aaXwNU+1WvDkoJcGpFTL3MN1Lt73HfMx/m+qTOc AcghmJghtntR7pStFbTTXmGqglSbOLBnXnd9CbttRLjp1ID47+mjEGkkMV+YUo6UV8UbUooZW 5MIEJt0KX9VMNhUB+1p3dzlw7wEQ+X5Ks3jVRyMAcOsN9WdbZICe26jRy0ThYnSDAqL7ZV8+a 6Jxl3DEagj6lrfgiUE3341+fNaSSfshaiBoIAByqELR69d6pxHzSfGyQxWhu9SmE3YL44tQAS vRlY2KCSTkS5RgUjFMt7ncxhNJD6Zmp3fBehZPPTgja15kVCEjnKRBEAiw72/n1+gGRr+SNqB CYmvh9cbVU8QhgeMzBHZqYB566CnSV6V5lqz0PCiHCXAHIXXzoLLyjeLrq2ElLqG8jXhVwGdw 6gohM4k8YjeDfaKEYYLmO80AQSM3tG5P3DCCiOxpKax02WA+8Re74derpQZlsPrZC1izC2Ylc KHUMQ0x78XxvH0TWvH7MXhRHVGtk1IRruGZ/MzyAQV14A2oHc/LQMRlSDhOIpZ/eyHxME6MSk oun1FpAn2Stf6LQwpNLH+izKXRm56UcVyKgs7v9jpeM4fkSxUVgQhpPZKYuYh6oPBPliwgaEU gLLkdD9nDl6LFWMmJHPG38ACg2ZYVckjDzNWCHXqcFw7V/DIrfOqvjfFy39kx6c/9c/xGA4kx 2m3499rLkKBRIGvYrMf35UELgsFV0cbBT7Jn8YYFvCfm3/gO1GGbOkk+hhjxGmeL4o6Hul68 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:152337 Archived-At: >> Maybe better to represent a list of prev/next buffers as a tree? >> Then inserting a new buffer inside it will create a leaf that >> can be ignored for navigation. An analogy of this is undo-tree. > > More precisely, navigating in the tree trunk and ignoring branches. Note that 'display-buffer-in-previous-window' doesn't care about the order in which a buffer appears in a window's previous buffers list. It only wants to know whether it's there and traversing a tree for that purpose looks like overkill. OTOH we would still have to decide what to do with a window's buffer when displaying another buffer in that window via 'display-buffer': Make it the first buffer we would want to switch to in the next 'switch-to-prev-buffer' call or make it insignificant (a leaf in your parlance). I currently tend to favor a solution like the below (we could also use the 'buffer-predicate' frame parameter for that purpose but that would affect 'other-buffer' as well, something I'd like to avoid). The solution below should behave as follows: Assume TAGS is shown in the selected window. Then doing 'switch-to-prev-buffer' followed by 'switch-to-next-buffer' there should get me back to TAGS. Doing =E2=80=98display-buffer=E2=80=99 there followed by 'switch-to-prev-buffer= ' should get me to the buffer shown there before TAGS. Then I could set the default of 'debugger-bury-or-kill' to 'append' and *Backtrace* would not show up accidentally via 'switch-to-prev-buffer' but still remain on the list of previous buffers so 'display-buffer-in-previous-window' will find it. WDYT? martin (defcustom switch-to-prev-buffer-skip-regexp "\\*Backtrace\\*\\|TAGS" "Regexp matching names of buffer `switch-to-prev-buffer' should skip. The default matches the *Backtrace* and the TAGS buffers." :type '(repeat (regexp :format "%v")) :group 'windows) (defun switch-to-prev-buffer (&optional window bury-or-kill) "In WINDOW switch to previous buffer. WINDOW must be a live window and defaults to the selected one. Return the buffer switched to, nil if no suitable buffer could be found. Optional argument BURY-OR-KILL non-nil means the buffer currently shown in WINDOW is about to be buried or killed and consequently shall not be switched to in future invocations of this command. As a special case, if BURY-OR-KILL equals `append', this means to move the buffer to the end of WINDOW's previous buffers list so a future invocation of `switch-to-prev-buffer' less likely switches to it." (interactive) (let* ((window (window-normalize-window window t)) (frame (window-frame window)) (window-side (window-parameter window 'window-side)) (old-buffer (window-buffer window)) ;; Save this since it's destroyed by `set-window-buffer'. (next-buffers (window-next-buffers window)) (pred (frame-parameter frame 'buffer-predicate)) entry new-buffer killed-buffers visible) (when (window-minibuffer-p window) ;; Don't switch in minibuffer window. (unless (setq window (minibuffer-selected-window)) (error "Window %s is a minibuffer window" window))) (unless (memq (window-dedicated-p window) '(nil side)) ;; Don't switch in dedicated window. (error "Window %s is dedicated to buffer %s" window old-buffer)) (catch 'found ;; Scan WINDOW's previous buffers first, skipping entries of next ;; buffers. (dolist (entry (window-prev-buffers window)) (when (and (setq new-buffer (car entry)) (or (buffer-live-p new-buffer) (not (setq killed-buffers (cons new-buffer killed-buffers)))) (not (eq new-buffer old-buffer)) (not (string-match-p switch-to-prev-buffer-skip-regexp (buffer-name new-buffer))) (or (null pred) (funcall pred new-buffer)) ;; When BURY-OR-KILL is nil, avoid switching to a ;; buffer in WINDOW's next buffers list. (or bury-or-kill (not (memq new-buffer next-buffers)))) (if (and (not switch-to-visible-buffer) (get-buffer-window new-buffer frame)) ;; Try to avoid showing a buffer visible in some other ;; window. (setq visible new-buffer) (set-window-buffer-start-and-point window new-buffer (nth 1 entry) (nth 2 entry)) (throw 'found t)))) ;; Scan reverted buffer list of WINDOW's frame next, skipping ;; entries of next buffers. Note that when we bury or kill a ;; buffer we don't reverse the global buffer list to avoid showing= ;; a buried buffer instead. Otherwise, we must reverse the global= ;; buffer list in order to make sure that switching to the ;; previous/next buffer traverse it in opposite directions. Skip ;; this step for side windows. (unless window-side (dolist (buffer (if bury-or-kill (buffer-list frame) (nreverse (buffer-list frame)))) (when (and (buffer-live-p buffer) (not (eq buffer old-buffer)) (not (string-match-p switch-to-prev-buffer-skip-regexp (buffer-name new-buffer))) (or (null pred) (funcall pred buffer)) (not (eq (aref (buffer-name buffer) 0) ?\s)) ;; Don't show a buffer shown in a side window befor= e. (not (buffer-local-value 'window--sides-shown buffe= r)) (or bury-or-kill (not (memq buffer next-buffers))))= (if (and (not switch-to-visible-buffer) (get-buffer-window buffer frame)) ;; Try to avoid showing a buffer visible in some other w= indow. (unless visible (setq visible buffer)) (setq new-buffer buffer) (set-window-buffer-start-and-point window new-buffer) (throw 'found t))))) (unless bury-or-kill ;; Scan reverted next buffers last (must not use nreverse ;; here!). (dolist (buffer (reverse next-buffers)) ;; Actually, buffer _must_ be live here since otherwise it ;; would have been caught in the scan of previous buffers. (when (and (or (buffer-live-p buffer) (not (setq killed-buffers (cons buffer killed-buffers)))) (not (eq buffer old-buffer)) (not (string-match-p switch-to-prev-buffer-skip-regexp (buffer-name new-buffer))) (or (null pred) (funcall pred buffer)) (setq entry (assq buffer (window-prev-buffers window)))) (setq new-buffer buffer) (set-window-buffer-start-and-point window new-buffer (nth 1 entry) (nth 2 entry)) (throw 'found t)))) ;; Show a buffer visible in another window. (when visible (setq new-buffer visible) (set-window-buffer-start-and-point window new-buffer))) (if bury-or-kill (let ((entry (and (eq bury-or-kill 'append) (assq old-buffer (window-prev-buffers window))))) ;; Remove `old-buffer' from WINDOW's previous and (restored list ;; of) next buffers. (set-window-prev-buffers window (assq-delete-all old-buffer (window-prev-buffers window))) (set-window-next-buffers window (delq old-buffer next-buffers)) (when entry ;; Append old-buffer's entry to list of WINDOW's previous ;; buffers so it's less likely to get switched to soon but ;; `display-buffer-in-previous-window' can nevertheless find ;; it. (set-window-prev-buffers window (append (window-prev-buffers window) (list entry))))) ;; Move `old-buffer' to head of WINDOW's restored list of next ;; buffers. (set-window-next-buffers window (cons old-buffer (delq old-buffer next-buffers)))) ;; Remove killed buffers from WINDOW's previous and next buffers. (when killed-buffers (dolist (buffer killed-buffers) (set-window-prev-buffers window (assq-delete-all buffer (window-prev-buffers window))) (set-window-next-buffers window (delq buffer (window-next-buffers window))))) ;; Return new-buffer. new-buffer))